2020年10月16日 星期五

PyTorch學習後實作筆記

在接觸Deep Learning後,除了課堂上所學的TensorFlow
慢慢也會知道其它的工具,而最有名的一個就是PyTorch
本來光是學個TensorFlow就夠頭痛的
要再學其它的實在有點懶
不過推薦的人都說這pytorch比tensorflow簡單
好學,好用,好改
看著看著還蠻心動的

在接觸過以pytorch寫的yolov4工具時
以「不然就至少學點基礎吧」的心態下去接觸
第一時間就是看不太懂,覺得有點被騙了(哪有比較簡單)
感覺多寫了好多東西啊
最後是看了Python Programming上的教學影片後
才總算學了基礎
順便學英文

不過真的會了嗎?
想起以前學習時,有時總覺得應該懂了
寫試題時卻往往卡住
開頭會了,變化確不會,實在稱不上學會啦
那麼要知道會不會就是來一段實作啦
就以TensorFlow官方影片Intro to Machine Learning (ML Zero to Hero - Part 1)裡範例

改成pytorch的形式來驗證吧

這段code很簡單
就下面這幾行,功能就是用深度學習去推出xs與ys的關係式
from tensor import keras
import numpy as np

model = keras.Sequential([keras.layers.Dense(units=1, input_shape=[1])])
model.compile(optimizer='sgd', loss='mean_squared_error')

xs = np.array([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys = np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)
# ys = 2xs - 1

model.fit(xs, ys, epochs=500)

print(model.predict(10.0))

就把這段改成用pytorch寫
我們一段一段來
import torch
import torch.nn as nn
"""
依TensorFlow範例建立神經網路,以1層,1個輸入跟1個輸出的單層神經網路
model = keras.Sequential([keras.layers.Dense(units= 1, input_shape=[1])])"""
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.dense = nn.Linear(1, 1) #就建一層
        
    def forward(self,x):
        x = self.dense(x) #傳也是一層        
        return x
        
net =Net()
這段看來,確實多少了不少程式碼要寫
也是我一開始以為被騙了其中一部分
pytorch的作法是繼承nn.Module來建構類神經網路
並在初始化(__init__)時,指定有哪些層
然後在正向傳播(forward)函式中指定怎麼傳送這一層
另外激勵函數的指定,也是在forward中處理的
是比較複雜,但看懂了也沒什麼
就是像這樣寫
x = self.dense(x)
x = F.relu(x)
把網路層結果經過激勵函數再輸出

再來就是決定損失函數與優化器的部分
"""
依範例使用SGD當optimizer,損失函數用mean_squared_error
model.compile(optimizer='sgd', loss='mean_squared_error')
"""
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr= 0.001)

mseloss = nn.MSELoss()
沒有很複雜
而且說實話,其實pytorch的損失函數可以不用寫在這裡
在訓練時決定就好,當然優化器也是
只是這次照著tensorflow的範例來,照著寫而已

接著就是給訓練資料與標籤,這就沒什麼啦
"""
依原範例,給於兩組數列,一組輸入xs,一組輸出ys
xs = np.array([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0])
ys = np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0])
"""
xs = torch.Tensor([[-1.0], [0.0], [1.0], [2.0], [3.0], [4.0]])
ys = torch.Tensor([[-3.0], [-1.0], [1.0], [3.0], [5.0], [7.0]])

最後,開始訓練
"""
依原範例,用500個epochs來訓練
model.fit(xs, ys, epochs=500)
"""
EPOCHS = 500

#使用pytorch寫法
for epoch in range(EPOCHS):
    for i, x in enumerate(xs):
        #還不會建train的dataset
        #土法練鋼,用i定位y的輸出值
        y = ys[i] #從ys裡取得標籤y
        net.zero_grad() #梯度歸零
        output = net(x) #使用類神經網路預測
        loss = mseloss(output, y) #預測值與目標y計算損失函數
        loss.backward() #反向傳播
        optimizer.step() #優化器更新權重參數
    if epoch % 100 == 0:
        print(f"Loss: {loss}") #每100次顯示損失函數的值
相對於tensorflow的model.fit()
這邊真的是多寫了非常多
可是也詳細很多
就是標準的類神經網路處理流程
先將梯度歸零準備訓練
把輸入資料丟進類神經網路中計算
計算結果與標籤進行損失函數再次計算
依損失函數計算值反向傳播求導
並使用優化器進行權重更新
非常完整

訓練完成後,我們一樣想要計算的值丟入訓練好的模型
"""
print(model.predict([10.0,20.0]))
"""
print(net(torch.Tensor(10.0)))
可以得到近似於19的值
完成

理解完並實作這個範例後
Keras的運作確實還是最簡單的
但那是Keras,並不是TensorFlow
一直以來我並沒有學會TensorFlow,我只是學會Keras而已
如果要我棄用Keras直接用TensorFlow寫的話,我真的不會寫
但是PyTorch步驟雖較多,反而是完整的
它的基礎真的就是基礎,要再疊上去擴充改寫,是同一套東西
從這個意義來說,真的是比較簡單的
再來運作上完全符合理論上所教的那些
所以從理論上轉到實作上的計算,真的不難
有這兩大優點,難怪那麼多人推祟
我也跳槽好了 XD

1 則留言:

Unknown 提到...

I appreciate you taking the time and effort to share your knowledge. This material proved to be really efficient and beneficial to me. Thank you very much for providing this information. Continue to write your blog. 

Data Engineering Solutions

Data Analytics Solutions

Artificial Intelligence Solutions

Data Modernization Services