kaedeasset記事 · Notes霧走町 流氷に眠る

答えるか、聞き返すか、黙るか。採用線 0.33 と聞き返し 0.27

Answer, ask back, or stay silent: an accept line of 0.33 and an ask-back line of 0.27

 D08-4-T16-reject-option・技術・日本語入力でプレイする仕組み

入力を解いて返すclassification with a reject optionselective classification (selective prediction)risk-coverage trade-offconformal predictionk-NN OOD detection (deep nearest neighbors)claude自然言語処理

港で佐伯に「船の調子はどうだ」と入力すると、佐伯は「……事件の夜の居場所か? それとも別の話か」と聞き返します。
いちばん近い意図の点が 0.311 で、答える線 0.33 には届かず、聞き返す線 0.27 は超えたからです。
この回は、答えないという判断を、点数のどこで、どの順で決めているかを書きます。

前の回(T15)で、入力をいまの場面で有効な意図の中のどれかに当てるところまで書きました。
当てたら必ず答える、という作りにすると、どの意図でもない入力にも何かを答えてしまいます。
そこで、答えない選択肢を持たせます。

この回の位置と、前後の回#

区切り: T03〜T24 日本語入力を解いて返すまで(22 回のうち 14 回目)
先に読むとよい回: T08(二つの点を混ぜる)・T15(意図の分類)
次に読む回: T17(通じなかった会話を戻す)

名前 — classification with a reject option#

正式名
classification with a reject option(棄却つき分類)
関連
selective classification(selective prediction・選択的予測)、risk–coverage trade-off、conformal prediction(使っていない)
略称
なし
日本語
棄却つき分類、リジェクト付き分類、選択的分類
初出・代表
棄却の最適な規則は Chow, "On Optimum Recognition Error and Reject Tradeoff"(IEEE Transactions on Information Theory 16(1), 1970)。選択的分類の理論は El-Yaniv & Wiener, "On the Foundations of Noise-free Selective Classification"(JMLR 11, 2010)。conformal prediction は Vovk, Gammerman & Shafer, "Algorithmic Learning in a Random World"(Springer, 2005)

棄却つき分類とは#

棄却つき分類(classification with a reject option)とは、分類器に「どれでもない」「答えない」という出力を足す考え方です。
パターン認識の分野で、読めない字を無理に読まずに人へ回す、という使い方が典型です。

Chow の規則は、事後確率で書くと簡単です。

最も確からしいクラスの事後確率 max_k P(k | x) が 1 − t 未満なら棄却する

t は、棄却するコストと誤るコストの比で決まります。
誤りの率と棄却の率は、この線の上で交換の関係にあり、線を上げれば誤りが減って棄却が増えます。
事後確率が正しければ、この規則が誤りと棄却の組み合わせとして最適になります。

選択的分類は、同じことを二つの関数の組で書きます。

(f, g) f(x) はどのクラスか、g(x) は答えるか(0 か 1)

g が 1 を返す割合を coverage(被覆率)、答えた分の中での誤り率を selective risk と呼びます。
coverage を下げるほど、答えた分の精度は上がります。
この関係を描いたのが risk–coverage curve です。
深層学習では、softmax の最大値を g の点に使う方法が基準線としてよく使われます。

conformal prediction は、答えの集合に保証をつける方法です。
ラベルつきの校正用の標本を取っておき、そこでの点の分布から閾値を決めると、新しい入力の正解がその集合に入る確率を 1 − α 以上にできます。
仮定は、校正用の標本と本番の入力が交換可能(ふつうは i.i.d.)であることだけです。

よく知られた弱点は三つです。

  • 点が確率になっていない。分類器の点は校正されていないことが多く、Chow の規則の前提が崩れます
  • 分布のずれ。校正したときと違う入力が来ると、閾値の意味が変わります
  • 範囲外の入力に高い点が出る。見たことのない入力でも、どれかのクラスに自信を持ってしまうことがあります

うちの判定は三段#

採るか採らないかの二択ではなく、三段に分けています。

  • 答える(ACCEPT)… 点が採用線以上
  • 聞き返す(F1)… 採用線に届かないが、聞き返しの下限以上
  • 受け流す(F4)… どちらにも届かない。他所でなら答えられる話なら、そちらへ回す(F2)

聞き返しは「はい」で確定、「違う」で取り下げになるので、外しても行き止まりになりません(T17 の回)。
棄却した入力を、捨てずに一問で確かめに行く、という形です。

閾値は全部、作品の thresholds.json にあります。

