1 ポイント 投稿者 GN⁺ 2024-05-27 | 1件のコメント | WhatsAppで共有
  • mistral-finetune は、Mistralモデルをメモリ効率よく高性能にファインチューニングするための軽量コードベースであり、現在このリポジトリはアーカイブされていて、もはや積極的にはメンテナンスされていない
  • 学習方式は、ほとんどの重みを固定し、低ランク行列摂動の形をした追加重みの1〜2%だけを学習するLoRAに基づいている
  • 最大効率のためにA100またはH100 GPUの利用が推奨されており、コードはマルチGPU単一ノード学習に最適化されているが、7Bのような小さなモデルは単一GPUでも可能
  • 対応モデルには 7B、Mixtral 8x7B、Mixtral 8x22B、Mistral-Nemo 12B、Mistral Large v2 123B Instruct が含まれ、Mistral-Nemo と Large v2 にはそれぞれシーケンス長と学習率に関する制約がある
  • データは jsonl 形式と厳格なスキーマに従う必要があり、学習前に utils.validate_data で形式検証と学習時間の推定を行う手順が重要

プロジェクトの状態と目的

  • mistral-finetune リポジトリは Archived 状態で、これ以上積極的にはメンテナンスされていない
  • コミュニティの需要がある、またはファインチューニングのエコシステムに価値を加えられると判断された場合、今後新しいライブラリや大規模アップデートが出る可能性がある
  • 目的は、Mistralモデルをファインチューニングするためのシンプルでガイド付きの入口を提供すること
  • このコードベースは、特にデータ形式についてかなり明確な方針を持っており、複数のモデルアーキテクチャやハードウェア種別を包括する汎用ツールを目指してはいない
  • より汎用的なアプローチとしては torchtune のようなプロジェクトを参照できる

ファインチューニング方式とハードウェア推奨事項

  • mistral-finetuneLoRA に基づいている
    • モデル重みの大半は固定される
    • 低ランク行列摂動形式の追加重みの1〜2%だけを学習する
  • 最大効率のためにA100またはH100 GPUの利用が推奨される
  • コードはマルチGPU単一ノード学習環境に最適化されている
  • 7Bのような小さなモデルであれば単一GPUでも十分

最近の互換モデル更新

  • 2024年8月13日から Mistral Large v2mistral-finetune と互換になった
    • 123B Instruct チェックポイントをダウンロードし、model_id_or_path をそのチェックポイントのディレクトリに設定する必要がある
    • モデルサイズが大きいため、ファインチューニングにははるかに多くのメモリが必要
    • 現時点では seq_len8192以下 に設定する必要がある
    • 他モデルより低い学習率が推奨され、ほとんどの場合 lr=1e-6 がうまく機能するとされている
  • 2024年7月19日から Mistral Nemomistral-finetune と互換になった
    • 12B Base または Instruct モデルをダウンロードし、model_id_or_path をチェックポイントディレクトリに設定する必要がある
    • Tekkenizer をサポートする mistral-common バージョンが必要で、pip install --upgrade mistral-common>=1.3.1 をインストールする必要がある
    • 語彙サイズが大きいため、CE loss のピークメモリ要件が増加し、現時点ではより多くのメモリが必要
    • 現時点では seq_len16384以下 に設定する必要がある
    • 7B v3 と同様のハイパーパラメータを使うことが推奨されている

インストールとモデルのダウンロード

  • 開始手順はリポジトリのクローンと依存関係のインストールで構成される
  • 公式Mistralモデルのファインチューニングが推奨されており、README は以下のモデルのダウンロードリンクとチェックサムを提供している
  • 8x7B Base V1 と 8x7B Instruct V1 は、ファインチューニング前にv3 tokenizerを使い、語彙サイズを 32768 に拡張する必要がある
  • ダウンロードしたモデルフォルダのパスは、学習 YAML の model_id_or_path に絶対パスで指定する必要がある

