上文介紹了TensorFlow和機器學習的關係,而機器學習其中最重要的部分就是模型,我們懂得製作和建立和訓練它,才算懂得機器學習和TensorFlow。這次的分享介紹如何使用Tensorflow製作和訓練一個簡單模型。
什麼是模型??
首先需要了解什麼是模型(Model),先節錄一些權威ML網站怎樣說:
NVIDA 連接
- A machine learning model is an expression of an algorithm that combs through mountains of data to find patterns or make predictions.
Coursera 連接
- Machine learning models are computer programs that are used to recognize patterns in data or make predictions.
微軟 (Microsoft) 連接
- 機器學習模型是已定型以辨識特定模式類型的檔案。 您可以使用一組資料來將模型定型,為其提供演算法,使其可用於透過那些資料進行推理,並從中學習。
簡單來說,模型就是:
一個程序,可以利用輸入數據進行推理(prediction)
可以透過數據進行學習(即是訓練模型)
包含一些算法(不同的ML模型,內部是基於不同算法)
ML模型不是只有一種;針對不同問題,他們有不同算法和類;例如目前最火熱的ChatGPT,他使用大型語言模型(LLM - Large Language Model),還有MidJourney (文字生圖的工具)使用穩定擴散模型(Stable Diffusion Model)。
而這篇文章會介紹最容易理解和實作的線性回歸模型 (Linear Regression Model)。
學習需求與準備
在進入以下內容之前, 先講解一些你需要準備什麼,才能一遍看一邊做。
文章的代碼,是使用Python3、TensorFlow、Numpy和Matplotlab進行開發:
你可以使用以下開發環境:
本機的Python和VS Code (其他IDE也可),並安裝以下Library
pip3 install tensorflow
pip3 install numpy
pip3 install matplotlab
Google Colab - 有google account就能使用
如果未學習Python的話,可以在以下網站了解
另外,也準備ChatGPT 或 poe,有些學習中的問題,可以請教AI
定義問題
製作模型之前,首先就是需要定義問題,也是就是Model需要輸出的結果;
這文章想解決的問題是:
輸入直徑(x),計算才圓周的長度(y);
當然,學過數學都知道計算圓周的公式是:圓周 = pi * 直徑
但是假如我們不停公式,使用機器學習,電腦是否可以學會,就是這次實作的目標;
而這個問題的好處在於,大家不用特別找數據開始,而預測結果,大家也容易驗證。
設計模型
定義問題後,我們就可以設計模型;設計模型需要考慮以下事情:
定義輸入、輸出
選擇需要使用的算法(Algorithm)
如何獲取數據集(Dataset)
這個計算圓周的問題很簡單:
輸入(x):直徑
輸出(y): 圓周
算法:Linear Regression
當然,研究和設計一個全新的ML模型是一件很艱難的事情,需要有很多Data Science學問,還有需要很多實驗才能做到。
預備數據集(Dataset)
計算圓周的數據會從實際測量來獲取,但是由於現在是學習ML,
我們利用圓周公式來計算。我們從這裡開始編寫代碼:
- 匯入相關library
import tensorflow
import numpy as np
import matplotlib.pyplot as plt
- 定義數據
PI = 3.14159265358979323846
# Define the diameter of the circle
test_x = np.arange(100).astype(np.float32)
# Define the perimeter of the circle by formula with random
test_y = test_x * PI + np.random.normal(0, 8, len(test_x))
這裡用的 np (numpy)是一個可以方便計算數據array的工具;
除了計算 y 值之外,這裡還用他的隨機功能
- 顯示數據
# show the data
plt.scatter(test_x, test_y)
plt.show()
這裡用上了matplotlab (plt)來顯示數據。
程序運行到這裡,會出現以下圖片,可以使用 Cmd+W 把圖片關閉。
製作模型
製作模型,簡單來說,就是基於數學或統計公式把結果計算出來;整個項目的公式,就是 pi x input
,當然我們未知pi 是什麼,所以暫定為1;有些Model,會用Random作為初始值。
以下Model的代碼:
#1
class PerimeterModel:
def __init__(self):
self.pi = tensorflow.Variable(1.0)
def __call__(self, input):
return self.pi * input
# 2: Simple Test
test_input = np.array([1, 2, 3])
model = PerimeterModel()
print("model result", model(test_input))
代碼解說:
首先,利用定義python class,並使用
tensorflow.Variable
定義pi值;然後,在__call__
定義計算的邏輯,也就是pi x input diameter
。
使用__call__
,就能更簡單地調用 Model。簡單測試Model,由於未訓練模型,當然是輸出錯誤結果。
另外,使用了__call__
,就能直接使用model(input)
,不用另外定義method 名字。
編寫Loss Function
模型(Model)定義後,就需要定義計算錯誤的方法;
計算錯的方法是方法是用”Model結果“和”已知的結果“,進行比較並計算錯誤數值。計算結果不能只是true / false,必須輸出數值才能幫助optimiser進行調整。
而Loss functions有很多不同的做法,而這個project用的是Linear regression最常用的function。如果想看看Tensorflow提供那些,可以參考這裡:
https://www.tensorflow.org/api_docs/python/tf/keras/losses
以下是項目Loss Function的代碼:
# Loss function
# 1
def mean_square_error(predicted_y, actual_y):
return tensorflow.reduce_mean( # 2
tensorflow.square(predicted_y - actual_y) # 3
)
# 4
test_input = np.array([1, 2, 3])
predicted_output = model(test_input)
actual_output = test_input * PI
error = mean_square_error(predicted_output, actual_output)
print("error", error)
代碼解說:
定義 loss function的 method
tensorflow.reduce_mean
是把array所有結果計算平均值:
大概公式是sum(values) / count(values)
tensorflow.square
就是把array的數值進行Square,這樣做可以把消除負數和提升錯誤的幅度。另一種類似的計算就是取Absolute value。測試 Mean Square Error Loss Function的效果,正式使用時不會用到的。
優化器(Optimizer)
當Model和Loss Function準備好,下一步就是加入“優化(optimize)”的步驟,這步驟的程序通常叫optimiser,Tensorflow本身也提供了很多optimizer,例如:SGD(Stochastic Gradient Descent)、Adam等,詳細可以看看一下連結:
https://www.tensorflow.org/api_docs/python/tf/keras/optimizers
不過,這個項目暫時不使用這些Optimizer,會自己利用Tensorflow.GradientTape
來實現。 GradientTape利用微積分的理論,計算出gradient,然後可以用這個數值來調整model的參數(即是 pi 值)。
有時間,可以看看ML大師Andrew Ng的解說:
https://youtu.be/uJryes5Vk1o?si=4TsAa7uZfLed6_zk
以下是Optimizer代碼
# 1
def optimize(model, input, actual_result, learning_rate):
# 2
with tensorflow.GradientTape() as gt:
# 3
predicted = model(input)
loss = mean_square_error(predicted, actual_result)
# 4
pi_delta = gt.gradient(loss, model.pi)
# 5
model.pi.assign_sub(pi_delta * learning_rate)
代碼解說:
定義Optimizer method,需要以下參數:
input: 輸入數值,就是圓的直徑
actual_result:正確結果,就是圓的圓周
learning_rate:學習速度
啟用 GradientTape
使用model預測結果,並用loss function計算當前誤差
計算Gradient,也就是調整 pi 的 delta 改變
修改 model 參數,就是pi 數值,這裡會使用tensorflow的
assign_sub
來改變。這裡會用上一個叫learning_rate
的變量來調節學習速度,如果太快的話,會令loss不斷提升,導致訓練失敗。
訓練模型
最後一步,就是訓練模型。這一步簡單來說,進行多次predict 和 optimize,而通常這個步驟,會紀錄不同迭代(epoch)的錯誤率(Loss),以便分析訓練是否有問題。
這是相關代碼:
# 1
def train(model, test_x, test_y, num_epochs=100, learning_rate=0.001):
# 2
epochs = []
losses = []
# 3
for epoch in range(num_epochs):
# 4
optimize(model, test_x, test_y, learning_rate)
# 5: log the loss of each epoch
predicted = model(test_x)
loss = mean_square_error(predicted, test_y)
epochs.append(epoch)
losses.append(loss.numpy())
print("epoch: ", epoch, " loss: ", loss.numpy(),
" pi: ", model.pi.numpy())
# 6: show the loss using chart
plt.plot(epochs, losses)
plt.show()
# 7
model = PerimeterModel()
train(model, test_x, test_y, num_epochs=300, learning_rate=0.00005)
代碼解說:
定義訓練模型的Method,有一下參數:
test_x : 數據集的x,也就是輸入值 - 項目的數據:直徑
test_y : 數據集的y,也就是正確結果 - 項目的數據:圓周
num_epochs:迭代次數,在ML中,通常用epoch這個詞語
learning_rate:學習速度,影響修改pi的幅度;太大:優化不了,太少:增加epoch數
定義紀錄不同epoch loss數據的變量
進行訓練的循環
優化模型:關於優化邏輯,在上一段已經有詳細解說
紀錄Loss的變化
使用圖表顯示Loss的變化
調用 訓練邏輯
完整代碼:(Google Colab Notebook)
https://colab.research.google.com/drive/12NI0WumV90pC6tQ2yd74eQwghoTLo4E5?usp=sharing
思考問題
開發/建立模型,那些部分最難處理?
如果有一個需要ML的問題,你會怎樣啟動(Kickstart)?
總結
為何我製作這個題目(實作Model),因為我覺得這個基礎對理解機器學習十分重要;之後將會提及的課題,例如數據集,如果連Model需要什麼的輸入也不了解,其實很難找到合心水的數據。又或者應用Model,也是需要了解Model的輸入/輸出並做出相應的配套。
希望這篇文章讓大家對ML Model有更好基礎,讓學習其他ML課題更簡單。
最後,歡迎大家也可以找我交流,可透過Facebook和Twitter聯繫我;
另外,請加入我的FB專頁,有新文章發布時,大家就能立即知道了。
Facebook 專頁連結:https://www.facebook.com/kencoder1024
Twitter連結:https://twitter.com/kenlakoo