"accept": 0.27,
"acceptB": 0.33,
"embedWeight": 0.7,
"embedFloor": 0.82,
"confirmFloor": 0.27,
"marginF1": 0.08,
"smalltalkMargin": 0.05,
"deductionMargin": 0.08,
"repeatMargin": 0.3,
"f2Dominance": 0.2,
"normVersion": 1

accept は表層の点だけで照合するときの線、acceptB は埋め込みを混ぜたときの線です。
ふだんは埋め込みを混ぜるので、採用線は 0.33 です。
normVersion が正規化の版と合わないと、読み込みを拒否します(T03 の回)。

順位の点と、判断の点#

選択的分類の f と g に当たるものを、別の量として持っています。
AdvMatcher.hpp の query から写します。

Cd.SmalltalkPenalty = It->bSmalltalk ? Th.smalltalkMargin : 0.0;
Cd.Penalty = Cd.SmalltalkPenalty;
Cd.bSeen = ResolvesToSeenStage(*It);
if (Cd.bSeen) { Cd.RepeatPenalty = std::min(Th.repeatMargin, Cd.Bonus); Cd.Penalty += Cd.RepeatPenalty; }
Cd.Score = Cd.Cos + Cd.Bonus - Cd.Penalty;
…
const double Accept = (WB > 0.0) ? Th.acceptB : Th.accept;
const double Confidence = BestRank + BestPenalty;

雑談の減点と、既に聞いた段の減点は、順位を決めるためだけのものです。
本筋と雑談が競ったら本筋を勝たせたい。けれど、競う相手がいない場面で雑談に答えないのは困る。
そこで、順位は減点込みの点(BestRank)で決め、答えるかどうかは減点を戻した点(Confidence)で決めます。

今日の実測です。

佐伯に「今日は寒いですね」→ 雑談の「天気」。順位の点 0.297、判断の点 0.347

減点込みの 0.297 で比べていたら、採用線 0.33 に届かず、佐伯は黙っていました。
8 月に、雑談の 5 件がこれで答えられずに落ちたので、二つを分けました。
ソースのコメントは、これを selective prediction の g(x) と名前で呼んでいます。

判定の順番#

query の後半を、順に写します(推理の決定の僅差の処理は省きます)。

if (Best && Confidence >= Accept && !bThinDeduction)
{
R.Kind = MatchResult::EKind::Accepted;
…
}
const bool bNearAccept =
Best && Confidence >= Accept - Th.marginF1 && BonusFor(*Best) > 0.0;
const bool bOverFloor =
Best && Th.confirmFloor > 0.0 && Confidence >= Th.confirmFloor;
if (bNearAccept || bOverFloor)
{
R.Kind = MatchResult::EKind::ConfirmF1;
R.bWeakConfirm = !bNearAccept;
…
}
…
const bool bLocalIsWeak = (BestRank < Accept - Th.marginF1);
if (BestAny && bLocalIsWeak && BestAnyScore >= Accept &&
BestAnyScore >= BestRank + Th.f2Dominance)
{
R.Kind = MatchResult::EKind::RedirectF2;
…
}
R.Kind = MatchResult::EKind::None;

  1. 判断の点が採用線以上なら答える。ただし推理の決定で 1 位と 2 位の差が 0.08 未満なら、答えずに「どの決め手のことか」を聞き返す
  2. 採用線から 0.08 以内で、固有名詞が一つでも当たっていれば聞き返す(話題語の裏付けのある聞き返し)
  3. それ以外でも、判断の点が 0.27 以上なら聞き返す(裏付けのない聞き返し。言い方を「……〇〇か? それとも別の話か」に変える)
  4. ここで有効な候補が弱く(採用線 − 0.08 未満)、他所でなら採用線を超え、しかも現地より 0.2 以上強い意図があれば、そちらへ回す
  5. どれでもなければ受け流す

今日の実測を、この順に並べます。

  • 「今日は寒いですね」0.347 → 1 で答える
  • 「船の調子はどうだ」0.311 → 2 は固有名詞が無いので外れ、3 で聞き返す(F1.WEAK)
  • 「検分の結果を教えてください」現地 0.205、他所の「検分の結果」1.150 → 4 で駐在所へ回す。佐伯「そいつは駐在所の話だ。あっちを当たれ。検分の記録は駐在所にある」
  • 「好きな色は何ですか」0.149 → 5 で受け流す。佐伯「……」

