継続事前学習の内容を忘却せずにSupervised fine tuningしたい

この記事の続きはこちらです。

https://qiita.com/ikedachin/items/a698c6ef3c3797e44f59


# 1. 意図と背景
大規模言語モデル2024講座（東京大学、松尾・岩澤研）に参加しました。はい。講義はとっくに終わりました。w
**が、ずっと課題を抱えていて、まだまだ取り組んでます。**
        
<br>

- **動機**
元々の動機が、大規模言語モデルの最終課題にも合致しているんですが、比較的小型のモデルに新しく知識を埋め込み、その知識を使って出力してくれるモデルを作りたいからです。
製造現場や機密事項などは、オプトアウトしたAPIにもまだまだ入れられないというのが実情だし、これはなかなか変わらない。また、通信環境がないところでも使いたい。
特に製造現場は想定外の動きになると人が怪我するかもしれないので、使うとしてもローカルモデルになってしまう。そのためには知識を埋め込んだ上で、Q＆Aしてくれたり、評価をしてくれるモデルが必要なんです。

<br>

- **課題とモチベーション**
講義を受けても解決しない課題が僕には残ってしまいました。それが、**忘却問題**。
**ベースモデルを継続事前学習（CPT）して得た知識**が、Supervised fine tuning（SFT）によって**忘却**してしまう。その対策を検討したい。
それが今回のモチベーションです。

<br>

- **前提**
継続事前学習 → Supervised fine tuningの学習の手順を以下のように固定してお話しします。

    1. ベースモデル（インストラクションチューニングされていないモデル）を使ってLoRAでCPT
    1. ベースモデルとLoRAモデルをマージしてCPT-modelを作成
    1. CPT-modelと別のLoRAモデルを新規に作って、SFT
    1. CPT-modelにLoRAモデルを組み合わせることで評価を実施
    <br>
    
    - 学習にはunslothを使用してLoRAで学習する


<br><br>

# 2. 継続事前学習（CPT）の復習
- **ざっくり解説**
学習したい内容をテキストで次単語予測させるように学習させるだけです。データセットはトークンに収まる範囲で次単語予測させ、逆伝播させてパラメータを更新。
流石にGPUは頼りない（GoogleColaboratory使用）なので、LoRAで学習しました。

https://qiita.com/ikedachin/items/d32654c500add759c23f

unsloth最高！

<br>

そしてベースモデルにマージ

https://qiita.com/ikedachin/items/c539de6c9e7e05c91e18

これも色々とトラップがあり、苦労しました。


<br>

この時、「石破氏は」と入力した時の出力イメージはこんな感じ

```
石破茂氏は「自民党総裁選に出馬するにあたり、国民の皆様にお約束したいこと」と題した動画を公開。冒頭で「私は、石破新政権が発足したら、直ちに衆議院解散総選挙を行うべきだと考えています」とし、その理由について説明した。
まず1つ目は、岸田文雄首相（67）による政治と金問題への対応だ。石破氏は「総理自身が、<以下略>
```
文章の続きが出るように入力に入れてあげるのがミソ。

<br><br>


# 3. Supervised fine-tune（SFT）の復習
ここからさらに受け答えの形になるように学習させていきます。これでチャットモデルとして利用可能になります。

```
Q:石破茂氏は何をしている人ですか？
A:石破茂氏は内閣総理大臣です。
```
こんな感じ。
詳しくはこちらで

https://qiita.com/ikedachin/items/eb833076ce3c8342cd61


出力の方法は目的に合わせて色々と学習可能。要約させたり、点数つけたり。

<br><br>


# 4. ネットを漁って対策を考える
多分、同じ課題にぶち当たってる人はたくさんいるだろうと検索してみました。

https://arxiv.org/pdf/2205.09357

https://qiita.com/taka_yayoi/items/7f50d3ebbe4bebd6877c

https://www.entrypointai.com/blog/lora-fine-tuning/

https://www.skillupai.com/blog/tech/continual-learning/


手法として捉えるならざっくり、以下の方法

- SFTの時にCPTで使ったデータを織り交ぜる
- パラメータ更新時にノルムを使って小さな更新幅に抑え込む
- 学習させるLayerを制限したり、学習率を下げたり、lora_alphaの値をCPTとSFTで変えたり



ということで**三つ目の方法**を検討することにした。（2025/1/16現在はlayerとlora_alphaのみ）
~~だって、一つ目はデータの準備が大変だし、二つ目は実装方法がわかんないし・・・。~~

