0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人で GPU 1 台・数日・数ドルで、frontier LLM の精度と Jev の速さを持つ 4B の判定モデルを開発

0
Posted at

はじめに

以前、判断特化 AI「Jev」を契約書のチェックで実測した記事を書きました。

【Jev は業務で使えるのか? 契約書レビューで実測】
https://qiita.com/matu79go/items/375459d17411f9e73607

ここの記事でも検証しましたが、Jev は、選択肢から選ぶ判定を約 0.3 秒で返します。

一方で、答える前に深く考えることはしない(推論はしない)ので、順を追わないと解けない判定(推論が要る判定)では崩れることも判明しました。

GPT や Gemini などの frontier LLM は、深い推論もこなせますが、1 件に数秒かかり、使うたびに料金がかかります。

Jevの速さを保ったまま、Frontierレベルの考えることもできる判定モデルを、個人の開発環境で作れないか。

この問いから作ったのが、4B(40 億パラメータ)のオープンモデル Reflex-1 です。Google の公開モデル Gemma 4 E4B を土台に、個人の開発環境で、数日・数ドルで作りました。

Jev・frontier LLM との比較

frontier LLM
(GPT-5.6 / Gemini 3.8)
Jev
(typesafe/jev-1.13)
Reflex-1
即答の判定 ▲ 精度は高いが 1〜3 秒 ● 同じ精度の水準、0.3 秒 ● 同じ精度の水準、0.1〜0.2 秒
推論が要る判定 ▲ 考えさせれば正確、数秒 × 崩れる ● 約 1 秒(学習した判定)
自社の判定を追加 × できない × できない ● 学習できる
考えた中身の確認 ● 思考の出力を読む × なし ● 潜在の各段を言葉に戻す
画像 ● 対応 × 非対応 ● 1 枚 約 0.2 秒
手元で動くか × クラウドのみ × クラウドのみ ● GPU 1 枚、4bit で 9.8 GB
重みの公開 × 非公開 × 非公開 ● 公開
使うたびの料金 × トークン課金 × 呼び出し課金 ● なし
リクエストの形 ▲ チャット ● Decisions API ● Jev と同じ形

この記事では、次の 3 つを扱います。

  • Jev・frontier LLM との比較結果
  • Colab で動かす手順と、リクエストの形(Jev と同じ形です)
  • 速さの仕組み(即答の判定と、言葉にせずに考える「潜在推論」)

重みとコードは公開しています。

結果: Jev・frontier LLM と比べる

即答の判定: 精度は同じ水準、Jev の約 3 倍速い

問い合わせの振り分けや感情の判定のような「選択肢から 1 つ選ぶ判定」を、公開されている判定のテスト 5 種類で比べました。

モデル 正解率(5 種類の平均) 1 件の待ち時間
GPT-5.6 Sol(reasoning なし) 85.6% 1.24 秒
Gemini 3.8 Flash(reasoning なし) 84.8% 2.28 秒
Jev 83.6% 0.30 秒
Reflex-1 84.2% 0.10 秒

即答の判定の早押し

画像も読める

Jev は文章だけですが、Reflex-1 は画像も判定できます。料理の写真を 10 種類に分けるテストでは、正解率 98.5%(GPT-5.6・Gemini は 98%)で、1 枚 0.2 秒台でした(GPT-5.6・Gemini は 2〜3 秒)。

画像の分類

推論が要る判定: 追加学習すれば、frontier LLM の精度を 0.8 秒で

Jevは深い思考ができないため、推論が必要なタスクは精度があがりません。
それを解決するために、推論の問題もこなせるように改良しました。

下記の問題は、「10 人が順に『前の人は嘘つきだ』『前の人は正直だ』と言っていき、最後の人が正直かどうかを当てる」論理パズル(BIG-Bench Hard の web_of_lies を 10 段に深くしたもの)です。1 人ずつ順に追わないと解けません。同じ 50 問で比べました。

