1. 程式人生 > >深度學習第一課 線性迴歸

深度學習第一課 線性迴歸

最近在學習李沐的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物件