深度学习入门之线性模型和梯度下降
線性模型和梯度下降
這是神經網絡的第一課,我們會學習一個非常簡單的模型,線性回歸,同時也會學習一個優化算法-梯度下降法,對這個模型進行優化。線性回歸是監督學習里面一個非常簡單的模型,同時梯度下降也是深度學習中應用最廣的優化算法,我們將從這里開始我們的深度學習之旅。
一元線性回歸
一元線性模型非常簡單,假設我們有變量 xix_ixi? 和目標 yiy_iyi?,每個 i 對應于一個數據點,希望建立一個模型
y^i=wxi+b\hat{y}_i = w x_i + b y^?i?=wxi?+b
y^i\hat{y}_iy^?i? 是我們預測的結果,希望通過 y^i\hat{y}_iy^?i? 來擬合目標 yiy_iyi?,通俗來講就是找到這個函數擬合 yiy_iyi? 使得誤差最小,即最小化
1n∑i=1n(y^i?yi)2\frac{1}{n} \sum_{i=1}^n(\hat{y}_i - y_i)^2 n1?i=1∑n?(y^?i??yi?)2
那么如何最小化這個誤差呢?
這里需要用到梯度下降,這是我們接觸到的第一個優化算法,非常簡單,但是卻非常強大,在深度學習中被大量使用,所以讓我們從簡單的例子出發了解梯度下降法的原理
梯度下降法
在梯度下降法中,我們首先要明確梯度的概念,隨后我們再了解如何使用梯度進行下降。
梯度
梯度在數學上就是導數,如果是一個多元函數,那么梯度就是偏導數。比如一個函數f(x, y),那么 f 的梯度就是
(?f?x,?f?y)(\frac{\partial f}{\partial x},\ \frac{\partial f}{\partial y}) (?x?f?,??y?f?)
可以稱為 grad f(x, y) 或者 ?f(x,y)\nabla f(x, y)?f(x,y)。具體某一點 (x0,y0)(x_0,\ y_0)(x0?,?y0?) 的梯度就是 ?f(x0,y0)\nabla f(x_0,\ y_0)?f(x0?,?y0?)。
上面是原理部分,下面通過一個例子來進一步學習線性模型
import torch import numpy as np from torch.autograd import Variable import matplotlib.pyplot as plttorch.manual_seed(2017) # 讀入數據 x 和 y x_train = np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168],[9.779], [6.182], [7.59], [2.167], [7.042],[10.791], [5.313], [7.997], [3.1]], dtype=np.float32)y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573],[3.366], [2.596], [2.53], [1.221], [2.827],[3.465], [1.65], [2.904], [1.3]], dtype=np.float32)# 畫出圖像 plt.plot(x_train, y_train, 'bo') plt.show() # 轉換成 Tensor x_train = torch.from_numpy(x_train) y_train = torch.from_numpy(y_train)# 定義參數 w 和 b w = Variable(torch.randn(1), requires_grad=True) # 隨機初始化 b = Variable(torch.zeros(1), requires_grad=True) # 使用 0 進行初始化# 構建線性回歸模型 x_train = Variable(x_train) y_train = Variable(y_train)def linear_model(x):return x * w + by_ = linear_model(x_train) """ 經過上面的步驟我們就定義好了模型,在進行參數更新之前,我們可以先看看模型的輸出結果長什么樣 """ plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real') plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated') plt.legend() plt.show()思考:紅色的點表示預測值,似乎排列成一條直線,請思考一下這些點是否在一條直線上?
這個時候需要計算我們的誤差函數,也就是
1n∑i=1n(y^i?yi)2\frac{1}{n} \sum_{i=1}^n(\hat{y}_i - y_i)^2 n1?i=1∑n?(y^?i??yi?)2
# 計算誤差 def get_loss(y_, y):return torch.mean((y_ - y_train) ** 2)loss = get_loss(y_, y_train)# 打印一下看看 loss 的大小 print(loss)Variable containing:
153.3520
[torch.FloatTensor of size 1]
定義好了誤差函數,接下來我們需要計算 w 和 b 的梯度了,這時得益于 PyTorch 的自動求導,我們不需要手動去算梯度,有興趣的同學可以手動計算一下,w 和 b 的梯度分別是
??w=2n∑i=1nxi(wxi+b?yi)??b=2n∑i=1n(wxi+b?yi)\frac{\partial}{\partial w} = \frac{2}{n} \sum_{i=1}^n x_i(w x_i + b - y_i) \\ \frac{\partial}{\partial b} = \frac{2}{n} \sum_{i=1}^n (w x_i + b - y_i) ?w??=n2?i=1∑n?xi?(wxi?+b?yi?)?b??=n2?i=1∑n?(wxi?+b?yi?)
# 自動求導 loss.backward()# 查看w和b的梯度 print(w.grad) print(b.grad)# 更新一次參數 w.data = w.data - 1e-2 * w.grad.data b.data = b.data - 1e-2 * b.grad.data# 更新參數之后,再一次查看模型輸出的結果 y_ = linear_model(x_train) plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real') plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated') plt.legend() plt.show()從上面的例子可以看到,更新之后紅色的線跑到了藍色的線下面,沒有特別好的擬合藍色的真實值,所以我們需要在進行幾次更新
# 進行10次更新 for e in range(10):y_ = linear_model(x_train)loss = get_loss(y_, y_train)# 梯度歸0w.grad.zero_()b.grad.zero_()loss.backward()# 更新一次參數w.data = w.data - 1e-2 * w.grad.datab.data = b.data - 1e-2 * b.grad.dataprint('epoch {},loss {}'.format(e, loss.data))# 10次更新參數之后,再一次查看模型輸出的結果 y_ = linear_model(x_train) plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real') plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated') plt.legend() plt.show()經過 10 次更新,我們發現紅色的預測結果已經比較好的擬合了藍色的真實值。
多項式回歸模型
下面我們更進一步,講一講多項式回歸。什么是多項式回歸呢?非常簡單,根據上面的線性回歸模型
y^=wx+b\hat{y} = w x + b y^?=wx+b
這里是關于 x 的一個一次多項式,這個模型比較簡單,沒有辦法擬合比較復雜的模型,所以我們可以使用更高次的模型,比如
y^=w0+w1x+w2x2+w3x3+?\hat{y} = w_0 + w_1 x + w_2 x^2 + w_3 x^3 + \cdots y^?=w0?+w1?x+w2?x2+w3?x3+?
這樣就能夠擬合更加復雜的模型,這就是多項式模型,這里使用了 x 的更高次,同理還有多元回歸模型,形式也是一樣的,只是除了使用 x,還是更多的變量,比如 y、z 等等,同時他們的 loss 函數和簡單的線性回歸模型是一致的。
首先我們可以先定義一個需要擬合的目標函數,這個函數是個三次的多項式
# 定義一個多變量函數 w_target = np.array([0.5, 3, 2.4]) b_target = np.array([0.9])# 打印函數 f_des = 'y={:.2f}+{:.2f}*x+{:.2f}*x^2+{:.2f}*x^3' \.format(b_target[0], w_target[0], w_target[1], w_target[2]) print(f_des)y=0.90+0.50*x+3.00*x^2+2.40*x^3
我們可以先畫出這個多項式的圖像
x_sample = np.arange(-3., 3., 0.1) y_sample = b_target[0] + w_target[0] * x_sample + w_target[1] * x_sample ** 2 + w_target[2] * x_sample ** 3plt.plot(x_sample, y_sample, label='real curve') plt.show()接著我們可以構建數據集,需要 x 和 y,同時是一個三次多項式,所以我們取了 x,x2,x3x,\ x^2, x^3x,?x2,x3
# 構建數據 x 和 y # x 是一個如下矩陣 [x, x^2, x^3] # y 是函數的結果 [y]x_train = np.stack([x_sample ** i for i in range(1, 4)], axis=1) x_train = torch.from_numpy(x_train).float() # 轉換成 float tensory_train = torch.from_numpy(y_sample).float().unsqueeze(1) # 轉化成 float tensor接著我們可以定義需要優化的參數,就是前面這個函數里面的 wiw_iwi?
# 定義參數和模型 w = Variable(torch.randn(3, 1), requires_grad=True) b = Variable(torch.zeros(1), requires_grad=True)# 將 x 和 y 轉換成 Variable x_train = Variable(x_train) y_train = Variable(y_train)def multi_linear(x):return torch.mm(x, w) + b我們可以畫出沒有更新之前的模型和真實的模型之間的對比
# 畫出更新之前的模型 y_pred = multi_linear(x_train)plt.plot(x_train.data.numpy()[:, 0], y_pred.data.numpy(), label='fitting curve', color='r') plt.plot(x_train.data.numpy()[:, 0], y_sample, label='real curve', color='b') plt.legend()可以發現,這兩條曲線之間存在差異,我們計算一下他們之間的誤差
# 計算誤差,這里的誤差和一元的線性模型的誤差是相同的,前面已經定義過了 get_loss loss = get_loss(y_pred, y_train) print(loss)# 自動求導 loss.backward()# 查看梯度 print(w.grad) print(b.grad)# 更新一下參數 w.data = w.data - 0.001 * w.grad.data b.data = b.data - 0.001 * b.grad.data# 畫出更新一次之后的模型 y_pred = multi_linear(x_train)plt.plot(x_train.data.numpy()[:, 0], y_pred.data.numpy(), label='fitting curve', color='r') plt.plot(x_train.data.numpy()[:, 0], y_sample, label='real curve', color='b') plt.legend() plt.show()因為只更新了一次,所以兩條曲線之間的差異仍然存在,我們進行 100 次迭代
# 進行 100 次參數更新 for e in range(100):y_pred = multi_linear(x_train)loss = get_loss(y_pred, y_train)w.grad.data.zero_()b.grad.data.zero_()loss.backward()# 更新參數w.data = w.data - 0.001 * w.grad.datab.data = b.data - 0.001 * b.grad.dataif (e + 1) % 20 == 0:print('epoch {}, Loss: {:.5f}'.format(e+1, loss.data[0]))可以看到更新完成之后 loss 已經非常小了,我們畫出更新之后的曲線對比
# 畫出更新之后的結果 y_pred = multi_linear(x_train)plt.plot(x_train.data.numpy()[:, 0], y_pred.data.numpy(), label='fitting curve', color='r') plt.plot(x_train.data.numpy()[:, 0], y_sample, label='real curve', color='b') plt.legend()可以看到,經過 100 次更新之后,可以看到擬合的線和真實的線已經完全重合了
總結
以上是生活随笔為你收集整理的深度学习入门之线性模型和梯度下降的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Numpy:高性能科学计算和数据分析的基
- 下一篇: 浅谈如何学习深度学习(经验之谈,仅供参考