モデル 正解率 1 問の待ち時間
GPT-5.6 Sol(reasoning なし) 46% 約 1.2 秒
Jev 52% 約 0.3 秒
Gemini 3.8 Flash(reasoning あり) 100% 2.7 秒
Reflex-1(この課題を追加学習) 100% 0.8 秒

即答するモデルは、Jev も GPT5.6 Sol(reasoningなし) も当てずっぽうに近い正解率です。reasoning modeの Gemini は全問正解しますが、1 問 2.7 秒かかります。

Reflex-1 は全問正解を 0.8 秒で出しました。

推論の早押し

推論は、課題ごとの追加学習で身につけたものです。学習していない推論は解けません。学習は Latent Reasoning (後ほど詳しく解説します)という手法を用いました。この手法によって深い推論でもJev並みの応答速度がでるようになりました。

Google Colab で動かす

ここからは実際に Reflex-1を動かすための説明に入ります。
Google Colab のノートブックを開いて、上から順に実行するだけで動きます。

ランタイムは L4 か A100 を選んでください(bfloat16 が必要です。無料の T4 は非対応)。初回は 4bit 版の土台モデル(9.3 GB)と、学習済みの課題 3 つ分の部品(1.8 GB)をダウンロードします。

1. サーバーを起動する

Reflex-1 は、Jev と同じ形のリクエストを受け付けるサーバーとして動きます。

!git clone -q https://github.com/matu79go/reflex-1.git
%cd reflex-1
!pip -q install -r requirements.txt
# 4bit に量子化済みの土台モデル(9.3 GB)
BASE = 'matu79go/Reflex-1-4B-bnb-4bit'

import subprocess, time, json, base64, requests
srv = subprocess.Popen(['python', '-m', 'reflex.server', '--base', BASE, '--skills', 'skills.json', '--port', '8097'],
                       stdout=open('server.log', 'w'), stderr=subprocess.STDOUT)
for _ in range(240):
    try:
        if requests.get('http://localhost:8097/health', timeout=2).ok:
            print('ready'); break
    except Exception:
        pass
    time.sleep(5)

def decide(req):
    return requests.post('http://localhost:8097/v1/decisions', json=req, timeout=600).json()

2. 即答の判定: 問い合わせの振り分け

リクエストの形は Jev と同じです。state に判定したい文章、questions に質問と選択肢を書きます。選択肢には短い説明を付けられます。

desks = {'credit_score': 'credit scores or ratings', 'transfer': 'moving money between accounts',
         'lost_card': 'a lost or stolen card', 'none': 'none of these'}
for text in ['I want to know my credit rating', 'send 200 dollars to my savings account',
             'I think someone stole my card', 'what is the weather tomorrow']:
    r = decide({'state': text,
                'questions': {'desk': {'type': 'choice',
                                       'instructions': 'Which desk should handle this inquiry?',
                                       'criteria': desks}}})
    a = r['answers']['desk']
    print(f"{text!r:45} -> {a['choice']:12} ({a['confidence']:.2f}, {r['latency_ms']} ms)")

Colab の L4 で実行した結果です。

'I want to know my credit rating'             -> credit_score (1.00, 982 ms)
'send 200 dollars to my savings account'      -> transfer     (1.00, 281 ms)
'I think someone stole my card'               -> lost_card    (1.00, 262 ms)
'what is the weather tomorrow'                -> none         (1.00, 261 ms)

最初の 1 件は準備の時間を含むので遅く、2 件目からは 0.26 秒前後です。

比較表の 0.10 秒は、開発に使った GX10(NVIDIA GB10)で、即答の判定を vLLM(FP8)で動かしたときの値です。Colab のノートブックは手軽さを優先して、Transformers と 4bit 量子化で動かしているので、そのぶん遅くなります。

応答はこの形です。選択肢ごとの確率も返るので、自信の低いものだけ人に回す、といった使い方ができます。

