---
# System prepended metadata

title: '[Finetuning Large Language Models ]  課程筆記- 訓練過程(Training process)'
tags: [AI, GenAI, NLP, Finetune, Generative AI, DeepLearning.AI, LLM, Deeplearning, 生成式AI]

---

### [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)
![](https://hackmd.io/_uploads/rJRSReHfT.png =400x)

- 訓練過程的核心
    * 添加訓練數據：首先，你需要提供一定量的訓練數據，這些數據將用於訓練模型，使其能夠更好地執行特定任務
    * 計算損失：模型在初次預測時可能會有所偏差，因此需要計算模型的預測與實際結果之間的差異，這稱為損失
    * 透過模型進行反向傳播(Backprop through model)：當模型計算出損失後，它將使用反向傳播算法來找出哪些權重和偏差導致了高損失
    * 更新權重：根據計算出的損失，模型的權重將進行調整，以改善其預測能力

- 超參數(Hyperparameters)
    - 學習率(Learning rate)
        - 這是一個控制模型學習速度的參數。太高的學習率可能會導致模型在訓練過程中忽略某些細節，而太低的學習率則可能會使訓練過程過於緩慢
    - 學習率計劃器(Learning rate scheduler)
        - 這是一種動態調整學習率的方法，通常會在訓練過程中根據某些條件減少學習率
    - 優化器超參數(Optimizer hyperparameters)
        - 這些參數控制優化器的行為，優化器是用於更新模型權重的工具。不同的優化器和其超參數可以影響模型的訓練速度和效果

### 訓練流程的程式碼示意(Run through general chunks of training process in code)
這邊用的範例是pytorch的訓練流程
![](https://hackmd.io/_uploads/Bkwq4bBf6.png =400x)
- 訓練流程概述
    * 設定訓練循環(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)
 ![](https://hackmd.io/_uploads/ryeHRZSf6.png)