<br><br>

# 5. 仮説
いろいろと~~浅く、狭く~~調べた結果、知識保持とインストラクションのバランスを確認するために、以下の2点が影響すると考えた。
- CPTとSFTの目的にあった層を学習させた方が良いのではないか
- lora_alphaの影響が効くのではないか
- 学習率もCPTとSFTで変えるといいのではないか

<br>

- 理由１：
大規模言語モデルの講座の中で、「知識はMLP層」に「トークン同士の関係性はtransformer層」に学習されているという論文が紹介されていたので、CPTとSFTでは層を変えてみることにしてみた。

- 理由２：
lora_alphaはlow rank matricsの影響の度合いを決める係数っぽいので、CPTでは高めに、SFTでは低めにすることがを確認してみた。
↓を参照

https://docs.unsloth.ai/get-started/beginner-start-here/lora-parameters-encyclopedia

- 理由３：
ゆっくり学習させれば、ある一定のlossの谷から抜け出すことはないのではないか？（normでもおなじか？）

<br><br>

# 6. 実施方法
CPTとSFTのやり方は過去の投稿に書いたので、どこを触ったかだけ説明します。
変更するところはCPTもSFTともに同じところです。

```Python:LoRAモデルを作るところ
model = FastLanguageModel.get_peft_model(
    model,
    r = 32, # LoRAのランク
    target_modules =  ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj", "embed_tokens", "lm_head",],
    lora_alpha = 16,
    lora_dropout = 0.2,
    bias = "none",
    use_gradient_checkpointing = "unsloth",
    random_state = 3407,
    use_rslora = False,
    loftq_config = None,
    max_seq_length = max_seq_length,
)
```

ここの`target_modules`と`lora_alpha`を変更するだけです。

<br><br>


# 7. モデルの構築順
### モデルの構築手順
下記の通りに構築手順を固定しました。（１にも書きましたが繰り返し）
    1. ベースモデル（インストラクションチューニングされていないモデル）を使ってLoRAでCPT
    1. ベースモデルとLoRAモデルをマージしてCPT-modelを作成
    1. CPT-modelと別のLoRAモデルを新規に作って、SFT
    1. CPT-modelにLoRAモデルを組み合わせることで評価を実施

<br>

### ベースモデル
    - llm-jp-3-3.7b（軽量なモデルでテスト）
<br>

### CPT学習データセット
    kajuma/CC-news-2024-July-October-cleaned
    - 前処理
    - 9月10月のデータ飲みに絞り込み
    - タイトルっぽいところは削除

<br>

### SFT学習データセット
    - llm-jp/magpie-sft-v1.0からランダムに5000データ
    - DeL-TaiseiOzaki/Tengentoppa-sft-mini-vol1.0からランダムに15000データ
    これらをシャッフルして使用（ランダムシード固定）

<br>

### ハイパラ
        
| パラメ | CPT | SFT |
| --- | --- | --- |
| target_modules | "q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj", "embed_tokens", "lm_head" | 条件SFT-module-A：<br>"q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"<br>条件SFT-module-B：<br>"q_proj", "k_proj", "v_proj", "o_proj" |
| lora_alpha | 32<br>128 | 32<br>8|






<br><br>


# 8. 結果
以下の質問に回答させてみた。総裁選の投票日は9/27でした。

**Q：２７日の自民党総裁戦の決選投票で誰が勝ちましたか？**

