DUICUO

オープンソースのモデルマージツールである MergeKit を使用して、独自のカスタムモデルを開発します。

翻訳者 |朱賢宗

校正者 | Chonglou

導入

モデルマージとは、2つ以上のLLMを1つのモデルに統合する手法です。これは比較的新しい実験的なアプローチであり、少ない投資で(GPUを必要とせず)新しいモデルを作成できます。モデルマージは非常に優れた効果を発揮し、この手法に基づく最先端モデルが数多くOpen LLMリーダーボードに登場しています。

このチュートリアルでは、オープンソースのMergeKitライブラリを用いてモデルのマージを実装します。具体的には、4つのマージ手法を確認し、それぞれの設定例を示します。その後、MergeKitを用いて独自のモデル(Marcoro14-7B-slerp)を作成します。このモデルは、Open LLMリーダーボード(2023年2月1日時点)で最も優れたパフォーマンスを示したモデルの1つとなっています。

この記事で紹介したサンプルプロジェクトのソースコードは、GitHubとGoogle Colabで公開しています。また、 MergeKitをより簡単に実行するために、私が改良したLazyMergekit自動ノートブックプログラムを使用することをお勧めします。

マージアルゴリズム

このセクションでは、MergeKitに現在実装されている4つの手法に焦点を当てます。線形アルゴリズムやタスク演算アルゴリズムなど、他にもアルゴリズムが存在することに注意してください。モデルのマージに関する論文にご興味をお持ちの方は、Hugging Faceに掲載されているこのトピックに関する優れた論文集をぜひお読みください。

1. SLERPアルゴリズム

球面線形補間(SLERP)は、2つのベクトル間を滑らかに補間する手法です。このアルゴリズムは、変化率を一定に保ち、ベクトルが存在する球面空間の幾何学的特性を維持します。

SLERPを従来の線形補間よりも優先する理由はいくつかあります。例えば、高次元空間では、線形補間によって補間ベクトルのサイズが縮小される(つまり、重みの割合が減少する)可能性があります。さらに、重みの方向の変化は、重みの大きさの変化よりも、より意味のある情報(特徴学習や表現など)を表すことが多いからです。

