Home 論文解説: Self-Consistency Improves Chain of Thought Reasoning in Language Models
投稿
キャンセル

📄 論文解説: Self-Consistency Improves Chain of Thought Reasoning in Language Models

論文概要(Abstract)

Self-Consistencyは、Chain-of-Thought(CoT)Promptingの精度を大幅に向上させるデコーディング戦略です。Wang et al.(2022, Google Brain)は、従来のGreedyデコーディングに代えて、複数の推論パスをサンプリングし、最も一貫性の高い回答を多数決で選択する手法を提案しました。GSM8Kで+17.9%、SVAMPで+11.0%、AQuAで+12.2%の改善を達成し、ICLR 2023に採択されています。

この記事は Zenn記事: 2026年版プロンプトテクニック大全:8手法の使い分けとコンテキスト設計 の深掘りです。

情報源

  • arXiv ID: 2203.11171
  • URL: https://arxiv.org/abs/2203.11171
  • 著者: Xuezhi Wang, Jason Wei, Dale Schuurmans, Quoc Le, Ed Chi et al.(Google Brain)
  • 発表年: 2022(ICLR 2023採択)
  • 分野: cs.CL, cs.AI

背景と動機(Background & Motivation)

Chain-of-Thought(CoT)Promptingは、LLMに中間推論ステップを生成させることで推論精度を向上させる画期的な手法でした。しかし、CoTにはGreedyデコーディング(temperature=0で最も確率の高いトークンを逐次選択)を使用するという制約がありました。

人間の推論を考えると、複雑な問題に対して1つの解法だけでなく複数のアプローチで解き、それらの結果が一致すれば正解である確信が高まります。例えば「$23 \times 17$」を暗算するとき、$(20+3) \times 17 = 340 + 51 = 391$ と $23 \times (20-3) = 460 - 69 = 391$ の2通りで計算し、同じ結果になれば安心できます。

Wang et al.はこの直感を形式化し、「複雑な問題には多様な正しい推論パスが存在し、それらは同じ正解に収束する」という仮説のもと、Self-Consistencyデコーディング戦略を提案しました。

主要な貢献(Key Contributions)

  • 貢献1: CoTのGreedyデコーディングを、多様な推論パスのサンプリング+多数決に置き換えるSelf-Consistency手法を提案。追加学習・ファインチューニング不要
  • 貢献2: 算術推論(GSM8K +17.9%)、常識推論(StrategyQA +6.4%)、記号推論(ARC-challenge +3.9%)の全領域で一貫した改善を実証
  • 貢献3: サンプル数と精度の関係を分析し、対数的改善カーブ(初期サンプルほど効果大、40サンプル以降は収穫逓減)を明らかにした

技術的詳細(Technical Details)

Self-Consistencyの数学的定式化

Self-Consistencyは、推論パス上での周辺化として定式化できます。

入力 $x$ に対して、最終回答 $a$ を求める問題を考えます。CoTでは推論チェーン $r$ を経由して回答を生成します。

\[\hat{a} = \arg\max_a \sum_{r \in \mathcal{R}} p(r, a \mid x)\]

ここで、

  • $x$: 入力(問題文)
  • $r$: 推論パス(Chain of Thought)
  • $a$: 最終回答
  • $\mathcal{R}$: サンプリングされた推論パスの集合
  • $p(r, a \mid x)$: モデルが入力 $x$ に対して推論パス $r$ と回答 $a$ を生成する同時確率

実用的には、この周辺化を以下のサンプリング近似で実装します。

\[\hat{a} = \arg\max_a \sum_{i=1}^{N} \mathbb{1}[a_i = a]\]

ここで、

  • $N$: サンプル数
  • $a_i$: $i$番目のサンプルから抽出された回答
  • $\mathbb{1}[\cdot]$: 指示関数(条件が真なら1、偽なら0)

つまり、$N$回のサンプリングで得られた回答の中で最も頻度の高いものを選択します(多数決)。

3ステップのアルゴリズム

Self-Consistencyは以下の3ステップで構成されます。

