🍕

Google ColabとUnslothを使ってLlama 3 (8B)をファインチューニングし、Ollamaにデプロイする方法

2024/07/18に公開

このチュートリアルでは、UnslothとGoogle Colabを使って無料でLlama-3をファインチューニングし、独自のチャットボットを作成する方法を段階的に説明します。作成したチャットボットは、Ollamaを使ってローカルコンピュータ上か、Google Colabの無料GPUインスタンス上で実行できます。

Unslothは、ファインチューニングしたモデルをOllamaに自動的にエクスポートし、Modelfileも自動生成します。

Unsloth Github: https://github.com/unslothai/unsloth

Unslothとは?

Unslothは、Llama-3、Mistral、Phi-3、GemmaなどのLLMのファインチューニングを2倍高速化し、メモリ使用量を70%削減します。しかも、精度の低下はありません。Unslothを無料で使うには、無料GPUを提供するインターフェースであるGoogle Colabを利用します。

  • Ollama:
  • Llama-3 Alpaca (このチュートリアルで使用するノートブック):
  • CSV/Excel Ollamaガイド:

ノートブックを使用するには、Googleアカウントにログインする必要があります。

Ollamaとは?

Ollamaは、自分のコンピュータから簡単かつ迅速に言語モデルを実行できるようにするツールです。Llama-3のような言語モデルをバックグラウンドで実行するプログラムを起動します。言語モデルに質問したい場合は、Ollamaにリクエストを送信するだけで、すぐに結果が返ってきます。このチュートリアルでは、Ollamaを推論エンジンとして使用します。

Unslothのインストール

Colabノートブックを使用したことがない場合は、ノートブック自体について簡単に説明します。

  • 再生ボタン: 各「セル」にあります。このボタンをクリックすると、そのセルのコードが実行されます。セルをスキップしたり、順番を無視して実行したりしないでください。エラーが発生した場合は、実行されなかったセルを再実行するだけです。再生ボタンをクリックする代わりに、CTRL + ENTERを押すこともできます。
  • ランタイムボタン: 上部のツールバーにあります。このボタンを使用して「すべて実行」をクリックすると、ノートブック全体を一度に実行できます。

最初のインストールセルは次のようになります。括弧内の再生ボタンをクリックしてください。オープンソースのGithubパッケージを取得し、他のパッケージをインストールします。

%%capture
# Unsloth、Xformers (Flash Attention)、その他のすべてのパッケージをインストール
!pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
!pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes

ファインチューニングするモデルの選択

ファインチューニング用のモデルを選択しましょう。ここでは、Meta / FacebookのLlama-3をデフォルトで使用します。これは、なんと15兆個の「トークン」でトレーニングされています。1つのトークンを1つの英単語と考えてください。これは、約35万冊の百科事典に相当します。その他の人気モデルとしては、Mistral、Phi-3(OpenAI自身のGPT-4出力を使用してトレーニング)、GoogleのGemma(13兆個のトークン!)などがあります。

Unslothはこれらのモデルなどをサポートしています。実際に、Hugging Faceモデルハブからモデルを入力して、動作するかどうかを確認してみてください。動作しない場合はエラーが発生します。

from unsloth import FastLanguageModel
import torch
max_seq_length = 2048  # 任意の値を選択可能。RoPEスケーリングは内部で自動的にサポート
dtype = None  # 自動検出の場合はNone。Tesla T4、V100の場合はFloat16、Ampere以降の場合はBfloat16
load_in_4bit = True  # メモリ使用量を削減するために4ビット量子化を使用。Falseも可能

