现代C++中的从头开始深度学习:【6/8】成本函数

现代C++中的从头开始深度学习:成本函数

一、说明

        在机器学习中,我们通常将问题建模为函数。因此,我们的大部分工作都包括寻找使用已知模型近似函数的方法。在这种情况下,成本函数起着核心作用。

        这个故事是我们之前关于卷积的讨论的续集。今天,我们将介绍成本函数的概念,展示常见示例并学习如何编码和绘制它们。与往常一样,从头开始纯C++和本征。

二、关于本系列

        在本系列中,我们将学习如何仅使用普通和现代C++对必须知道的深度学习算法进行编码,例如卷积、反向传播、激活函数、优化器、深度神经网络等。

这个故事是:C++中的成本函数

现代C++中的从头开始深度学习【3/8】:激活函数 

现代C++中的从头开始深度学习:【4/8】梯度下降 

现代C++中的从头开始深度学习:【5/8】卷积 

...更多内容即将推出。

三、机器学习中的建模

        作为人工智能工程师,我们通常将每个任务或问题定义为一个功能。

        例如,如果我们正在开发一个人脸识别系统,我们的第一步是将问题定义为将输入图像映射到标识符的函数:

        对于医疗诊断系统,我们可以定义一个函数来将症状映射到诊断:

        我们可以编写一个模型来提供给定单词序列的图像:

        这是一个无穷无尽的清单。使用函数来表示任务或问题是实现机器学习系统的简化方法。

问题往往是:如何知道 F() 公式?

四、近似函数

        事实上,使用公式或规则序列定义F(X)是不可行的(有一天我将解释原因)。

        一般来说,我们不是找到或定义正确的函数 F(X),而是尝试找到 F(X) 的近似值。 让我们通过假设函数来称这种近似,或者简单地称为H(X)。

        乍一看,这没有意义:如果我们需要找到近似函数 H(X),为什么我们不尝试直接找到 F(X)

        答案是:我们知道H(X)。虽然我们对F(X)知之甚少,但我们几乎知道H(X)的一切:它的公式,参数等。关于 H(X),我们唯一不知道的是它的参数值。

        事实上,机器学习的主要关注点是找到为给定问题和数据确定合适参数值的方法。让我们看看我们如何执行它。

在机器学习术语中,H(X)被称为“F(X)的近似值”。H(X)的存在被通用近似定理所涵盖。

五、成本函数和通用逼近定理

        考虑这样一种情况:我们知道输入的值和相应的输出,但我们不知道 的公式。例如,我们知道如果输入是,那么结果就是。XY = F(X)F(X)X = 1.0F(1.0)Y = 2.0

        4 X 和 F(X) 的映射

        现在,考虑我们有一个已知的函数,我们想知道是否是 的良好近似。因此,我们计算并找到.H(X)H(X)F(X)T = H(1.0)T = 1.9

        这个值有多糟糕,因为我们知道真正的值是什么时候?T = 1.9Y = 2.0X = 1.0

        用于量化 和 之间的差额的成本的指标由成本函数调用。YT

请注意,Y 是期望值,T 是我们猜测获得的实际值H(X)

成本函数的概念是机器学习的核心。让我们以最常见的成本函数为例。

六、均方误差

        最著名的成本函数是均方误差:

        其中 Ti 由核 k 对 Xi 的卷积给出:

我们在上一个故事中讨论了卷积

        请注意,我们有 n 对 (Yn, T n),每都是期望值 Yi 和实际值 Tn 的组合。例如:

        因此,MSE 的评估如下:

我们可以编写MSE的第一个版本,如下所示:

auto MSE = [](const std::vector<double> &Y_true, const std::vector<double> &Y_pred) {if (Y_true.empty()) throw std::invalid_argument("Y_true cannot be empty.");if (Y_true.size() != Y_pred.size()) throw std::invalid_argument("Y_true and Y_pred sizes do not match.");auto quadratic = [](const double a, const double b) {double result = a - b;return result * result;};const int N = Y_true.size();double acc = std::inner_product(Y_true.begin(), Y_true.end(), Y_pred.begin(), 0.0, std::plus<>(), quadratic);double result = acc / N;return result;
};

        现在我们知道了如何计算MSE,让我们看看如何使用它来近似函数。

七、使用MSE找到最佳参数的直觉

        假设我们有一个映射 F(X) 合成生成:

F(X) = 2*X + N(0, 0.1)

        其中 N(0, 0.1) 表示从正态分布中抽取的随机值,平均值 = 0,标准差 = 0.1。我们可以通过以下方式生成示例数据:

