网站域名空间地址,wordpress iis 404页面,网页设计尺寸参考表,做做同城网站好还是做垂直网站好这篇文章确实需要一定的数学基础#xff0c;第一次接触的小伙伴可以先看一下我示例演绎这个主题的前两篇文章#xff1a;
示例演绎机器学习中#xff08;深度学习#xff09;神经网络的数学基础——快速理解核心概念#xff08;一#xff09;#xff1a;
政安晨#…这篇文章确实需要一定的数学基础第一次接触的小伙伴可以先看一下我示例演绎这个主题的前两篇文章
示例演绎机器学习中深度学习神经网络的数学基础——快速理解核心概念一
政安晨示例演绎机器学习中深度学习神经网络的数学基础——快速理解核心概念一{两篇文章讲清楚}https://blog.csdn.net/snowdenkeke/article/details/136089968示例演绎机器学习中深度学习神经网络的数学基础——快速理解核心概念二
政安晨示例演绎机器学习中深度学习神经网络的数学基础——快速理解核心概念二{两篇文章讲清楚}https://blog.csdn.net/snowdenkeke/article/details/136090846 简述概念
在机器学习中神经网络是一种常用的模型用于解决各种问题如图像识别、自然语言处理等。神经网络通过一系列的神经元也称为节点组成的层次结构来模拟人脑的神经系统。
神经网络的训练过程可以看作是一个优化问题目标是找到最优的参数来最小化损失函数。为了实现这个目标梯度和导数是非常重要的概念。
梯度是损失函数对于参数的导数。在神经网络中我们使用梯度来更新参数以使损失函数最小化。通过计算损失函数对于每个参数的梯度我们可以确定应该如何调整参数的值以逐渐减少损失。
导数是函数在某一点的斜率或变化率。在神经网络中我们将损失函数视为参数的函数并计算其在参数点处的导数。这告诉我们在该点上损失函数是如何随参数的变化而变化的。
通过梯度和导数我们可以了解损失函数如何随参数的变化而变化并根据这些信息来调整参数的值以改善模型的性能。梯度下降是一种常用的优化算法它使用梯度的信息来逐步调整参数的值以最小化损失函数。
总结起来神经网络中的梯度和导数是用于优化模型的重要概念。它们提供了关于损失函数随参数变化的信息帮助我们调整参数的值以改善模型性能。
基于梯度的优化
如同咱们前面文章提到的对于咱们前面提到的深度学习中的模型而言每个神经网络层都对输入数据进行如下变换
output relu(dot(input, W) b)
这里W和b是张量均为该层的属性。它们被称为该层的权重weight或可训练参数trainable parameter分别对应属性kernel和bias。这些权重包含模型从训练数据中学到的信息。
咱们先大概了解一下
在机器学习中神经网络的kernel或称为kernel function指的是一种用于计算两个数据样本之间相似度的函数。这个函数会将输入的数据样本映射到一个高维特征空间并在该特征空间中计算两个样本之间的相似度或距离。通过定义适当的kernel函数可以处理非线性问题并且可以提高神经网络的表达能力和预测性能。常见的kernel函数有线性核函数、多项式核函数、高斯核函数等。这些kernel函数可以根据具体的问题和数据特征选择和定义。在神经网络中kernel函数通常用于支持向量机SVM和卷积神经网络CNN等模型中用于计算样本之间的相似度。
同时神经网络的bias偏差指的是模型在学习过程中对目标函数的预测的偏离程度。神经网络的bias项是模型的一个可学习参数用于调整模型的输出值。它通常被添加到神经网络的每一层的神经元上以调整模型的预测结果与真实值之间的偏差。bias可以理解为模型的预测的基准线它的值决定了模型对于不同类型数据的初始偏好。通过调整bias的值可以使模型更加适应不同类型的数据分布。
一开始这些权重矩阵取较小的随机值这一步叫作随机初始化random initialization。
当然W和b都是随机的relu(dot(input, W) b)不会得到任何有用的表示。虽然得到的表示没有意义但这是一个起点。下一步则是根据反馈信号逐步调节这些权重。这个逐步调节的过程叫作训练training也就是机器学习中的“学习”过程。
上述过程发生在一个训练循环training loop内其具体流程如下在一个循环中重复下列步骤直到损失值变得足够小
1) 抽取训练样本x和对应目标y_true组成的一个数据批量。
2) 在x上运行模型这一步叫作前向传播forward pass得到预测值y_pred。
3) 计算模型在这批数据上的损失值用于衡量y_pred和y_true之间的差距。
4) 更新模型的所有权重以略微减小模型在这批数据上的损失值。
最终得到的模型在训练数据上的损失值非常小即预测值y_pred与预期目标y_true之间的差距非常小模型已“学会”将输入映射到正确的目标虽然看起来很复杂但如果您将其简化为基本步骤那么会发现它变得非常简单。
第1步看起来很简单只是输入/输出I/O的代码。
第2步和第3步仅仅是应用了一些张量运算所以你完全可以利用咱们在前两篇文章里演绎的知识来实现这两步。
难点在于第4步更新模型的权重。对于模型的某个权重系数你怎么知道这个系数应该增大还是减小以及变化多少呢 一种简单的解决方案是
保持模型的其他权重不变只考虑某一个标量系数让其尝试不同的取值。
假设这个系数的初始值为0.3。
对一批数据做完前向传播后模型在这批数据上的损失值是0.5。
如果将这个系数改为0.35并重新运行前向传播那么损失值增大为0.6。
但如果将这个系数减小到0.25那么损失值减小为0.4。
在这个例子中将系数减小0.05似乎有助于让损失值最小化。
对于模型的所有系数都要重复这一过程。 但上述这种方法非常低效因为系数有很多通常有上千个有时甚至多达上百万个对每个系数都要计算两次前向传播计算代价很大。其实有一种更好的方法梯度下降法gradient descent。
梯度下降是驱动现代神经网络的优化方法其要点如下
我们的模型用到的所有函数比如dot或都以一种平滑、连续的方式对输入进行变换。
举个例子对于z x yy的微小变化只会导致z的微小变化如果你知道y的变化方向就可以推断出z的变化方向。
用数学语言来讲这些函数是可微differentiable的将这样的函数组合在一起得到的函数仍然是可微的尤其是将模型系数映射到模型在数据批量上损失值的函数也是可微的模型系数的微小变化将导致损失值发生可预测的微小变化。
我们可以用一个叫作梯度gradient的数学运算符来描述模型系数向不同方向移动时损失值如何变化计算出梯度就可以利用它来更新系数使损失值减小在一次更新中全部完成而不是一次更新一个系数。
咱们接下来更进一步来解释这个概念
导数
假设有一个光滑的连续函数f(x) y将一个数字x映射到另一个数字y。我们以下图所示的函数为例 由于函数是连续的因此x的微小变化只会导致y的微小变化——这就是函数连续性continuity的直观解释。假设x增加了一个很小的因子epsilon_x这导致y发生了很小的变化epsilon_y如下图所示 此外由于函数是光滑的意思是函数曲线没有任何突变的角度因此在某个点p附近
如果epsilon_x足够小就可以将f近似地看作斜率为a的线性函数
这样epsilon_y就等于a * epsilon_x。
f(x epsilon_x) y a * epsilon_x
显然只有在x足够接近p时这个线性近似才有效。
斜率a被称为f在p点的导数derivative。
·如果a为负那么说明x在p点附近的微增将导致f(x)减小如下图所示
·如果a为正那么x的微增将导致f(x)增大。
·此外a的绝对值导数大小表示这种增大或减小的速度。 对于每个可微函数f(x)可微的意思是“可以被求导”比如光滑的连续函数可以被求导都存在一个导数函数f(x)将x的值映射为f在该点局部线性近似的斜率。
例如cos(x)的导数是-sin(x)f(x) a * x的导数是f(x) a。
优化的目的就是找到使f(x)最小化的x值就此而言函数求导是一个非常强大的工具。如果你想将x改变一个很小的因子epsilon_x目的是将f(x)最小化并且你知道f的导数那么问题已经解决了导数描述的就是改变x后f(x)会如何变化。如果你想减小f(x)的值那么只需将x沿着导数的反方向移动一小步。
张量运算的导数梯度
上文提到的函数f是将一个标量值x映射为另一个标量值y你可以将函数绘制为二维平面上的一条曲线。
现在想象有一个函数将标量元组(x, y)映射为一个标量值z那么这是一个向量运算。你可以将它绘制为三维空间以x、y、z为坐标轴中的二维表面surface。同样你还可以想象以矩阵为输入的函数、以3阶张量为输入的函数等等。
导数这一概念可以应用于任意函数只要函数所对应的表面是连续且光滑的。张量运算或张量函数的导数叫作梯度gradient。梯度就是将导数这一概念推广到以张量为输入的函数。还记不记得对于一个标量函数来说导数是如何表示函数曲线的局部斜率local slope的同样张量函数的梯度表示该函数所对应多维表面的曲率curvature。它表示的是当输入参数发生变化时函数输出如何变化。 咱们再举例。 假设我们有 一个输入向量x数据集中的一个样本 一个矩阵W模型权重 一个目标值y_true模型应该学到的与x相关的结果 一个损失函数loss用于衡量模型当前预测值与y_true之间的差距。 你可以用W来计算预测值y_pred然后计算损失值即预测值y_pred与目标值y_true之间的差距。
# 利用模型权重W对x进行预测
y_pred dot(W, x)# 估算预测值的偏差有多大
loss_value loss(y_pred, y_true)
现在我们想利用梯度来更新W以使loss_value变小。
如何做到这一点呢
如果输入数据x和y_true保持不变那么可以将前面的运算看作一个将模型权重W的值映射到损失值的函数。
# f描述的是当W变化时损失值所形成的曲线或高维表面
loss_value f(W)
假设W的当前值为W0f在W0点的导数是一个张量grad(loss_value, W0)其形状与W相同每个元素grad(loss_value, W0)[i, j]表示当W0[i, j]发生变化时loss_value变化的方向和大小。
张量grad(loss_value, W0)是函数f(W) loss_value在W0处的梯度也叫作“loss_value相对于W在W0附近的梯度”。
偏导数
张量运算grad(f(W), W)以矩阵W为输入它可以表示为标量函数grad_ij(f(W), w_ij)的组合每个标量函数返回的是loss_value f(W)相对于W[i, j]的导数假设W的其他所有元素都不变。grad_ij叫作f相对于W[i, j]的偏导数partial derivative。
grad(loss_value, W0)具体代表什么呢
我们在前面看到单变量函数f(x)的导数可以看作函数f曲线的斜率。同样grad(loss_value, W0)可以看作表示loss_value f(W)在W0附近最陡上升方向的张量也表示这一上升方向的斜率。每个偏导数表示f在某个方向上的斜率。
对于一个函数f(x)你可以通过将x沿着导数的反方向移动一小步来减小f(x)的值。同样对于一个张量函数f(W)你也可以通过将W沿着梯度的反方向移动来减小loss_value f(W)。
比如W1 W0 - step * grad(f(W0), W0)其中step是一个很小的比例因子。也就是说沿着f最陡上升的反方向移动直观上看可以移动到曲线上更低的位置。注意比例因子step是必需的因为grad(loss_value, W0)只是W0附近曲率的近似值所以不能离W0太远。
随机梯度下降
给定一个可微函数理论上可以用解析法找到它的最小值函数的最小值就是导数为0的点因此只需找到所有导数为0的点然后比较函数在其中哪个点的取值最小。
将这一方法应用于神经网络就是用解析法求出损失函数最小值对应的所有权重值。可以通过对方程grad(f(W), W) 0求解W来实现这一方法。这是一个包含N个变量的多项式方程其中N是模型的系数个数。当N 2或N 3时可以对这样的方程进行求解但对于实际的神经网络是无法求解的因为参数的个数不会少于几千个而且经常有上千万个。
不过你可以使用刚才开头总结的算法基于当前在随机数据批量上的损失值一点一点地对参数进行调节。
我们要处理的是一个可微函数所以可以计算出它的梯度从而有效地实现第4步沿着梯度的反方向更新权重每次损失值都会减小一点
刚才咱们提到的步骤
(1)抽取训练样本x和对应目标y_true组成的一个数据批量。
(2)在x上运行模型得到预测值y_pred。这一步叫作前向传播。
(3)计算模型在这批数据上的损失值用于衡量y_pred和y_true之间的差距。
(4)计算损失相对于模型参数的梯度。这一步叫作反向传播backward pass。
(5)将参数沿着梯度的反方向移动一小步比如W - learning_rate *gradient从而使这批数据上的损失值减小一些。学习率learning_rate是一个调节梯度下降“速度”的标量因子。
我们刚刚介绍的方法叫作小批量随机梯度下降mini-batch stochastic gradient descent简称小批量SGD。 接下里咱们用下图给出了一维的示例模型只有一个参数并且只有一个训练样本 如你所见直观上来看learning_rate因子的取值很重要
如果取值太小那么沿着曲线下降需要很多次迭代而且可能会陷入局部极小点。
如果取值过大那么更新权重值之后可能会出现在曲线上完全随机的位置。
注意小批量SGD算法的一个变体是每次迭代只抽取一个样本和目标而不是抽取一批数据。这叫作真SGDtrue SGD有别于小批量SGD。
还可以走向另一个极端每次迭代都在所有数据上运行这叫作批量梯度下降batch gradient descent。
这样做的话每次更新权重都会更加准确但计算成本也高得多。这两个极端之间有效的折中方法则是选择合理的小批量大小。
下图展示的是一维参数空间中的梯度下降但在实践中需要在高维空间中使用梯度下降。
神经网络的每一个权重系数都是空间中的一个自由维度神经网络则可能包含数万个甚至上百万个参数。为了对损失表面有更直观的认识你还可以将沿着二维损失表面的梯度下降可视化如下图所示
但你不可能将神经网络的真实训练过程可视化因为无法用人类可以理解的方式来可视化1 000 000维空间。因此最好记住在这些低维表示中建立的直觉实践中不一定总是准确的。这一直是深度学习研究的问题来源。 此外SGD还有多种变体比如带动量的SGD、Adagrad、RMSprop等。
它们的不同之处在于计算下一次权重更新时还要考虑上一次权重更新而不是仅考虑当前的梯度值这些变体被称为优化方法optimization method或优化器optimizer。动量的概念尤其值得关注它被用于许多变体动量解决了SGD的两个问题收敛速度和局部极小值。
下图给出了损失作为模型参数的函数的曲线 在某个参数值附近有一个局部极小点local minimum在这个点附近向左和向右移动都会导致损失值增大。
如果使用学习率较小的SGD对参数进行优化那么优化过程可能会陷入局部极小点而无法找到全局极小点。
使用动量方法可以避免这样的问题这一方法的灵感来源于物理学一个有用的思维模型是将优化过程想象成小球从损失函数曲线上滚下来如果小球的动量足够大那么它不会卡在峡谷里最终会到达全局极小点。动量方法的实现过程是每一步移动小球不仅要考虑当前的斜率值当前的加速度还要考虑当前的速度由之前的加速度产生。
这在实践中的含义是更新参数w不仅要考虑当前梯度值还要考虑上一次参数更新其简单实现如下
past_velocity 0.# 不变的动量因子
momentum 0.1# 优化循环
while loss 0.01:w, loss, gradient get_current_parameters()velocity past_velocity * momentum - learning_rate * gradientw w momentum * velocity - learning_rate * gradientpast_velocity velocityupdate_parameter(w)
链式求导反向传播算法
在前面的算法中我们假设函数是可微的所以很容易计算其梯度。
但这种假设是合理的吗
我们在实践中如何计算复杂表达式的梯度
对于咱们开头说到的双层模型我们如何计算出损失相对于权重的梯度这时就需要用到反向传播算法backpropagation algorithm。
链式法则
反向传播是这样一种方法利用简单运算如加法、relu或张量积的导数可以轻松计算出这些基本运算的任意复杂组合的梯度。重要的是神经网络由许多链接在一起的张量运算组成每个张量运算的导数都是已知的且都很简单。
例如
咱们上文给的代码定义的模型可以表示为一个由变量W1、b1、W2和b2分别属于第1个和第2个Dense层参数化的函数其中用到的基本运算是dot、relu、softmax和以及损失函数loss这些运算都是很容易求导的。
loss_value loss(y_true, softmax(dot(relu(dot(inputs, W1) b1), W2) b2))
根据微积分的知识这种函数链可以利用下面这个恒等式进行求导它叫作链式法则chain rule。
考虑两个函数f和g以及它们的复合函数fgfg(x) f(g(x))。
def fg(x):x1 g(x)y f(x1)return y
链式法则规定grad(y, x) grad(y, x1) * grad(x1, x)。因此只要知道f和g的导数就可以求出fg的导数如果添加更多的中间函数看起来就像是一条链因此得名链式法则。
def fghj(x):x1 j(x)x2 h(x1)x3 g(x2)y f(x3)return ygrad(y, x) (grad(y, x3) * grad(x3, x2) * grad(x2, x1) * grad(x1, x))
将链式法则应用于神经网络梯度值的计算就得到了一种叫作反向传播的算法。
咱们来具体看一下它的工作原理
用计算图进行自动微分
思考反向传播的一种有用方法是利用计算图compu- tation graph。计算图是TensorFlow和深度学习革命的核心数据结构。它是一种由运算比如我们用到的张量运算构成的有向无环图。
计算图是计算机科学中一个非常成功的抽象概念。
有了计算图我们可以将计算看作数据将可计算的表达式编码为机器可读的数据结构然后用于另一个程序的输入或输出。
例如你可以想象这样一个程序接收一个计算图作为输入并返回一个新的计算图新计算图可实现相同计算的大规模分布式版本。这意味着你可以对任意计算实现分布式而无须自己编写分布式逻辑。或者想象这样一个程序接收一个计算图作为输入然后自动计算它所对应表达式的导数。如果将计算表示为一个明确的图数据结构而不是.py文件中的几行ASCII字符那么做这些事情就容易多了。
如今人们利用能够自动微分的现代框架来实现神经网络比如TensorFlow。自动微分是利用刚才咱们所述的计算图来实现的。自动微分可以计算任意可微张量运算组合的梯度只需要写出前向传播而无须做任何额外工作。
ensorFlow的梯度带GradientTape是一个API让你可以充分利用TensorFlow强大的自动微分能力。它是一个Python作用域scope能够以计算图有时也被称为“条带”tape的形式“记录”在其中运行的张量运算。计算图可用来获取任意输出相对于任意变量或变量集的梯度这些变量或变量集都是tf.Variable类的实例tf.Variable是一类用于保存可变状态的张量比如神经网络的权重就是tf.Variable的实例。
import tensorflow as tf# 将标量Variable的值初始化为0
x tf.Variable(0.) #创建一个GradientTape作用域
with tf.GradientTape() as tape:# 在作用域内对变量做一些张量运算y 2 * x 3# 利用梯度带获取输出y相对于变量x的梯度
grad_of_y_wrt_x tape.gradient(y, x)
GradientTape也可用于张量运算
# 将Variable初始化为形状为(2, 2)的零张量
x tf.Variable(tf.zeros((2, 2)))with tf.GradientTape() as tape:y 2 * x 3# grad_of_y_wrt_x是一个形状为(2, 2)的张量形状与x相同表示y 2 * a 3在x [[0, 0], [0, 0]]附近的曲率
grad_of_y_wrt_x tape.gradient(y, x)
它还适用于变量列表
W tf.Variable(tf.random.uniform((2, 2)))
b tf.Variable(tf.zeros((2,)))
x tf.random.uniform((2, 2))
with tf.GradientTape() as tape:# 在TensorFlow中matmul是指点积y tf.matmul(x, W) b# grad_of_y_wrt_W_and_b是由两个张量组成的列表这两个张量的形状分别与W和b相同
grad_of_y_wrt_W_and_b tape.gradient(y, [W, b])
小结论
模型由许多层链接在一起组成并将输入数据映射为预测值。随后损失函数将这些预测值与目标值进行比较得到一个损失值用于衡量模型预测值与预期结果之间的匹配程度。优化器将利用这个损失值来更新模型权重。 这是那个比较清晰的神经网络、层、损失函数与优化器之间的关系。