# 2024-09-20 DL
- 主題:**Keras**
- 放映影片:`Video_2024-08-14_115653._類神經網路_03.mp4` 播放完畢
- 搭配講義:[**DL Lecture 01 (How to construct an NN - Part)**](https://drive.google.com/file/d/1ugcciON1F1hrOS72I_7BOiqn_6VIxsGe/view?usp=drive_link)
- 分工
- 主持人: @Ot4v6SRLSZ2amlJNMb6Ynw
- 教學組
- 領讀人: @sin-iu-ho
- 編譯組: @sin-iu-ho @munin
- 紀錄組
- 文字組: @munin
- 影音組: @as854398 (音質太差,不錄影)
## 課程內容筆記
- 目的:搭建輸入為 3,隱藏層 1 層,輸出為 1 的類神經網路。

- 整體類神經網路的學習方式

- 損失函數幫助估計誤差,而優化函數用來調整權重,最終使損失最小化。
- 損失估計 (Loss Estimation):損失函數是用來衡量模型預測值與實際值之間誤差的函數。在訓練模型時,我們希望通過優化過程將這個誤差最小化。
- 權重調整 (Weight Adjustment) :這部分涉及模型在損失函數基礎上進行參數更新,以最小化損失函數,達到優化目標。
- 準備輸入資料
- 搭建第一層隱藏層
```python=
Model.add(Dense(128, activation = 'relu', input_dim = 3))
```
- 建立第一個隱藏層的同時,也要將輸入層設定好
- `input_dim = 3` 代表 3 個輸入
- 但也可以將輸入層另外拉出設定(下方示範)
- 輸出層
```python=
Model.add(Dense(1, activation = 'sigmoid'))
```
- 輸出層,只輸出 1 個
- 因為此處是解決二元分類的問題(輸出的資料 y 只有 0 和 1),所以 `activation` (激活函式)僅能選擇 `sigmoid`
- 查看模型搭建的狀況
```python=
Model.summary()
```
- 此處模型的參數量 3x128+128=512 為可以訓練的參數
- 損失估計(Loss function)
```python=
Model.compile(optimizer = 'rmsprop', loss = 'binary_crossentropy', metrics = ['accuracy'])
```
- `optimizer`:優化器設定
- `loss`:損失函數,(老師說)這不是人類可以了解ㄉ
- `metrics`:評比(表現評量)
- `accuracy`:正確率
- 權重調整(SGD+BP)
```python=
Model.fit(X,y,epochs = 1000, batch_size = 3, verbose = 1)
```
- 利用前述的 `optimizer`(優化器)和 `loss`(損失函數),會根據損失函數計算出的誤差來調整每個神經元之間的權重。具體來說,模型會通過 `反向傳播(backpropagation)` 來計算每一個神經元對總損失的貢獻,並根據這些貢獻使用優化器來更新神經元間的權重,這樣模型就能逐步減小預測錯誤。
- 訓練過程中,將訓練資料放入神經網路中,模型會計算出預測結果,與實際結果相比較後得出損失值,接著根據優化器更新神經元的權重,使模型在後續的訓練中表現得更好。
:::spoiler 什麼是反向傳播(backpropagation)?
反向傳播(backpropagation)是一種優化神經網路的技術,用來更新網路中每個神經元的權重。它的目的是根據模型的預測誤差來調整這些權重,從而使預測結果更接近實際值。
具體來說,反向傳播過程分為以下幾個步驟:
1. **前向傳播(Forward Propagation)**:將輸入資料放入神經網路,經過隱藏層的計算,最終得到輸出結果(模型的預測值)。
2. **計算損失**:將網路輸出的預測值與實際的目標值進行比較,使用損失函數來計算誤差(損失值),表示模型預測與實際值的差距。
3. **反向傳播誤差**:從輸出層開始,反向計算每個神經元對損失的影響。這個過程通過鏈式法則(chain rule),逐層向前追溯,計算每個神經元的偏導數(即權重的梯度),這樣模型知道該如何調整權重來減小誤差。
4. **更新權重**:使用優化器(如梯度下降法),根據計算出的梯度來更新每個神經元的權重,使預測誤差逐漸減小。這是通過調整網路的參數(權重和偏差)來實現的。
反向傳播的核心思想就是讓模型逐步學習如何減少誤差,從而在給定的訓練資料上進行更準確的預測。
:::
- `batch_size`(批次大小)
- 在訓練模型時,`batch_size` 定義了每次更新權重時,所使用的樣本數量。
- 例如,若 `batch_size` 設為 3,則模型會從資料集中選擇 3 筆資料,進行一次前向傳播、計算損失、再進行反向傳播來更新權重。
- 在這個案例中,若資料集有 8 筆資料,最多只能有 8 個資料點,因此可以選擇批次大小不超過 8。
- `epochs`(迭代次數)
- 算是一種 iteration ,涉及計算 Loss、metrics,表示完整訓練資料集被送入模型進行前向傳播和反向傳播的次數。
- 每個 `epoch` 包含若干次的前向與反向計算,直到遍歷完所有訓練資料。
- 每個 `epoch` 是一個完整的「回合」,並不等於一次計算,而是所有資料都經過一次模型訓練的過程。
- `verbose`(顯示訓練狀況)
- 控制訓練過程中的輸出訊息,顯示訓練進度和結果,預設為1(auto)。
- 設為 `0` 則不顯示任何信息
- 設為 `1`,會以`進度條`顯示每個 `epoch` 的詳細訓練信息 例如:
Epoch 1/2
186219/186219 [==============================] - 85s 455us/step - loss: 0.5815 - acc:
0.7728 - val_loss: 0.4917 - val_acc: 0.8029
- 設為`2`會以純數字$\frac{n}{totalEpochs}$形式顯示每個epoch訓練信息,而不顯示進度條。 例如:
Epoch 1/2- 88s - loss: 0.5746 - acc: 0.7753 - val_loss: 0.4816 - val_acc: 0.8075
- 訓練循環(training loop):compile() & fit()
- 預測
- 通常採用 predict() 或 evaluate() 方法
```python=
import numpy as np
X_test = np.array([[0,0,0]])
Model.predict(X_test)
Model.evaluate(X,y)
```
- `predict(X_test)`:因為是預測 0 或 1 的二元分類問題,所以這邊會得出 0-1 之間的浮點數
- `evaluate(X,y)`:顯示模型對資料集的表現如何,計算 Loss function 與 metrics
- 把輸入層從第一層隱藏層放出來的方式,指定輸入層的 shape
```python=
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Input #
Model = Sequential()
Model.add(Input(shape=(3,))) #
Model.add(Dense(128, activation = 'relu'))
Model.add(Dense(1, activation = 'sigmoid'))
```
- 課後討論速記
- 資料集英文大小寫的差別
- 向量:一維結構,使用小寫字母表示。
- 矩陣:二維結構,使用大寫字母表示,像一個「面」。
- 張量:三維或更高維度結構,通常也是大寫字母表示。
- 解決回歸問題的有哪些損失函數?[MAE](https://hackmd.io/@learnai2024/mldl-encyclopedia#Mean-square-error)、[RMSE](https://hackmd.io/@learnai2024/mldl-encyclopedia#RMSE)
- Keras 中的 Sequential API 和 Functional API 的差異
- Sequential API(序列式 API)
- 此處老師使用的案例是 Sequential API ,當模型的結構是簡單的逐層堆疊,且每一層的輸入來自上一層的輸出,這種「一層一層」的線性/序列式結構適合用 Sequential API 來實現。
- 應用場景如:影像分類、回歸任務等。
- Functional API(函數式 API)
- 當模型的結構較為複雜,涉及到多輸入、多輸出、共享層或需要自定義拓撲結構時,可以使用 Functional API。
- 應用場景如:多模態的輸入(處理影像和文本的模型)、多輸出模型等。
- Model 是 Sequential 的實例,Model 之後所接的方法,都是 Sequential 的方法,例如 add()、compile()、fit() 等。
- 資料集通常分為 Training Data、Evaluation Data、Testing Data(對訓練模型來說的新資料)
- 什麼是 overfitting 與 generalization?
- [Overfitting](https://hackmd.io/@learnai2024/mldl-encyclopedia#Overfitting)(過擬合):使用有看過的資料(訓練集)表現很好,但使用沒看過的資料(測試集或其他沒使用過的資料)表現很差。
- [Generalization](https://hackmd.io/@learnai2024/mldl-encyclopedia#Generalization)(泛化能力):使用有遇過(訓練集)或沒遇過(測試集)的資料皆表現很好。
- `input_dim` 和 `input_shape` 都是在定義神經網路的輸入層時常見的參數
- `input_dim` 是維度,而 `input_shape` 是形狀。
- `input_dim` :用來指定輸入的維度(即向量的維度數量)
- 適用情境:通常用在一維資料(如序列或特徵向量)上。這個參數多出現在像是 `Dense` 層這類的一維資料輸入。
- 定義:`input_dim = 3` 表示輸入是一個一維向量,該向量的長度是 `3`,這代表這個模型的每個樣本有 `3` 個特徵值。
- Example:`input_dim=3` 表示輸入是一個一維向量 `[x1, x2, x3]`,所以輸入的形狀其實是 `(3,)`。
- `input_shape`:用來定義輸入資料的形狀(包括各維度的大小),需要傳遞一個 tuple。
- 適用情境:適合用於多維資料(如二維圖片、三維視頻)或一維資料。它可以在任何層(如卷積層、LSTM層等)中使用來定義輸入的完整形狀。
- 定義:`input_shape = (3, )` 表示輸入是一個一維向量,它的形狀是 `(3,)`。這樣的寫法明確指出了輸入的形狀,不僅是維度,也指明了該維度的具體大小。
- Example:如果你有一個 28x28 的灰階圖片,你會用 `input_shape=(28, 28, 1)`(三維資料)。
- 為什麼二元分類的問題,隱藏層的 activation 是用 `ReLU` 函式,而輸出層是用 `Sigmoid`?
- [ReLU](https://hackmd.io/@learnai2024/mldl-encyclopedia#ReLU)

- [sigmoid](https://hackmd.io/@learnai2024/mldl-encyclopedia#Sigmoid-function)

- 避免梯度消失(下回讀書會討論)
- 引入非線性(nonlinearity)。
- 當所有層都是線性組合時,無論堆疊多少層,最後的結果還是可以通過一個線性函數來表示,這樣就無法有效學習和擬合非線性關係。
- 啟動函數(如 ReLU、Sigmoid、Tanh 等)能夠將輸入轉換成非線性的輸出,使神經網路能夠擬合複雜的非線性資料,從而增強模型的表現能力。
- 以買iphone來舉例sigmoid : 會買的情況為1,不會買的情況為0,在這sigmoid中算是一種機率分布,我們可以設定一個斷點/門檻;當其超過50%直接強制變成1(會買),小於50%則是直接變成0(不會買),但為了顧及非線性因此會使用sigmoid函數。(這裡聽起來有可能是指除了sigmoid函數也可能會有其他函數也可以用買iphone來舉例) @sin-iu-ho 麻煩確認一下
:::spoiler 參考資料 {#ref}
- 同學提供 in Chat Room
1. ReLU 的使用時機: 隱藏層中的首選激活函數:ReLU 是目前神經網絡中最常用的激活函數,尤其是在深度網絡的隱藏層中,因為它計算高效,並且能有效解決梯度消失問題。 適合大多數任務的隱藏層:無論是圖像分類、自然語言處理還是其他任務,只要是隱藏層,ReLU 通常是首選激活函數,因為它能使模型學習到更深層的特徵。 大數據集和深層神經網絡:ReLU 能夠快速收斂,特別適合於大規模數據集和深層網絡。
2. Sigmoid 的使用時機: 輸出層適合二分類問題:Sigmoid 常用於二分類問題的輸出層,因為它可以將輸出值壓縮到 [ 0 , 1 ] [0,1] 之間,解釋為概率。當模型需要預測某個樣本屬於某個類別的概率時,Sigmoid 是理想選擇。 適合概率預測:當你需要將輸出值解釋為概率(如二分類或多標籤分類),Sigmoid 是非常合適的。
:::
## 問題與討論
==陸續新增中==
:::spoiler 我們今天所搭建的神經網路適用哪一種機器學習任務?
二元分類(binary classification)
:::
:::spoiler 我們用了 Keras 的哪一種 API 來搭建神經網路?
- [x] Sequential:線性或序列式的網路架構。(講義 p.28)
- [ ] Functional
:::
:::spoiler 我們用了 [`Sequential`](https://www.tensorflow.org/api_docs/python/tf/keras/Sequential) 類別的哪些方法?
- [x] `add`
- [x] `summary`
- [x] `compile`
- [x] `fit`
- [x] `evaluate`
- [x] `predict`
- [ ] `save`
- [ ] `load_weights`
:::
:::spoiler 如何搭建一個含有 128 個神經元的密集層(全連接層)?
使用 [`tf.keras.layers.Dense`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense)
假設使用 ReLU 作為啟動函數。
```python=
from tensorflow.keras.layers import Dense
model.add(Dense(128, activation='relu'))
```
如果這是第一層,還需要指定輸入的形狀。
- 輸入層可以在第一層定義時一併指定
```python=
Model.add(Dense(128, activation='relu', input_dim =3 ))
```
- 也可以在第一個隱藏層之前單獨指定
```python=
Model = Sequential()
Model.add(Input(shape=(3,)))
```
:::
:::spoiler 在範例中,哪一層使用了哪一種啟動函數?為什麼?
```python=
Model = Sequential()
Model.add(Input(shape=(3,)))
Model.add(Dense(128,activation = 'relu', input_shape = (3,) ))
Model.add(Dense(1, activation = 'sigmoid'))
```
在第一個隱藏層是使用 ReLU,在輸出層是使用 sigmoid,理由詳見 [參考資料](#ref)
:::
:::spoiler 我們用哪一種損失函數?為什麼?
二元交叉熵(binary cross entropy),因為是二元分類任務。
:::
:::spoiler `fit` 方法中使用了哪些參數?它們分別代表什麼?
- [x] `epoch`
- [x] `batch_size`
- [x] `verbose`
:::
## 延伸閱讀
- input_dim:在 TensorFlow/Keras 2.x 中,input_dim 是一個早期 Keras API 中的參數,並不是 TensorFlow 2.x 的標準參數。在 TensorFlow 2.x 中,`input_dim` 這個參數實際上已經被 `input_shape` 取代。它不再作為顯式參數出現在現代的 TensorFlow 源代碼中。如果你寫了 model.add(Dense(64, input_dim=100)) 這種語法,它實際上是通過 input_shape=(100,) 的方式來處理的。原因是 Keras 的 Dense 層會在初始化的時候,將這些額外的參數(如 input_dim)視為 input_shape 的簡化形式來自動轉換。那麼問題來了,哪裡的代碼處理了這種自動轉換?事實上,input_dim 參數的處理是發生在 Dense 層的基類 Layer 中,而不是 Dense 層本身。它是通過 Keras 的 Input 或 build 方法來自動解析的。雖然 input_dim 作為早期 API 的遺留參數,已經在新的 Keras API 中被 input_shape 取代,但它仍然可以兼容,因為內部會自動轉換。
[SourceCode](https://github.com/keras-team/keras/blob/v3.3.3/keras/src/layers/layer.py#L59-L1448 )
以下為Dense的父層Layer其中源代碼,實際上由Layer這個類別處理input_dim這個參數
``` python
input_dim_arg = kwargs.pop("input_dim", None)
if input_dim_arg is not None:
input_shape_arg = (input_dim_arg,)
```
- 反向傳播: {%youtube ibJpTrp5mcE%}
## 其他議題
1. [**期初成員問卷**](https://forms.gle/gMWuL2W5uonh1tJN9)
- 2024-09-27 以前開放作答
2. 讀書會分工
- 職位安排(待下週確認)
- 主持人:主持會議流程,協調工作事項分配
- 教學組
- 領讀人:講課、導讀書籍,或針對影片帶領問題討論
- 編譯組:將紀錄組的文字紀錄整合講義內容,在 HackMD 上編寫讀書會筆記
- 紀錄組
- 文字組:速記課程內容;收集聊天室話題
- 影音組:控制課程影片播放;(如有需要)側錄讀書會過程
- ==讀書會參與者輪流擔任不同職位,以促進參與度==。
3. 音質太差的配套措施
- [ ] **方案 A**:使用講義搭配 Colab 程式碼,由領讀人主講
- [ ] **方案 B**:由領讀人(學務組)事先看完影片,再到讀書會上主講;此方案需要領讀人(學務組)大量付出心血,需提高誘因。
4. 新增分享會/讀書會
- 面試經驗分享:羽喬發起,上課時間預定為 2024-09-25 19:00~:20:00
- 數學基礎讀書會: @sin-iu-ho 發起,上課時間預定為
- 2024-09-24 10:00--12:00
- 2024-09-26 19:00--21:00