境界#

  • 閾値ちょうど。採用も聞き返しも >= で比べるので、ちょうど 0.33 は答え、ちょうど 0.27 は聞き返します。他所へ回すかの「弱い」だけは < です
  • 聞き返しの幅。2 の幅は採用線から marginF1(0.08)なので 0.25 からですが、固有名詞の当たりが条件です。当たりが無ければ 3 の 0.27 からです
  • 候補が無い。有効な意図が一つも無ければ、理由を「有効な意図が 1 件もない」として受け流します
  • 同点。1 位は厳密に大きいときだけ入れ替えるので、同点なら先に読み込んだ意図です(T15 の回)。差 0 は「僅差」に数えます

閾値を振った実測#

thresholds.json は書き換えず、検査の道具の引数で採用線だけを振りました。

開発用の固定ケース golden/dev(176 件。うち「どの意図でもない」が正解のもの 34 件)

採用線 ACC どの意図でもない入力への聞き返し 進行しない応答で受理
0.25 100.0% 0 29
0.29 100.0% 1 25
0.33 100.0% 8 18
0.37 100.0% 10 16
0.41 99.4% 11 15

取り違えの検査 probe-critical(244 件)

採用線 1 手で正解(ACC) 聞き返しに「はい」で届く分を足す(REACH)
0.25 92.6% 93.0%
0.29 90.6% 92.2%
0.33 88.9% 92.2%
0.37 82.4% 92.2%
0.41 79.9% 92.2%

採用線を上げると、1 手で答える分は減り、その分が聞き返しに移って、「はい」まで含めれば届く分は 92.2% で変わりません。
これが、三段にした理由をそのまま数字にしたものです。
棄却した分を聞き返しで拾うので、線の位置の損が小さい。

聞き返しの下限も振りました(採用線は 0.33 のまま)。
probe-critical の REACH は、下限 0(無効)で 88.9%、0.20 で 93.4%、0.27 で 92.2%、0.33 で 88.9%。
その代わり、どの意図でもない入力への聞き返し(golden/dev)は 0.20 で 15 件、0.27 で 8 件、0.33 で 0 件です。
0.27 は、この二つの間で手で決めた値です。

名前どおりでない所 — classification with a reject option#

classification with a reject option の、校正していない形です。

  • 点は確率ではありません。表層と埋め込みを混ぜた近さに、固有名詞の加点を足した量です。Chow の規則の前提(正しい事後確率)はありません
  • 閾値は手で決めた固定値です。校正していないので、取りこぼしの率の保証はありません
  • 棄却が二段(聞き返す・受け流す)と、回す(他所へ)に分かれています
  • 他所へ回すかの「現地が弱い」だけ、減点込みの点で見ています。ソースのコメントにも、この非対称は挙動を変えないために残している、と書いてあります

もう一つ、正直に書きます。
golden/dev は、採用線を 0.10 まで下げても、取り違え(どの意図でもない入力で進行してしまう)が 0 件のままでした。
数え方が「進行する段が受理されたら誤り」で、雑談として受理された分は誤りに数えないからです。
0.10 では、どの意図でもない 34 件が全部、何かの雑談として受理されていました。
進行の取り違えを防いでいるのは閾値ではなく、段の材料と主張の条件です(T19・T20 の回)。
閾値が決めているのは、返事が問いに合っているか、という体験の方です。
今日も、佐伯に場違いな問いをして、関係の薄い段に受理された例を見ています(T15 の回の「朝食」)。

2022 年の名前で言い直す — k-NN OOD detection#

うちの「いちばん近い言い換えまでの近さに線を引く」形には、2022 年に付いた名前があります。
Sun, Ming, Zhu & Li, "Out-of-Distribution Detection with Deep Nearest Neighbors"(ICML 2022, PMLR 162, pp. 20827–20840)。
この回は Chow 1970 の棄却つき分類で書きましたが、名前のある技術を調べ直したときに見つけ、論文を読んだので、この名前でも言い直しておきます。

論文の方法は 4 行で書けます。

  1. 学習データを、ニューラルネットの最後の手前の層の特徴 φ(x) にして、L2 正規化する: z = φ(x) / ‖φ(x)‖₂
  2. 新しい入力 z* について、学習データ全部とのユークリッド距離 ‖z_i − z*‖₂ を測り、近い順に並べる
  3. k 番目に近いものまでの距離 r_k(z*) = ‖z* − z_(k)‖₂ を取る
  4. 判定は 1{ −r_k(z*) ≥ λ }。近ければ分布内(答えてよい)、遠ければ分布外

