深度学习第一课 线性回归

最近在学习李沐的Mxnet/Gluon深度学习的线性回归部分,线性回归是很基本的一种监督学习,分类问题。

以前学习完一遍吴恩达的《machine learning》,并把《机器学习实战》里面的主要代码都实现一遍,现在有点忘记了,正好开始深度学习,开始线性回归查缺补漏,MXnet框架其实比较小众,但这次学习主要是专注于算法的原理,框架只不过是工具。

这次温故而知新,现将需要的要点材料整理如下:

  • 梯度下降可参考:https://www.cnblogs.com/pinard/p/5970503.html,小批量的随机梯度上升(下降)算法是对于整体样本的梯度上升(下降)算法与单个样本的随机梯度上升(下降)算法的折中,兼具了二者的优点。

在机器学习中的无约束优化算法,除了梯度下降以外,还有前面提到的最小二乘法,此外还有牛顿法和拟牛顿法。

    梯度下降法和最小二乘法相比,梯度下降法需要选择步长,而最小二乘法不需要。梯度下降法是迭代求解,最小二乘法是计算解析解。如果样本量不算很大,且存在解析解,最小二乘法比起梯度下降法要有优势,计算速度很快。但是如果样本量很大,用最小二乘法由于需要求一个超级大的逆矩阵,这时就很难或者很慢才能求解解析解了,使用迭代的梯度下降法比较有优势。

    梯度下降法和牛顿法/拟牛顿法相比,两者都是迭代求解,不过梯度下降法是梯度求解,而牛顿法/拟牛顿法是用二阶的海森矩阵的逆矩阵或伪逆矩阵求解。相对而言,使用牛顿法/拟牛顿法收敛更快。但是每次迭代的时间比梯度下降法长。

线性回归原理比较简单,如同《机器学习实战》中的例子是可以求导到w的数值解,但若对于比较复杂的情况,可能无法求导其数值解,需要进行梯度下降的方法来进行优化,主要分为以下几步,代码为使用MXnet框架下的线性回归手动实现:

  1. 读取数据
  2. 参数初始化
  3. 正向传播(计算yhat,定义loss等)
  4. 反向传播(求解梯度等)
  5. 模型训练(求解所需的w,b值)
  6. 进行预测(对data_test,预测yhat,并与真实值进行比较)
  7. 优化(调节超参数等)
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对象

猜你喜欢

转载自blog.csdn.net/dake13/article/details/83019857