SLERP アルゴリズムの実装は、次の手順に基づいています。

  • 入力ベクトルを単位長さに正規化して、大きさではなく方向を表すようにします。
  • これらのベクトル間の角度を計算するには、内積を使用します。
  • ベクトルがほぼ同一直線上にある場合、効率性を向上させるため、デフォルトで線形補間が実行されます。そうでない場合、SLERPは補間係数t(最初のベクトルは100%、2番目のベクトルは100%)とベクトル間の角度に基づいてスケーリング係数を計算します。
  • これらの係数は元のベクトルに重み付けするために使用され、その後、元のベクトルが合計されて補間ベクトルが得られます。
  • SLERPは現在最も人気のあるマージ手法ですが、一度に2つのモデルしかマージできません。ただし、Mistral-7B-Merge-14-v0.1モデル(https://huggingface.co/EmbeddedLLM/Mistral-7B-Merge-14-v0.1)で使用されているように、複数のモデルを階層的に結合することは可能です。

以下は SLERP 構成の例です。

 slices: - sources: - model: OpenPipe/mistral-ft-optimized-1218 layer_range: [0, 32] - model: mlabonne/NeuralHermes-2.5-Mistral-7B layer_range: [0, 32] merge_method: slerp base_model: OpenPipe/mistral-ft-optimized-1218 parameters: t: - filter: self_attn value: [0, 0.5, 0.3, 0.7, 1] - filter: mlp value: [1, 0.5, 0.7, 0.3, 0] - value: 0.5 dtype: bfloat16

これは、両モデルの各層に適用された典型的なSLERP構成です。補間係数tの入力値の勾配に注目してください。自己焦点層とMLP層のパラメータには、それぞれOpenPipe/mistral-ft-optimized-1218mlabonne/NeuralHermes-2.5-mistral-7Bの異なる組み合わせが使用されます。他の層では、2つのモデルを50/50の割合でブレンドして使用します。

この最終モデル mmabonne/NeuralPipe-7B-Serrp は、Hugging Face Hub で見つけることができます

2. TIESアルゴリズム

Yadavらは論文において複数のタスク固有のモデルを単一のマルチタスクモデルに効率的に統合することを目的としたTIES-Mergingアルゴリズムを紹介しました。このアプローチは、モデル統合における2つの主要な課題に対処します。

  • モデルパラメータの冗長性:タスク固有のモデルにおける冗長なパラメータを特定し、排除します。これは、ファインチューニング中に行われた変更に焦点を当て、最も重要な変更の上位k%を特定し、残りを破棄することで実現されます。
  • パラメータ表記の矛盾:異なるモデルが同じパラメータに対して相反する調整を示唆する場合、矛盾が生じます。TIESマージは、すべてのモデルにおいて最も重要な変化の方向を表す統一された表記ベクトルを作成することで、これらの矛盾を解決します。TIESマージは、以下の3つのステップで構成されます。
  • トリミング: 最も重要なパラメータ (密度パラメータ) の小さなサブセットのみを保持し、残りをゼロにリセットすることで、タスク固有のモデルの冗長性を削減します。
  • 選択符号: 累積的な大きさの最も支配的な方向 (正または負) に基づいて均一な符号ベクトルを作成することにより、異なるモデル間の符号の競合を解決します。
  • 分離マージ: ゼロ値を除いて、統一されたシンボルベクトルに揃えられたパラメータ値を平均します。

SLERP アルゴリズムとは異なり、TIES アルゴリズムでは複数のモデルを一度にマージできます。

TIES 構成の例を次に示します。

 models: - model: mistralai/Mistral-7B-v0.1 # 基本模型不需要任何参数- model: OpenPipe/mistral-ft-optimized-1218 parameters: density: 0.5 weight: 0.5 - model: mlabonne/NeuralHermes-2.5-Mistral-7B parameters: density: 0.5 weight: 0.3 merge_method: ties base_model: mistralai/Mistral-7B-v0.1 parameters: normalize: true dtype: float16

この設定では、Mistral-7Bモデルをベースモデルとして増分重みを計算します。同じ2つのモデル、mistral-ft-optimized-1218(50%)とNeuralHermes-2.5-mistral-7B(30%)をマージし、正規化します。ここで、密度パラメータは、各モデルのパラメータの50%のみを保持することを意味します(残りの半分はベースモデルから取得されます)。

上記の設定では、重みの合計が1と等しくありませんが、`normalize:true`パラメータによって内部的に自動的に正規化されます。この設定は、OpenHermes-2.5-neural-chat-7b-v-7bの作者によって提供されたパラメータに着想を得ています

この最終モデル、 mmabonne/NeuralPipe-7B-ties は、 Hugging Face Hub で見つけることができます

3. DAREアルゴリズム

2023 年に Yu らによって導入されたDARE アルゴリズムはTIES に似た方法を使用しますが、主に 2 つの違いがあります。

  • プルーニング: DARE は微調整された重みをランダムに元の値 (基本モデルの値) にリセットします。
  • 再スケーリング:DAREは、モデル出力の期待値がほぼ一定になるように重みを再スケーリングします。スケーリング係数を用いて、2つ(またはそれ以上)のモデルの再スケーリングされた重みをベースモデルの重みに加算します。

MergeKit はこのメソッドを、シンボル選択ステップのある TIES (dare_ties) とシンボル選択ステップのない TIES (dare_linear) の 2 つのスタイルで実装します。

DARE 構成の例を次に示します。

 models: - model: mistralai/Mistral-7B-v0.1 #基本模型不需要任何参数- model: samir-fama/SamirGPT-v1 parameters: density: 0.53 weight: 0.4 - model: abacusai/Slerp-CM-mist-dpo parameters: density: 0.53 weight: 0.3 - model: EmbeddedLLM/Mistral-7B-Merge-14-v0.2 parameters: density: 0.53 weight: 0.3 merge_method: dare_ties base_model: mistralai/Mistral-7B-v0.1 parameters: int8_mask: true dtype: bfloat16

この設定では、`dare_ties` を用いて3つの異なるMistral-7Bベースのモデルをマージしました。今回は、重みの合計が1になるように重みを選択しました(合計は0.9~1.1の範囲である必要があります)。密度パラメータ `density` は論文で提案されている値(<0.5)よりもわずかに高く設定していますが、一貫してより良い結果が得られているようです(https://github.com/cg123/mergekit/issues/26 のリンクの議論を参照)。

mlabonne/Daredevil-7BはHugging Face Hubでご覧いただけます。これは本論文における最良のマージモデルであり、Marcoro14-7Bのslerpを凌駕しています。

4. パススルーアルゴリズム

パススルー法は従来のアプローチとは大きく異なります。異なるLLMのレイヤーを連結することで、非常に多くのパラメータを持つモデル(例えば、7Bパラメータのモデルを2つ組み合わせた9Bモデル)を作成できます。これらのモデルは、コミュニティでは「フランケンシュタイン・マージ」または「フランケンシュタイン・モデル」と呼ばれることがよくあります。

この技術は非常に実験的ですが、Llama 2 70Bモデル2台を用いたgoliath-120bモデルなど、印象的なモデルの作成に成功しています。最近発表されたSOLAR-10.7B-v1.0モデルでも同じアイデアが採用されており、論文はこれを「深度拡大」と呼んでいます

パススルー方式の構成例を以下に示します。

 slices: - sources: - model: OpenPipe/mistral-ft-optimized-1218 layer_range: [0, 32] - sources: - model: mlabonne/NeuralHermes-2.5-Mistral-7B layer_range: [24, 32] merge_method: passthrough dtype: bfloat16

結果として得られるフランケンシュタインマージは、最初のモデルの32レイヤーすべてと、2番目のモデルの8レイヤーを追加します。これにより、合計40レイヤー、899億個のパラメータを持つフランケンシュタインマージが作成されます。この構成は、GML-Mistral-merged-v1にインスパイアされています。

Hugging Face Hub: mlabonne/NeuralPipe-9B-merged で見つけることができます

独自のモデルをマージする

このセクションでは、MergeKit を使用してマージ構成を読み込み、実行し、生成されたモデルを Hugging Face Hub にアップロードします。

まず、以下に示すように、ソース コードから直接 MergeKit をインストールします。

 !git clone https://github.com/cg123/mergekit.git !cd mergekit && pip install -q -e .

以下のコードブロックでは、YAML形式のマージ設定を読み込みます。また、将来使用するためにマージモデルの名前も指定します。前のセクションから任意の設定をコピー&ペーストできます。

今回は、 Marcroni-7B-v3Mistral-7B-Merge-14-v0.1という2つの異なるモデルを使用し、SLRP方式でマージします。設定はYAMLファイルとして保存し、mergeコマンドの入力として使用します。

 import yaml MODEL_NAME = "Marcoro14-7B-slerp" yaml_config = """ slices: - sources: - model: AIDC-ai-business/Marcoroni-7B-v3 layer_range: [0, 32] - model: EmbeddedLLM/Mistral-7B-Merge-14-v0.1 layer_range: [0, 32] merge_method: slerp base_model: AIDC-ai-business/Marcoroni-7B-v3 parameters: t: - filter: self_attn value: [0, 0.5, 0.3, 0.7, 1] - filter: mlp value: [1, 0.5, 0.7, 0.3, 0] - value: 0.5 dtype: bfloat16 """ # 将配置保存为yaml文件with open('config.yaml', 'w', encoding="utf-8") as f: f.write(yaml_config)

次のパラメータを使用してマージ コマンドを実行します。

  • --copy-tokenizer: ベースモデルからトークナイザーをコピーします。
  • --allow-crimes および --out-shard-size: モデルを、RAM が少ない CPU で計算できる小さなコード フラグメントに分割します。
  • --lazy-unpickle: メモリ使用量を削減するために、実験的な遅延unpickleを有効にします。また、一部のモデルでは --trust_remote_code フラグが必要になる場合があります(Mistral-7Bを除く)。

このコマンドは、マージ構成にリストされているすべてのモデルの重みをダウンロードし、選択したマージ方法を実行します (約 10 分かかります)。

 # 合并模型!mergekit-yaml config.yaml merge --copy-tokenizer --allow-crimes --out-shard-size 1B --lazy-unpickl

モデルはマージされ、「merge」ディレクトリに保存されました。アップロードする前に、再現性に必要なすべての情報を含んだreadmeファイルを作成できます。以下のコードブロックはJinjaテンプレートを定義し、マージ設定からのデータを自動的に入力します。

 !pip install -qU huggingface_hub from huggingface_hub import ModelCard, ModelCardData from jinja2 import Template username = "mlabonne" template_text = """ --- license: apache-2.0 tags: - merge - mergekit - lazymergekit {%- for model in models %} - {{ model }} {%- endfor %} --- # {{ model_name }} {{ model_name }} is a merge of the following models using [mergekit](https://github.com/cg123/mergekit): {%- for model in models %} * [{{ model }}](https://huggingface.co/{{ model }}) {%- endfor %} ## �� Configuration ```yaml {{- yaml_config -}} ``` """ #创建一个Jinja 模板对象jinja_template = Template(template_text.strip()) # 从配置文件中取得一个模型列表data = yaml.safe_load(yaml_config) if "models" in data: models = [data["models"][i]["model"] for i in range(len(data["models"])) if "parameters" in data["models"][i]] elif "parameters" in data: models = [data["slices"][0]["sources"][i]["model"] for i in range(len(data["slices"][0]["sources"]))] elif "slices" in data: models = [data["slices"][i]["sources"][0]["model"] for i in range(len(data["slices"]))] else: raise Exception("No models or slices found in yaml config") # 填充模板content = jinja_template.render( model_name=MODEL_NAME, models=models, yaml_cnotallow=yaml_config, username=username, ) # 保存模型卡card = ModelCard(content) card.save('merge/README.md')现在,我们已经创建了模型卡ModelCard。接下来,我们可以将整个文件夹推送到Hugging Face Hub上。 from google.colab import userdata from huggingface_hub import HfApi username = "mlabonne" #在Google Colab网页的secrets面板上定义api = HfApi(token=userdata.get("HF_TOKEN")) api.create_repo( repo_id=f"{username}/{MODEL_NAME}", repo_type="model" ) api.upload_folder( repo_id=f"{username}/{MODEL_NAME}", folder_path="merge", )

このモデルはHugging Face Hub(mlabonne/Marcoro14-7B-slerp)からダウンロードできます。別のラップトップでは、以下のコードを使って無料のT4 GPUでモデルをテストできます。

 !pip install -qU transformers accelerate from transformers import AutoTokenizer import transformers import torch model = "mlabonne/Marcoro14-7B-slerp" messages = [{"role": "user", "content": "What is a large language model?"}] tokenizer = AutoTokenizer.from_pretrained(model) prompt = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) pipeline = transformers.pipeline( "text-generation", model=model, torch_dtype=torch.float16, device_map="auto", ) outputs = pipeline(prompt, max_new_tokens=256, do_sample=True, temperature=0.7, top_k=50, top_p=0.95)

「大規模言語モデルとは何か?」という質問を投げかけたところ、次のような出力が得られました。

 “A large language model is a type of artificial intelligence (AI) system that has been trained on vast amounts of text data. It's designed to understand and generate human-like language, making predictions on what words or phrases might come next in a sentence or document. These models use complex algorithms and neural network architectures to learn from the data and improve their performance over time. Some well-known large language models include GPT-3 from OpenAI and BERT from Google.”

中国語での意味は次のようになります。「大規模言語モデルとは、大量のテキストデータで訓練された人工知能システムです。人間のような言語を理解・生成し、文や文書に出現する可能性のある次の単語や句を予測するように設計されています。これらのモデルは、高度なアルゴリズムとニューラルネットワークアーキテクチャを用いてデータから学習し、時間の経過とともにパフォーマンスを向上させます。よく知られている大規模言語モデルには、OpenAIのGPT-3やGoogleのBERTなどがあります。」
結果は有望に見えますが、より包括的な評価が必要です。現在、この一般的なモデルには、非常に興味深い評価ツールがいくつか登場しています。

  • Chatbot Arena は、人間の投票に基づいて Elo ベースの LLM リーダーボードを作成できます。
  • MT-bench(上記と同じリンク)は、GPT-4 を基準として使用し、一連の複数ラウンドの質問に対するモデルの応答を評価します。
  • NousSearchベンチマークスイートは、AGIEVAL、GPT4ALL、TruthfulQA、Bigbenchの4つの評価ベンチマークを統合しています。GPT4ALL自体には、HellaSwag、OpenBookQA、Winogrande、ARC Easy、ARC Challenge、BoolQ、PIQAなどのツールが含まれています。
  • Open LLM リーダーボードには、ARC、HellaSwag、MMLU、Winogrande、GSM8K、TruthfulQA の 6 つの評価ベンチマークが用意されています。

残念ながら、私たちのモデルをChatbot Arenaベンチマークプラットフォームに提出することはできませんでした。代わりに、Open LLMリーダーボードとNousSearchベンチマークを使用して評価することにしました。

私たちのモデルをOpen LLMリーダーボード(「ここから送信!」タブ)に提出しました。この記事の冒頭で述べたように、このモデルはリーダーボードで70億パラメータモデルの中で最高の評価を得ました。結果は以下の通りです。

画像は著者より提供されました。

オープンなLLMリーダーボードの問題は、これらのベンチマークが公開されていることです。つまり、より良い結果を得るために、誰でもテストデータでLLMを学習できるということです。最良のモデルをマージすることで、私たち自身の結果も「汚染」されてしまいます。Marcoro14-7B-slerpモデルも「汚染」され、マージに使用されたモデルの一部は既にテストセットで学習済みであったと想定しても間違いないでしょう。リーダーボードをハックするのではなく、最良のモデルを作成したい場合は、マージされていないモデルのみを使用して独自のマージを作成することをお勧めします。

そのため、OpenLLMのリーダーボードだけに頼るのではなく、 LLM AutoEvalツールを使ってNousSearchベンチマークスイートのスコアをシンプルなColabノートブックで自動計算することにしました。以下は、優れたOpenHermes-2.5-Mistral-7Bモデル比較した結果です。

画像は著者より提供されました。

各ベンチマークにおいて、このモデルと比較して大幅な改善を達成しました。NousSearchベンチマークスイートは、Open LLMリーダーボードのARC Challenge、TruthfulQA、HellaSwag、Winograndeといったタスクを共有している点にご注意ください。私の知る限り、Bigbenchは唯一完全に異なるベンチマークです(そうでない場合はお気軽にご連絡ください)。ただし、今回の統合に使用したモデルの1つは、現在もBigbenchで学習可能です。

結論は

この記事では、4つの異なるアルゴリズムを用いたLLMのマージの概念を紹介します。SLERP、TIES、DARE、Passthroughの仕組みを詳しく説明し、それぞれの設定例を示します。最後に、MergeKitのSLERPアルゴリズムを適用してMarcoro14-7B-SLERPモデルを作成し、Hugging Face Hubにアップロードします。最終的に、Open LLM Leaderboard(7Bモデルの中で最高のパフォーマンス)とNousSearchという2つのベンチマークスイートで優れたパフォーマンスを達成しました。独自のマージを作成したい場合は、自動化ノートブックプログラムであるLazyMergekitの使用をお勧めします。

複数のモデルを組み合わせるもう一つのアプローチは、それらを単一のハイブリッドエキスパートシステム(MoE)アーキテクチャに統合することです。次の記事では、これをどのように実現し、 Mixtralのような独自のモデルを作成するかを詳しく説明します。最後に、この記事が気に入ったら、 MediumとTwitterで@mlabonneをフォローしてください。

翻訳者紹介

Zhu Xianzong 氏は、51CTO コミュニティ エディター、51CTO 専門ブロガー兼講師、維坊の大学のコンピューター教師、そしてフリー プログラミング コミュニティのベテランです。

原題: mergekit による大規模言語モデルのマージ、著者: Maxime Labonne