# 4倍高速なダウンロードとOOMの回避のためにサポートされている4ビット事前量子化モデル
fourbit_models = [
    "unsloth/mistral-7b-v0.3-bnb-4bit",  # 新しいMistral v3は2倍高速
    "unsloth/mistral-7b-instruct-v0.3-bnb-4bit",
    "unsloth/llama-3-8b-bnb-4bit",  # Llama-3 15兆トークンモデルは2倍高速
    "unsloth/llama-3-8b-Instruct-bnb-4bit",
    "unsloth/llama-3-70b-bnb-4bit",
    "unsloth/Phi-3-mini-4k-instruct",  # Phi-3は2倍高速
    "unsloth/Phi-3-medium-4k-instruct",
    "unsloth/mistral-7b-bnb-4bit",
    "unsloth/gemma-7b-bnb-4bit",  # Gemmaは2.2倍高速
]  # その他のモデルについては、https://huggingface.co/unsloth をご覧ください

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/llama-3-8b-bnb-4bit",
    max_seq_length=max_seq_length,
    dtype=dtype,
    load_in_4bit=load_in_4bit,
    # token="hf_...",  # meta-llama/Llama-2-7b-hfのようなゲート付きモデルを使用する場合は、これを使用
)

次の3つの設定を調整できます:

  • max_seq_length = 2048: これはモデルのコンテキスト長を決定します。例えば、Geminiのコンテキスト長は100万以上ですが、Llama-3のコンテキスト長は8192です。任意の数値を選択できますが、テスト目的では2048を推奨します。Unslothは非常に長いコンテキストのファインチューニングもサポートしており、最大コンテキスト長の4倍まで拡張できることが示されています。
  • dtype = None: 通常はNoneのままで問題ありませんが、新しいGPUの場合はtorch.float16またはtorch.bfloat16を選択できます。
  • load_in_4bit = True: 4ビット量子化でファインチューニングを行います。これによりメモリ使用量が4分の1に削減され、無料の16GBメモリGPUでも実際にファインチューニングを行うことができます。4ビット量子化は、重みを限られた数のセットに変換してメモリ使用量を削減します。欠点は1〜2%の精度低下ですが、わずかな精度向上を望む場合は、H100などのより大きなGPUでこれをFalseに設定します。

セルを実行すると、Unslothのバージョン、使用しているモデル、GPUのメモリ量、その他の統計情報などが出力されます。これらの情報は無視して構いません。

ファインチューニングのパラメータ

ファインチューニングをカスタマイズするには、上記の数字を編集できますが、適切な数字がすでに選択されているため、無視しても構いません。

model = FastLanguageModel.get_peft_model(
    model,
    r=16,  # 0より大きい任意の数値を選択してください!8、16、32、64、128を推奨します
    target_modules=[
        "q_proj",
        "k_proj",
        "v_proj",
        "o_proj",
        "gate_proj",
        "up_proj",
        "down_proj",
    ],
    lora_alpha=16,
    lora_dropout=0,  # 任意の値をサポートしていますが、= 0が最適化されています
    bias="none",  # 任意の値をサポートしていますが、= "none"が最適化されています
    # [新機能] "unsloth"はVRAMの使用量を30%削減し、2倍のサイズのバッチサイズに対応します!
    use_gradient_checkpointing="unsloth",  # 非常に長いコンテキストの場合は、Trueまたは"unsloth"を使用します
    random_state=3407,
    use_rslora=False,  # ランク安定化LoRAをサポートしています
    loftq_config=None,  # LoftQもサポートしています
)

