MXNET的导数计算
import mxnet.ndarray as nd
import mxnet.autograd as ag
x = nd.array([[1, 2], [3, 4]])
x.attach_grad()
with ag.record():
y = x * 2
z = y * x
z.backward()
x.grad == 4*x
- x.attach_grad向系统申请x导数存放的空间;
- ag.record()显式地记录求导的方程;
- z.backward()对z进行求导;
- x.grad对z进行求x的偏导
利用梯度下降,逐次逼近结果
假设函数为凹形的,目标是寻找函数的最小值,则需要每次x的取值都使f(x)的值在减小直至取到最小值。
将函数按泰勒公式展开,可以得到当x每次更新为x=x-nf’(x)时,f(x)的值在逐渐减小。
要满足≈成立条件:
- 需要n做足够小;
- 函数f(x)的导数足够小
上面就是深度学习中,常用到的梯度下降的依据,其中n为学习率。
这个公式也可以解释:
- 为什么需要将学习率设为足够小,否则会产生不能拟合的情况?(因为学习率太大,随机梯度的依据点不满足。
- 为什么做归一化效果会好一些?(可以保证f(x)的导数小一些)
有上面的知识点做支撑,分析线性回归的部分训练程序
def square_loss(yhat, y):
# 注意这里我们把y变形成yhat的形状来避免矩阵形状的自动转换
return (yhat - y.reshape(yhat.shape)) ** 2
def SGD(params, lr):
for param in params:
param[:] = param - lr * param.grad
for data, label in data_iter():
with autograd.record():
output = net(data)
loss = square_loss(output, label)
loss.backward()
SGD(params, learning_rate)
- 首先,训练的目的是要求loss足够小,这样的问题就可以转换为梯度下降的问题,需要对loss求参数param的偏导;
- 然后,根据上述泰勒展开式的结论,通过SGD函数更新参数param,来使loss逐渐变小;
- 最后,用数据迭代器重复上述操作(随机梯度下降),再epoch多次全部数据。