データ形式の要件

  • すべてのデータファイルは jsonl 形式でなければならない
  • 事前学習データは "text" キーにプレーンテキストを格納する
  • Instruction データは "messages" キーに会話のリストを格納する
    • 各項目は "content""role" キーを含む
    • "role""user""assistant""system" のいずれか
    • 損失は "role" == "assistant" の場合にのみ計算される
    • assistant メッセージに "weight": 0 を指定すると、そのメッセージの学習を除外できる
  • 関数呼び出しデータも "messages" キーに会話のリストを格納する
    • 各項目は "role""content" または "tool_calls" キーを含む
    • "role""user""assistant""system""tool" のいずれか
    • 損失は "role" == "assistant" の場合にのみ計算される
    • "tool_calls""id""tool_call_id" は、ちょうど9文字長のランダム文字列である必要がある
    • README では、これをデータ準備スクリプトで自動生成する方法を推奨している

データ検証とサンプルワークフロー

  • 学習開始前に utils.validate_data でデータ形式を検証し、学習時間を推定する必要がある
  • Instruction の例では Ultachat_200k の一部を使用する
    • Pandas で parquet データを読み込む
    • 学習95%、評価5%に分割する
    • jsonl として保存する
    • example/7B.yamldata.instruct_datadata.eval_instruct_data にパスを指定する
  • 検証過程で、一部の会話が user ロールで終わっている問題が見つかることがある
    • assistant メッセージのみ学習するため、最後の user メッセージは不要な処理対象になる
    • utils.reformat_data.py でデータを修正できる
  • 修正後に再検証すると、データトークン数、学習トークン数、epoch 数、max_steps、推定時間などの要約が出力される
  • README の例では max_steps=500 だとデータセットを約5周し、8xH100 クラスターで約30分かかる設定で、max_steps=300 を推奨している

関数呼び出しファインチューニングの例

  • 関数呼び出しの例では Glaive function calling dataset を使用する
  • データは Pandas で読み込み、学習95%・評価5%に分けたうえで jsonl として保存する
  • 元のデータセットは要求される関数呼び出し形式に従っていないため、再フォーマットが必要
    • "from""user" に置き換える必要がある
    • 不要な "\n" 文字を削除する必要がある
  • utils.reformat_data_glaive.py を使うと、大半のサンプルを正しい形式にできる
  • あらゆる種類のデータセットで動作する再フォーマットスクリプトを書くことは不可能なので、要求形式に従っていないデータセットには別途再フォーマットスクリプトが必要になる場合がある
  • utils.validate_data --create_corrected を使うと、残ったエラーを取り除いて .corrected データセットを生成できる

学習の実行と結果例

  • データ検証後に学習を開始できる
  • より高速な学習のために max_steps300 に設定する構成が推奨される
  • run_dir は実験フォルダとして設定する必要があり、任意で wandb.project を指定して Weights & Biases のロギングを利用できる
  • 学習の実行には torchrun を使い、--nproc-per-node は利用可能な GPU 数に設定する必要がある
  • UltraChat の学習は 8xH100 ノードで約 30分 かかり、得られた重みは MT Bench スコア約 6.3 を出せる
  • Glaive の学習は 8xH100 ノードで約 1時間 かかり、得られた重みは関数呼び出しで良好に動作すると案内されている

学習設定の主要項目

  • model_id_or_path: 学習開始に使う事前学習モデル、またはローカルモデルディレクトリのパス
  • run_dir: チェックポイントとメトリクスを保存するディレクトリ
  • seq_len: 学習シーケンス長で、サンプルは効率のため seq_len 長に合わせてパッキングされる
  • batch_size: GPU あたりの学習サンプル数
    • 全体の有効トークンバッチサイズは num_gpus x batch_size x seq_len
  • max_steps: 総学習反復回数
    • 学習中に見る総トークン数は max_steps x num_gpus x batch_size x seq_len
  • optim.lr: オプティマイザの初期学習率
  • optim.weight_decay: 重み減衰で、README では 0.1 を維持 することを推奨している
  • optim.pct_start: PyTorch OneCycleLR の warm-up フェーズ比率
  • lora.rank: LoRA アダプタのサイズで、64以下 が推奨される
  • seed: 初期化とデータシャッフル・サンプリングの再現性のための乱数シード
  • data.instruct_data: instruction 学習データのパス
    • 単一の jsonl ファイル、jsonl ディレクトリ、または重み付きの複数データソースを指定できる
  • data.data: 任意の追加事前学習データのパス
  • data.eval_instruct_data: 任意の評価用 instruction データのパス
  • eval_freq, no_eval, ckpt_freq: 評価・中間評価・チェックポイント保存の周期を制御する
  • save_adapters: LoRA チェックポイントのみ保存するか、LoRA をベースモデルにマージして完全なモデルとして保存するかを決める
    • save_adapters=False は、単一プロセスで完全なモデルを保存できる十分な CPU と GPU メモリが必要で、通常は 7B モデルでのみ可能

