# 章節包:自然語言處理(NLP)W4(10/1)第 07 章「PyTorch:用模組搭模型」
PyTorch 教學(助教,2024 錄影)影片 0:25:47–0:40:04,YouTube ID sg22677pUEs,逐字稿 C:\D槽\TAICA課程\自然語言處理\第四周1151001\W4_PyTorch教學_助教.逐字稿.txt。Notion 章節頁 https://app.notion.com/p/3ecfc631b03081d0869df37240433e19(頁 ID 3ecfc631b03081d0869df37240433e19),頁面標題「07 PyTorch:用模組搭模型(0:25–0:40)」。
## 1. 第一行(直接照抄,不要改)
[自然語言處理](https://app.notion.com/p/3e6fc631b03081b4a9e8f91f3411f61f) › [W4(10/1)](https://app.notion.com/p/3ecfc631b03081b8aa2cf4a97467ed41) › 07|PyTorch 教學(助教,2024 錄影)影片 [0:25:47–0:40:04](https://www.youtube.com/watch?v=sg22677pUEs&t=1547s)|投影片 pytorch_tutorial_NTHU_NLP p.24–32|上一章 [06 PyTorch:訓練主循環與 Tensor(0:00–0:25)](https://app.notion.com/p/3ecfc631b03081579f0eeb810083a514)|下一章 [08 PyTorch:自動微分與訓練迴圈(0:40–1:04)](https://app.notion.com/p/3ecfc631b030817fa3aceb0a27afd016)
## 1b. 最後一行(直接照抄,放在 Self-check 後面,當全頁最後一行)
讀完了嗎?下一章:[08 PyTorch:自動微分與訓練迴圈(0:40–1:04)](https://app.notion.com/p/3ecfc631b030817fa3aceb0a27afd016)|回到週頁:[W4(10/1)](https://app.notion.com/p/3ecfc631b03081b8aa2cf4a97467ed41)
## 2. 各段標題(照順序;每段一個 ## 標題,直接照抄連結)
- `## [0:25:47](https://www.youtube.com/watch?v=sg22677pUEs&t=1547s) 模型的骨架:nn.Module` 老師講什麼:模型的參數用 Tensor 存,外面包一層 torch.nn.Module。自己的模型要繼承它,寫兩件事:初始化(宣告有哪些層)和 forward(資料進來怎麼處理、產出 logits);把資料丟給模型時,它會自動呼叫 forward。
- `## [0:28:03](https://www.youtube.com/watch?v=sg22677pUEs&t=1683s) 常用的層` 老師講什麼:線性層(全連接)、卷積層、RNN/LSTM(處理序列)、max pooling、embedding(把 ID 換成向量,本質是查表式的矩陣乘法)、Batch Normalization(減平均除標準差,避免數值發散),以及 Sequential、ModuleList、ModuleDict 這些容器。
- `## [0:30:14](https://www.youtube.com/watch?v=sg22677pUEs&t=1814s) 模型的成員函式` 老師講什麼:state_dict 回傳「參數名稱→參數值」的有序字典,named_parameters 用迴圈逐一列出參數名稱與 Tensor,parameters 只給參數本身;train/eval 用來切換訓練模式與驗證模式。
- `## [0:31:29](https://www.youtube.com/watch?v=sg22677pUEs&t=1889s) ModuleList 與 Sequential` 老師講什麼:很多個相似的層可以放進 ModuleList,用編號取出,減少重複寫法;Sequential 把多層串成一個大層,資料進來會自動依序經過每一層(例如線性→ReLU→線性),前一層的輸出就是下一層的輸入。
- `## [0:34:07](https://www.youtube.com/watch?v=sg22677pUEs&t=2047s) 為什麼不能用 Python 的 list` 老師講什麼:state_dict 等功能是用遞迴往下找每個子模組來收集參數;用 Python 一般 list 裝的層不會被登記成子模組,結果參數清單是空的。結論:有參數的子層一定要用模組類別裝。
- `## [0:38:01](https://www.youtube.com/watch?v=sg22677pUEs&t=2281s) 訓練模式與驗證模式` 老師講什麼:Dropout(訓練時隨機丟掉部分元素防過擬合)和 Batch Normalization 只在訓練模式作用;訓練前呼叫 train、驗證時呼叫 eval,兩者也是遞迴套用到所有子模組,再次印證要「模組裡放模組」。
## 3. 老師強調/會考/不考的地方(原句已驗證;寫進筆記時 ASR 錯字要改正)
- (0:39:54) [強調] 「所以這也是印證了我們之前說的要在模組裡面寫模組不要在模組裡面寫Python基本性別」 → 模型裡帶參數的子層要用 nn.Module 類別(如 ModuleList)裝,不要用 Python 一般的 list;助教在 0:37:30 下過一次結論,這裡又重複一次
## 3b. 數學段候選(程式抓的,只是提示;寫「跳過提示」行用)
0 段候選(門檻 3.0 字/30 秒)
## 4. 這章摘要與重要度
(助教 PyTorch 教學影片,時間是那支影片的時間)PyTorch 的模型都是一個「模組」:開頭先宣告有哪些層,再寫資料進來要怎麼一層層處理;模組可以一層包一層,存參數、切換訓練或驗證模式時會自動往下找到每一層。(一般)
## 5. 整堂課的提醒(ASR 錯字、老師口誤、投影片缺公式等;只用跟這章有關的)
- 這支只有約 1 小時 20 分(老師 1:18:56 下課),下半場改看助教預錄的 PyTorch 教學影片(約一個半小時),筆記在第 06–09 章,章名前面有「PyTorch:」,影片時間是那支影片自己的時間。
- PyTorch 教學是 2024 年錄的舊影片,片中提到的作業說法(例如建議用 teacher forcing、之後要用 Hugging Face)不代表今年,今年作業以今年公告為準。
- 課表寫的是「Text Classification, NB, NN」,但實際上還在講 W2_Word 投影片(p.17–47)的語言模型和詞向量;Naive Bayes 只在 0:55:59 拿來對比「統計」和「模型學習」。
- 開頭 0:00:27–0:02:24 有網路和回音問題,0:03:55–0:04:32 在調整直播畫面,內容沒有缺。
- 逐字稿有語音辨識重複行(0:27:41–0:29:20 幾乎每句重複兩次、0:39:37 一句重複四次),不影響理解。
- 全片沒有下課休息,一路講完(0:00:01–1:26:08)。
- 逐字稿 0:01:32–0:01:53 有語音辨識重複句與亂碼(同一句重複五次、CUDA 版本被辨識成 ientes/analytical sci-fi/evangelical sci-fi),內容只是「別直接 pip install,到官網選版本」。
- 0:35:46 老師說「這是新的嗎」,接著改用口述講 Google Bomb。p.31 的文字檔裡已經有「Google Bomb/Data Poisoning」,可能是 10/1 更新版才加的,直播畫面也許還是舊版。不確定。
- p.33–38 的 word2vec 細節,老師是用回顧的方式講的,沒有逐頁翻:p.34 共現矩陣、p.38 SGD 那頁沒有明確講到;0:47:21 的 A、B、C softmax 計算例子,對應的是 p.35 還是 p.36(只有圖),不確定。
- 老師好幾次把模型輸出的「機率」說成 perplexity(例如 0:45:48、0:48:31),應該是口誤,寫筆記時要寫成 probability,不要寫成困惑度。
- 老師 1:08:44 已經宣布下課,接著又講了約 5 分鐘 activation function(p.46–47),1:13:47 才真正收尾,所以第 05 章沒有在 1:08:44 切開。1:13:27 說的「這一段的敘述」應該是指 p.47 的 softmax、sigmoid、tanh、ReLU 表格,只用一句帶過。p.48(In text viewpoint)沒講,下週應該從 p.48 開始。
- 第 04 章長約 13.5 分鐘,比建議的 15 分鐘短一點;它講 contextual embedding,跟第 05 章的 NN 基礎主題不同,所以沒有合併。
- [PyTorch 影片,第 06–09 章] 投影片 p.7 寫模型是 y = ax²+b,助教口頭說成「y等於ax加b」(0:04:08);投影片寫「four data points」但只列三個點 (-1,1)、(1,2)、(2,3),助教口頭念的點也對不上(0:04:36 說 -1 對 1、-1 對 2、-2 對 3)。寫筆記以投影片的 y = ax²+b 和三個點為準。
- [PyTorch 影片,第 06–09 章] 逐字稿有大量語音辨識錯字,寫手要自己還原:T度=梯度、correct function=collate function、translation=truncation、badge size=batch size、relude/Renew=ReLU、MN backward=MmBackward、nodegrade=no_grad、width.backward=with torch.no_grad()、nonpy=NumPy、viewed=view、birth=BERT、復迴圈=for 迴圈、增刮號=中括號、高雄宇=高宏宇;0:23:00 的「3e」應是 stride (3, 1)、0:22:02 的「13」是 (1, 3)。
- [PyTorch 影片,第 06–09 章] 助教把 BERT 稱為「auto encoder」(1:21:5x 起),對應投影片 p.60–61 的「Transformer Auto-encoder」,指的是編碼器式 Transformer,不是一般說的自編碼器;寫筆記時要說清楚,避免混淆。
- [PyTorch 影片,第 06–09 章] 第 2 章只有約 14 分鐘,略低於 15 分鐘下限;因為「模組」是獨立概念,而第 3 章(自動微分+訓練迴圈)已約 25 分鐘,沒有再合併。若主 session 想更細,第 3 章可在 0:51:20 切成「自動微分」與「損失函數、優化器與線性迴歸」兩章(各約 11、13.5 分鐘)。
- [PyTorch 影片,第 06–09 章] 投影片檔放在 2026 資料夾,影片是 2024 年錄的;對照下來頁序與講解內容一致(p.62 是結尾的笑話頁,沒有內容),但不確定 2026 版投影片是否和 2024 錄影時的版本完全相同。
- [PyTorch 影片,第 06–09 章] emphasis 只放了助教明講作業相關或重複強調的地方;另外兩處助教有說「注意」或「建議」但跟作業無關,沒列進去:0:53:00「不要用訓練的資料來測試」、0:24:47「儘量用矩陣運算的方式來運算」(兩句都已過 quote_check)。
- [寫手注意,第 06–09 章] 這四章是助教的程式教學,但主理人不看程式碼、考試不考寫程式:預設看得到的內容寫「這個元件在做什麼、為什麼需要它」+生活比喻(例:optimizer 像導航決定下一步往哪走);程式碼最多一小段,放進「(進階,可跳過)」摺疊。Exam-ready 只放投影片上的英文概念句(例如 tensor、autograd、loss、optimizer 的說明),不放程式碼行;投影片沒有完整英文句時用短的英文定義並標 (my wording)。Self-check 問「為什麼/比較」,不問語法。助教不是老師,不標【老師強調】,要標就寫【助教強調】+時間。
## 6. 投影片文字(這章範圍)
**這幾頁的公式或內容只在圖裡(文字檔抓不到),寫 Exam-ready 與公式前先用 Read 看這幾張圖:**
- pytorch_tutorial_NTHU_NLP p.24 → C:\D槽\TAICA課程\_work\notes-v2\nlp-w4\img\brief_pytorch_tutorial_NTHU_NLP_p024.png
- pytorch_tutorial_NTHU_NLP p.27 → C:\D槽\TAICA課程\_work\notes-v2\nlp-w4\img\brief_pytorch_tutorial_NTHU_NLP_p027.png
- pytorch_tutorial_NTHU_NLP p.28 → C:\D槽\TAICA課程\_work\notes-v2\nlp-w4\img\brief_pytorch_tutorial_NTHU_NLP_p028.png
- pytorch_tutorial_NTHU_NLP p.30 → C:\D槽\TAICA課程\_work\notes-v2\nlp-w4\img\brief_pytorch_tutorial_NTHU_NLP_p030.png
- pytorch_tutorial_NTHU_NLP p.31 → C:\D槽\TAICA課程\_work\notes-v2\nlp-w4\img\brief_pytorch_tutorial_NTHU_NLP_p031.png
- pytorch_tutorial_NTHU_NLP p.32 → C:\D槽\TAICA課程\_work\notes-v2\nlp-w4\img\brief_pytorch_tutorial_NTHU_NLP_p032.png
--- pytorch_tutorial_NTHU_NLP p.24 ---
Construct a Model
24
The model is defined as:
class myModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.layers = …
def forward(self, input):
...
return ...
model = myModel()
logits = model(input)
Obtain the output logits
torch.nn.Module.__call__
A Model in PyTorch is basically a torch.nn.Module object
Two member functions that must be defined
when constructing deep learning models
--- pytorch_tutorial_NTHU_NLP p.25 ---
Construct a Model
Components in a model
25
Module
Function
torch.nn.Linear
Linear projection layer (fully connected)
torch.nn.Conv2d(1d/3d)
1/2/3d convolution layer
torch.nn.RNN
Recurrent Neural Network layer
torch.nn.LSTM
Long Short-term memory network layer
torch.nn.MaxPool2d(1d/3d)
Max pooling layer
torch.nn.Embedding
Embedding layer
torch.nn.BatchNorm2d(1d/3d)
Batch normalization layer
torch.nn.Sequential
Sequentially combined moduls
torch.nn.ModuleList
List of modules
torch.nn.ModuleDict
Dictionary of modules
--- pytorch_tutorial_NTHU_NLP p.26 ---
Member functions in a Model
Most commonly used member functions.
26
Module
Function
model.forward()
Forward pass
model.state_dict()
Return an OrderedDict contains parameter names and
tensors
model.parameters()
Return an iterator for parameter tensors
model.named_parameters()
Return an iterator for parameter names and tensors
model.train()
Training mode
model.eval()
Evaluation mode
--- pytorch_tutorial_NTHU_NLP p.27 ---
Model Components
27
torch.nn.ModuleList:
class myModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.linear1 = torch.nn.Linear(128, 128)
self.linear2 = torch.nn.Linear(128, 128)
self.linear3 = torch.nn.Linear(128, 128)
def forward(self, input):
output1 = self.linear1(input)
output2 = self.linear2(input)
output3 = self.linear3(input)
return output1, output2, output3
class myModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.linear_list = torch.nn.ModuleList([
torch.nn.Linear(128, 128) for _ in range(3)
])
def forward(self, input):
outputs = ()
for i in range(3):
outputs += (self.linear_list[i](input), )
return outputs
Rewrite
--- pytorch_tutorial_NTHU_NLP p.28 ---
Model Components
torch.nn.Sequential:
28
def forward(self, input):
for module in self:
input = module(input)
return input
class myModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.linear1 = torch.nn.Linear(128, 128)
self.act = torch.nn.ReLU()
self.linear2 = torch.nn.Linear(128, 2)
def forward(self, input):
x = self.linear1(input)
x = self.act(x)
output = self.linear2(x)
return output
Source code
Rewrite
class myModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.layers = torch.nn.Sequential(
torch.nn.Linear(128, 128),
torch.nn.ReLU(),
torch.nn.Linear(128, 2),
)
def forward(self, input):
output = self.layers(input)
return output
--- pytorch_tutorial_NTHU_NLP p.29 ---
Use Modules in Modules
We recommend using torch.nn.Module objects within
a torch.nn.Module instead of basic Python data structures when parameters
are involved.
oThis ensures that the parameters are properly registered, tracked, and
optimized during training.
29
--- pytorch_tutorial_NTHU_NLP p.30 ---
Use Modules in Modules
e.g. model.state_dict() (return a state dictionary that contains all parameter
names and tensors) source code:
30
def state_dict(self, *args, destination=None, prefix='', keep_vars=False):
...
if destination is None:
destination = OrderedDict()
destination._metadata = OrderedDict()
...
for name, module in self._modules.items():
if module is not None:
module.state_dict(destination=destination, prefix=prefix + name + '.', keep_vars=keep_vars)
...
return destination
In most of the functions in a Module object (train(), eval(), parameters() … ), the
model recursively applies operations to all sub-modules. (just like a tree structure)
As a result, it is better to use ModuleList, which is a torch.nn.Module object.
--- pytorch_tutorial_NTHU_NLP p.31 ---
Use Modules in Modules
31
class myModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.linear_list = torch.nn.ModuleList([
torch.nn.Linear(128, 128) for _ in range(3)
])
def forward(self, input):
outputs = ()
for i in range(3):
outputs += (self.linear_list[i](input), )
return outputs
class myModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.linear_list = [
torch.nn.Linear(128, 128) for _ in range(3)
]
def forward(self, input):
outputs = ()
for i in range(3):
outputs += (self.linear_list[i](input), )
return outputs
ModuleList version:
List version:
print(model._modules) :
print(model._modules) :
--- pytorch_tutorial_NTHU_NLP p.32 ---
train() and Eval()
The member functions model.train() and model.eval() are for mode transfer.
(recursively)
Training mode:
oThe training mode in PyTorch activates certain layers and behaviors that are only needed
during training such as Dropout and Batch Normalization.
oIn this mode, the model adjusts its parameters through backpropagation and updates the
gradients during training.
Evaluation mode:
oThe evaluation mode is used for evaluation and inference, where layers like Dropout are
disabled and Batch Normalization uses fixed statistics instead of updating them.
oThis ensures that the model behaves consistently and produces deterministic outputs during
testing or inference without modifying its internal state.
32
## 7. 逐字稿(0:25:47 前後各多 1 分鐘,原始行)
[00:24:47] 儘量用矩陣運算的方式來運算
[00:24:50] 而不要用循序的方式來運算
[00:24:52] 因為tensor它內部
[00:24:55] 它對於這個矩陣運算有自己的
[00:24:58] 並行化的一些加速過程
[00:25:01] 假如我們這邊舉的一個範例是我們要normalize
[00:25:05] 所謂的normalize
[00:25:06] 就是
[00:25:07] 減平均除以標準差
[00:25:11] 這個過程我們可以
[00:25:12] 寫兩個套兩個復迴圈來寫
[00:25:15] 也可以
[00:25:15] 就是
[00:25:16] 用矩陣
[00:25:18] 矩陣運算的方式來寫
[00:25:20] 那這邊我們會發現
[00:25:22] 它的效能會差很多
[00:25:24] 因為這就是
[00:25:25] 我們就
[00:25:26] 因為矩陣運算它實際上
[00:25:28] 相當於利用了PyTorch內部的一些加速功能
[00:25:31] 但是如果你是循序的話
[00:25:34] 它實際上就是你就是強制它一個一個來算
[00:25:37] 這其實是
[00:25:40] 相當耗時間的
[00:25:41] 也是一個相當沒有效率的做法
[00:25:45] 然後
[00:25:47] 接下來我們介紹了
[00:25:50] 建構模型的或者和資料的一個基本單位就是Tensor
[00:25:55] 那接下來我們就是要
[00:25:57] 通過這個Tensor來建構一個模型
[00:25:59] 那Tensor在模型當中的主要的一個
[00:26:03] 角色
[00:26:03] 就是
[00:26:04] 就是它的參數
[00:26:07] 在一個模型當中
[00:26:08] 它底層的參數
[00:26:10] 就是通過Tensor來存儲的
[00:26:12] 並且在Tensor的這個參數之上
[00:26:16] 有一個大的資料結構
[00:26:18] 叫做torch.nn.module
[00:26:21] 也就是
[00:26:22] 模組
[00:26:23] 所謂的模組
[00:26:25] 我們所有的模型它都是
[00:26:28] 它都需要是一個模組的物件
[00:26:31] 那假如說我們要創建一個新的
[00:26:33] 我們自己的模型
[00:26:34] 我們就繼承著這個模組
[00:26:37] torch.nn.module
[00:26:39] 然後再去複寫它的
[00:26:43] 我們自己特有的這樣一個
[00:26:46] 初始化的函數跟
[00:26:49] forward函數
[00:26:51] 初始化的函數它主要是定義
[00:26:53] 模型當中有哪些層
[00:26:55] 比方說我們可以有
[00:26:56] 線性的層還有什麼卷積層RNN層
[00:27:00] 各種各樣的層
[00:27:01] 然後
[00:27:02] 這個forward函數
[00:27:04] 就是當我們有一筆資料投進來的時候
[00:27:07] 模型要吃那筆資料的時候
[00:27:09] 那筆資料
[00:27:11] 它需要通過怎樣的處理方式
[00:27:14] 來獲得模型的output
[00:27:19] 那
[00:27:19] 這邊
[00:27:21] 也就是我們有這樣一個物件以後
[00:27:23] 新創建出來一個
[00:27:26] 這樣一個物件
[00:27:27] 然後物件在吃資料
[00:27:29] 這個input就是資料
[00:27:31] 把資料丟給這個模型以後
[00:27:34] 模型就會
[00:27:35] 自己處理去
[00:27:37] return出這個
[00:27:38] output就是我們所謂的logits
[00:27:41] 那這樣一個
[00:27:42] 這樣一個function這樣一個
[00:27:45] 把資料丟進來的這樣一個過程
[00:27:48] 它會呼叫這個torch.nn.module裡面的這個call
[00:27:51] 這個function
[00:27:52] 然後這個call function
[00:27:54] 會直接去呼叫它的forward
[00:28:00] 然後
[00:28:01] 這邊
[00:28:03] 有一個大概的就是在我們initialize模型的時候我們可以定義的一些層
[00:28:08] 像是linear
[00:28:09] 就是
[00:28:10] 常用的線性層
[00:28:11] 所謂的線性層就是
[00:28:13] 乘以一個矩陣
[00:28:15] 那當然我們
[00:28:17] 如果
[00:28:18] 形象的表示它其實就是一個
[00:28:20] fully connected
[00:28:21] 全連接的層
[00:28:23] 那
[00:28:23] 這邊
[00:28:24] convolution
[00:28:25] 這邊是卷積層
[00:28:27] 第二個是卷積層
[00:28:28] 卷積層大家在圖像處理的時候肯定是
[00:28:32] 經常會遇到
[00:28:33] 是一個非常有名的層
[00:28:34] 它可以是2D 1D 3D
[00:28:37] 在早期的NLP的使作過程當中
[00:28:39] 也會
[00:28:40] 時不時的出現這個卷積層
[00:28:43] 然後RNN跟LSTM
[00:28:45] 這個在我們NLP的課上應該經常有
[00:28:49] 接觸到
[00:28:50] 那這兩個層其實就是序列資料生成的
[00:28:53] 序列資料生成的一個模組
[00:28:57] 然後max pooling這個也是常用於圖像處理的
[00:29:01] 內容
[00:29:03] 然後embedding
[00:29:04] embedding往往是把資料
[00:29:06] 往往是把
[00:29:07] 一些電腦
[00:29:09] 實際上看沒辦法處理的資料轉化成能看得懂的
[00:29:12] 也就是說把一個
[00:29:14] 某個東西轉化成一個向量
[00:29:16] 那這個東西它又會有個對應的ID
[00:29:20] 通過這個embedding層把ID映射到向量
[00:29:25] 它內部其實也就是一個
[00:29:27] 矩陣乘法的一個形式
[00:29:29] 然後再是Batch Normalize
[00:29:31] 這個是我們在運算的時候它會有
[00:29:34] 它會需要
[00:29:36] 時不時的
[00:29:38] 進行一些
[00:29:39] 減平均除以標準差的動作
[00:29:41] 來防止它的資料過於發散過於極端
[00:29:45] 然後Sequential跟ModuleList、ModuleDict
[00:29:48] 是
[00:29:49] 通過
[00:29:50] 大家可以就ModuleList跟ModuleDict
[00:29:52] 就是
[00:29:54] 模組版本的Python的List跟Dictionary
[00:29:58] 那這個Sequential其實就是把
[00:30:00] 很多個
[00:30:01] 層包成一個
[00:30:03] 上下串成一個大層
[00:30:07] 然後我們
[00:30:09] 在這個模型背面
[00:30:11] 建構出來以後
[00:30:12] 模型也會有一些自己的
[00:30:14] Member Function
[00:30:15] 比方說
[00:30:16] Forward
[00:30:17] 剛剛我們有講過就是
[00:30:18] 資料進來以後要怎麼處理
[00:30:20] 然後StateDictionary
[00:30:23] 它會回傳一個OrderDictionary
[00:30:25] 那這個Dictionary它的key
[00:30:27] 是
[00:30:28] 參數的名稱
[00:30:30] 然後它的value就是參數的值
[00:30:32] 參數的內容
[00:30:34] 也就是參數對應的向量
[00:30:36] 那這邊
[00:30:37] 這邊
[00:30:38] StateDictionary它其實
[00:30:40] 我們可以連
[00:30:41] 它其實跟NameParameter有一點比較像一點
[00:30:45] 但是NameParameter它
[00:30:46] 回傳的是一個
[00:30:48] 回傳的是一個迭代器
[00:30:50] 就是我們可以用
[00:30:52] 復迴圈
[00:30:53] 來展現它裡面
[00:30:55] 把裡面的內容給Print出來
[00:30:57] 它裡面Print也是
[00:30:59] 參數的名稱跟Tensor
[00:31:01] 那這邊
[00:31:02] 沒有Name的Parameter它實際上只會
[00:31:05] 它這個迭代器只會OP出來一些
[00:31:07] 只會吐一些
[00:31:08] 就是參數的
[00:31:09] 內容
[00:31:12] 然後model.train和EVAL
[00:31:15] 它就是把模型的
[00:31:17] 模型的
[00:31:19] 一個模式轉換
[00:31:20] 就是把它變成Train
[00:31:22] 或者是
[00:31:23] Evaluation
[00:31:25] 訓練模式跟驗證模式之間的轉換
[00:31:29] 首先我們來看就是ModuleList該怎麼
[00:31:32] 大概的做法
[00:31:34] 左邊是我們創建出來的一個模型
[00:31:37] 那這個模型它裡面有三層
[00:31:39] 一層
[00:31:40] 三層都是Linear而且差不多
[00:31:43] 那在一個Input進來以後
[00:31:45] 這個Input會分別位給這三層
[00:31:47] 並且獲得他們各自的Output
[00:31:50] 這個各自的Output串成一串
[00:31:52] 然後
[00:31:54] Return出來
[00:31:55] 那這一個方式其實就可以改寫成
[00:31:58] 就是因為它這三個
[00:32:00] 這三個Linear它實際上是
[00:32:02] 從
[00:32:03] 我們可以把它直接寫成一個
[00:32:05] List
[00:32:06] 的形式
[00:32:08] 那這個List
[00:32:11] 它其實
[00:32:12] 它也就是跟Python的List有點相似的地方
[00:32:15] 就是它可以通過這個中括號一個整數的方式
[00:32:18] 來取
[00:32:19] 它我們要的是其中的
[00:32:21] 某一層
[00:32:23] 當這個層越來越多就當這邊的Linear越來越多的時候
[00:32:28] 很多很多的Linear
[00:32:29] 那實際上用這種方式其實會大大減少我們的
[00:32:33] 就是Coding的難度吧
[00:32:34] 就Coding的複雜程度
[00:32:39] 然後
[00:32:39] 第二個
[00:32:41] 是有關於Sequential
[00:32:43] Sequential它底層的做法
[00:32:45] Sequential它有一個
[00:32:46] 自帶的Forward
[00:32:48] 就是它的Input喂進來
[00:32:50] 它會
[00:32:51] 依序的餵給它自己的每一層
[00:32:55] 每一個模組每一個
[00:32:57] 麾下的模組
[00:32:58] 然後
[00:33:00] 這個前一個output
[00:33:02] 就會餵給下一個的
[00:33:03] 喂到下一個作為下一個的Input
[00:33:06] 這樣一層一層喂下去
[00:33:08] 一直到獲得這個最終的output
[00:33:13] 就像在這裡我們這邊的左邊的模型它有三層
[00:33:17] 第一層是Linear
[00:33:18] Linear的output再過一層Renew
[00:33:21] 就是過一層
[00:33:22] 激活函數
[00:33:23] 然後再
[00:33:24] 過一層Linear
[00:33:26] 那麼這邊就可以寫成把這三層包成一個大的Sequential
[00:33:31] 這個Sequential就是
[00:33:32] 第一層是Linear第二層是Renew
[00:33:34] 第三層還是Linear
[00:33:36] 在一筆資料進來的時候
[00:33:37] 就可以直接丟給這個大的
[00:33:40] 組合起來這個層
[00:33:42] 它就會直接在底
[00:33:43] 底層幫我們
[00:33:45] 第一層的output會給第二層
[00:33:46] 第二層的output會給第三層
[00:33:48] 第三層的output再output出來
[00:33:49] 再return出來
[00:33:50] 作為
[00:33:51] Forward return value
[00:33:54] 然後這個是
[00:33:56] 這個是Sequential這個
[00:33:59] 這個函數
[00:34:00] 這個功能
[00:34:02] 是這個模組它能夠
[00:34:04] 完成的一些功能
[00:34:07] 然後另外
[00:34:09] 為什麼我們就
[00:34:10] 接下來我們就會可能會產生一個問題就是為什麼我們不用
[00:34:13] Python它自己的
[00:34:15] List
[00:34:16] 而我們一定要用
[00:34:17] Module List
[00:34:19] 因為Module List其實我們剛剛也看到
[00:34:21] 它實際上完成的功能也就是
[00:34:25] 很大程度上
[00:34:27] 也就是
[00:34:28] Python List的這樣一個功能
[00:34:32] 就是
[00:34:32] 存儲各種各樣的模型然後串成一個List的功能
[00:34:35] 那為什麼我不直接用Python的List
[00:34:38] 但實際上
[00:34:39] 我們就會發現
[00:34:40] 這個
[00:34:41] 我們
[00:34:42] 仔細去看它每一個
[00:34:43] 每一個Member Function的底層Code
[00:34:46] 我們就會發現
[00:34:48] 它很多的Code的實作
[00:34:50] 都是用一個遞迴的方式實作
[00:34:52] 也就是當我們
[00:34:54] 比方說像下面這個例子
[00:34:56] 當我們去呼叫StateDictionary的時候
[00:34:58] 它實際上
[00:34:59] 我們回顧一下StateDictionary
[00:35:02] 它需要return回來的
[00:35:04] 是這個模型
[00:35:07] 的所有參數名稱
[00:35:09] 跟參數的
[00:35:11] 內容
[00:35:12] 參數的Tensor
[00:35:13] 它組成了一個
[00:35:15] OrderDictionary
[00:35:17] 那也就是說
[00:35:18] 我們呼叫這個函數的時候
[00:35:21] 我們的Python需要往下找
[00:35:23] 找出所有的
[00:35:26] 所有的
[00:35:27] 參數
[00:35:28] 和它們對應的名稱並且return回來
[00:35:31] 這個尋找的過程
[00:35:32] 是一個
[00:35:33] 遞迴的過程
[00:35:35] 在呼叫StateDictionary的時候在下面
[00:35:38] 它會呼叫
[00:35:39] 自己每一個模組
[00:35:42] 每一個子模組的
[00:35:43] 呼叫StateDictionary
[00:35:45] 並把它給加進來
[00:35:47] 加到自己的
[00:35:49] 加到這個
[00:35:51] 副模組
[00:35:52] 它的StateDictionary裡面去
[00:35:55] 所以
[00:35:56] 這邊是
[00:35:57] 通過NameCommon
[00:35:58] 通過這個復迴圈來便利Self.下滑線Module的這個
[00:36:03] 成員變量
[00:36:04] 這個成員變量其實存的就是
[00:36:06] 模組類型的東西
[00:36:07] 那假如所以假如說
[00:36:09] 我們把
[00:36:11] 我們把
[00:36:12] 我們不用
[00:36:14] 模組類別的東西我們就用Python的基本類別
[00:36:16] 它如果只是一個List
[00:36:18] 那麼
[00:36:19] 實際上它就並不是一個模組類別的東西
[00:36:23] 所以它就不會被存進來
[00:36:25] 就像這個範例
[00:36:26] 左邊
[00:36:27] 是一個
[00:36:29] 用ModuleList來實作的一個
[00:36:33] 實作的一個模型
[00:36:34] 右邊我們只是用Python的基本型
[00:36:37] 也就是
[00:36:37] 增刮號的那個模組
[00:36:40] 然後我們再把我們
[00:36:41] 創建出這樣一個物件以後在下面就創建出一個物件以後
[00:36:45] 再把這個物件的下滑線模組這個東西
[00:36:48] 也就是我們StateDictionary
[00:36:50] 要遞迴要去尋找的這樣
[00:36:52] 就是
[00:36:53] 用來遞迴的這個
[00:36:55] 成員變量
[00:36:56] 把它印出來以後發現
[00:36:58] 用
[00:36:59] ModuleList
[00:37:01] 它實際上能夠順利的存到這個下滑線模組這個
[00:37:05] 成員變量裡面去
[00:37:06] 但是如果我們用List
[00:37:07] 它實際上這個模組是空的
[00:37:09] 也就是當我們
[00:37:11] 需要去回
[00:37:11] 回傳它所有參數的名稱的時候我們去呼叫StateDictionary的時候
[00:37:16] 如果我們用Python的基本型
[00:37:19] 實際上我們回傳出來是個空的東西
[00:37:21] 因為
[00:37:22] 它這個模組它裡面沒有存任何東西
[00:37:27] 所以這就是告訴我們就是
[00:37:28] 告訴我們一個結論就是
[00:37:30] 在
[00:37:31] 寫模型的時候
[00:37:33] 只要我們的
[00:37:35] 模組它裡面是有參數只要裡面有東
[00:37:38] 這個成員變量它裡面有參數
[00:37:40] 它是一個層的定義
[00:37:42] 模組的定義
[00:37:43] 那我們就要用Module
[00:37:44] Torch.nn.Module
[00:37:47] 這一個類別的東西
[00:37:50] 來實現對於
[00:37:52] 來實現對於這些
[00:37:54] 模組的存儲
[00:37:55] 而不要用Python的基本
[00:37:56] 型別
[00:38:00] 然後
[00:38:01] 接下來就是有關於訓練模式跟
[00:38:04] 驗證模式
[00:38:05] 因為剛剛我們在介紹
[00:38:07] Model
[00:38:08] 介紹模型的
[00:38:09] 成員函數的時候我們有介紹過
[00:38:12] 就是在訓練模式跟驗證模式之間的轉換
[00:38:15] 在訓練模式當中
[00:38:18] 因為我們要對模型做訓練
[00:38:21] 那模型當中可能會有一些像Dropout
[00:38:23] 就在訓練時候為了防止overfitting
[00:38:26] 所做的一些
[00:38:28] 所做的一個
[00:38:30] 拋棄部分
[00:38:32] 拋棄部分元素的一個處理
[00:38:34] 一個Dropout和一個BatchNormalize
[00:38:37] 這個也是在訓練過程當中我們會需要用到的
[00:38:41] 那這兩個
[00:38:42] 它會在Train訓練模式的時候被激活
[00:38:46] 它只會在訓練模式的時候
[00:38:49] 發揮作用
[00:38:50] 就Dropout才會真的丟東西
[00:38:52] 而在
[00:38:53] 驗證模式的時候
[00:38:56] Dropout就會不起作用
[00:38:58] 它這個Dropout跟BatchNormalize
[00:39:00] 就會不起作用
[00:39:04] 那這是訓練模式跟驗證模式的區別
[00:39:06] 一般來說訓練模式就是我們在訓練模型之前
[00:39:09] 我們會Model.Train
[00:39:11] 把它
[00:39:12] 把這個模型以及下面所有的子模組都變成訓練模式
[00:39:16] 然後在驗證的時候
[00:39:18] 就在我們有
[00:39:18] Evaluate
[00:39:19] 就是
[00:39:20] 驗證集驗證Dataset進來的時候
[00:39:23] 會
[00:39:24] 呼叫這個Model.EVAL的這個
[00:39:27] 函數
[00:39:28] 把它變成驗證的模式
[00:39:31] 然後這兩個模式
[00:39:32] 它都是用遞迴的方式
[00:39:34] 也就是我們呼叫一個模型的
[00:39:38] Train的時候
[00:39:39] 它會
[00:39:40] 尋找下面的每一個
[00:39:42] 尋找下面的各個模組
[00:39:45] 也子模組就是每一層
[00:39:46] 每一個torch.n.module
[00:39:48] 然後就類別的東西
[00:39:49] 它都會去呼叫它的Train
[00:39:52] 它也是這樣遞迴下去的
[00:39:54] 所以這也是印證了我們之前說的
[00:39:56] 要在模組裡面寫模組
[00:39:57] 不要在模組裡面寫Python基本性別
[00:40:01] 然後
[00:40:04] 我們介紹完了模型大概的建構
[00:40:06] 接下來我們就是要訓練這個模型
[00:40:09] 那訓練我們會有兩步吧
[00:40:10] 就首先
[00:40:11] 資料會
[00:40:12] 未進來獲得預測結果
[00:40:14] 預測結果會傳出loss
[00:40:15] 我們最小化loss就會回傳T度
[00:40:19] 那這個T度
[00:40:20] 通過
[00:40:21] 一個叫
[00:40:21] 反向傳播的方式來計算
[00:40:23] 也就是
[00:40:24] 這邊的loss.backward
[00:40:27] 這個backward它完成的具體功能
[00:40:31] 就是
[00:40:32] 逐層的往回
[00:40:34] 去計算偏微分
[00:40:35] 去計算T度
[00:40:38] 通過這個偏微分來計算T度以後
[00:40:41] 再把T度存在
[00:40:43] 各個參數的
[00:40:44] .grade這個變量裡面
[00:40:47] 注意是各個參數的grade這個變量
[00:40:50] 而不是中間計算結果的變量
[00:40:53] 的grade
[00:40:54] 成員變量這裡面
[00:40:57] 它在計算的時候呢
[00:40:58] 會通過一個
[00:41:00] 有象
[00:41:01] 無環圖
[00:41:02] 就是
[00:41:03] DAG
## 8. 寫作規則
(這是 `_筆記SOP.md` 第 3.1、4、5、6 節的濃縮版。兩者衝突時以 SOP 為準。)
讀者:碩士生,兩門課期末是英文考試。要只看筆記就能學會,講得比老師好懂。畫面要簡潔。
**概念優先(2026-09-26 主理人)**:主理人只想懂概念,不想補數學、不想看程式碼和座標圖。兩門課的考試也都是問答題、不考算式(AI W1 1:16:52;NLP W3 1:47:41、2:48:36)。所以:
- 每段預設看得到的只有:白話摘要(2–4 句)+**一句生活比喻**(例:模擬退火像投資理財,年輕時敢冒險、越老越保守)+「考試可能怎麼問」一句。
- 數學推導、公式、手算、程式碼、座標圖,全部收進標題寫「(進階,可跳過)」的摺疊,例如「它到底怎麼運作?(進階,可跳過)」。每段最多一個進階摺疊,不要寫長篇計算。
- 演算法要能「用文字說出步驟」(考試可能要你描述),這一點放在預設看得到的地方,不用數字。
- **重心比例**:白話理論與概念模式(它在解決什麼問題、核心想法、跟別的方法差在哪、優缺點、生活比喻)占主要篇幅;數學與程式細節只用一兩句帶過,細節收進進階摺疊。
**圖文並茂(2026-09-26 主理人:不要只有文字)**:
- 每章至少 2–3 個圖,放在**預設看得到**的地方,每個圖前後各用一兩句白話說明「這張圖在看什麼」。
- 流程、步驟、因果、比較 → 用 mermaid 流程圖(```mermaid,flowchart LR 或 TD;節點文字用中文、加雙引號;一張圖不超過 10 個節點)。
- 投影片上的示意圖、架構圖 → 用 [[IMG: …]] 放投影片圖。
- 仍守「每個 ## 段落最多一種視覺元素」。
### 輸出兩個檔
1. `chNN.md`(Notion 寫法,不含頁面標題),結構固定:
- 第一行:章節包第 1 節那行,原樣照抄。
- 第二行起(有數學段才寫):**跳過提示**,每段一行,讓主理人看影片時知道從哪跳到哪。用章節包第 3b 節的候選當提示,對照第 7 節逐字稿確認(只標老師連續講公式、推導、矩陣、微積分、機率計算、程式細節超過約 1 分鐘的段落;概念講解和比喻不算):
`跳過提示:(1:31:02–1:35:40) 老師在推導梯度公式,聽不懂可以直接跳到 [1:35:40](YouTube 連結),接著講「步長 α 怎麼選」。`
- `## 重點`:三點中文,每點一到兩句。
- `## Exam-ready`:3–10 行英文,**從章節包的投影片文字逐字抄**,每行 `- **Term**: "原句"(Ch3 p.14)`。老師有明確證據才在行尾加 `【老師強調】(h:mm:ss)`。
**每一行下面一定要有一行縮排的中文解釋**(主理人英文不好,看不懂的英文等於沒用):
```
- **Hill climbing**: "It keeps track of one current state and on each iteration moves to the neighboring state with highest value."(Ch4 p.5)
- 中文:爬山法只記住「現在這一個狀態」,每一輪都移到分數最高的鄰居。白話:一直往比較高的地方走一步。
```
中文要先把句子意思講清楚,再補一句白話;最後用「英文(中文)」列出這句裡 1–3 個難字,例:sparse(稀疏)、distinct terms(不重複的字)。
**一行只放一句投影片原句**。同一頁有多句要考就拆成多行,每行各接一行中文;不要用分號串三句以上,不要把計算量 O(...) 塞進去。
- 章節包第 2 節的每一段:`## [h:mm:ss](連結) 標題`(照抄),下面 2–4 句白話摘要,其餘全部收進摺疊:
```
問句(例:用生活例子講,BFS 在做什麼?)
內容
```
摺疊種類(需要才放):用生活例子講?/它到底怎麼運作?/要先懂什麼?(老師假設你會的數學或概念,短版教學)/老師原話是什麼?(「原話」(h:mm:ss),只放重要的,最多 5 句)。
- 「它到底怎麼運作?」要用一組小數字把這段的演算法**真的跑 1–3 步**(例:算出梯度、更新一次、比較兩個 α),不是只示範定義的加減乘除。全章盡量沿用同一組數字,讓前一段的答案能在下一段被驗證。
- 每段正文要回答讀者最可能卡住的一個「為什麼」。投影片公式方向跟題目相反、或投影片說「解不出來」時,用一兩句講出原因,自己補的標(我補充)。
- 投影片句子停在公式前(公式在圖裡)時:Exam-ready 在粗體詞條上補公式、引號內保持原句;正文寫出同一條式子。公式圖看章節包第 6 節列出的 PNG。
- `## Self-check`:2–4 題英文考題,答案收摺疊。**至少一題考老師強調的內容**;只出 explain/why/compare 這類問答題,**不出要代數字計算的題目**(考試不考算式);不出「老師和投影片哪裡不同」這類不會考的題目。每題格式:
```
Q1. English question?(中文:中文題目)
**Answer**: English answer.
中文:把答案完整講一遍(不是只翻一句),讓看不懂英文的人也知道要怎麼答。
```
- **最後一行**:章節包第 1b 節那行(下一章連結),原樣照抄。讓讀完的人直接點下一章。
- 不要把章節包或這份規則裡的指示句寫進筆記(例如「寫筆記時照投影片寫」「已改正 ASR 錯字」)。
- 長度:全文不超過 16,000 字元(跟 check_note.py 同一個數字)。**不要為了壓字數反覆刪改**(實測一章最多花 12 輪在刪字);超過時只刪進階摺疊裡的第二組算例,比喻、比較表、圖說、「老師說不用背」的提醒都不刪。
- 預設看得到的正文不放計算量 O(...)、代號對照(例如 SMART 字母)、課本出處考據,一律移進進階摺疊。
2. `chNN.concepts.json`:JSON 陣列,4–12 個考試可能問的術語,每個物件:
`name`(英文)、`zh`、`type`(概念/演算法/公式/人物事件/前置知識/行政)、`signal`("老師說會考"/"老師強調"/"核心(我判斷)"/"")、`evidence`(有 signal 前兩種時必填:原句+時間)、`definition_en`(投影片原句;沒有就註明 (textbook)/(lecture)/(my wording))、`plain`(一句中文)、`a4`(≤150 字元英文,可夾極短中文;期末拼貼用的小方塊)、`time`、`slides`、`prereq`(英文名陣列)。
### 風格鐵律
- 不用 emoji 或裝飾符號(✓✗★⚠ 都不要;→ 可以)。不用 callout。不用 `$`。時間不要用 code 樣式。
- 每個 `##` 段落最多一種視覺元素:一張圖、或一個表格、或一個 mermaid。
- 摺疊標題是問句,前面不加符號。
- 圖片最多 3 張,只放文字取代不了的圖。放法:單獨一行 `[[IMG: | 中文圖說]]`,PNG 用 `slides_to_png.py <圖片資料夾> <頁> --dpi=110` 產生。
- 考試訊號只在老師明確說時標。老師只說「不用背」「不講」就寫「注意:……」。
- 老師口誤或跟投影片不同:照投影片寫,加「注意:老師口頭說的是……」。
- 引用老師的話時,ASR 錯字改成正確的字。
### 沒有投影片時
不要憑記憶逐字重現課本段落或數值表。英文定義用自己的話寫、句尾標 (my wording);Exam-ready 每行標「(自擬,投影片待補)」。例子只用老師講的。
### 寫完之後(只做一次)
跑檢查:
`C:\Users\user\.cache\meeting-record\venv\Scripts\python.exe C:\Users\user\.claude\scripts\check_note.py --transcript <逐字稿> --slides <投影片 txt …> --start <起> --end <訖> --vid <影片 ID>`
- STYLE/VISUAL/TIME/FORMAT:全部改掉。
- QUOTE:確認是不是你改正了 ASR 錯字(是就保留),不是就改成原文或拿掉引號。
- ENGLISH:確認是不是投影片斷行造成的(是就保留),不是就改成投影片原句。
**省額度守則**:章節包裡已經有你需要的全部資料。不要再去讀整份逐字稿、整份投影片、segments.json 或手冊。一次寫好整個檔(Write 一次),檢查後集中修改。