### [Deeplearning.ai GenAI/LLM系列課程筆記](https://learn.deeplearning.ai/)
#### [Large Language Models with Semantic Search。大型語言模型與語義搜索 ](https://hackmd.io/@YungHuiHsu/rku-vjhZT)
#### [Finetuning Large Language Models。微調大型語言模型](https://hackmd.io/@YungHuiHsu/HJ6AT8XG6)
- [為何要微調(Why finetune)](https://hackmd.io/@YungHuiHsu/HJ6AT8XG6)
- [微調的適用範圍(Where finetuning fits in)](https://hackmd.io/@YungHuiHsu/Bkfyyh7zp)
- [指令調整(Instruction-tuning)](https://hackmd.io/@YungHuiHsu/B18Hg2XMa)
- [資料準備(Data preparation)](https://hackmd.io/@YungHuiHsu/ByR-G24GT)
- [訓練過程(Training process)](https://hackmd.io/@YungHuiHsu/rJP6F2Vf6)
- [評估與迭代(Evaluation and iteration)](https://hackmd.io/@YungHuiHsu/ryfM524Ga)
- [考量與開始(Considerations on getting started now)](https://hackmd.io/@YungHuiHsu/r1KGob8fT)
---
### 其他重要參考資源(蒐集中)
#### [State of Open Source AI Book - 2023 Edition](https://book.premai.io/state-of-open-source-ai/)
---
# Finetuning Large Language Models
## [訓練過程(Training process)](https://learn.deeplearning.ai/finetuning-large-language-models/lesson/6/training-process)
### 課程概要
- 提供完整的訓練流程demo
* LLM的訓練過程與其他神經網絡相似,涉及添加訓練數據、計算損失和更新權重
* 使用PyTorch和HuggingFace可以進行深入的模型訓練,且有專用代碼示範
* Lamini Llama庫提供簡化的模型訓練方法,只需三行代碼即可完成
* 訓練後的模型可以在本地保存並加載,並進行微調以提高效
### 訓練:與其他神經網絡相同(Training: same as other neural networks)

- 訓練過程的核心
* 添加訓練數據:首先,你需要提供一定量的訓練數據,這些數據將用於訓練模型,使其能夠更好地執行特定任務
* 計算損失:模型在初次預測時可能會有所偏差,因此需要計算模型的預測與實際結果之間的差異,這稱為損失
* 透過模型進行反向傳播(Backprop through model):當模型計算出損失後,它將使用反向傳播算法來找出哪些權重和偏差導致了高損失
* 更新權重:根據計算出的損失,模型的權重將進行調整,以改善其預測能力
- 超參數(Hyperparameters)
- 學習率(Learning rate)
- 這是一個控制模型學習速度的參數。太高的學習率可能會導致模型在訓練過程中忽略某些細節,而太低的學習率則可能會使訓練過程過於緩慢
- 學習率計劃器(Learning rate scheduler)
- 這是一種動態調整學習率的方法,通常會在訓練過程中根據某些條件減少學習率
- 優化器超參數(Optimizer hyperparameters)
- 這些參數控制優化器的行為,優化器是用於更新模型權重的工具。不同的優化器和其超參數可以影響模型的訓練速度和效果
### 訓練流程的程式碼示意(Run through general chunks of training process in code)
這邊用的範例是pytorch的訓練流程

- 訓練流程概述
* 設定訓練循環(Epochs):一個epoch代表模型已經過整個訓練數據集一次。根據需要,你可能會多次遍歷整個數據集
* 數據分批(Batching):數據被分成多個小批次,每個批次包含一定數量的數據。這些批次在訓練過程中逐一送入模型
* 模型輸出:將每個批次的數據放入模型以獲得輸出
* 計算損失:根據模型的輸出和真實的答案計算損失
* 反向傳播(Backpropagation):這是一個重要的步驟,用於計算每個參數的梯度
* 更新優化器:使用先前計算的梯度更新模型的參數
- 用Lamini的lib可以簡化到3行
是否又會重演keras很難debug又讓人無法了解細節的問題呢? 總之是加快普及應用,但要做客製化的處理可能還是需要底層點的工具
```PYTHON=
from llama import BasicModelRunner
model = BasicModelRunner("EleutherAI/pythia-410m")
model.load_data_from_jsonlines("lamini_docs.jsonl", input_key="question", output_key="answer")
model.train(is_public=True)
```
### lab 05_Training_lab_student
直接看使用模型跟推理的部分
- Set up the model, training config, and tokenizer
```py=
model_name = "EleutherAI/pythia-70m"
training_config = {
"model": {
"pretrained_name": model_name,
"max_length" : 2048
},
"datasets": {
"use_hf": use_hf,
"path": dataset_path
},
"verbose": True
}
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
train_dataset, test_dataset = tokenize_and_split_data(training_config, tokenizer)
```
- Load the base model
```python=
base_model = AutoModelForCausalLM.from_pretrained(model_name)
base_model.to(device)
```
- 檢視模型內部
```text=
GPTNeoXForCausalLM(
(gpt_neox): GPTNeoXModel(
(embed_in): Embedding(50304, 512)
(emb_dropout): Dropout(p=0.0, inplace=False)
(layers): ModuleList(
(0-5): 6 x GPTNeoXLayer(
(input_layernorm): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
(post_attention_layernorm): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
(post_attention_dropout): Dropout(p=0.0, inplace=False)
(post_mlp_dropout): Dropout(p=0.0, inplace=False)
(attention): GPTNeoXAttention(
(rotary_emb): GPTNeoXRotaryEmbedding()
(query_key_value): Linear(in_features=512, out_features=1536, bias=True)
(dense): Linear(in_features=512, out_features=512, bias=True)
(attention_dropout): Dropout(p=0.0, inplace=False)
)
(mlp): GPTNeoXMLP(
(dense_h_to_4h): Linear(in_features=512, out_features=2048, bias=True)
(dense_4h_to_h): Linear(in_features=2048, out_features=512, bias=True)
(act): GELUActivation()
)
)
)
(final_layer_norm): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
)
(embed_out): Linear(in_features=512, out_features=50304, bias=False)
```
- 訓練的各種超參數設定 Setup training
- 各種細節都包在class `TrainingArguments`內了,範例code有提供註解,以下摘錄比較重要的參數設定說明
- max_steps=max_steps
- 最大訓練步驟數:每一步對應於一批數據的訓練。如果此值不為-1,它將覆蓋num_train_epochs,意味著訓練將在達到這個步驟數時停止
- gradient_accumulation_steps=4
- 梯度累積步驟數:在這麼多的步驟中,梯度將被累積,然後一次性更新模型。這允許使用更大的有效批次大小,而不增加記憶體使用量
- metric_for_best_model="eval_loss"
- 用於選擇最佳模型的指標:在這種情況下,它是評估損失
- greater_is_better=False
- 指標的方向:對於損失,較低的值是更好的,所以設為False
大致現代模型的各種奇淫巧計(?)都被封裝在裡面了,以前可是手刻了好多功能,相信沒有訓練經驗的人也能很快上手
```python=
training_args = TrainingArguments(
# Learning rate
learning_rate=1.0e-5,
# Number of training epochs
num_train_epochs=1,
# Max steps to train for (each step is a batch of data)
# Overrides num_train_epochs, if not -1
max_steps=max_steps,
# Batch size for training
per_device_train_batch_size=1,
# Directory to save model checkpoints
output_dir=output_dir,
# Other arguments
overwrite_output_dir=False, # Overwrite the content of the output directory
disable_tqdm=False, # Disable progress bars
eval_steps=120, # Number of update steps between two evaluations
save_steps=120, # After # steps model is saved
warmup_steps=1, # Number of warmup steps for learning rate scheduler
per_device_eval_batch_size=1, # Batch size for evaluation
evaluation_strategy="steps",
logging_strategy="steps",
logging_steps=1,
optim="adafactor",
gradient_accumulation_steps = 4,
gradient_checkpointing=False,
# Parameters for early stopping
load_best_model_at_end=True,
save_total_limit=1,
metric_for_best_model="eval_loss",
greater_is_better=False
)
```
- 檢視模型占用的記憶體及運算量
- 浮點運算次數(FLOPs)是一個常用於評估模型計算複雜性的指標
- 計算模型在給定的輸入長度和梯度累積步驟下的總浮點運算次數
```python=
model_flops = (
base_model.floating_point_ops(
{
"input_ids": torch.zeros(
(1, training_config["model"]["max_length"])
)
}
)
* training_args.gradient_accumulation_steps
)
# print(base_model)
print("Memory footprint", base_model.get_memory_footprint() / 1e9, "GB")
# Memory footprint 0.30687256 GB
print("Flops", model_flops / 1e9, "GFLOPs")
# Flops 2195.667812352 GFLOPs
```
- 各種材料都丟進`Trainer`內開啟訓練
- 包含模型、資料(訓練與驗證資料)、超參數設定等
- 比較特別的是模型運量也要丟入(model_flops)
```py=
trainer = Trainer(
model=base_model,
model_flops=model_flops,
total_steps=max_steps,
args=training_args,
train_dataset=train_dataset,
eval_dataset=test_dataset,
)
training_output = trainer.train()
```
後面的lab範例還包括:
- 運行更大的訓練模型並探索調節(Run much larger trained model and explore moderation)
- 使用更大的模型進行inference,並探索如何使用調節來改善輸出
- 使用小模型探索調節(Explore moderation using small model)
- 使用小型模型進行推斷,並探索如何使用調節來改善輸出。
- 使用Lamini的3行代碼微調模型(Finetune a model in 3 lines of code using Lamini)
- 顯示如何使用Lamini的llama庫以極少的代碼進行模型微調
放上一些lab的範例比較不同模型的表現,看看簡單訓練過的小模型表現(trained model)