閾値 λ は、分布内のデータの高い割合(論文の例では 95%)が分布内と判定されるように、分布内のデータだけで決めます。
分布外のデータは閾値の決定に使いません(論文の言い方では OOD-agnostic)。
論文が挙げる利点は 4 つです。
分布の形を仮定しない(Mahalanobis 距離はクラスごとのガウス分布を仮定する。論文は埋め込みが正規性の検定に落ちることを確かめています)、分布外のデータを要らない、実装が簡単、モデルを選ばない。

実験で効いた所は、こちらに直接関係します。

  • 特徴の L2 正規化が決定的で、正規化なしに比べて FPR95(分布内の 95% を通す線での誤受理率)を 61.05% 改善した
  • k は CIFAR-10 で 50、CIFAR-100 で 200、ImageNet で 1,000 を、検証で選んだ
  • 学習データを 1% に間引くと最適な k は 10 になり、性能は全データとほぼ同じだった(ImageNet の平均 FPR95 が 38.47 → 39.18)
  • k が 1,000 未満なら推論の速さはほとんど変わらない

理論の節では、k 番目までの距離を密度の推定と見て、Huber の汚染モデル P = εP_out + (1 − ε)P_in の下で、この判定が推定されたベイズの二値判定と一致することを示しています(Theorem 6.1)。

うちに当てはめると、こうなります。

  • 学習データ=言い換え 2,845 文。特徴=multilingual-e5-small の 384 次元を L2 正規化したもの(T05)。正規化が決定的という論文の結果と、うちがコサインで比べている事実は、同じことを言っています。正規化した特徴のユークリッド距離はコサインの単調な関数で(‖u − v‖² = 2 − 2cos)、近い順の並びは一致します
  • k=1。意図ごとにいちばん近い言い換えを取り、全体でいちばん近いものを線と比べるので、論文の k=1 の形です。論文は 1% に間引くと最適な k が 10 になると報告していて、うちの 2,845 文は論文の 1%(1 万 3 千枚弱)よりさらに小さいので、k が小さいのは筋が通っています。ただし k=1 は外れ値に最も弱い設定で、言い換えが 1 本おかしな所にあると、そこだけ分布内が広がります。これは L18(T43)と golden(T38)で外から見張っています
  • 閾値。論文は分布内の 95% が通るように決めますが、うちは手で置いた 0.33 と 0.27 です。golden/dev 176 件で測ると 0.33 は正解の 100% が通る点なので、論文の流儀で言えば TPR 100% の点です。違いは向きで、論文は「分布内のデータから λ を決める」、うちは「決めた後で分布内の通り率を測る」です
  • 距離が一つではない。うちの点は埋め込みの近さだけでなく、表層の近さと固有名詞の加点を混ぜた量(T08・T10)なので、論文の r_k と一対一には対応しません。純粋な k-NN OOD は、埋め込みだけで線を引く形です
  • 棄却が三段。論文の判定は分布内か外かの二値で、うちはその間に「聞き返す」の帯があります(λ が 2 本)

名前の対応として書くと、classification with a reject option(Chow 1970)は「答えない出力を持つ」という考え方の名前、k-NN OOD detection(Sun ほか 2022)は「最近傍までの距離で線を引く」という方法の名前です。
うちは、考え方は前者、方法は後者の k=1 の形、閾値の決め方はどちらでもない手置き、になります。

弱点と、採らなかった案 — classification with a reject option#

conformal prediction で校正する案は、採っていません。
校正には、本番と同じ分布のラベルつきの標本が要ります。
うちの検査ケースは作者と開発の AI が書いたもので、プレイヤーの実際の入力の分布ではありません。
保証の前提が無いまま式だけ当てても、保証は付きません。
2026-08-18 に、この理由でやらないと決め、閾値は据え置きが正しいと測って確かめました。

ほかの案です。

  • 順位だけで融合する RRF に替える。順位には点の大きさが無いので、聞き返しの帯が消えます(T09 の回で、実装して測り、負けました)
  • 場面ごとに閾値を変える。閾値の数が増えるほど、どの値が効いたのか分からなくなります
  • 答える線を高くして、聞き返しを増やす。上の表のとおり、届く分は変わらず、1 手で答える分だけが減ります。聞き返しは 1 手かかるので、多すぎると会話が重くなります

答えない判断は、捨てる判断ではなく、確かめに行く判断にする。
そうすると、線を 1 本の正解の値に決めなくても、体験が壊れにくくなります。

検索語#

classification with a reject option
Chow reject rule
selective classification risk-coverage
conformal prediction
KNN OOD detection deep nearest neighbors

佐伯さんに船のことを聞くと、何と聞き返されるか。『霧走町 流氷に眠る』の第一章はブラウザで入力して確かめられます。プロフィールのリンクから。

#claude #自然言語処理