LLMによる分類

LLMなど生成AI(generative AI)の対義語は、識別AI(discriminative AI)、平たく言えば分類器(classifier)である。しかし、LLMも分類器として使えそうである。そこで、ちょっと試してみた。

材料は、私も少しかかわった第7回 中高生情報学研究コンテストポスターを使う。130編のポスターがある。ポスターのPDFをそのまま使うのは難しそうなので、タイトルと説明文だけを使うことにする。

どういう分類にすればいいかは生成AIに相談して、次の2分類にした。

130編を一つのプロンプトに列挙して開発系:分析系に分類させたところ、GPT-4oは83:47、Gemini 2.0 Flashは97:33、Claude 3.7 Sonnetは69:61に分類した(Gemini 2.5はまだ出ていなかった)。ローカルLLMのGemma 3 27Bでは130編まとめては無理だったようで、途中から全部同じ分類になってしまった。

いずれにしても、一つのプロンプトに複数の内容を含めると、一定の基準で分類されない可能性があるので、一つずつ与えて分類させることにした。まずGPT-4o:

from openai import OpenAI
client = OpenAI()

def ai(prompt):
    response = client.responses.create(
        model="gpt-4o",
        max_output_tokens=1024,  # min 16
        temperature=0,
        input=prompt.strip()
    )
    print(response.output_text.strip())

with open("list.txt") as f:
    lines = f.readlines()

for line in lines:
    ai(f"次の記述は、中高生情報学研究コンテストに応募された作品のタイトルと概要です。この作品を、開発系(Web・ロボティクス・処理系など)と分析系(統計・データ分析・機械学習・AI)に分類するとすれば、どちらになるでしょうか? 開発系なら「D」、分析系なら「A」と答えてください。\n\n{line}")

最初DまたはAと答えてもらうつもりで max_output_tokens=16 にしたのだが、いくつかについては「どっちとも考えられるが、強いて言えば…」みたいな長ったらしい回答をして、16トークンでは肝心の答えまでたどりつかなかったので、1024に増やした。これはプロンプトでD、Aどちらか以外は答えるなと指示すべきだった。

結果は78:52で、全部まとめてプロンプトに入れた場合と若干違う。

Gemma 3 27Bでもやってみた:

from ollama import chat

def ai(prompt):
    response = chat(
        model="gemma3:27b-it-q8_0",
        messages=[{ 'role': 'user', 'content': prompt }],
        options={ "temperature": 0, "num_ctx": 2048 }
    )
    return response['message']['content'].strip()

with open("list.txt") as f:
    lines = f.readlines()

for line in lines:
    ans = ai(f"次の記述は、中高生情報学研究コンテストに応募された作品のタイトルと概要です。この作品を、開発系(Web・ロボティクス・処理系など)と分析系(統計・データ分析・機械学習・AI)に分類するとすれば、どちらになるでしょうか? 開発系なら「D」、分析系なら「A」と答えてください。\n\n{line}")
    print(ans)

Gemma 3はすべてDまたはAだけで答えてくれたので集計が簡単であった。結果は95:35である。

この時点で、データ取得時の都合でリストの各行の先頭に0〜129の番号とタブ(\t)が付いていることを思い出し、それをループの先頭で次のように消してから処理してみた。

    line = re.sub(r"^.*?\t", "", line)

内容は同じはずだが、番号を消したところ96:34になった。つまり開発系が一つ増えた、と思ったら、実際には3つ増えて2つ減っていた。けっこう微妙である。

まとめると、生成AIによる分類は、人間による分類と同様に微妙である。どのモデルで処理してもほぼ同じ結果になるような明確なプロンプトが作れればいいのだが、難しそうだ。

いくつか回答例(few-shot prompting)を与えるといいかもしれない:

開発系(D)と分析系(A)に分類してください。



タイトル: ○○○
内容: ○○○
分類: D



タイトル: ○○○
内容: ○○○
分類: A


タイトル: ○○○
内容: ○○○
分類:

さらに、CoT (Chain-of-Thought) prompting の考え方を使って、分類の前に理由を出力させると、さらに正確になるかもしれない。