機器學習筆記(1):線性迴歸

菩提樹下的楊過發表於2017-10-31

初次接觸機器學習的朋友們,建議先把這篇概念性的科普文章,精讀5遍以上:神經網路淺講:從神經元到深度學習

下列程式碼來自 https://zh.gluon.ai/chapter_supervised-learning/linear-regression-scratch.html

裡面有大量的矩陣向量的操作,不熟悉NDArray的,建議先看上一篇mxnet安裝及NDArray初體驗

下面這個示例的思路,先講解一下,不然不知道它們在幹嘛:)

先給出一個線性方程(1),如下圖:

利用這個方程生成一堆資料集,然後再建立一個線性迴歸模型(2),如下圖:

等價於下面這樣:

(注:上圖中的b1 , b2 ... 其實相同)

再利用隨機梯度下降法,進行迭代運算,計算預測值yhat,直到下面的損失函式

不斷減小(即:收斂),然後看看這時得到的引數w(是一個向星)以及偏置值b是否跟線性方程中設定的引數[2, -3.4]以及4.2相同,如果很接近,說明我們用深度學習演算法,基於一堆資料成功預測出了想要的結果(即:線性迴歸成功),這種已知答案,利用一堆資料進行訓練的學習方法,也稱為有監督學習。

 1 from mxnet import ndarray as nd
 2 from mxnet import autograd
 3 import random
 4 
 5 num_inputs = 2
 6 num_examples = 1000
 7 
 8 true_w = [2, -3.4]
 9 true_b = 4.2
10 
11 X = nd.random_normal(shape=(num_examples, num_inputs)) #1000行,2列的資料集
12 y = true_w[0] * X[:, 0] + true_w[1] * X[:, 1] + true_b #已知答案的結果
13 y += .01 * nd.random_normal(shape=y.shape) #加入噪音
14 
15 batch_size = 10
16 def data_iter():
17     #產生一個隨機索引列表
18     idx = list(range(num_examples))
19     random.shuffle(idx)
20     for i in range(0, num_examples, batch_size):
21         j = nd.array(idx[i:min(i+batch_size,num_examples)])
22         yield nd.take(X, j), nd.take(y, j) #每次隨機從X中取出10行資料,以及對應的結果y值
23 
24 #初始化模型引數(即:需要求解的引數變數)
25 w = nd.random_normal(shape=(num_inputs, 1))
26 b = nd.zeros((1,))
27 params = [w, b]
28 
29 #建立梯度
30 for param in params:
31     param.attach_grad()
32     
33 #定義線性迴歸模型
34 def net(X):
35     return nd.dot(X, w) + b
36 
37 #定義損失函式
38 def square_loss(yhat, y):
39     # 注意這裡我們把y變形成yhat的形狀來避免自動廣播
40     return (yhat - y.reshape(yhat.shape)) ** 2
41 
42 #隨機梯度下降法
43 def SGD(params, lr):
44     for param in params:
45         param[:] = param - lr * param.grad
46         
47 
48 #訓練
49 epochs = 5
50 learning_rate = .001
51 for e in range(epochs):
52     total_loss = 0
53     for data, label in data_iter():
54         with autograd.record():
55             output = net(data)
56             loss = square_loss(output, label)
57         loss.backward()
58         SGD(params, learning_rate)
59 
60         total_loss += nd.sum(loss).asscalar()
61     print("Epoch %d, average loss: %f" % (e, total_loss/num_examples))
62 
63 print(true_w) #列印答案
64 print(w) #列印求解結果
65 
66 print(true_b) #列印答案
67 print(b) #列印求解結果
Epoch 0, average loss: 6.012281
Epoch 1, average loss: 0.102830
Epoch 2, average loss: 0.001909
Epoch 3, average loss: 0.000133
Epoch 4, average loss: 0.000101 #5次迭代後,已經快速收斂
[2, -3.4] #已知答案

[[ 2.00017834] #求解結果
 [-3.40006614]]
<NDArray 2x1 @cpu(0)>
4.2

[ 4.19863892]
<NDArray 1 @cpu(0)>

相關文章