ステップ1: CoTプロンプトの構築

標準的なCoT Few-shotプロンプトを構築します(Wei et al., 2022と同じ)。

ステップ2: 多様な推論パスのサンプリング

Temperature $T > 0$(論文では$T = 0.7$推奨)でLLMから$N$個の応答をサンプリングします。

\[(r_i, a_i) \sim p(\cdot \mid x; T), \quad i = 1, \ldots, N\]

Temperatureを上げることで、異なる推論パスが生成されます。同じ問題でも「先に掛け算をする」「先に足し算をする」など多様なアプローチが得られます。

ステップ3: 多数決による回答選択

各サンプルから最終回答 $a_i$ を抽出し、最も頻度の高い回答を採用します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from collections import Counter
from openai import OpenAI

def self_consistency(
    question: str,
    exemplars: list[dict[str, str]],
    n_samples: int = 5,
    temperature: float = 0.7,
    model: str = "gpt-4"
) -> tuple[str, float]:
    """Self-Consistency デコーディングの実装

    Args:
        question: 解きたい問題文
        exemplars: CoT例示のリスト
        n_samples: サンプリング回数(5-40推奨)
        temperature: サンプリング温度(0.5-1.0推奨)
        model: 使用するモデルID

    Returns:
        (最も一貫性の高い回答, その回答の割合)
    """
    client = OpenAI()

    # CoTプロンプト構築
    messages = [
        {"role": "system", "content": "問題を段階的に考えて解いてください。"}
    ]
    for ex in exemplars:
        messages.append({"role": "user", "content": ex["question"]})
        messages.append({
            "role": "assistant",
            "content": f"{ex['thought']}\n答えは{ex['answer']}"
        })
    messages.append({"role": "user", "content": question})

    # ステップ2: 複数の推論パスをサンプリング
    answers = []
    for _ in range(n_samples):
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            temperature=temperature,
            max_tokens=512
        )
        raw = response.choices[0].message.content
        answer = extract_answer(raw)
        answers.append(answer)

    # ステップ3: 多数決
    counter = Counter(answers)
    most_common_answer, count = counter.most_common(1)[0]
    consistency_ratio = count / n_samples

    return most_common_answer, consistency_ratio


def extract_answer(response: str) -> str:
    """応答テキストから最終回答を抽出"""
    import re
    patterns = [r"答えは(.+?)。", r"The answer is (.+?)\."]
    for pattern in patterns:
        match = re.search(pattern, response)
        if match:
            return match.group(1).strip()
    numbers = re.findall(r"-?\d+\.?\d*", response)
    return numbers[-1] if numbers else response.strip()

サンプル数と精度の関係

論文で報告されたサンプル数$N$と精度の関係は対数的改善カーブを示します。

サンプル数 $N$GSM8K精度 (PaLM 540B)CoT単体との差
1(CoT単体)56.5%baseline
568.2%+11.7%
1071.0%+14.5%
2073.5%+17.0%
4074.4%+17.9%

$N=5$で改善の約65%を獲得できるため、コスト効率を考えると$N=5$が実用的な選択です。$N=40$までスケールすると精度は最大化しますが、コストは40倍になります。

重み付き多数決(拡張手法)

論文では単純多数決を使用していますが、各サンプルのログ確率を重みとして使用する拡張も可能です。

\[\hat{a} = \arg\max_a \sum_{i=1}^{N} w_i \cdot \mathbb{1}[a_i = a]\]

ここで $w_i = \exp(\log p(r_i, a_i \mid x))$ は $i$番目のサンプルのモデル信頼度です。ただし論文では、単純多数決と重み付き多数決の性能差は小さいと報告されています。

実装のポイント(Implementation)

ハイパーパラメータのチューニング

  1. サンプル数 $N$: コスト・精度トレードオフで決定。$N=5$がコスト効率最良。高精度が必要なら$N=10-20$
  2. Temperature $T$: $T=0.5-1.0$の範囲。$T=0.7$が多くのタスクで安定。$T$が高すぎると無関係な推論パスが増加
  3. 回答抽出: 最終回答を正確に抽出する正規表現パターンが重要。抽出失敗は精度低下に直結