{
  "answers": {
    "desk": {
      "choice": "credit_score",
      "probs": {"credit_score": 1.0, "transfer": 0.0, "lost_card": 0.0, "none": 0.0},
      "confidence": 1.0
    }
  },
  "mode": "instant",
  "latency_ms": 262
}

3. 画像の判定

image に画像を base64 で渡すだけです(Jev にはない拡張です)。

img = requests.get("https://commons.wikimedia.org/wiki/Special:FilePath/Margherita_pizza_55.jpg?width=640",
                   headers={'User-Agent': 'reflex-1-quickstart'}).content
dishes = {k: '' for k in ['pizza', 'sushi', 'ramen', 'hamburger', 'ice cream', 'steak',
                          'french fries', 'fried rice', 'caesar salad', 'chocolate cake']}
r = decide({'state': 'Classify the dish in the attached photo.',
            'image': base64.b64encode(img).decode(),
            'questions': {'dish': {'type': 'choice', 'instructions': 'Which dish is this?', 'criteria': dishes}}})
print(r['answers']['dish']['choice'], r['answers']['dish']['confidence'], r['latency_ms'], 'ms')
pizza 1.0 510 ms

4. 推論が要る判定と、考えた中身の確認

mode を deep にして、学習済みの課題を skill で指定します。trace を付けると、モデルが内部で考えた各段を言葉に戻して返します。

names = ['Sherrie', 'Vernell', 'Alexis', 'Michaela', 'Delbert', 'Jerry', 'Amberly', 'Crista']
import random
random.seed(1)
parts = [f'{names[0]} tells the truth.']
for prev, cur in zip(names, names[1:]):
    parts.append(f"{cur} says {prev} {random.choice(['lies', 'tells the truth'])}.")
state = 'Question: ' + ' '.join(parts) + f' Does {names[-1]} tell the truth?'

r = decide({'state': state, 'mode': 'deep', 'skill': 'web_of_lies', 'trace': True,
            'questions': {'answer': {'type': 'choice', 'instructions': 'Answer Yes or No.',
                                     'criteria': {'Yes': '', 'No': ''}}}})
print(r['answers']['answer']['choice'], r['latency_ms'], 'ms')
print('\n'.join(r['answers']['answer']['trace']))
No 2166 ms
start -> Sherrie tells the truth
Vernell says Sherrie lies -> Vernell lies
Alexis says Vernell lies -> Alexis tells the truth
Michaela says Alexis tells the truth -> Michaela tells the truth
Delbert says Michaela lies -> Delbert lies
Jerry says Delbert tells the truth -> Jerry lies
Amberly says Jerry tells the truth -> Amberly lies
Crista says Amberly tells the truth -> Crista lies

1 行ごとに推論のステップが表示されます。今回はLaten reasoning(後述します)を使っており、モデルは答える前に言葉を出力しません。Latentの意味ベクトルのみで推論するようにすることで、言葉に比べて数倍の速度で処理をすることが可能になります。

さらに、今回工夫したのは、モデルは答える前に文字を 1 つも出していませんが、各段で誰が正直で誰が嘘つきかを順に追っていたことが、後から読めるように文字で検証できるということです。

つまり、言葉で推論をしないが、検証したいときだけ、各段のベクトルを横から言葉に戻して読めるようにしました。

学習済みの課題は、嘘つきの連鎖(web_of_lies)・真偽式(boolean_expressions)・道順(navigate)の 3 つです。問題文は学習データと同じ書き方(X says Y lies. など)にそろえてください。Colab の L4 では 1 問 2〜3 秒、GX10 では 0.8 秒でした。

5. 文章で答える

type を text にすると、短い文章で理由を返します(これも Jev にはない拡張です)。

r = decide({'state': 'Comment: You are an absolute clown.',
            'questions': {'why': {'type': 'text',
                                  'instructions': 'In one sentence, is this comment insulting? Why?',
                                  'max_tokens': 60}}})
print(r['answers']['why']['text'])
Yes, this comment is insulting because it directly attacks the recipient's character or behavior using a derogatory term.

