# 使用機器學習解決問題的五步驟：模型訓練


<!--more-->

## 前言

本篇是「機器學習入門觀念」系列的第五篇。前一篇我們談了[「建立資料集」](../prepare-dataset/)，知道資料集怎麼準備、為什麼它決定了模型的上限。資料備好之後，接下來要做的事情就是這篇的主角：模型訓練。

{{< image src="machine-learning-five-steps-1.jpg" alt="機器學習解決問題流程的五個步驟示意圖，第三步「訓練模型」被標示出來" caption="用機器學習解決問題的第三步驟：模型訓練" >}}

這篇會先把「模型訓練到底在訓練什麼」講清楚，再帶到實際動手寫程式時會碰到的幾個名詞：超參數 (Hyperparameter)、常用的 Python 函式庫，以及常見的模型種類。

## 資料集到模型訓練

建立好資料集之後，通常不會整包拿去訓練，而是先切成兩份：訓練資料集 (Training Dataset) 與測試資料集 (Test Dataset)。

訓練資料集顧名思義是拿來訓練模型的。等模型訓練完，我們會想知道它到底學得好不好，這時候如果拿訓練時看過的資料來考它，考出來的分數不算數 —— 就像考試前先看過考卷一樣。所以我們刻意留一份模型沒看過的資料，也就是測試資料集，用它來檢驗模型的真實表現。

## 模型訓練的意義

在「機器學習的模型、訓練與推論」一文中，我們談過機器學習裡的「模型」其實就是一個「函式」。函式接受一個輸入，經過運算之後回傳一個輸出，而函式裡有許多「參數」(Parameter)，正是這些參數決定了輸出會長什麼樣子。

有了這個前提，模型訓練的概念就可以寫成一句話：

> 透過某種方式不停地調整模型中的參數 (Parameter) 數值，使得模型的輸出愈來愈精準，也就是最小化損失函數 (Loss Function)。

這句話裡出現了兩個關鍵名詞：參數 (Parameter) 與損失函數 (Loss Function)。把它們拆開來看：

- **參數 (Parameter)**：模型就是一個函式，函式裡存在許多參數，這些參數與輸入一起運算後得到輸出。舉例來說，有一個函式 F1(x) = 3x + 5，其中的 3 與 5 就是這個函式的參數；輸入 6 進去，函式會輸出 F1(6) = 23。函式當然可以更複雜、擁有更多參數，例如 F2(x) = 3x² + 2x − 10，此時 3、2 與 -10 都是這個函式的參數，輸入 1 進去會得到 F2(1) = -5。

- **損失函數 (Loss Function)**：損失函數是模型訓練中的關鍵角色，它的工作是衡量「目前這個模型有多爛」。以上面的 F2(x) 為例，三個參數各自都可以替換成千萬種不同的數字，我們要從中挑出一組最好的，靠的就是損失函數。既然它也是函式，一樣有輸入與輸出：

  **Loss Function(模型的參數) = 模型有多壞**

  把目前模型的參數丟進損失函數，它會回傳這組參數有多糟。輸出的數值愈大，代表模型愈差。所以訓練的目標很直觀：想辦法把這個數值壓低。

用房價預測來想像會更具體一點：模型預測某間房子 1000 萬，實際成交 1200 萬，那 200 萬的落差就是損失函數要量化的東西。整份訓練資料的落差愈小，代表這組參數挑得愈好。

## 模型訓練步驟的循環

把上面的內容統整起來，模型的訓練過程其實就是不斷重複以下三個步驟：

1. 輸入訓練資料集到模型中
2. 透過損失函數計算目前模型的好壞
3. 更新模型中的參數，使得損失函數的數值下降 (提升模型的品質)

跑一輪、算一次損失、調一次參數，然後再跑下一輪。至於什麼時候停？停止條件是我們自己決定的，可能是重複 10000 次後停止，也可能是當損失函數的數值下降到某個程度後就停止。

## 模型訓練時的超參數 (Hyperparameter)

了解訓練流程之後，接著看看實際寫程式時會碰到的名詞，第一個是「超參數」(Hyperparameter)。

模型在建立與訓練的過程中，有些數值是必須由我們手動設定的，模型自己沒辦法在訓練中學習調整，這類數值就叫超參數。最簡單的例子是上一節提到的「訓練次數」：要跑幾輪是我們自己決定的，可以憑經驗直接給一個數字，也可以設定某些條件，滿足了就停止訓練。