| CPT条件 | SFT条件 | SFT modules | 回答 | コメント |
| --- | --- | --- | --- | --- |
| lora_alpha=32 | lora_alpha=8 | SFT-module-A | ２７日に行われた自民党の総裁選挙で、石破茂氏と岸田文雄氏による決選投票を行い、結果は僅差ながら石破茂元幹事長（６６）が勝利しました。２８日付朝日新聞によると、今回の総選挙では「政治改革」や「経済政策」などが争点となり、有権者からは「国民目線での議論ができる人がいい」という声も聞かれたそうです。また、今回は女性候補がいないことも話題になりました。 | 岸田さんではなく、高市さん。石破さんは67歳。女性候補はいた（高市さん）<br>CPTの記憶はあるが、少し弱い。 |
| lora_alpha=32 | lora_alpha=32 | SFT-module-A | 未実施 | 
| lora_alpha=32 | lora_alpha=8 | SFT-module-B |２７日に行われた自民党の総裁選挙は、石破茂氏と岸田文雄氏による一騎打ちとなりました。結果は僅差で、石破茂氏が勝利しました。 | 岸田さんではなく、高市さん。<br>CPTの記憶はあるが、少し弱い。|
| lora_alpha=32 | lora_alpha=32 | SFT-module-B |２７日に行われた自民党の総裁選挙は、石破茂氏と岸田文雄氏による一騎打ちとなりました。結果は僅差で、石破茂氏が勝利しました。 | 岸田さんではなく、高市さん。<br>CPTの記憶はあるが少し弱い。|
| **lora_alpha=128** | **lora_alpha=8** | **SFT-module-A** | **２７日に行われた自民党の総裁選挙で、石破茂氏と高市早苗氏による決選投票を行い、結果は石破茂元幹事長（67）が、新たな首相となりました。** | **正解**<br>ほぼ、理想の回答 |
| lora_alpha=128 | lora_alpha=32 | SFT-module-A | 未実施 |
| lora_alpha=128 | lora_alpha=8 | SFT-module-B |２７日に行われた自民党の総裁選挙は、石破茂氏と高市早苗氏による一騎打ちとなり、結果、石破茂氏が新たな首相となりました。この決定はどのようにして決められたのでしょうか。また、今回選ばれた人物はどのような政策を掲げているのか、またどのような背景があるのでしょうか?今回は、この問題について詳しく解説します。まず初めに、27日の自民党総裁選では、2人の候補者から1人選ぶという方法で、最終的に1人が選出されました。これは「多数決」ではなく、あくまでも党内での意思統一のために用いられる手法です。そのため、どちらの方がより多く支持されているかということよりも、それぞれの主張や考え方の違いなどを考慮し、総合的な判断によって選択されます。具体的には、<長すぎるので省略> | 記憶はあるものの、EOSがこず、インストラクションチューニングが不完全|
| lora_alpha=128 | lora_alpha=32 | SFT-module-B | 未実施 |  |


きっと、石破さんが何度も総裁戦に挑んでいることと、実際に初めて総裁になったことから知識の混濁のようなものが見られるのかもしれない。
そういうことを考えると、**「SFTの時にCPTで使ったデータを織り交ぜた」**データセットを作ってSFTに織り交ぜることは必要かもしれない。

<br><br>


# 9. 結果（中間結果）
CPTの記憶を残しつつSFTによって出力形式の調整を行うとき、現状の結果では以下のことが言えると思う。

| パラメ | CPT | SFT |
| --- | --- | --- |
| lora_alpha |大き目が良さそう<br>今回は128 | 小さめが良さそう<br>今回は8|
| target_modules | CPTのおすすめのまま<br>"embed_tokens", "lm_head"を追加 | SFTおすすめのまま<br>CPTで追加した二つは入れない |


まだ、断定はできないけれど、仮説はある程度あっているのかもしれない。
ここから先はきっと評価用データセットを作らないといけないと思う。

ということで、

***現在、評価用データセットを作成中です***

人力で作っているので、まぁ～時間がかかる。
ひとまず目標は100件。みんなの苦労が身に染みるわぁ。

ああ、個人開発って楽しくも苦しい。ｗ

<br><br>

# 10. 終わっていないけど、おわりに
ということで、私の探索の旅はまだまだ続きそうです。

で、Langchainもやらなきゃ・・・

<br><br>

# 11. 本投稿に際して
本投稿は東京大学　松尾・岩澤研の「大規模言語モデル2024」講座を受講し、受講後にも継続して試行錯誤している内容を投稿させていただきました。

https://weblab.t.u-tokyo.ac.jp/lecture/course-list/large-language-model/

この講座、本当に素晴らしい講座でしたので、大規模言語モデルがなんたるや！を知りたい方はぜひとも参加されてみてはいかがでしょうか？僕が大学時代だった30年前（古っ）、何を話しているのかわからなかったけど、松尾・岩澤研の講師の皆さんはめっちゃわかりやすい。これマジで神ってるっす。

ちなみに、私は日本ディープラーニング協会のE資格を持っているので、その枠で申し込むことができました。合わせてE資格取得もおすすめいたします。E資格、G検定を取得すると入れるコミュニティにもいい情報にあふれてますのでお勧めしておきます。

https://www.jdla.org/certificate/engineer/

<br><br>

おしまい（というわけではない。ｗ）