3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

小さなLLM(Llama-3.2-1B)をQLoRAでファインチューニングしてFunction Callingを覚えさせてみた

3
Posted at

小さなLLMをQLoRAでファインチューニングして、Function Callingを覚えさせてみた

小さなオープンモデルは、ツール呼び出し(function calling)が苦手なことが多いです。「何をすべきか」は理解して正しい関数も選ぶのに、出力するJSONの構造が微妙に間違っていて、そのままではパーサーが実行できない——ということが起きます。

この記事では、Llama-3.2-1B-Instruct をQLoRAでファインチューニングして、その「構造のズレ」を直した記録をまとめます。すべて Kaggle の無料T4 GPU で動かしました。課金なしです。

学習用というより、自分の理解のために手を動かしてみた小さなプロジェクトです。


何が問題だったか

学習前のベースモデルに、標準的なツール定義(get_weather)を渡して名古屋の天気を聞いてみると、こう返ってきました。

{"type": "function", "function": "get_weather", "parameters": {"city": "Nagoya", "unit": "celsius"}}

意図は合っています(関数も都市も正しい)。でも構造が2か所おかしい。

  1. "function" が文字列になっている。本来はここに namearguments を持つオブジェクトが入るべきなのに、平坦になっている。
  2. "parameters" を使っている。ツールを「定義」するときは parameters ですが、実際に「呼び出す」ときの引数は arguments に入れるのが正しい。モデルはこの2つを混同していました。

面白かったのは、2つ目のエラーの原因です。Llama のチャットテンプレート自体が「parameters というキーで返せ」とモデルに指示していたのです。一方で最近の慣習(そして学習データ)は arguments を使う。つまりベースモデルはデタラメを出していたのではなく、テンプレートの古い指示に忠実に従っていただけでした。こういう「作り込まれた挙動」を上書きできるのが、ファインチューニングの効くところです。


結果

ファインチューニング後、同じプロンプトでこうなりました。

[{"name": "get_weather", "arguments": {"city": "Nagoya", "unit": "celsius"}}]

2つのエラーが両方とも直っています。namearguments が正しくなり、学習データが使っているリスト形式で包まれるようになりました。試した他のプロンプトでも同じ形式が安定して出ました。


やったこと

ベースモデル: meta-llama/Llama-3.2-1B-Instruct

あえて一番小さい1Bを選びました。ツール呼び出しがもともと苦手なので、before/after の差がはっきり出るからです。強いモデルだと最初からだいたい正しく出せてしまい、見せ場がありません。

データセット: Salesforce/xlam-function-calling-60k

各サンプルが「ユーザーの質問・使えるツール・正しい呼び出し」の3点セットになっています。今回は500件だけ使いました。少ないですが、出力フォーマットを覚えさせるだけならこれで十分でした。

手法: QLoRA。2つの組み合わせです。

  • 量子化 — ベースモデルを4bitで読み込み、メモリ使用量を約1/4に。これで無料のT4に載ります。
  • LoRA — 12億パラメータ全部を学習するのではなく、ベースは凍結して、小さなアダプター(約1100万パラメータ、全体の0.9%)だけを学習する。

全体ではなくアダプターだけを学習するので、無料GPUで動き、成果物も約40MBと小さく済みます。

学習設定: 2エポック、実効バッチサイズ16、学習率2e-4、rank 16。最終的な mean token accuracy は約88%でした。


つまずいたところ(正直な記録)

  • bitsandbytes が import できない — インストール後にカーネルを再起動しないと反映されませんでした。コンパイル済みライブラリではよくあるやつです。
  • 学習直後の生成が文字化けした — モデルが学習モードのままだったのが原因。model.eval() で推論モードに切り替えたら直りました。
  • セッションリセットでアダプターが消えかけた — Kaggle の作業ディレクトリはセッションごとにリセットされます。保存先のパスを勘違いしていて焦りましたが、保存したバージョンの output に残っていて助かりました。学習したものはすぐ Hugging Face に push するのが安全です。

限界

500件・2エポックで「出力フォーマットを直す」ことに絞ったので、幅広いツールに対応できる汎用モデルではありません。構造の正しさは確認しましたが、難しい・曖昧な質問で正しいツールを選べるかまでは評価していません。同じ手順を3Bや7Bのベースに適用すれば、実用的なモデルになるはずです。


まとめ

Function Calling は、モデルが「話す」だけでなく「実際に何かをする」ための仕組みです。小さいモデルやローカルモデルを使うチームにとって、「意図は理解しているのに、実行できる形式の呼び出しを出せない」というギャップは地味に効く問題で、そこは小さくて安いファインチューニングで埋められます。かかったのは無料GPUの時間だけでした。

学習したアダプター: Thanush16/llama-3.2-1b-function-calling

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?