目的は、これらの数値を変更して精度を向上させながら、オーバーフィッティングを防ぐことです。オーバーフィッティングとは、言語モデルがデータセットを暗記してしまい、新しい質問に答えられなくなることです。最終的なモデルは、未知の質問に答えられるように、暗記ではなく、一般化できるようにしたいと考えています。

  • r = 16: ファインチューニングプロセスのランク。数値が大きいほど多くのメモリを使用し、速度は遅くなりますが、難しいタスクの精度が向上する可能性があります。通常は、8(高速なファインチューニングの場合)から128までの数値を推奨します。大きすぎる数値は、オーバーフィッティングを引き起こし、モデルの品質を損なう可能性があります。
  • target_modules = ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj",]: ファインチューニングするすべてのモジュールを選択します。メモリ使用量を削減してトレーニングを高速化するために、いくつか削除することもできますが、お勧めしません。すべてのモジュールでトレーニングしてください。
  • lora_alpha = 16: ファインチューニングのスケーリング係数。数値が大きいほど、ファインチューニングはデータセットについて多く学習しますが、オーバーフィッティングを促進する可能性があります。ランクrと同じか、2倍にすることをお勧めします。
  • lora_dropout = 0: トレーニングを高速化するために、これを0のままにします。オーバーフィッティングを減らすことはできますが、それほどではありません。
  • bias = "none": トレーニングを高速化し、オーバーフィッティングを減らすために、これを0のままにします。
  • use_gradient_checkpointing = "unsloth": オプションは、True、False、"unsloth"です。"unsloth"を推奨します。これは、メモリ使用量をさらに30%削減し、非常に長いコンテキストのファインチューニングをサポートしているためです。詳細については、https://unsloth.ai/blog/long-context をご覧ください。
  • random_state = 3407: 決定論的な実行を決定する数値。トレーニングとファインチューニングには乱数が必要なので、この数値を設定すると実験の再現性が得られます。
  • use_rslora = False: lora_alpha = 16を自動的に設定する高度な機能です。必要に応じて使用できます。
  • loftq_config = None: LoRA行列を重みの上位r個の特異ベクトルに初期化する高度な機能です。精度がいくらか向上する可能性がありますが、開始時にメモリ使用量が急増する可能性があります。

Alpacaデータセット

ここでは、GPT-4自体を使って作成されたAlpacaデータセットを使用します。これは52,000個の指示と出力のリストで、Llama-1のリリース時に非常に人気がありました。これにより、ベースとなるLLMのファインチューニングをChatGPTと競合できるレベルにまで引き上げることができました。

https://huggingface.co/datasets/vicgalle/alpaca-gpt4 から、GPT4バージョンのAlpacaデータセットにアクセスできます。データセットの最初の古いバージョンは、https://github.com/tatsu-lab/stanford_alpaca にあります。

from datasets import load_dataset
dataset = load_dataset("vicgalle/alpaca-gpt4", split = "train")
print(dataset.column_names)
['instruction', 'input', 'output', 'text']

各行を1つの大きなプロンプトに結合します。これを使用して言語モデルをファインチューニングすることで、ChatGPTと非常によく似た動作を実現できます。このプロセスを、教師あり指示ファインチューニングと呼びます。

ファインチューニングのための複数列

ChatGPTスタイルのアシスタントでは、通常1つの指示/1つのプロンプトしか許可されておらず、複数の列/入力は許可されていません。例えば、ChatGPTでは複数のプロンプトではなく、1つのプロンプトを送信する必要があります。

これは、ファインチューニングが実際に機能するためには、複数の列を1つの大きなプロンプトに「マージ」する必要があることを意味します。

例えば、有名なタイタニック号のデータセットには多くの列があります。乗客の年齢、客室クラス、料金などに基づいて、その乗客が生存したか死亡したかを予測するのが課題でした。これをそのままChatGPTに渡すことはできません。むしろ、この情報を1つの大きなプロンプトに「マージ」する必要があります。

例えば、その乗客に関するすべての情報を含む「マージ」された単一のプロンプトでChatGPTに質問し、乗客が死亡したか生存したかを推測または予測するよう依頼できます。

他のファインチューニングライブラリでは、ファインチューニングのために、すべての列を1つのプロンプトにマージしてデータセットを手動で準備する必要があります。Unslothでは、これを一度に行うto_sharegptという関数を用意しています。

タイタニック号のファインチューニングノートブックにアクセスしたり、CSVまたはExcelファイルをアップロードしたりするには、https://colab.research.google.com/drive/1VYkncZMfGFkeCEgN2IzbZIKEDkyQuJAS?usp=sharing にアクセスしてください。