推論と Weights & Biases

  • 学習済みモデルの推論には mistral-inference の利用が推奨される
  • pip install mistral_inference でインストールできる
  • mistral-chat 実行時に --lora_path に保存済み lora.safetensors のパスを指定すると、LoRA 重みを利用できる
  • Weights and Biases サポートが含まれており、学習メトリクスと実験を監視できる
    • pip install wandb でインストールする
    • API キーは WANDB_API_KEY 環境変数で渡す方式が推奨される
    • セキュリティ上、API キーは YAML 設定からは読み込まない
    • 学習損失、評価損失、学習率などが wandb プロジェクトダッシュボードに記録・可視化される
  • 詳しい使い方は Weights and Biases documentation を参照できる

モデル拡張と FAQ

  • v3 tokenizer と互換性のある Mistral モデルのみファインチューニングできる
  • 互換モデルの語彙サイズは 32768 である必要があり、32000 ではない
  • 語彙サイズ 32000 の旧モデルは utils.extend_model_vocab で 32768 まで拡張できる
  • MoE モデルのファインチューニングでは、性能のばらつきがより大きく現れる
    • 異なる seed で同じ MoE ファインチューニングを複数回実行し、最も性能の良い結果を選ぶ方法が提案されている
    • dense モデルでは、このような大きな分散は観測されていない
  • 学習に使われたトークン数は、utils.validate_data.py に YAML 学習ファイルを入力して確認できる
  • CUDA out-of-memory エラーが発生した場合は、GPU あたりのバッチサイズを減らせる
    • バッチサイズは seq_len x batch_size
    • batch_size を 1 に設定し、seq_len を下げる方法が提案されている
  • ライブラリは Apache 2.0 License で提供される
  • このライブラリやモデルを、第三者の知的財産権を含む権利を侵害・悪用・違反する形で使用してはならない