並列化による高速化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import asyncio
from openai import AsyncOpenAI

async def self_consistency_async(
    question: str,
    exemplars: list[dict[str, str]],
    n_samples: int = 5,
    temperature: float = 0.7,
    model: str = "gpt-4"
) -> tuple[str, float]:
    """非同期並列版Self-Consistency

    全サンプルを並列にリクエストすることで
    レイテンシをO(N)からO(1)に改善
    """
    client = AsyncOpenAI()

    messages = build_cot_messages(question, exemplars)

    # 全サンプルを並列リクエスト
    tasks = [
        client.chat.completions.create(
            model=model,
            messages=messages,
            temperature=temperature,
            max_tokens=512
        )
        for _ in range(n_samples)
    ]
    responses = await asyncio.gather(*tasks)

    # 回答抽出と多数決
    answers = [extract_answer(r.choices[0].message.content) for r in responses]
    counter = Counter(answers)
    best_answer, count = counter.most_common(1)[0]

    return best_answer, count / n_samples

よくあるバグ・落とし穴

  • Temperature=0の誤り: Self-Consistencyの効果はサンプルの多様性に依存。$T=0$では全サンプルが同一になり、多数決が無意味になる
  • 回答の正規化不足: 「11」と「11個」と「11.0」を別回答としてカウントすると精度が低下。数値正規化が必須
  • コスト見積もりの甘さ: $N=5$でAPIコストは5倍。大量のリクエストがあるプロダクション環境では予算超過のリスク
  • 連続値タスクへの不適合: 回帰問題(価格予測等)では回答が一致しにくく、多数決が機能しない。閾値ベースのビニングが必要

Production Deployment Guide

AWS実装パターン(コスト最適化重視)

Self-Consistencyは$N$倍のAPIコール増加を伴うため、コスト管理が特に重要です。

トラフィック量別の推奨構成:

規模月間リクエスト推奨構成月額コスト主要サービス
Small~3,000 (100/日)Serverless$100-400Lambda + Bedrock + DynamoDB
Medium~30,000 (1,000/日)Hybrid$1,000-3,000Lambda + ECS Fargate + ElastiCache
Large300,000+ (10,000/日)Container$8,000-20,000EKS + Karpenter + EC2 Spot

※ Self-Consistency ($N=5$) のため、標準CoTの約5倍のBedrock利用料

コスト削減テクニック:

  • Prompt Caching: CoT例示部分をキャッシュ(全$N$サンプルで共有、30-90%削減)
  • 適応的サンプル数: 一致率が高い場合は早期終了(例: 3/3一致で残り2サンプル省略)
  • 結果キャッシュ: 同一入力の結果をDynamoDBに保存(TTL: 24時間)
  • モデル選択: 簡単なタスクはHaiku($0.25/MTok)、複雑なタスクのみSonnet($3/MTok)

コスト試算の注意事項: 上記は2026年2月時点のAWS ap-northeast-1(東京)リージョン料金に基づく概算値です。Self-Consistencyのコストはサンプル数$N$に線形比例します。最新料金はAWS料金計算ツールで確認してください。

Terraformインフラコード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
resource "aws_lambda_function" "sc_handler" {
  filename      = "lambda.zip"
  function_name = "self-consistency-handler"
  role          = aws_iam_role.lambda_sc.arn
  handler       = "index.handler"
  runtime       = "python3.12"
  timeout       = 120  # N=5のサンプリングに対応
  memory_size   = 1024
  environment {
    variables = {
      BEDROCK_MODEL_ID    = "anthropic.claude-3-5-haiku-20241022-v1:0"
      SC_SAMPLES          = "5"
      SC_TEMPERATURE      = "0.7"
      DYNAMODB_TABLE      = aws_dynamodb_table.sc_cache.name
      ENABLE_EARLY_EXIT   = "true"
    }
  }
}

