最近在学习李沐的Mxnet/Gluon深度学习的线性回归部分,线性回归是很基本的一种监督学习,分类问题。
以前学习完一遍吴恩达的《machine learning》,并把《机器学习实战》里面的主要代码都实现一遍,现在有点忘记了,正好开始深度学习,开始线性回归查缺补漏,MXnet框架其实比较小众,但这次学习主要是专注于算法的原理,框架只不过是工具。
这次温故而知新,现将需要的要点材料整理如下:
- 梯度下降可参考:https://www.cnblogs.com/pinard/p/5970503.html,小批量的随机梯度上升(下降)算法是对于整体样本的梯度上升(下降)算法与单个样本的随机梯度上升(下降)算法的折中,兼具了二者的优点。
在机器学习中的无约束优化算法,除了梯度下降以外,还有前面提到的最小二乘法,此外还有牛顿法和拟牛顿法。
梯度下降法和最小二乘法相比,梯度下降法需要选择步长,而最小二乘法不需要。梯度下降法是迭代求解,最小二乘法是计算解析解。如果样本量不算很大,且存在解析解,最小二乘法比起梯度下降法要有优势,计算速度很快。但是如果样本量很大,用最小二乘法由于需要求一个超级大的逆矩阵,这时就很难或者很慢才能求解解析解了,使用迭代的梯度下降法比较有优势。
梯度下降法和牛顿法/拟牛顿法相比,两者都是迭代求解,不过梯度下降法是梯度求解,而牛顿法/拟牛顿法是用二阶的海森矩阵的逆矩阵或伪逆矩阵求解。相对而言,使用牛顿法/拟牛顿法收敛更快。但是每次迭代的时间比梯度下降法长。
线性回归原理比较简单,如同《机器学习实战》中的例子是可以求导到w的数值解,但若对于比较复杂的情况,可能无法求导其数值解,需要进行梯度下降的方法来进行优化,主要分为以下几步,代码为使用MXnet框架下的线性回归手动实现:
- 读取数据
- 参数初始化
- 正向传播(计算yhat,定义loss等)
- 反向传播(求解梯度等)
- 模型训练(求解所需的w,b值)
- 进行预测(对data_test,预测yhat,并与真实值进行比较)
- 优化(调节超参数等)
import mxnet.ndarray as nd
from mxnet import autograd
import random
m = 1000
n = 2
true_w = [2, -3.4]
true_b = 4.2
features = nd.random.normal(scale = 1,shape = (m,n))
labels = true_w[0] * features[:,0] + true_w[1] * features[:,1] +true_b
labels += nd.random.normal(scale = 0.01,shape= labels.shape)
#读取数据
def data_iter(batch_size,features,labels):
m = len(features)
indice = list(range(m))
random.shuffle(indice) #直接改变indice
for i in range(0,m,batch_size):
j = nd.array(indice[i:min(i+batch_size,m)])
yield nd.take(features,j),nd.take(labels,j)
batch_size = 10
#for X,y in data_iter(batch_size,features,labels):
#print(X,y)
#break
#初始化参数
w = nd.random.normal(scale = 0.01,shape= (n,1))
b = nd.zeros(shape = (1,))
#分配求导所需空间
w.attach_grad()
b.attach_grad()
#正向传播与损失函数loss的定义
def net(X,w,b):
return nd.dot(X,w) + b
def loss(y_hat,y):
return (y_hat - y.reshape(y_hat.shape))**2/2
#反向传播求梯度
def sgd(params,lr,batch_size):
for param in params:
param[:] = param - lr * param.grad/batch_size
#模型训练
lr = 1
epochs = 3 #迭代次数
for epoch in range(epochs):
for X,y in data_iter(batch_size,features,labels):
with autograd.record():
l = loss(net(X,w,b),y)
l.backward()
sgd([w,b],lr,batch_size) #通过几次迭代,得到最终的[w,b]的预测值
train_l = loss(net(features,w,b),labels)#将上一步的到的预测值w,b代入公式中计算对于整体样本的loss
print('epoch %d , loss %f'%(epoch + 1 ,train_l.mean().asnumpy()))
print(true_w,w)
print(true_b,b)
这里记录几个模块函数:
1)MXnet中的求导功能autograd(),举个例子:
import mxnet.ndarray as nd
import mxnet.autograd as ag
x = nd.array([[2]])
z = nd.array([[4]])
x.attach_grad()
z.attach_grad()
with ag.record():
y = x ** 2 + z**3
y.backward()
print(x.grad,z.grad)
结果为:
2)random.shuffle():
3)nd.take():
其用法同np.take():
4)yield:
同return近似,但每次迭代从上个位置开始继续。
5)_, figs = plt.subplots(1, n, figsize=(15, 15))中的‘_’就是一个单纯的下划线,表示一个figure对象