from unsloth import to_sharegpt
dataset = to_sharegpt(
    dataset,
    merged_prompt="{instruction}[[\nYour input is:\n{input}]]",
    output_column_name="output",
    conversation_extension=3,  # より長い会話を処理するには、これを増やしてください
)

これは少し複雑ですが、多くのカスタマイズが可能です。いくつかのポイントを説明します:

  • すべての列名は中括弧{}で囲む必要があります。これらは、実際のCSV/Excelファイルの列名です。
  • オプションのテキストコンポーネントは、[[]]で囲む必要があります。例えば、「input」列が空の場合、マージ関数はテキストを表示せず、これをスキップします。これは、値が不足しているデータセットに役立ちます。
  • output_column_nameに出力またはターゲット/予測列を選択します。Alpacaデータセットの場合、これはoutputになります。

例えば、タイタニック号のデータセットでは、以下のように各列/テキストをオプションにすることで、大きなマージされたプロンプト形式を作成できます。

データが不足しているデータセットが次のように表されるとします:

Embarked  Age  Fare
S  23  
18  7.25

この場合、次のような結果は避けたいでしょう:

The passenger embarked from S. Their age is 23. Their fare is EMPTY.

The passenger embarked from EMPTY. Their age is 18. Their fare is $7.25.

代わりに、[[]]を使用して列をオプションで囲むことで、この情報を完全に除外できます:

[[The passenger embarked from S.]] [[Their age is 23.]] [[Their fare is EMPTY.]]

[[The passenger embarked from EMPTY.]] [[Their age is 18.]] [[Their fare is $7.25.]]

これにより、以下のようになります:

The passenger embarked from S. Their age is 23.

Their age is 18. Their fare is $7.25.

複数ターンの会話

Alpacaデータセットはシングルターンであることに注意が必要です。一方、ChatGPTの使用はインタラクティブで、複数ターンの会話が可能です。ファインチューニングされた言語モデルが、ChatGPTのように複数ターンの会話をどのように行うかを学習させたいと考えています。

そこで、conversation_extensionパラメータを導入しました。これはシングルターンのデータセットからランダムな行を選択し、それらを1つの会話にマージします。例えば、3に設定すると、3つの行をランダムに選択して1つにマージします。長すぎるとトレーニングが遅くなる可能性がありますが、チャットボットと最終的なファインチューニングの質が大幅に向上する可能性があります。

次に、output_column_nameを予測/出力列に設定します。Alpacaデータセットの場合、これはoutput列になります。

from unsloth import standardize_sharegpt
dataset = standardize_sharegpt(dataset)

次に、standardize_sharegpt関数を使用して、データセットをファインチューニングに適した形式に変換します。これは必ず呼び出してください。

カスタマイズ可能なチャットテンプレート

これで、ファインチューニング自体に使用するチャットテンプレートを指定できます。非常に有名なAlpacaの形式を以下に示します:

alpaca_prompt = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.

### Instruction:
{}

### Input:
{}

### Response:
{}"""

しかし、ChatGPTスタイルのファインチューニングでは1つのプロンプトしか必要ないと前述しました。Unslothを使用してすべてのデータセット列を1つに正常にマージしたので、1つの入力列(指示)と1つの出力でチャットテンプレートを作成できます。

chat_template = """Below are some instructions that describe some tasks. Write responses that appropriately completes each request.

### Instruction:
{INPUT}

### Response:
{OUTPUT}"""

したがって、カスタムの指示を書くなど、自由にテンプレートをカスタマイズできます。指示には{INPUT}フィールド、モデルの出力フィールドには{OUTPUT}フィールドを配置する必要があります。

または、Llama-3テンプレート自体を使用することもできます(これは、Llama-3のinstructバージョンを使用する場合にのみ機能します):

chat_template = """<|begin_of_text|><|start_header_id|>system<|end_header_id|>

{SYSTEM}<|eot_id|><|start_header_id|>user<|end_header_id|>

{INPUT}<|eot_id|><|start_header_id|>assistant<|end_header_id|>