リクエストの形のまとめ

項目 Jev Reflex-1
state(判定したい内容) ○ ○
questions の type: choice(instructions・criteria) ○ ○
image(画像) × ○
mode: deep + skill(推論が要る判定) × ○
trace(考えた中身を言葉で) × ○
type: text(文章で答える) × ○

Jev 向けに書いたリクエストは、送り先を変えればそのまま通ります。

速さの仕組み

即答の判定: 1 回の計算で、選択肢の確率を読む

ふつうの LLM は答えを 1 文字ずつ書き出します。Reflex-1 の即答の判定は、文章を書かせません。問題と選択肢を 1 回だけ読ませ、「次に来る単語」の確率のうち、各選択肢の先頭の単語の確率だけを取り出します。

# reflex/model.py より(要点のみ)
first = [tok.encode(name, add_special_tokens=False)[0] for name in options]  # 各選択肢の先頭の単語
out = model(**inputs)                                   # 問題と選択肢を 1 回読むだけ
probs = torch.softmax(out.logits[0, -1, first], -1)     # 選択肢の中だけで確率にする

生成のループがないので、待ち時間は「1 回読む時間」だけです。選択肢の先頭の単語が重なる場合は、A・B・C… の記号で答えさせて元の選択肢に戻します。

推論が要る判定: 言葉にせずに考えるLatent Reasoning (潜在学習)

reasoning ありの LLM は、考える過程を文章として書き出してから答えます。考えるほど書く量が増え、そのぶん遅くなります。

Reflex-1 は、考える過程を文字にしません。

文字に出さないで思考の連鎖(Chain Of Thought)をするこの手法を、Laten reasoning (潜在学習)と呼びます。

具体的には下記のステップを踏みます。

  1. 問題を読んだ後、モデルの最後の層の出力(ベクトル)を、文字にせずにそのまま入力に戻す
  2. これを「1 段」として、必要な段数だけ繰り返す(嘘つきの連鎖なら 1 人 1 段)
  3. 最後に答えの選択肢の確率を読む
# reflex/model.py の deep() の流れ(要点のみ)
out = model(input_ids=prompt)                  # 問題を読む
h = out.last_hidden_state[:, -1:]              # 最後の層の出力
for _ in range(steps):                         # 1 人 1 段
    e = proj(h)                                # 出力を入力の形に戻す小さな部品
    out = model(inputs_embeds=e, past_key_values=out.past_key_values)
    h = out.last_hidden_state                  # 文字にせず、次の段へ
answer = read_option_probs(out)                # 最後に答えの確率だけ読む

1 段は、文字を何十個も書き出す代わりに、モデルを 1 回通すだけです。これが 0.8 秒の理由です。

こうすることで、推論が必要な問題もJev並みの素早い速度でこなすことが可能になります。

考えた中身を読めるようにする学習

文字にせず考えると、中身が見えなくなるという欠点があります。

Reflex-1 では、学習のときに「各段の出力を、モデルが元から持っている言葉の出口(LM head)に通すと、その段で考えるべき 1 行(例: Vernell says Sherrie lies -> Vernell lies)になる」ように学習させています。

そのため、推論のときも各段を同じ出口に通すだけで、考えた中身を言葉として取り出せます。先ほどの trace の出力がそれです。

これによって、どのように推論したのかを言葉で検証できるようになり、セキュリティ面でも検証可能なAIモデルとして活用できます。

追加学習の中身

課題ごとに、次の 2 つを学習させています。土台の Gemma 4 E4B の重みは変えません。

  • LoRA: 土台モデルに差し込む小さな追加の重み
  • 潜在推論用の小さな部品: 出力を入力の形に戻す部品と、各段の位置を示す部品

1 つの課題の学習は、GPU 1 枚で 1.4〜2.2 時間でした。学習済みの部品は、課題ごとに約 610 MB で Hugging Face に置いています。

開発環境とかかった費用

