HN 日本語サマリー

← 一覧へ戻る
AI・機械学習

Geminiに9ドルで自身の後継機をトレーニングさせた

I had Gemini train its own replacement for $9 (petervijeh.com)

80 pointsby p-s-v34 コメント

要約

この記事は、Redditのナイフ愛好家フォーラムからブランド、モデル、素材名を抽出するタスクにおいて、高価なGemini APIの代わりに、より安価でオープンソースのGLiNERモデルをファインチューニングするプロジェクトについて詳述しています。Geminiによる9ドルのラベル付けデータセットを用いてGLiNERをトレーニングした結果、Geminiの精度(F1スコア約0.65)に対し、GLiNERは0.83のF1スコアを達成し、コストを大幅に削減しつつ、ローカルでの高速処理を実現しました。

全文翻訳

Geminiに9ドルで自身の後継機をトレーニングさせた

私は料理が好きで、それが高価なシェフナイフへの執着へと発展しました。そのため、人々がナイフについて議論しているRedditのスレッドをスクレイピングし、言及されているすべてのブランド、モデル、鋼材を抽出して、何が購入され、議論されているかを見ています。

テキストから製品名を抽出する作業は、名前付きエンティティ認識(NER)と呼ばれ、小規模なモデルが10年間行ってきたことです。私はGemini 3.1 Proを使用してこれを実行しており、コメントごとに1回の有料API呼び出しでした。これは過剰でしたが、機能しました。「白い鋼2(white #2)のMazakiを手に入れた、古いFibroxよりずっと良い」というコメントから、Mazakiをブランド、Fibroxをモデル、白い鋼2を鋼材として抽出し、それ以外は何も返しませんでした。しかし、スクレイパーは新しいコメントをすべてプルするため、投稿量に応じて請求額が増加し、それを制限する唯一の方法はコメントをスキップすることでした。

明らかな代替策として、GLiNERというオープンNERモデルをゼロショットで実行したところ、コストはゼロになり、精度は約0.65 F1(Geminiの回答に対する推定値)に低下しました。この差が、この記事の残りの部分で説明することです。Geminiに4,290件のコメントを一度だけラベル付けさせ、GLiNERにそれを学習させることは可能でしょうか?

  • 何をしたか: Gemini 3.1 Proが一度作成したラベルを基に、Redditコメント内のブランド、モデル、素材をタグ付けするために、GLiNER large v2.5(459M)をファインチューニングしました。
  • なぜか: ゼロショットのGLiNERは、約0.65 F1(推定)を記録しました。Geminiは良好なスコアでしたが、スクレイパーが実行されている間、すべてのコメントに課金されました。
  • アプローチ: Geminiにはオフセットではなく文字列を要求しました。オフセットはコードで計算しました。製品が含まれていないコメントをネガティブ例として追加しました。2回目の実行の前に、225件のコメントを検証セットとしてロックしました。
  • 問題: 10回の実行のうち5回は、実用的なモデルが生成されませんでした。3回は設定で失敗しました。2回は、アテンションマスクと同じように埋めた words_mask というテンソルで失敗しました。
  • 結果: Geminiのラベルに対して0.83 F1を達成しました。最も良い結果を出した実行は、Tesla T4で24分かかりました。ラベルに9ドル、10回の実行全体でのGPU時間は約2.50ドル、デバッグに数日かかりました。

何をしようとしたか

計画は3つのステップでした。まずGeminiに数千件のRedditコメントを一度だけラベル付けさせ、すべてのブランド、モデル、鋼材に印を付けさせます。次に、そのラベルでGLiNERをトレーニングします。その後、それ以降のすべてのコメントを自分のマシンでGLiNERを実行し、Geminiへの呼び出しを停止します。

Geminiは9ドルで4,290件のコメントをラベル付けしました。これは1コメントあたり0.0021ドルです。つまり、トレーニング済みモデルは、後続のコメントが同じ長さで、すでに所有しているGPUで実行される限り、約4,291コメント目で元が取れることになります。成功のテストは単純でした。モデルが一度も見たことのない225件のコメントで、Geminiがタグ付けしたのと同じ単語をどれくらいの頻度でタグ付けするか?この記事のすべてのスコアについて、1つの注意点を念頭に置いてください。Geminiのラベルを手作業でチェックした人はいません。そのため、モデルは真実に対してではなく、Geminiに対して採点されています。Geminiが間違っていた場合、モデルは間違いをコピーしたことで正しくマークされ、それを修正したことで間違ってマークされます。

アプローチ

GeminiはOpenRouter経由で、温度0、25分でコメントをラベル付けしました。最も重要だったプロンプトの決定は、文字オフセットをモデルに要求しないことでした。文字のカウントが悪く、スパンが2~3文字ずれて返されます。プロンプトは正確な部分文字列とラベルを要求し、TypeScriptがオフセットを見つけます。文字列がコメントにない場合、エンティティはドロップされ、ログに記録されます。

// モデルは文字列を返します。コードがオフセットを計算します。
{
  "entities": [
    { "text": "Benchmade", "label": "knife brand" },
    { "text": "940", "label": "knife model" },
    { "text": "S30V", "label": "knife steel" }
  ]
}

製品名には、一般的なトークナイザーが分割してしまう多くの句読点が含まれているため、正規表現を使用してVG-10、CPM-154、1.4116をそのまま保持し、それ以外の空白以外の文字を個別のトークンとして出力します。それでもトークン境界を逃すスパンは、推測するのではなくドロップされます。トレーニングセットの約30%は、(gyuto、carbon、handle、patina)のような既知の誤検出トリガーが含まれており、製品は含まれていないコメントで、空としてラベル付けされています。2回目の実行の前に、225件のコメントを検証セットとして確保し、それ以降は一切触りませんでした。トレーニングは、Modal上のTesla T4でHF Trainerを使用して実行されました。

per_device_train_batch_size = 2
gradient_accumulation_steps = 8
learning_rate = 1e-5
threshold = 0.45

モデルがトレーニングした内容
4,290件のフォーラムコメントをLLMが9ドルでアノテーションしたもの
1,575件のポジティブ(69.6%)
675件のネガティブ
2,250件のトレーニング例
2,029件のトレーニング
225件の検証/トレーニング分割(検証セットは実行10からロック済み)
3,907件のエンティティスパン
ブランド 1,720件
製品モデル 1,345件
素材仕様 842件
例の約30%は意図的にエンティティを全く含んでいません。

何がうまくいかなかったか

5回の実行では、モデルは何も学習しませんでした。最初の3回は設定で失敗し、GLiNERでHF Trainerを使用する人は誰でも午後には遭遇するでしょう。

実行何がうまくいかなかったか修正
1GLiNERのデフォルト max_steps=10000 が num_train_epochs=3 を上書きした; 39エポック学習したmax_steps を明示的に設定
2load_best_model_at_end が eval_strategy なしで例外をスローしたeval_strategy を "steps" に設定
3Trainerが "model." プレフィックスなしでstate-dictキーを保存した。GLiNERのローダーはそれを期待している保存時にプレフィックスを戻す
4ネガティブ例で ner_labels が欠落していたすべての例にラベルリストを設定
4–5words_mask がバイナリで構築された; ロスが70–130でフラットになった増分単語インデックスを出力する

実行4と5は高価なものでした。GLiNERの tokenize_inputs は壊れたReddit絵文字でクラッシュしたため、パッチを当てました。そのパッチは words_mask というテンソルを埋める必要があります。これは attention_mask の隣にあり、同じ形状を持ち、私がこれまでに構築したすべての attention_mask は、実際のトークンに対して1、パディングに対して0です。私はそのように構築しました。名前や形状からは、それがアテンションマスク以外の何物でもないということは何も示唆されていませんでした。

トレーニングは完了まで実行されました。ロスは130前後で始まり、約70に低下し、そこに留まりました。クラッシュも警告もNaNもなく、通常のサイズの勾配、スケジュール通りのチェックポイント保存、ほぼゼロの評価F1でした。最初にラベルリストを疑いました。なぜなら、実行4でもラベルが設定されていないネガティブがあったからです。それを修正して再実行したところ、同じフラットなロスが得られました。実行5で唯一間違っていたのは words_mask で、私がこれまでに見たことのないテンソルでした。

10回のトレーニング実行
最初の5回は実用的なモデルを生成しませんでした — すべて配管、モデリングなし
0.0 0.2 0.4 0.6 0.8 1.0
失敗
本番で最も良いF1を記録
✕ R1 ステップキャップ
✕ R2 設定
✕ R3 チェックポイント
✕ R4 単語マスク
✕ R5 単語マスク
スコアなし
R6 初めて成功 0.800
R7 チューニング 209M 0.879
R8 459M 0.799
R9 ネガティブ多すぎ 0.832
R10 検証セットロック
実行1~5は完全に失敗しました。破線は、単語マスク修正後の全体的なF1を示しています。

どうやって修正したか

ドキュメントではなく、GLiNERのトレーニングループを読みました。words_mask はマスクではありません。それは単語インデックスです:特殊トークン、プロンプトトークン、パディングトークンは0、そして実際の各単語の最初のサブトークンは1、2、3となります。スパンスコアリングヘッドは、これを使用してサブトークンを単語にプールします。1で埋めると、コメント全体が1つの単語であるとみなされ、モデルはその巨大なトークン内でブランドや素材のスパンを見つけるように求められます。それは不可能なので、ロスはフラットなままで、どの入力が間違っているかはわかりません。

# 私が書いたもの           # GLiNERが期待するもの
words_mask = [1,1,1,1,1]  words_mask = [0,1,2,2,3]
                          #  [CLS] Mazaki wh ##ite #2

インデックスを修正すると、実行6は最初の試みで学習しました。残りはロックされたセットに対するチューニングでした。209Mの中規模モデルは0.800に達しました。459Mの大規模モデル(T4にはグラデーション累積が必要)は0.83に達しました。10倍の敵対的ネガティブ(51件ではなく510件)はF1を0.799に低下させたため、実行10は51件に戻りました。クラスごとの閾値(グローバルカットオフではなく)により、MagnaCut、S35VN、HAP40のような鋼材名はブランドよりも低い信頼度でスコアリングされるため、素材の再現率が0.787から0.911に向上しました。すべての大規模実行はエポック2で底を打ち、それ以降は過学習します。2,000件の例では、それはデータセットサイズの問題であり、早期停止が解決策です。

エンティティクラスごとのF1
ゼロショットベースライン vs ファインチューニング済みチェックポイント、同じホールドアウトデータ
ゼロショット(推定)
ファインチューニング済み 209M
ファインチューニング済み 459M
0.0 0.2 0.4 0.6 0.8 1.0
約0.65
0.800
0.879
全体
n/a
0.858
0.904
ブランド
n/a
0.775
0.877
製品
n/a
0.712
0.829
仕様
より大きなエンコーダーは、語彙が完全にドメイン固有である場合に最も役立ちます。

学んだこと

うまくいきました。モデルはローカルで実行され、見たことのないコメントに対して0.83 F1でGeminiのラベルに一致し、「carbon steel」は鋼材ではなくカテゴリであり、「PM2」は時にはSpyderco Paramilitary 2を意味し、時には単なる文字であることを認識しています。以前の実行では、ランダムな分割で0.879を記録しました。それを結果としてカウントしません。ランダムな分割では、私の変更のせいにしていたF1の2回の低下は、検証セットにどのコメントが配置されたかに起因することが判明しました。

理論上、プロジェクトのコストはランチよりも安かったです。ラベルに9ドル、GPUに2.50ドル。私にコストがかかったのは、コードはすべてチェックを通過したにもかかわらず間違っていたテンソルに費やした数日間です。私は、小規模なファインチューニングジョブでは、失われた日数が通常のケースだと考えています。モデルとデータが問題であることはめったになく、それらの間のコードが失敗し、間違った入力テンソルからのフラットなロスは、難しいデータからのフラットなロスと同じように見えます。より良いラベルセットと、私が手作業で構築するすべてのテンソルに対するアサーションのどちらかを選ばなければならないとしたら、アサーションを選びます。

このモデルはNew Knife Dayを動かしており、Redditのユーザーがどのナイフを購入し、議論しているかを追跡しています。ナイフ関連の詳しい記事はそちらにあります。モデルカード、トレーニングスクリプト、2,250件のラベル付きコメントはHugging Faceにあり、以下にリンクされています。

一目でわかる

問題

Redditコメントからブランド、モデル、素材の名前を見つけ、それらの周りの一般的な単語をスキップする。コメントごとにLLMに支払うことなく。

アプローチ

Geminiに一度コメントをラベル付けさせ、そのラベルでGLiNER large v2.5(DeBERTa-v3-largeエンコーダー)をファインチューニングし、ローカルで実行する。

結果

トレーニング前に固定された225件のコメントの検証セットで0.83 F1。クラスごとの閾値で素材の再現率0.911。

コスト

Geminiラベルに9ドル、10回の実行全体でT4時間約2.50ドル。

スタック

スクレイパーとラベルにはTypeScriptとMongoDB、ModalでのトレーニングにはPythonとPyTorch、モデル提供にはFastAPI。