所以這裡有兩種「參數」很容易搞混，記住這個分界就好：模型裡的參數 (Parameter) 是訓練過程中會被自動調整的，超參數 (Hyperparameter) 則是我們在訓練開始前就得先設定好、訓練中不會自己變動的。

## 常用的 Python 函式庫

真的要動手建立模型或訓練模型時，有許多現成的套件與框架可以用，不必從頭刻。

以傳統的機器學習模型而言，最常使用的函式庫是：

- [**scikit-learn**](https://scikit-learn.org/stable/)

若是深度學習模型，常用的函式庫有：

- [**TensorFlow**](https://www.tensorflow.org/)
- [**PyTorch**](https://pytorch.org/)
- [**MXNet**](https://mxnet.apache.org/versions/1.8.0/) (補充：MXNet 後來已退役進入 Apache Attic，新專案建議直接選 PyTorch 或 TensorFlow)

這裡就先不深入介紹，網路上關於這些函式庫的使用方式與設計概念都有非常完整的資源。

## 常見的模型種類

在[「定義問題」](../define-problem/)一文中，我們談過要先辨識「問題」屬於哪一種機器學習的任務，才能建立相對應的模型。實際上機器學習的模型百百種，「選模型」本身就是一個不斷嘗試 (Trial-and-Error) 的過程。這裡把它們大致分成三類。

- **線性模型 (Linear Model)**

在這個入門系列中，我們介紹的模型多半屬於這一類。這類模型通常比較單純，可以用一個數學函式直接表示，例如 F(x) = 2x³ + 3x² − 10x + 5，輸入不同的 x 就會得到不同的輸出。在「定義問題」那篇裡，我們也用房價預測的例子說明過，這類模型適合處理「線性回歸」(Linear Regression) 的問題，因此又稱為線性回歸模型。

那如果碰到的是「分類」問題，還能用線性模型嗎？當然可以。以「二元分類問題」(Binary Classification) 為例，也就是把輸入的資料分成 A 類別或 B 類別，我們可以把線性回歸模型的輸出再通過一個函式轉換，讓輸出範圍一定落在 0 ~ 1 之間，再用這個 0 ~ 1 的數字表示屬於其中一個類別的機率。

線性回歸模型加上這層函式轉換之後形成的新模型，就是**羅吉斯回歸模型 (Logistic Regression Model)**。

- **樹狀模型 (Tree-Based Model)**

樹狀模型在這個系列中也很常出現。它的做法是用像「樹」一樣的結構，把輸入的資料一層一層往下分類，最後得到一個結果。

舉例來說，手上有一個人的基本資料，包含身高、血型、興趣、專長、年齡等等，我們想預測他的職業，判斷過程可能是這樣：

1. 年齡大於 25 歲嗎？如果不是，就「是學生」；如果是，就「不是學生」。
2. 有在寫程式嗎？如果有，就「是工程師」；如果沒有，就「是其他」。

上面這串判斷過程，用樹狀結構畫出來就是這樣：

{{< image src="tree-based-model.jpg" alt="樹狀模型的判斷流程示意圖，從根節點依序以年齡、是否寫程式等條件分支，最後落到職業類別" caption="樹狀模型" >}}

- **深度學習模型 (Deep Learning Model)**

深度學習模型是近幾年特別火熱的題目。它模仿人類「大腦」的結構，用一層又一層的神經元 (Neuron) 建構模型。深度學習模型同樣百百種，依據任務屬性不同會適用不同類型的模型，這裡列出幾個最常見的：

**前饋神經網路 (Feed Forward Neural Network, FFNN)**：最早發明也最簡單的神經網路，把神經元一層 (Layer) 一層地疊在一起，層與層之間透過權重 (Weight) 把資訊往下傳遞。

**卷積神經網路 (Convolutional Neural Network, CNN)**：善於從圖像中找到有價值的資訊，廣泛應用在圖像處理的任務中。

**循環神經網路 (Recurrent Neural Network, RNN)**：善於從時間序列的輸入資料中汲取有價值的資訊，廣泛應用於自然語言處理的任務中。

## 結論

這篇文章談了「模型訓練」的意義，把參數 (Parameter) 與損失函數 (Loss Function) 這兩個核心概念拆開來看，也整理了實作時會遇到的幾個議題：超參數、常用函式庫，以及模型的種類。

老實說，文章後半段已經算是比較進階的內容，第一次讀不太吸收得了是很正常的，不用氣餒。這些名詞在後續文章裡還會反覆出現，看多了自然就熟了。

下一篇文章，我們會接著討論模型訓練完成之後的評估階段：[模型評估](../model-evaluate/)。

