本文分別用Numpy、Tensor、autograd來實現同一個機器學習任務,比較它們之間的異同及各自優缺點,從而加深大家對PyTorch的理解。
一、使用Numpy實現機器學習
首先,我們用最原始的Numpy實現有關回歸的一個機器學習任務,不用PyTorch中的包或類。
主要步驟包括:
- 首先,給出一個數組x,然後基於表達式y=3x2+2,加上一些噪音數據到達另一組數據y。
- 然後,構建一個機器學習模型,學習表達式y=wx2+b的兩個參數w、b。利用數組x,y的數據爲訓練數據。
- 最後,採用梯度梯度下降法,通過多次迭代,學習到w、b的值。
以下爲實戰環節的具體步驟:
1)導入需要的庫。
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
2)生成輸入數據x及目標數據y。
設置隨機數種子,即生成同一份數據,以便使用多種方法進行比較。
np.random.seed(666)
x = np.linspace(-1, 1, 100).reshape(100, 1)
y = 3 * np.power(x, 2) + 2 + 0.2 * np.random.rand(x.size).reshape(100, 1)
3)查看x、y數據分佈情況。
# 繪圖
plt.scatter(x,y)
plt.show()
4)初始化權重參數。
# 隨機初始化參數
w = np.random.rand(1,1)
b = np.random.rand(1,1)
5)訓練模型。
定義損失函數,假設批量大小爲100:
對損失函數求導:
利用梯度下降法學習參數,學習率爲lr。
用代碼實現上面這些表達式:
lr = 0.001 # 學習率
for i in range(800):
# 前向傳播
y_pred = np.power(x, 2) * w + b
# 定義損失函數
loss = 0.5 * (y_pred - y) ** 2
loss = loss.sum()
# 計算梯度
grad_w = np.sum((y_pred - y) * np.power(x, 2))
grad_b = np.sum(y_pred - y)
# 使用梯度下降法,是loss最小
w -= lr * grad_w
b -= lr * grad_b
6)可視化結果。
plt.plot(x, y_pred, 'r-', label='predict')
plt.scatter(x, y, color='blue', marker='o', label='true')
plt.xlim(-1, 1)
plt.ylim(2, 6)
plt.legend()
plt.show()
print(w, b)
[[2.99850472]] [[2.0989827]]
從結果看來,學習效果還是還是比較理想的。
二、使用Tensor及Antograd實現機器學習
上節可以說是純手工完成一個機器學習任務,數據用Numpy表示,梯度及學習是自己定義並構建學習模型。這種方法適合於比較簡單的情況,如果稍微複雜一些,代碼量將幾何級增加。那是否有更方便的方法呢?
本節我們將使用PyTorch的一個自動求導的包——antograd,利用這個包及對應的Tensor,便可利用自動反向傳播來求梯度,無須手工計算梯度。
以下爲實戰環節的具體步驟:
1)導入需要的庫。
import torch as t
from matplotlib import pyplot as plt
%matplotlib inline
2)生成訓練數據,並可視化數據分佈情況。
# 隨機種子
torch.manual_seed(666)
# 生成x座標數據,x爲tensor,需要把x的形狀裝換爲100×1
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)
# 生成y座標數據,y爲tensor,形狀爲100×1,另加上一些噪聲
y = 3 * x.pow(2) + 2 + 0.2 * torch.rand(x.size())
# 繪圖,把tensor數據轉換爲numpy數據
plt.scatter(x.numpy(), y.numpy())
plt.show()
3)初始化權重參數。
# 隨機初始化參數,參數w,b爲需要學習的,故需requires_grad=True
w = torch.randn(1, 1, dtype = torch.float, requires_grad=True)
b = torch.zeros(1, 1, dtype = torch.float, requires_grad=True)
4)訓練模型。
lr = 0.001 # 學習率
for i in range(800):
# 前向傳播
y_pred = x.pow(2).mm(w) + b
# 定義損失函數
loss = 0.5 * (y_pred - y) ** 2
loss = loss.sum()
# 自動計算梯度,梯度存放在grad屬性中
loss.backward()
# 手動更新參數,需要用torch.no_grad(),使上下文環境中切斷自動求導的計算
with torch.no_grad():
w -= lr * w.grad
b -= lr * b.grad
# 梯度清零
w.grad.zero_()
b.grad.zero_()
5)可視化訓練結果。
plt.plot(x.numpy(), y_pred.detach().numpy(), 'r-', label='predict') # predict
plt.scatter(x.numpy(), y.numpy(), color='blue', marker='o', label='true') # true data
plt.xlim(-1, 1)
plt.ylim(2, 6)
plt.legend()
plt.show()
print(w, b)
tensor([[2.9578]], requires_grad=True) tensor([[2.0990]], requires_grad=True)
這個結果與使用Numpy實現機器學習差不多。