专业编程基础技术教程

网站首页 > 基础教程 正文

梯度下降方法与求导 梯度下降求导过程

ccvgpt 2024-10-23 09:31:57 基础教程 10 ℃

前言

之前的文章多次提到了利用梯度下降的最优化方法,求一个已经确定好机器学习当中的4个关键部分的问题的最优解。比如对于房价预测的问题,1)对于输入的数字化表示,可以用包含房子面积,房子年份,等等的一个向量表示输入,2)对于输出则是房子的实际成交价格,3)对于输入到输出的映射方法,可以用Linear Regression,4)对于映射方法的评价标准,可以用Abs Criterion,也就是预测值和实际值的差值的绝对值。确定了这些内容,就可以利用梯度下降的最优化方法,对映射方法当中未知数进行求解,使映射达到一个最佳状态。工程师在平日的工作当中,并不能对梯度下降方法做什么变化,或者创新,研究领域对此有一些研究,但是还是属于少数。虽然如此,但是梯度下降最优化方法是机器学习当中重要的一个环节,对这个部分的充分理解,将有助于设计出更利用目标的,机器学习当中的4个关键部分,例如,在设计映射时,需要保证映射是可导的,这样才能用梯度下降的方法求解。

梯度下降方法与求导 梯度下降求导过程

理论

只要确定了机器学习当中的4个关键部分,就可以将

表示成,和输入,目标输出,映射相关的函数。其中输入和目标输出都是确定的数值,在大多数情况下,映射当中会有一些不确定的未知数,这些未知数可以通过最优化的方法求得,使得

尽可能小。

为了展示,这里将表示

的函数简化,

。其图形化表示如下,x轴方向代表

,y轴方向代表,

为了求得

的最优值,使

最小,从图中很容易看出来,

的最小值是,在当

的时候。简单说来,可以通过求

函数的导函数,在导数为0时,即为最小值的位置。但是在实际情况下,

的表达式非常复杂,包含有上百,上千个变量,在解导数为0的方程时复杂度很高,计算量很大。因此研究者发明了一种更利用计算机计算的求

为最小值时,

的值的方法。


对于

随机取一个值:比如

,此时

。我们知道

,此时

。这意味着,如果

增加一点点,

将增加一点点的6倍,反过来,

减少一点点,

也将减少一点点,这样就有办法,一步一步将

变小,从而求得使

最小

的值了。

这里设置一点点为,0.5。因为0.5比一点点要大很多,所以

的变化不会严格地是0.5 的 6 倍,但是对于我们的目标影响并不大。


第一步迭代:此时

第二次迭代:此时

第三次迭代:此时

...


这里更新

的方式是很简单,只根据导数的方向,如果导数是正的,则将

减小一点点,或者导数是负的,则将

增加一点点,这样子,慢慢接近想要的值,如果发现,对

进行变化,

变化不大,之类的,就可以停止迭代了。


Torch当中的计算模块

当前很多深度学习的库都内置了一些映射方法,还有映射方法的评价标准,其中函数计算,以求导的部分都有内部方法可以直接调用。这里以Lua Torch这个深度学习的计算框架为例,给出一些使用的例子。大部分深度学习库的设计都大同小异,大家在理解其它库时,也可以套用这里的思路,不过同时需要注意其细微的差别,例如Lua Torch vs Python Torch。

上图左边方框内是线性变换的模块,将二维变换到一维。右图是一个MSE Criterion求差值的平方的模块,用来计算线性变换这种映射的效果。

上图左边方框内是线性变换的模块,将二维变换到一维。右图是一个Abs Criterion求差值的绝对值的模块,用来计算线性变换这种映射的效果。圆圈代表的是变量,红色圆圈代表的是已知的数,这里以一个数量的例子作为代表,x1, x2 代表一个二维输入向量的两个元素,y表示目标的值10。绿色圆圈表示模块当中未知数,或者说可变的数。没有颜色的圆圈代表一些中间变量。方块表示一些操作,比如乘法,加法,减法,平方等等。这是一种形象地表示。


其Lua Torch相关的代码如下,

Forward方向,也就是计算函数的结果,下面的例子是一个线性变换的函数,Linear Regression当中使用到的

require 'nn';

l = nn.Linear(2, 1)
l.weight[1][1] = 1
l.weight[1][2] = 5
l.bias[1] = 3
a = torch.Tensor(2)
a[1] = 2
a[2] = 3
res = l:forward(a) --res = 2 * 1 + 3 * 5 + 3 = 20, 
print(res)
--will print 
--20
--[torch.DoubleTensor of size 1]


crit = nn.MSECriterion()
targets = torch.Tensor(1)
targets[1] = 10
cost = crit:forward(res, targets)
print(cost) --cost = (20 - 10) * (20 - 10) = 100
--will print
--100


Backward:

当前结果

对各个可变变量求导的导数,`nn.Linear` , `nn.MSECriterion`都有提供。

其原理如下,

通过数学当中的求导链式法则,可以得出

require 'nn';

l = nn.Linear(2, 1)
l.weight[1][1] = 1
l.weight[1][2] = 5
l.bias[1] = 3
a = torch.Tensor(2)
a[1] = 2
a[2] = 3
res = l:forward(a) --res = 2 * 1 + 3 * 5 + 3 = 20, 
print(res)
--will print 
--20
--[torch.DoubleTensor of size 1]


crit = nn.MSECriterion()
targets = torch.Tensor(1)
targets[1] = 10
cost = crit:forward(res, targets)
print(cost) --cost = (20 - 10) * (20 - 10) = 100
--will print
--100

backward1 = crit:backward(res, targets) 
print(backward1) -- 2 * (20 - 10) = 20
--will print
--20
--[torch.DoubleTensor of size 1]

backward2 = l:backward(a, backward1) -- 需要 d(cost) / d(y') 的结果,也就是2(y'-y)
print(l.gradWeight) -- dw1 = 20 * 2 = 40, dw2 = 20 * 3 = 60
--will print
--40  60
--[torch.DoubleTensor of size 1x2]

print(l.gradBias)  --db = 20
--will print
--20
--[torch.DoubleTensor of size 1]




Tags:

最近发表
标签列表