resource "aws_dynamodb_table" "sc_cache" {
  name         = "sc-response-cache"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "input_hash"
  attribute { name = "input_hash"; type = "S" }
  ttl { attribute_name = "expire_at"; enabled = true }
}

コスト最適化チェックリスト

  • サンプル数$N$の最適化($N=5$で改善の65%を獲得)
  • 適応的早期終了の実装(一致率が高い場合にサンプル削減)
  • Prompt Cachingで例示部分をキャッシュ
  • 結果キャッシュ(DynamoDB TTL付き)
  • モデルルーティング(タスク難易度に応じたモデル選択)
  • Bedrock Batch API(非リアルタイム処理で50%割引)
  • 並列リクエストでレイテンシ最適化
  • AWS Budgets設定(Self-Consistencyは$N$倍のコスト増加に注意)
  • CloudWatchアラーム(トークン使用量スパイク検知)
  • コスト異常検知(Cost Anomaly Detection有効化)

実験結果(Results)

主要ベンチマーク

ベンチマークCoT単体Self-Consistency ($N=40$)改善幅
GSM8K56.5%74.4%+17.9%
SVAMP79.0%90.0%+11.0%
AQuA35.8%48.0%+12.2%
StrategyQA73.4%79.8%+6.4%
ARC-challenge85.2%89.1%+3.9%

全ベンチマークで一貫した改善が確認されています。特にGSM8K(数学文章題)とAQuA(代数推論)で大幅な改善が見られ、算術推論タスクとの相性の良さを示しています。

他手法との比較

Self-Consistencyの特徴は、追加の学習や外部モデルが不要な点です。

手法GSM8K (PaLM 540B)追加コスト
標準 Few-shot56.5%1x
CoT(Greedy)56.5%1x
CoT + Self-Consistency74.4%Nx(サンプル数倍)
CoT + Verifier(ファインチューニング)~55%学習データ+計算資源

実運用への応用(Practical Applications)

Self-Consistencyは「精度が最重要で、多少のコスト増加が許容される」ケースで特に有効です。

医療分野: 診断支援において、複数の推論パスが同じ診断に収束する場合の信頼度指標として活用。一致率(consistency ratio)が低い場合は「人間の医師にエスカレーション」というルーティングが可能です。

金融・法務: 契約書の条項解釈や規制準拠チェックなど、正確性が法的責任に直結する場面。Self-Consistencyによる一致率が閾値を下回る場合は自動処理を停止し、専門家レビューに回す設計が有効です。

コスト管理の実務判断: $N=5$(コスト5倍)で改善の65%、$N=10$(コスト10倍)で改善の81%を獲得。多くの実務では$N=5$のコスト・精度バランスが最適です。

関連研究(Related Work)

  • Chain-of-Thought Prompting (Wei et al., 2022): Self-Consistencyの基盤手法。Greedyデコーディングで単一の推論パスを生成
  • Universal Self-Consistency (Chen et al., 2023): LLM自身に最も一貫性の高い回答を選択させる拡張。多数決の代わりにLLMの判断を使用
  • Confidence-Based Self-Consistency (Google Research, 2024): 各サンプルの信頼度(ログ確率)を重みとして使用する拡張。単純多数決より高精度

まとめと今後の展望

Self-Consistencyは、CoTの自然な拡張として「精度を上げたいがファインチューニングはしたくない」という実務のニーズに応える手法です。$N=5$程度のサンプリングで大幅な精度向上が得られ、実装も多数決のロジックを追加するだけと比較的容易です。

今後の方向性として、適応的なサンプル数の決定(一致率に基づく早期終了)、信頼度ベースの重み付き投票、そして異なるモデルのアンサンブル(GPT-4とClaude 3.5の回答を統合)といった拡張が期待されます。

参考文献

この投稿は CC BY 4.0 でライセンスされています。

論文解説: Self-RAG — 自己反省トークンによる適応的検索・生成・批評の統合フレームワーク

論文解説: RAGAS — 参照フリーRAGパイプライン自動評価フレームワーク