{OUTPUT}<|eot_id|>"""

実際には、ChatGPTのようにシステムプロンプトをカスタマイズするのに役立つ、オプションの{SYSTEM}フィールドも使用できます。

また、CSVとExcelのアップロードを含むこのColabノートブックhttps://colab.research.google.com/drive/1VYkncZMfGFkeCEgN2IzbZIKEDkyQuJAS?usp=sharing の、乗客が死亡したか生存したかを予測する必要があったタイタニック号の予測タスクでは、次のようになります:

chat_template = """{SYSTEM}
USER: {INPUT}
ASSISTANT: {OUTPUT}"""
from unsloth import apply_chat_template
dataset = apply_chat_template(
    dataset,
    tokenizer=tokenizer,
    chat_template=chat_template,
    # default_system_message="You are a helpful assistant", << [オプション]
)

モデルのトレーニング

より長いステップでファインチューニングしたり、大きなバッチサイズでトレーニングしたりしない限り、以下の設定を編集しないことをお勧めします。

from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=max_seq_length,
    dataset_num_proc=2,
    packing=False,  # 短いシーケンスの場合、トレーニングを5倍高速化できます
    args=TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=5,
        max_steps=60,
        # num_train_epochs = 1,
        learning_rate=2e-4,
        fp16=not is_bfloat16_supported(),
        bf16=is_bfloat16_supported(),
        logging_steps=1,
        optim="adamw_8bit",
        weight_decay=0.01,
        lr_scheduler_type="linear",
        seed=3407,
        output_dir="outputs",
    ),
)

上記のパラメータを変更することは通常はお勧めしませんが、いくつか詳しく説明します:

  • per_device_train_batch_size = 2: GPUのメモリをより多く活用したい場合は、バッチサイズを増やします。また、トレーニングをよりスムーズにし、オーバーフィットを防ぐためにも、これを増やします。ただし、パディングの問題によりトレーニングが実際に遅くなる可能性があるため、通常はお勧めしません。代わりに、gradient_accumulation_stepsを増やすことをお勧めします。
  • gradient_accumulation_steps = 4: 上記のバッチサイズを増やすことと同じ効果がありますが、メモリ消費量には影響しません。通常、トレーニング損失曲線をよりスムーズにしたい場合は、これを増やすことをお勧めします。
  • max_steps = 60: トレーニングを高速化するために、ステップを60に設定しました。数時間かかる可能性のある完全なトレーニング実行の場合は、代わりにmax_stepsをコメントアウトし、num_train_epochs = 1に置き換えます。1に設定すると、データセット全体を1回完全にパスします。通常は1〜3パスを推奨します。それ以上は推奨しません。それ以上パスするとオーバーフィットの可能性が高くなります。
  • learning_rate = 2e-4: ファインチューニングプロセスを遅くしたい場合は学習率を下げますが、より高い精度の結果に収束する可能性があります。通常は、試してみる値として、2e-41e-45e-52e-5を推奨します。

トレーニング中にいくつかの数値のログが表示されます。これがトレーニング損失です。目標は、これをできるだけ0.5に近づけるようにパラメータを設定することです。ファインチューニングが1、0.8、または0.5に達しない場合は、いくつかの数値を調整する必要があるかもしれません。損失が0になる場合も良い兆候ではありません。

trainer_stats = trainer.train()

推論/モデルの実行

トレーニングプロセスが完了したら、モデルを実行してみましょう。以下のコードで、黄色で下線付きの部分を編集できます。実際、複数ターンのチャットボットを作成したので、過去にいくつかの会話をしていたかのようにモデルを呼び出すことができます。

FastLanguageModel.for_inference(model)  # ネイティブで2倍高速な推論を有効にします
messages = [  # 以下を変更してください!
    {"role": "user", "content": "フィボナッチ数列を続けてください。入力は1、1、2、3、5、8です。"},
]
input_ids = tokenizer.apply_chat_template(
    messages,
    add_generation_prompt=True,
    return_tensors="pt",
).to("cuda")

from transformers import TextStreamer

text_streamer = TextStreamer(tokenizer, skip_prompt=True)
_ = model.generate(
    input_ids, streamer=text_streamer, max_new_tokens=128, pad_token_id=tokenizer.eos_token_id
)

Unsloth自体はネイティブで2倍高速な推論を提供するため、FastLanguageModel.for_inference(model)を呼び出すことを忘れないでください。モデルにより長い応答を出力させたい場合は、max_new_tokens = 1282561024などのより大きな数値に設定します。結果が出るまでに時間がかかることに注意してください。

モデルの保存

これで、ファインチューニングされたモデルを、LoRAアダプターと呼ばれる小さな100MBのファイルとして保存できます。モデルをアップロードしたい場合は、代わりにHugging Faceハブにプッシュすることもできます。https://huggingface.co/settings/tokens からHugging Faceトークンを取得し、トークンを追加することを忘れないでください。

model.save_pretrained("lora_model")  # ローカルに保存
tokenizer.save_pretrained("lora_model")
# model.push_to_hub("your_name/lora_model", token = "...") # オンラインに保存
# tokenizer.push_to_hub("your_name/lora_model", token = "...") # オンラインに保存

モデルを保存したら、Unslothを使用してモデル自体を再度実行できます。FastLanguageModelを再度使用して、推論のために呼び出します。

if False:
    from unsloth import FastLanguageModel

    model, tokenizer = FastLanguageModel.from_pretrained(
        model_name="lora_model",  # トレーニングに使用したモデル
        max_seq_length=max_seq_length,
        dtype=dtype,
        load_in_4bit=load_in_4bit,
    )
    FastLanguageModel.for_inference(model)  # ネイティブで2倍高速な推論を有効にします
pass

messages = [  # 以下を変更してください!
    {
        "role": "user",
        "content": "シーケンスに関する特別なことを説明してください。入力は1、1、2、3、5、8です。",
    },
]
input_ids = tokenizer.apply_chat_template(
    messages,
    add_generation_prompt=True,
    return_tensors="pt",
).to("cuda")

from transformers import TextStreamer

text_streamer = TextStreamer(tokenizer, skip_prompt=True)
_ = model.generate(
    input_ids, streamer=text_streamer, max_new_tokens=128, pad_token_id=tokenizer.eos_token_id
)

Ollamaへのエクスポート

最後に、ファインチューニングしたモデルをOllama自体にエクスポートできます。まず、ColabノートブックにOllamaをインストールする必要があります。

!curl -fsSL https://ollama.com/install.sh | sh

次に、作成したファインチューニング済みモデルをllama.cppのGGUFフォーマットにエクスポートします。

# 8ビットQ8_0に保存
if True:
    model.save_pretrained_gguf("model", tokenizer)
# https://huggingface.co/settings/tokens にアクセスしてトークンを取得してください。
# また、hfを自分のユーザー名に変更してください。
if False:
    model.push_to_hub_gguf("hf/model", tokenizer, token="")

# 16ビットGGUFに保存
if False:
    model.save_pretrained_gguf("model", tokenizer, quantization_method="f16")
if False:
    model.push_to_hub_gguf("hf/model", tokenizer, quantization_method="f16", token="")

# q4_k_m GGUFに保存
if False:
    model.save_pretrained_gguf("model", tokenizer, quantization_method="q4_k_m")
if False:
    model.push_to_hub_gguf("hf/model", tokenizer, quantization_method="q4_k_m", token="")

# 複数のGGUFオプションに保存 - 複数必要な場合ははるかに高速です!
if False:
    model.push_to_hub_gguf(
        "hf/model",  # hfを自分のユーザー名に変更してください。
        tokenizer,
        quantization_method=["q4_k_m", "q8_0", "q5_k_m"],
        token="",  # https://huggingface.co/settings/tokens からトークンを取得してください
    )

すべての行をTrueに変更するのではなく、1行だけTrueに変更してください。そうしないと、非常に長い時間がかかります。通常は最初の行をTrueに設定することをお勧めします。これにより、ファインチューニングされたモデルをQ8_0形式(8ビット量子化)にすばやくエクスポートできます。また、q4_k_mなど、量子化メソッドのリスト全体にエクスポートすることもできます。

GGUFの詳細については、https://github.com/ggerganov/llama.cpp をご覧ください。

また、GGUFへのエクスポート方法について、手動での手順も記載しています: https://github.com/unslothai/unsloth/wiki#manually-saving-to-gguf

以下のような長いテキストのリストが表示されます - 5〜10分ほどお待ちください。

Loading checkpoint shards: 100%|██████████| 4/4 [00:00<00:00,  7.86it/s]
Merging 4 shards of model.safetensors: 100%|██████████| 4/4 [00:14<00:00,  3.61s/it]
Saving model to model/ggml-model-q8_0.gguf

そして最後に、以下のように表示されます。

GGUF file size: 3.89 GB

次に、Ollama自体をバックグラウンドで実行する必要があります。Colabは非同期呼び出しを好まないため、subprocessを使用しますが、通常は端末/コマンドプロンプトでollama serveを実行するだけです。

import subprocess
subprocess.Popen(["ollama", "serve"])
import time
time.sleep(3) # Ollamaがロードされるまで数秒間待ちます。

Modelfileの自動作成

Unslothが提供する工夫は、Ollamaが必要とするModelfileを自動的に作成することです。これは、設定のリストであり、ファインチューニングプロセスで使用したチャットテンプレートも含まれています。生成されたModelfileは、以下のように出力できます。

print(tokenizer._ollama_modelfile)

次に、Modelfileを使用して、Ollamaと互換性のあるモデルを作成するようにOllamaに指示します。

!ollama create unsloth_model -f ./model/Modelfile

Ollamaでの推論

独自のローカルマシン/無料のColabノートブックのバックグラウンドで実行されているOllamaサーバー自体を呼び出したい場合は、モデルを呼び出して推論を行うことができます。以下のコマンドの内容は編集可能です。

!curl http://localhost:11434/api/chat -d '{ \
    "model": "unsloth_model", \
    "messages": [ \
        { "role": "user", "content": "フィボナッチ数列を続けてください: 1, 1, 2, 3, 5, 8," } \
    ] \
    }'

インタラクティブなChatGPTスタイル

ファインチューニングされたモデルをChatGPTのように実際に実行するには、もう少し作業が必要です。まず、左側のサイドバーにある端末アイコンをクリックすると、端末がポップアップ表示されます。

次に、Enterキーを2回押して、端末ウィンドウの一部の奇妙な出力を削除する必要がある場合があります。数秒待ってから、「ollama run unsloth_model」と入力し、Enterキーを押します。

そして最後に、実際のChatGPTのように、ファインチューニングされたモデルと対話できます。CTRL + Dを押してシステムを終了し、Enterキーを押してチャットボットと会話します。

まとめ

これで完了です。Unslothを使用して、言語モデルを正常にファインチューニングし、Ollamaにエクスポートしました。しかも、2倍高速で、VRAM使用量は70%も削減されています。そして、これらはすべて、Google Colabノートブックで無料で実現できます。

報酬モデリングの実行方法、継続的な事前トレーニングの実行方法、vLLMまたはGGUFへのエクスポート方法、テキスト補完の実行方法、またはファインチューニングのヒントとコツの詳細については、Githubをご覧ください。

ここまで読んでいただき、ありがとうございました。

📒GoogleColabノートブック

https://colab.research.google.com/drive/18tOEt2JWs6xsRpPrbvjqKLJyuIawLlYe?usp=sharing

📒元のGoogleColabノートブック

https://colab.research.google.com/drive/1WZDi7APtQ9VsvOrQSSC5DDtxq159j8iZ?usp=sharing#scrollTo=MwEbRFl0Mf3E

Discussion