項目 内容
PC ASUS Ascent GX10 × 1 台(NVIDIA GB10、CPU と GPU の共有統合メモリ 128 GB)
土台のモデル Google Gemma 4 E4B(Apache 2.0)
開発期間 4日(比較の計測を含む)
費用 比較用の API 代(Jev・GPT-5.6・Gemini 3.8)合計 約 2.5 ドル。学習にクラウドは使っていない
動かすのに必要なメモリ 4bit で 9.8 GB / 16bit(量子化なし)で約 16 GB

まとめ

技術的観点

  • 即答の判定では、frontier LLM・Jev と同じ精度の水準で、0.10 秒で答えました(Jev の約 3 倍、GPT-5.6 の約 12 倍速い)。
  • 推論が要る判定では、課題ごとに追加学習すれば、frontier LLM と同じ全問正解を 0.8 秒で出せました。ただし学習していない推論は解けず、難しい課題では frontier LLM が上回ります。
  • リクエストは Jev と同じ形で、画像・推論・考えた中身の確認・文章での回答を足しています。

冒頭の比較表のとおり、Jev・frontier LLM にない「自社の判定の追加」「手元で動く」「使うたびの料金なし」を 1 つのモデルで満たしています。

ビジネスの観点

一般的な判定なら、Reflex-1 は Jev の速さと frontier LLM の精度を両立できます。
ただ、業務 AI で効果を発揮する大きな特徴(Jevやfrontier モデルにない)を持ちます。

自社のルールを追加学習させて、自社特有の判定も同じ速さと精度で回せることが、Jev にも frontier LLM にもない点です。

業務の判定の多くは、自社のルールや業務フローで決まることが一般的です。
請求書と発注書の突き合わせ(突合処理)、承認経路の判定、社内規程どおりかの確認などです。

重みが公開されていない Jev や frontier LLM では、こうした自社の判定を学習させることはできず、プロンプトで長く説明し、考えさせるしかありません。結果的に、処理が遅く成ったり、使うたびの費用も積み上がります。

Reflex-1 なら、自社の判定を学習させたモデルを自社の GPU で持てます。

  • 使うたびの料金がかからない
  • データが社外に出ない
  • 自社の判定を学習させられる
  • 同じ速さで、何万件でも回せる

推論を長くしてトークンを大量に使い、コストと成果が見合わなくなる今の問題に対する、一つの答えになると考えています。

長くなりましたが、個人の開発環境でも、判定という土俵に絞れば、frontier LLM の精度と Jev の速さに届くことが証明されました。

Colab で数分で試せるので、ぜひ動かしてみてください。

このプロジェクトについて

現在の AI は、大手テックが膨大な資本力で、より大きなモデルを作る競争になっており、AI を作る力も使う力も、一部の大手に集まっていきます。

私は、AI を大手の資本力に独占させるのではなく、小さな資本や個人レベルでも考えて作れるものにしたいと考えています。

その先に目指しているのは、それぞれの企業が、自社の KPI や目的に合った効率の良いモデルを自分で作り、自分で運用することです。

汎用の巨大なモデルを使うたびに料金を払い続けるのではなく、自社のルールを学習させたAIを自社で持つ、ということです。

Microsoft のサティア・ナデラ CEO も、2026 年 1 月の世界経済フォーラム(ダボス会議)で、「世界には企業の数と同じだけのモデルがあるべきだ」と述べています。

そして、企業の暗黙知を自社で管理するモデルの重みに埋め込めなければ、企業の価値はどこかのモデル会社に流れ出ていく、とも語っています。

このプロジェクトは、この考えを実現するための個人プロジェクトです。Reflex-1 は、その一端として開発しました。

GPU 1 台、数日、数ドルでも、土俵を選べば frontier LLMやJev と同じ精度と速さのものが開発できる。さらに、できたモデルは独自の学習ができる。Reflex-1 が、それを実現できるきっかけになればよいと考えています。

参考

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?