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