# 深度學習導論報告--Sequence Recognition Using RNN/LSTM/GRU > 資工四 411121273 鄭宇翔 >下表是我在kaggle上的名稱與帳號 >  ### 1. 目標 本次作業的目標是處理自然語言處理中的分類問題。我們需要利用教授提供的 `train.json`與 `vocabulary.json`,訓練一個深度學習模型,將文本正確分類至 Category_A 到 Category_E 五個類別中。 --- ### 2. 訓練與預測 我將訓練與預測分別撰寫為 `train.py` 與 `pre.py`兩個檔案。 教授特別說明 **not including the data files**,因此壓縮檔中包含: 1. train.py 2. pre.py 3. REPORT_LINK.txt 沒有包括報告中用到的圖表及教授給定的json檔案。 **執行方式分為兩步驟:** 1. **`train.py`** -> 讀取訓練資料,進行遷移學習,並將最好的模型權重存為`best.pth`。 -> 生成 Loss 與 Accuracy 曲線圖。 2. **`pre.py`** -> 讀取 `test.json` 與 `vocabulary.json`。 -> 載入 `best.pth` 模型權重。 -> 預測結果 `result.csv` 檔案。在預測階段 (`pre.py`) p.s. 為了避免相同的程式碼與變數重複寫在預測程式中,預測程式碼的某些參數是從`train.py` 導入,這樣做的好處是可以減少預測程式的代碼量,同時也比較方便做管理,相同的變數不需要手動更改兩次,因此如果教授(助教)要測試預測程式的話,請一定要將兩個檔案放在同個路徑下,否則會報錯。 --- ### 2.1 資料處理與模型設計 #### 2.1.1 遷移學習 在kaggle上有看到這次作業允許使用預訓練模型,所以我沒有從零開始訓練模型,而是選擇基於Transformer架構的模型做**遷移學習**。 選擇transformer的原因是成績的評定一部份是從kaggle平台上的排名所決定的,而目前的NLP領域中,transformer的表現優於傳統RNN等架構,所以選擇該架構可能會在競賽中比較有優勢。 --- #### 2.1.2 資料預處理流程 這次教授提供的資料格式比較特殊,原始資料給的不是英文句子,而是已經被轉換成數字的序列,直接丟進預訓練模型會導致錯誤,所以需要先將數字解碼成英文句子後,再次將句子編碼成預訓練模型能理解的格式,如下: 1. **解碼**:利用提供的字典,把數字還原回英文句子。 2. **編碼**:使用我選用的預訓練模型(DistilBERT)專用的 Tokenizer,將英文句子重新轉換成模型能理解的格式。 3. DataLoader:將轉換後的資料與標籤裝進DataLoader  --- #### 2.1.3 模型架構 **encoder:** 記得在課程中講述transformer章節時,主要分為兩個部分,包含編碼器與解碼器,而這次的作業是希望模型理解輸入並分類,不需要做生成,所以我們只需要關注Encoder就好。 在課程中有教學到經典的Encoder就是BERT,但標準版的BERT模型參數量對我的硬體來說太大了,我是在mac筆電上進行訓練,運算資源相對受限,此外雖然有統一記憶體架構,但顯存仍然不夠用,直接使用BERT會導致訓練的很吃力,所以我最終選擇了DistilBERT,它的好處有兩個: 1. **輕量化**:它的參數量比標準的BERT少了40%。 2. **比較好訓練**:參數量小可以讓我能設定更大的Batch Size。 **分類器:** 這次作業希望我們輸出的是分類,所以提取語意後,還需要一個分類器來進行題目要求的五個分類。 透過 Hugging Face 的 `AutoModelForSequenceClassification` 可以在模型後面接一個分類器。 因此整體主要分為兩步驟: 1. **理解語意**:將資料送入DistilBERT閱讀,並將語意存在標記的向量中。 2. **分類**:抓取特徵向量,變換對應到 5 個類別的機率。 **流程如下:** $$\text{input} \rightarrow \text{DistilBERT} \rightarrow \text{linear(768, 5)} \rightarrow \text{output 5 class}$$ --- #### 2.1.4 優化器與學習策略 * **優化器**: 使用 **AdamW**,因為`Transformers` 庫原生提供兩個優化器:**AdamW** 與 **AdaFactor**,我有找到官方的說明文件,如下圖所示:  * **Scheduler**: 當驗證集 Loss 在 1 個 epoch 內沒有下降時,將學習率衰減為原來的 0.5 倍,設定為1是因為我的電腦性能不足,訓練一個epoch需要非常久的時間,因此我希望每一輪模型都能夠有進步,所以一發生震盪就立刻減少學習率,此外模型學習的速度很快(大多在1-2個epoch可以達到100%準確率),因此設定為1也不會導致說學習率過低導致模型無法進步。 * **Early Stop**: 為了避免訓練過久導致Overfitting,當連續5個epoch準確率沒有提升時,提前終止訓練,並保留最佳模型 ,不同於之前選擇loss作為patience計數的原因是kaggle上的評分標準以分類的準確率為主,所以我希望當模型能夠分類的很準後就停止訓練,能節省很多時間。 --- ### 2.2 預測流程 **預測流程如下:** 1. **載入測試資料**: 讀取 `test.json`,並將序列解回原始文本。 2. **載入模型**: 讀取訓練好的模型`best.pth`。 3. **預測**: 開啟推論模式。 4. **輸出結果**: 將模型輸出的的所有數值取最大值`argmax`得到預測類別索引,再map到五個分類後寫入`result.csv`。 $$\text{test.json} \rightarrow \text{decod} \rightarrow \text{tokenizer} \rightarrow \text{model} \rightarrow \text{argmax} \rightarrow \text{result.csv}$$ --- ### 3. 實驗成果 下圖為訓練過程中的 Loss 與 Accuracy 曲線,此外將預測結果送入kaggle平台的公開測試中,可以取得100%準確率。 * **Loss 曲線**:可以觀察到 Train Loss 與 Val Loss在經過一epoch後就幾乎收斂,兩者差距不大,如下圖所示:  * **Accuracy 曲線**:因為kaggle平台的評分表準為預測準確率,因此驗證集的準確率曲線我認為比loss更重要(所以early stop的觸發條件也是acc),如下圖所示,可以發現,在經過一個epoch的訓練後,模型就能夠達到100%的準確率,且連續5個epoch都維持100%,觸發early stop。  --- ### 4. 心得與反思 #### 4.1 遇到的困難: ##### 4.1.1 json檔案 在過去遇過的作業中,若需要資料處理,大多是讀取csv檔案,而這次的作業教授給定的是json檔,因此對我來說是一項全新的練習與挑戰。 ##### 4.1.2 硬體 因為沒有訓練Transformer模型的經驗,因此一開始參數不太會調整,導致在經過很久的訓練後記憶體爆炸,整個需要重來,因此我也學習到在做模型訓練的時候也需要考慮到硬體設備的能力上限,但這也導致在實驗時一次嘗試的時間成本很高,訓練完一輪大約需要四十分鐘。 ##### 4.1.3 問題理解 沒有處理過相關的問題,因此我在下載完教授給的資料後花了很多時間在理解題目希望我做什麼,以及在使用預訓練模型時,需要做資料前處理與資料格式的轉換。 #### 4.2 學到了什麼? 這次作業最大的收穫是實作遷移學習,在預訓練模型基礎上做微調,並將輸出改成希望的分類,但在資料前處理的方面也遇到很多困難,教授給的訓練資料沒辦法直接使用,需要做一定的轉換,輸出端的分類器也需要額外接,不像在實作第一個作業MLP時,輸入輸出都很單純,直接在建構模型時直接指定就好。此外針對early stop的機制我從傳統的Val Loss改為 Val Acc,這是因為在訓練時我發現常常驗證的準確率都已經到100%了,但是我有加入排程器,所以學習率會動態調整導致early stop很難觸發,繼續訓練帶來的效益很低也會增加Overfitting的風險,也增加了訓練的時間成本,因此後來我想說既然kaggle上的評分標準是準確率的話,那當模型的準確率不能再進步時訓練就可以停止了。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up