#include <random>std::default_random_engine dre(time(0));std::normal_distribution<double> gaussian_dist(0., 0.1);
std::uniform_real_distribution<double> uniform_dist(0., 1.);std::vector<std::pair<double, double>> sample(90);std::generate(sample.begin(), sample.end(), [&gaussian_dist, &uniform_dist]() {double x = uniform_dist(dre);double noise = gaussian_dist(dre);double y = 2. * x + noise;return std::make_pair(x, y);
});

        如果我们使用任何电子表格软件绘制此示例,我们会得到如下所示的内容:

        请注意,我们知道 G(X) 和 F(X) 的公式。然而,在现实生活中,这些生成器功能是潜在现象的未公开秘密。在这里,在我们的示例中,我们只知道它们,因为我们正在生成合成数据来帮助我们更好地理解。

        在现实生活中,我们所知道的一切都是一个假设,即由H(X)= kX定义的假设函数H(X)可能是F(X)的良好近似值。 当然,我们还不知道k的值是多少。

        让我们看看如何使用 MSE 找出合适的 k 值。事实上,它就像为一系列不同的 k 绘制 MSE 一样简单:

std::vector<std::pair<double, double>> measures;double smallest_mse = 1'000'000'000.;
double best_k = -1;
double step = 0.1;for (double k = 0.; k < 4.1; k += step) {std::vector<double> ts(sample.size());std::transform(sample.begin(), sample.end(), ts.begin(), [k](const auto &pair) {return pair.first * k;});double mse = MSE(ys, ts);if (mse < smallest_mse) {smallest_mse = mse;best_k = k;}measures.push_back(std::make_pair(k, mse));
}std::cout << "best k was " << best_k << " for a MSE of " << smallest_mse << "\n";

        很多时候,这个程序输出的东西是这样的:

        best k was 2.1 for a MSE of 0.00828671

        如果我们用k绘制MSE(k),我们可以看到一个非常有趣的事实:

        k 从 0 到 4,步长为 0.1

        请注意,MSE(k) 的值在 k = 2 附近最小。实际上,2 是泛型函数 G(X) = 2X 的参数。

        给定数据并使用 0.1 的步长,当 k = 2.1 时,可以找到较小的 MSE(k) 值。这表明 H(X) = 2.1 X 是 F(X) 的良好近似值。 事实上,如果我们绘制F(X)、G(X)和H(X),我们有:

        通过上面的图表,我们可以意识到H(X实际上近似于F(X)。不过,我们可以尝试使用较小的步长(如 0.01 或 0.001)来找到更好的近似值。

代码可以在此存储库中找到

八、成本表面

        MSE(k) 乘以 k 的曲线是成本曲面的一维示例。

MSE 曲线是一维曲面

        前面的示例显示的是,我们可以使用成本表面的最小值来找到参数 k 的最佳拟合值。

该示例描述了机器学习中最重要的范式:通过成本函数最小化的函数近似

        上图显示了一个一维成本曲面,即给定一维k的成本曲线。在二维空间中,即当我们有两个k,即k1k2时,成本面看起来更像一个实际曲面:

2D 成本表面

        无论 k 是 1D、2D 还是更高维,找到最佳第 k 个值的过程都是相同的:找到成本曲线的最小值。

最小成本值也称为全局最小值

        在 1D 空间中,查找全局最小值的过程相对容易。然而,在高维度上,扫描所有空间以找到最小值可能会产生计算成本。在下一个故事中,我们将介绍大规模执行此搜索的算法。

        不仅k可以是高维的。在实际问题中,输出通常也是高维的。让我们学习如何在这种情况下计算 MSE。

九、高维输出上的MSE

        在现实世界的问题中,Y 和 T 是向量或矩阵。让我们看看如何处理这样的数据。

        如果输出是一维的,则MSE的先前公式将起作用。但是如果输出是多维的,我们需要稍微改变一下公式。例如:

        在这种情况下,Yn 和 Tn 不是标量值,而是大小矩阵。在将 MSE 应用于此数据之前,我们需要更改公式,如下所示:(2,3)

        在此公式中,N 是对数,R 是行数,C 是每对中的列数。像往常一样,我们可以使用 lambda 实现此版本的 MSE:

#include <numeric>
#include <iostream>#include <Eigen/Core>using Eigen::MatrixXd;int main() 
{auto MSE = [](const std::vector<MatrixXd> &Y_true, const std::vector<MatrixXd> &Y_pred) {if (Y_true.empty()) throw std::invalid_argument("Y_true cannot be empty.");if (Y_true.size() != Y_pred.size()) throw std::invalid_argument("Y_true and Y_pred sizes do not match.");const int N = Y_true.size();const int R = Y_true[0].rows();const int C = Y_true[0].cols();auto quadratic = [](const MatrixXd a, const MatrixXd b) {MatrixXd result = a - b;return result.cwiseProduct(result).sum();};double acc = std::inner_product(Y_true.begin(), Y_true.end(), Y_pred.begin(), 0.0, std::plus<>(), quadratic);double result = acc / (N * R * C);return result;};std::vector<MatrixXd> A(4, MatrixXd::Zero(2, 3)); A[0] << 1., 2., 1., -3., 0, 2.;A[1] << 5., -1., 3., 1., 0.5, -1.5; A[2] << -2., -2., 1., 1., -1., 1.; A[3] << -2., 0., 1., -1., -1., 3.;std::vector<MatrixXd> B(4, MatrixXd::Zero(2, 3)); B[0] << 0.5, 2., 1., 1., 1., 2.; B[1] << 4., -2., 2.5, 0.5, 1.5, -2.; B[2] << -2.5, -2.8, 0., 1.5, -1.2, 1.8; B[3] << -3., 1., -1., -1., -1., 3.5;std::cout << "MSE: " << MSE(A, B) << "\n";return 0;
}

        值得注意的是,无论 k 或 Y 是多维的还是不是多维的,MSE 始终是一个标量值。

十、其他成本函数

        除了MSE,深度学习模型中也经常出现其他成本函数。最常见的是分类交叉熵、对数 cosh 和余弦相似性。

我们将在接下来的故事中介绍这些功能,特别是当我们介绍分类非线性推理时。

十一、结论和下一步

        成本函数是机器学习中最重要的主题之一。在这个故事中,我们学习了如何编写最常用的成本函数MSE代码,以及如何使用它来适应一维问题。我们还了解了为什么成本函数对于查找函数近似如此重要。

        在下一个故事中,我们将学习如何使用成本函数从数据中训练卷积核。我们将介绍拟合内核的基本算法,并讨论训练机制的实现,例如 epoch、停止条件和超参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/72589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OC和Swift混编,导入头文件‘xxx-Swift.h‘ file not found

在OC的项目里加入Swift代码&#xff0c;创建完桥接文件后&#xff0c;需要倒入Swift头文件&#xff0c;头文件的格式为“项目名-Swift.h”。 如下图&#xff0c;我在Xcode上看到我的项目名为YichangPark&#xff0c;导入 #import "YiChangPark-Swift.h" 之后提示 “Y…

喜报 | 再度中标南网项目!AR 开启电力远程运维新智慧

近日&#xff0c;中国南方电网官网发布《2023年南方电网数字平台科技 (广东)有限公司物资品控远程协助软件采购项目中标公告》&#xff0c;ALVA Systems 凭借 ALVA Rainbow 创新应用竞得此标。 随着相关技术的逐步成熟&#xff0c;基础问题远程化解决已经在工业领域广泛应用。 …

NLP(1)--NLP基础与自注意力机制

目录 一、词向量 1、概述 2、向量表示 二、词向量离散表示 1、one-hot 2、Bag of words 3、TF-IDF表示 4、Bi-gram和N-gram 三、词向量分布式表示 1、Skip-Gram表示 2、CBOW表示 四、RNN 五、Seq2Seq 六、自注意力机制 1、注意力机制和自注意力机制 2、单个输出…

同旺科技USB to I2C 适配器烧写 Arduino 模块

所需设备&#xff1a; 内附链接 1、同旺科技USB to I2C 适配器 2、Arduino 模块 硬件连接&#xff1a; 用同旺科技USB to I2C 适配器连接芯片的TX、RX、GND; 打开Arduino IDE编辑工具&#xff0c; 点击“上传”按钮&#xff0c;完成程序的编译和烧录&#xff1b;

基于微信小程序的自习室系统设计与实现,可作为毕业设计

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 需求分析3.1用户需求分析3.1.1 学生用户3.1.3 管理员用户 4 数据库设计4.4.1 E…

【数据结构】树的基础入门

文章目录 什么是树树的常见术语树的表示树的应用 什么是树 相信大家刚学数据结构的时候最先接触的就是顺序表,栈,队列等线性结构. 而树则是一种非线性存储结构,存储的是具有“一对多”关系的数据元素的集合 非线性 体现在它是由n个有限结点(可以是零个结点)组成一个具有层次关…

HarmonyOS/OpenHarmony(Stage模型)应用开发组合手势(二)并行识别

并行识别组合手势对应的GestureMode为Parallel。并行识别组合手势中注册的手势将同时进行识别&#xff0c;直到所有手势识别结束。并行识别手势组合中的手势进行识别时互不影响。 以在一个Column组件上绑定点击手势和双击手势组成的并行识别手势为例&#xff0c;由于单击手势和…

Apinto 网关 V0.14 版本发布,6 大插件更新!

大家好&#xff01; 距离上次更新已经过去一段时间了&#xff0c;这段日子里我们一直在酝酿新的功能&#xff0c;本次的迭代将给大家带来 6 大插件的更新~一起来看看有哪些变化吧&#xff01; 新特性 1. 新增 额外参数v2 插件&#xff0c;支持对转发参数进行加密、拼接等操作…

【软件测试】单元测试、集成测试、系统测试有什么区别?

单元测试、集成测试、系统测试有什么区别 1、粒度不同 集成测试bai粒度居中&#xff0c;单元测试粒度最小&#xff0c;系统du测试粒度最大。 2、测试方式不同 集成测试一般由开发zhi小组采用白盒加黑盒的方式来测试&#xff0c;单元测试一般由开发小组采用白盒方式来测试&a…

基于Python开发的玛丽大冒险小游戏(源码+可执行程序exe文件+程序配置说明书+程序使用说明书)

一、项目简介 本项目是一套基于Python开发的玛丽冒险小游戏程序&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含&#xff1a;项目源码、项目文档等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xf…

关于ChatGPT的个人的一些观点

问题 1 Q: 你认为ChatGPT是一款非常有用的工具吗&#xff1f; A: 我认为ChatGPT是一款非常有用的工具。它可以帮助人们解决各种问题&#xff0c;包括技术问题、心理问题、生活问题等等。同时&#xff0c;ChatGPT也可以成为人们分享想法和交流的平台&#xff0c;增强人与人之间…

chrome_elf.dll丢失怎么办?修复chrome_elf.dll文件的方法

Chrome是目前最受欢迎的网络浏览器之一&#xff0c;然而有时用户可能会遇到Chrome_elf.dll丢失的问题。该DLL文件是Chrome浏览器的一个重要组成部分&#xff0c;负责启动和管理程序的各种功能。当Chrome_elf.dll丢失时&#xff0c;用户可能无法正常启动Chrome或执行某些功能。本…

MySQL 如何避免 RC 隔离级别下的 INSERT 死锁?

本文分析了 INSERT 及其变种&#xff08;REPLACE/INSERT ON DUPLICATE KEY UPDATE&#xff09;的几个场景的死锁及如何避免。 作者&#xff1a;张洛丹&#xff0c;DBA 数据库技术爱好者~ 爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编…

Mysql存储过程与存储函数

文章目录 1. 简介2. 存储过程的特点3. 存储过程操作语法4. 存储过程变量5. 其它语法6. 存储函数 1. 简介 存储过程是事先经过编译并存储在数据库中的一段SQL集合&#xff0c;调用存储过程可以简化应用开发人员的很多工作&#xff0c;减少数据在数据库和应用服务器之间的传输&a…

vs2019 c++开发linux应用

VS2019 C的跨平台开发——Linux开发_Mr_L_Y的博客-CSDN博客前言由于前段时间正好买了一个服务器来跑Tensorflow的推理模型&#xff0c;所以借这个机会把Linux的开发也一并补上。先声明我的服务器是Ubuntu16.04&#xff0c;下面文章的内容也是基于Ubuntu16.04的。为什么标题要写…

MySQL——连接查询

2023.9.4 连接查询相关sql92语句笔记&#xff1a; #连接查询。 又称多表查询&#xff0c;当查询的字段来自多个表时&#xff0c;就会用到连接查询。 #等值连接 /* ①多表等值连接的结果为多表的交集部分 ②n表连接&#xff0c;至少需要n-1个连接条件 ③多表的顺序没有要求 ④一…

论文阅读《Nougat:Neural Optical Understanding for Academic Documents》

摘要 科学知识主要存储在书籍和科学期刊中&#xff0c;通常以PDF的形式。然而PDF格式会导致语义信息的损失&#xff0c;特别是对于数学表达式。我们提出了Nougat&#xff0c;这是一种视觉transformer模型&#xff0c;它执行OCR任务&#xff0c;用于将科学文档处理成标记语言&a…

数据结构之栈的实现(附源码)

目录 一、栈的概念及结构 ​二、栈的实现 三、初学栈的练习题 一、栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出…

JS数组迭代方法实操

数组迭代方法有 1. every() 2.some() 3.foreach() 4.map() 5.filter 逐一操作&#xff0c;并简要区分之。 1 every() every() 方法使用指定的函数测试数组中所有的项&#xff0c;在数组的所有项都满足该条件时&#xff0c;才返回true&#xff0c;否则返回false&#xff1b; …

Win10下使用vim9

作为一个经常与文字打交道的Writer&#xff0c;你在学会Vim的基本操作之后&#xff0c;就一定会爱上Vim的。 以下是Windows10_64位&#xff08;专业版&#xff09;环境中安装、使用Vim9的全过程&#xff0c;分享一下&#xff1a; 一、下载、安装Vim9 去Vim官网去下载最新的Vi…