實作簡單TensorFlow模型(Model)

實作簡單TensorFlow模型(Model)

上文介紹了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 * 直徑

但是假如我們不停公式,使用機器學習,電腦是否可以學會,就是這次實作的目標;

而這個問題的好處在於,大家不用特別找數據開始,而預測結果,大家也容易驗證。

設計模型

定義問題後,我們就可以設計模型;設計模型需要考慮以下事情:

  1. 定義輸入、輸出

  2. 選擇需要使用的算法(Algorithm)

  3. 如何獲取數據集(Dataset)

這個計算圓周的問題很簡單:

  • 輸入(x):直徑

  • 輸出(y): 圓周

  • 算法:Linear Regression

當然,研究和設計一個全新的ML模型是一件很艱難的事情,需要有很多Data Science學問,還有需要很多實驗才能做到。

預備數據集(Dataset)

計算圓周的數據會從實際測量來獲取,但是由於現在是學習ML,
我們利用圓周公式來計算。我們從這裡開始編寫代碼:

  1. 匯入相關library
import tensorflow
import numpy as np
import matplotlib.pyplot as plt
  1. 定義數據
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 值之外,這裡還用他的隨機功能

  1. 顯示數據
# 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))

代碼解說:

  1. 首先,利用定義python class,並使用tensorflow.Variable定義pi值;然後,在 __call__ 定義計算的邏輯,也就是pi x input diameter
    使用__call__,就能更簡單地調用 Model。

  2. 簡單測試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)

代碼解說:

  1. 定義 loss function的 method

  2. tensorflow.reduce_mean是把array所有結果計算平均值:
    大概公式是 sum(values) / count(values)

  3. tensorflow.square就是把array的數值進行Square,這樣做可以把消除負數和提升錯誤的幅度。另一種類似的計算就是取Absolute value。

  4. 測試 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)

代碼解說:

  1. 定義Optimizer method,需要以下參數:

    • input: 輸入數值,就是圓的直徑

    • actual_result:正確結果,就是圓的圓周

    • learning_rate:學習速度

  2. 啟用 GradientTape

  3. 使用model預測結果,並用loss function計算當前誤差

  4. 計算Gradient,也就是調整 pi 的 delta 改變

  5. 修改 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)

代碼解說:

  1. 定義訓練模型的Method,有一下參數:

    • test_x : 數據集的x,也就是輸入值 - 項目的數據:直徑

    • test_y : 數據集的y,也就是正確結果 - 項目的數據:圓周

    • num_epochs:迭代次數,在ML中,通常用epoch這個詞語

    • learning_rate:學習速度,影響修改pi的幅度;太大:優化不了,太少:增加epoch數

  2. 定義紀錄不同epoch loss數據的變量

  3. 進行訓練的循環

  4. 優化模型:關於優化邏輯,在上一段已經有詳細解說

  5. 紀錄Loss的變化

  6. 使用圖表顯示Loss的變化

  7. 調用 訓練邏輯

完整代碼:(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

Did you find this article valuable?

Support AI研習工作坊 by becoming a sponsor. Any amount is appreciated!