深度學習第一課 線性迴歸
最近在學習李沐的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物件