1件のコメント

 
GN⁺ 2024-05-27
Hacker Newsのコメント
  • モデルの進歩がこれほど速いのに、ファインチューニングにはまだ価値があるのだろうか? 実際の活用事例が気になる。
    たとえば Bloomberg は昨年、金融データで GPT-3.5級の LLM を学習させたが、ほどなくして GPT-4-8k がほぼすべての金融タスクでそれを上回った。
    結局、私たちは高品質な評価データと、新しいモデルへ簡単に乗り換えられるアーキテクチャに注力するようになった。

    • その通り。英語以外の話者のデータがあり、特定の健康関連研究向けに設計された形式でアノテーションが付いている。
      LLM はこうしたアノテーションを見たことがなく、非英語圏向け LLM は企業の最優先事項でもなく、データプライバシーのためオフライン優先のモデルしか使えない。
      こういう状況では、汎用言語モデルをファインチューニングするのが非常にうまくはまる。
    • 特定の形式の出力を大量に生成する必要があるなら、ファインチューニングは有用かもしれない。
      定型メッセージでファインチューニングしておけば、モデルが自動的にその形式を生成するので、毎回のプロンプトで出力形式を説明するためのトークンをかなり節約できる。
    • GPT-4 が見たことのない社内企業データならどうだろう?
    • 従来の自然言語処理タスクでは、LLM は品詞タグ付けや特徴タグ付けのような専用の自然言語処理パイプラインよりかなり劣っている。
      ただし、ファインチューニングはその差をかなり埋めてくれる。
      狭い領域ではあるが、プログラミングの大半も同じだ。汎用 LLM を自分のデータ寄りにしたいという目的なら、ファインチューニングはあまり関係ない可能性が高い。
      しかし、非常に具体的でありながら曖昧な問題を解こうとしていて、LLM がその一部しか解決してくれないなら、ファインチューニングが最善である可能性が高い。
    • 関数呼び出しも理由になりうる。
      アプリにツールとやり取りするカスタム関数が多いなら、コンテキストトークンを使うよりファインチューニングを好むかもしれない。
  • これをやるにはどんな GPU が必要だろう? 3060 Ti のノートPC版、i9、RAM 16GB がある。
    AWS や GCP の割り当てはなく、Paperspace の話は聞いたことがあるが、進行中の顧客プロジェクトで Mistral モデルの一部を使う予定なので、Mistral のファインチューニングを早く始めたい。

    • 予算が完全に 0 ではないなら、ゲーミングデスクトップにすることを強く勧める。
      ゲーミング GPU は 300W の発熱を問題なく処理できるが、ノートPCの GPU がそんなことをしたら溶けてしまうだろうし、おそらく 100W 前後に制限される。
      放熱性能は速度に直接比例する。
      しかもデスクトップなら、より高速な GPU へのアップグレードや複数 GPU の利用も可能だ。
      ただし、特にマルチ GPU 構成はうるさく、部屋ひとつがすぐ暖まるほど熱を出す。
      今後数年間で GPU をフルロードで回す時間が 10% を超えないなら、クラウドのほうが安くつく可能性が高い。
    • このサイトを見ればよい: https://www.hardware-corner.net/llm-database/Mistral/
      モデルごとのハードウェア要件が整理されており、VRAM とシステムメモリを選んで使えるモデルを絞り込める。
    • Hetzner では月 184 ユーロのGPU サーバーが使える。
      うちの会社では、そこの RTX4000 で Mistral と Llama 3 をファインチューニングしてきた。
      RAM が 20GB しかないので少し制約はあるが、より大きな入力トークン数には量子化レベルを下げる方法が役立った。
      今では時間単位のレンタルも提供している。
    • openpipe を試してみるとよい。
      今、会社で使っているが、かなり良い結果が出ている。
  • よくある LLM の活用事例ごとに、どのツールが事実上の標準になるのかは非常に興味深い。
    エコシステムがあまりに分裂していて、ほとんどのツールは聞いたことすらない感じだ。
    数日前に Microsoft の Olive を見たが、まったく初めて知るツールだった。

  • すでに多くのオープンソース LLM が「実用になる」レベルに達している今、その周辺開発を容易にすることが重要だ。
    とりわけ、ユーザーであり開発者でもある人たちが、非公開データ、つまりモデルの事前学習に含まれていないデータを活用できるようにする必要がある。
    リポジトリには大規模モデル向けに最適化されていて A100/H100 が必要だと書かれているが、それでもこれは大型モデルより小型モデルに対してより役立つのではないかと感じる。
    「作れば人が来る」は、「ツールを提供すれば人が作る」へと拡張できる。

    • 「ツールを提供すれば人が作る」が成り立つのは、その技術を学ぶインセンティブが将来の利益への期待につながる場合だけだ。
  • 重み付けの部分が興味深い。
    HuggingFace の SFTTrainer は、望めば完成部分だけを学習させられるが、人間にはそれが自然に見えても、LLM は一般に入力全体を予測するよう学習したほうがうまくいく。
    この方式なら両方の長所を得られる。

  • 3090 や 4090 を 2 枚使って、より大きな派生モデルを学習できるよう最適化できるだろうか?

  • 自分のWhatsApp チャットモデルはどうやって学習させればよいのだろう?

    • 何を意味しているのか、もう少し明確である必要がある。
      自分の WhatsApp メッセージでモデルを学習させたいのか? 目的は何か? 自分のように書かせたいのか、それとも RAG ベースの質疑応答をしたいのかによって変わってくる。