世界を動かす技術を、日本語で。

ローカルLLM「Qwen 3:0.6B」を微調整して質問を分類する良好な結果

概要

  • 超小型LLM(Qwen 3:0.6B)を家事質問分類器としてファインチューニングする実験
  • メタデータカテゴリでベクトル検索範囲を限定し、RAG精度向上を目指す設計
  • ベースラインモデルは10%の精度、ファインチューニングで92%まで向上
  • カテゴリ名→2文字ID出力でさらに誤分類減少
  • 一部「水回り」カテゴリの混同など課題も残存

家庭内質問チャットボット開発の全体像

  • 家庭内情報管理 を目的としたチャットボット開発
  • RAG(Retrieval-Augmented Generation) による情報検索
    • ベクトルDB で家事履歴や予定などを管理
  • 質問分類 による検索範囲の絞り込み
    • 例:「プールポンプの交換時期?」→「pool」カテゴリのみ検索

小型LLMによる質問分類の実験設計

  • Qwen 3:4B :一般的な質問応答用LLM
  • Qwen 3:0.6B :質問分類用の超小型LLM
  • Unsloth + QLora によるファインチューニング
    • 850件 の家事QAデータセットを70/15/15で分割
  • テスト :131件の統合テストシナリオで精度評価

ベースライン(未学習モデル)の課題

  • Qwen 3:0.6B をプロンプトのみで分類器として使用
    • 指定カテゴリから1つだけ選ぶよう指示
  • 精度 :13/131(約10%)
    • 広義カテゴリ (electric/appliances等)への偏り
    • リスト外カテゴリ (apartments等)の生成
    • 例外 :ペインター分類不能、エアコン→electric誤判定

ファインチューニング1回目の結果

  • 同一プロンプト でUnslothを用いたファインチューニング
  • 精度 :104/131(約79%)に大幅向上
  • 誤判定傾向
    • 正しいカテゴリ名の断片出力(ac/airなど)
    • 「水回り」カテゴリ(pool, water heater, fountain等)の混同

ファインチューニング2回目:2文字ID方式

  • カテゴリ名→2文字ID へ変更
    • 例:「appliances」→「AA」
  • 精度 :120/131(約92%)にさらに向上
  • 誤判定例
    • water heater→pool(複数回)
    • gutters→mosquito
    • mosquito→garden lights
  • 考察 :意味重複のない固定ID出力で超小型LLMの精度が大幅向上

今後の課題と展望

  • 「水回り」カテゴリ のさらなるデータ強化
  • ユーザー修正フィードバック による再学習パイプライン
  • カテゴリ追加時の保守性 とプロンプト例示のバランス
  • Githubリポジトリ でプロジェクト公開中

追記:シンプルな分類器との比較実験

  • LLMファインチューニング 以外のアプローチ提案
    • ロジスティック回帰による分類器実験
  • 詳細は別記事 にて公開

このプロジェクトでは、 超小型LLMでも適切なデータセットと設計で高精度な質問分類が可能 なことが示された。一方で、カテゴリ間の意味的重複や新規カテゴリ追加時の運用性など、現実的な課題も明らかになった。

Hackerたちの意見

Qwen 0.6B、めっちゃクールだと思う!めっちゃ速いし、ここにあるように明確なニッチがあるよね。特にファインチューニングしたら、学生としても蒸留に興味があるな。

もし、主題分類みたいな些細な問題のためにファインチューニングするつもりなら、Scikit LearnのSGDClassifierを使った2-gramsで十分だと思うよ。トレーニングした分類器は1MB以下になるし、1分以内でトレーニングできるから、組み込みデバイスでも問題なく動くよ。小さなLLMは、テキスト分類において次の2つのケースで良い選択肢だと思う: - 文脈の例を提供して、それに基づく分類器を作る場合。 - 分類が単純な主題型分類器を超える場合。例えば、選択肢のある質問応答は分類の一種で、小さなLLMがうまく機能するけど、従来のML手法では無理だよ。

800例では無理だね。ngramモデルを考えるなら、フロンティアLLMを使って、馬鹿げた正規表現を書いてもらった方がいいと思う。

2-グラムと600Mパラメータのモデルの間には、良い選択肢がいくつかあるよね。2-グラムがここでうまくいくとは思えないし、このモデルが彼らの問題を解決するなら、なんで良い選択肢じゃないのかもよくわからないな。

BERTみたいな小さめのトランスフォーマーが合ってると思う。少ない例でも大丈夫だし、LLMを使って合成的に生成できるからね。現代のハードウェアでサクッとトレーニングできて、分類も速いし。数年前、LLMが出る前にこういうことやってて楽しかったな。

小さな言語モデルをファインチューニングしたいなら、gemma3:270mはサイズ的にかなり面白いよ。

言語モデルについてもっと深く掘り下げたいなら、これらのプロジェクトアイデアを試してみて: - タスクソースやGliNERのようなゼロショットエンコーダー - 自然言語推論: https://huggingface.co/blog/dleemiller/nli-xenc-ways-to-use - GRPOトレーニング - GEPAプロンプトチューニング Qwen 0.6B(またはGEPA、その後GRPO) - 埋め込みモデルを使って分類器(MLP、ロジスティック、SVM)をトレーニング - より大きなLLMを使って合成データセットを生成(多様性が欠けることに注意、まずはリアルなソースから「シードテキスト」を掘り出して) - 複数のカテゴリが有効な「難しい例」を合成生成して、好みの応答をDPOチューニングする。

そのリストはどこで手に入れたの?LLMについてもう少し深く関わる方法を探してるんだけど(今はかなりざっくりした理解しかないし、直接の仕事には関わってないから、詳しいことにはあまり詳しくないんだ)。

モデルが新しいカテゴリ(例えばアパート)を作り出して、提供された許可されたカテゴリのリストに従わない この特定の失敗モードは、出力が従うべき文法を提供することで解決できるのかな?(Qwenにこの機能があるかはわからないけど、例えば出力がパース可能なJSONであることを確保するために使われる)

できるよ。それはモデル自体ではなく、モデルを実行するもの(例えばLlama.cpp)が実装していることなんだ。思考をオンにすると、文法がすぐに複雑になるから、うまく動かすのは難しいよ(Qwen 0.6Bが思考できるかは覚えてないけど)。

うん、ロジットマスキングのような制約付きデコーディングを使って、語彙内の無効なトークンを-∞に強制して、実質的に選択から外すことができるよ。llama.cppは、フォーマットされた文法を受け入れることでこれを公開していると思う。

俺もそう思った。ここで使われてないのは意外だね(俺の見た限りでは)。

Hacker Newsで議論の続きを見る