目次
背景
- 分布外データの対処方法や機械学習におけるデータとデータソースの再考では、データそのものの収集・分割・品質管理という観点を扱った
- 分類タスクには、それとは別に「クラス・ラベルそのものをどう設計・管理するか」という固有の問題がある
- クラスの境界をどこに引くか、似ているクラス同士をどう切り分けるか、負例をどう定義するか、ラベルの信頼度をどう管理するかによって、同じデータ量でも学習・評価の質が大きく変わる
- 今回は、このクラス・ラベル設計という観点から再整理する
クラス設計の原則
完全性と無矛盾性
データセットが間違っていれば、モデルも間違える。では、不完全性のない完璧なデータセットは作れるのか。
- 完全性: 不可能。入力空間は無限であり、網羅はできない。現実的なユースケースを定義し、目標とするスコープを絞るしかない
- 無矛盾性: 可能。タクソノミーを定義し、運用でカバーすることで、無矛盾なデータセットを作ることはできる
これはゲーデルの不完全性定理に近い構図で、完全性と無矛盾性の両方を同時に満たすことはできないが、無矛盾性だけであれば設計次第で達成できるという整理になる。ただし、ソリテスパラドックスのように、境界の定義自体には曖昧さが残ることには注意する。
seedとタクソノミーというデータ仮説
- seedとは、データを収録・生成・収集する上で基本となるデータの設計書
- Data-Centric AIの観点では、seedがデータの分解能の基本であり、実験における最も重要な仮説になる
- 人間が対象世界をどの粒度・軸・関係性で分解するかという「データ仮説」を設計することが、知識空間(Knowledge Space)からデータ空間(Data Space)への射影規則を決めることに相当する
- この仮説を先に言語化したものがタクソノミーであり、タクソノミーを先に定義してからデータを集めることで、無矛盾性を担保しやすくなる
- タクソノミーに漏れがあると、学習・評価どちらでもカバーできない領域が生まれ、それがOODの一因にもなる
- ただし、実験計画法の要因実験のように、軸・粒度をすべてマニュアルで組み合わせて定義しようとすると、組み合わせ爆発でパターン数が破綻しやすい
- そのため、全パターンを人手で列挙するのではなく、実データから頻出パターンを抽出してタクソノミーを組み立てる方が現実的
- 例
- 文字レベルで扱う場合は、先にタクソノミーを定義してから分類する
- 音声データの場合は、音声学(Phonetics)のIPA(国際音声記号)をベースにデータの定義を行う
- 難しい課題では、失敗を見越してgrade(難易度)の定義をあらかじめ行う
- クラスが二値分類でも、あえてnegativeを多クラス化し、エラーパターンごとに学習させる
- 難しいクラスにはsubclassを定義してMECEに列挙する
- 精度が上がらないサブクラスには、対となるDyadのpairを作って対照学習する
- これが仮説となり、人によるデータレベルのinductive biasになる
タクソノミーとサブデータセットによる分割統治
- 困難は分割せよ、ではないが、サブデータセットを作って対処するのも有効
- サブデータセットは「grade(難易度)× クラス数」のように定義し、それぞれにタクソノミーとdefinitionを与える
- 大量の矛盾するデータよりも、少量の無矛盾なデータを作るイメージ
- 特に、意味の近いクラス同士を分類するinner-class classificationのようなケースで有効
- 実務上は、gradeでフォルダを切り、クラスでフォルダを切り、その中でさらにタクソノミーを分析してseedを生成するという流れになる
小さな範囲での学習可能性テスト
- データセットが無矛盾かつ完全であれば、gradeの低いものは学習できるはずである
- 最初に作ったseedデータをベースに、データ生成やaugmentationをする前に、素の状態でまずテストするとよい
- 小さく試して、どのgradeまで学習できるかを確認してから拡張する方が安全
- 精度が上がらない原因はモデルの容量や学習データの量ではなく、学習データそのものが矛盾していることも多い
- ただし、小さく多様性のない範囲での実験になるため、そのまま汎化性能を保証するとは言えない
- 基本を確認してから応用を学習させるという考え方
Gradeによる難易度設計
評価用データをgrade別に用意する
- Diag・Challengeのような評価用データは、難易度別に複数用意するとよい
- たとえTrainにデータを追加しても、それが基礎能力に悪影響を及ぼしている可能性もある
- そのため、学校の学年のように6段階程度でgrade別のholdoutデータセットを用意し、評価するとよい
- 「grade1は通っているから、その使い方に限定する」といった逃げ道を作れるようにする意味もある
- 例えば、paraphraseやreasonを付けたもの、否定形を混ぜたものはgradeを1段上げる、といった基準を決めておく
- paraphraseの例: 同義語への置き換え、受動態と能動態の変換、品詞の変更、文の統合・分割
holdoutだけに頼らない
- holdout・heldoutだけでは、学習ができたこと以外の証明にならない
- そのため、difficultケースや、生成プロセスから全く別に作ったデータをベースにした評価も併用するべき
- つまり、複数種類のDiag・Testを用意しておくのがよい
gradeによる精度の精緻化
- 仮にグレードを作っていないと、学習がうまくイカない場合は、低スコアになってしまう
- その場合は使えないモデルを作ったということで、採用されなくなる
- 他方、グレードを作った場合は、GradeXまでは80%で解けるのようにスコアがよく見える
- これは仮にうまくいかなかった時に、逃げ道としてどこまでは行けるかを明示する事ができる
- gradeXで80%までは行けるなら、次のグレードからアンサンブルにしようなどのような考え方も可能
- すなわち、Gradeやスコープは有用ということ
クラスの幾何学的デザイン(Geometric Class Design)
クラスの定義を絞る
- 精度が低いクラスに対して、データ量を増やして曖昧な境界を学習させるのではなく、クラス自体の範囲を狭める方法も有効
- クラスの判定対象を狭め、クラス間の境界が太くなるようにモデルを設計する
- 国土を広げて(データを増やして)国境線の太さ(クラスの境界の太さ)を確保するより、国土自体を小さくして境界を太くするという考え方
- もちろん、モデルの性能自体が原因の場合もある
コアとサーフェス
分類する空間は、大きく2種類に分けて考えられる。
- コア: 意味軸。人間が定義したseedで作成するか、実データをサンプリングして得る
- サーフェス: 表現軸。AIによってseedからaugmentationする(パラフレーズの生成など)
例えば文字ベースの分類では、あるクラスを決定する特徴的な属性を属性1、次点で優位な属性を属性2とし、これらの軸を掛け合わせてタクソノミーを作り、データをsubcat(サブカテゴリー)で分類する。クラス内の特徴を抽出してサンプルを生成するレシピを網羅することで、クラスの幾何学的な領域を設計できるようになる。
inner-classとinter-classでの一貫性
- 意味の近いクラスを分類する場合は、ラベルの矛盾が発生しやすい
- AというクラスとBというクラスのそれぞれのサンプルの中で、教師信号が一貫していないケースがある
- そのため、クラス間で矛盾がないかのチェックが必要
- そうでないと、モデルが安易な結論に陥りやすくなる
境界専用データセットを作る
- クラスの範囲を狭めて境界を太くしても、間違いは起こりうる
- 特に、物理的に意味が近い複数のクラスがある場合、その境界は間違いやすい
- そのため、クラスの際(きわ)専用のデータセットを作るのが有効
- 例えば12クラス分類の場合、2つを選ぶ組み合わせは
- 通りあり、境界の両側にそれぞれデータを用意する必要があるため
- 通りが、原理的には必要な境界クラス用データの数になる
境界データセットのためのクラスの選び方
- 66通りすべてを対象にするのは大変なので、ターゲットを絞った方がよい
- 混同行列から誤爆ランキングを出し、優先度の高い境界を判断する方法がある
- 他の指標との相関を見て判断する方法も考えられるが、同じデータを使った相関係数はトートロジーになるため注意が必要
Hard Caseの作り方
注意点
- 特徴の変化のかけ方によって、有益にも有害にもなるため注意が必要
- 例えば画像系では、特徴の一部を0でマスクして消す手法がよく使われる
- 同じ手法を音のデータに適用すると、うまくいかないことが多い
- 理由は、音の場合はマスクによる不自然さそのものを学習してしまうから
- そのため、単調なマスクだけでなく、ノイズによるマスクなど複数の手法を試す必要がある
shifted positive
- 例えば「太郎」を対象にする場合、最低でも「〜太郎」「〜太郎〜」「太郎〜」の3パターンを作れる
- 時系列的なずらしによってpositiveケースを増やす例で、データのかさ増しにも使える
adversarial negatives
- いわゆるhard negativeの一種
- 例えば「太郎」に対して、音的に似ている「tara」や「soro」のような、一部を変更した特徴量をnegativeとして用意する
- 意図的に似た音のケースを増やす例
Truncated Negative
- Positiveケースの一部を含むデータを、あえてNegativeとして用意する手法
- 例えば「太郎」という名前を分類したい場合、前半の「〜太」と後半の「郎〜」を、それぞれTruncated Negativeとして用意できる
- 全体を学習させたいが、部分だけで安易に分類させたくない場合に有効
- 部分切り出しによってデータ自体も増えるため、かさ増しにも有効
Hidden Negative
- 画像のFine-grained Classificationなどでは、特徴をマスクで隠して学習させる手法が有効とされている
- Hard NegativeをPositiveケースの一部を隠して作る手法
- 特徴的な部分をベースに学習が進んでしまうのを避け、あえて大局的な特徴を隠すことで、局所特徴を学習させる
- こちらもデータのかさ増しに有効
組み合わせ数を数える
- 上記のpositive/negativeのパターンは、特徴量の要素ごとにさらに増やせる
- 例えば「たろう」を対象にHidden Negativeを適用する場合、3文字なので3要素(A・B・C)とすると、正解はABCのみになる
- 計算すると、Hidden Negativeだけでも次のパターンが考えられる
- 2つ選ぶ: AB・AC・BC(3通り)
- 1つ選ぶ: A・B・C(3通り)
- 0個選ぶ: 選ばない(1通り)
- つまり、順番と要素が固定であれば、7パターンのHidden Negativeを作れる
Noneクラス・Negationクラスの設計
Noneクラス(負例クラス)を追加する
- 低い確信度を単純に棄却するだけでなく、明示的なNoneまたはOtherクラスを追加する
- これにより、モデルは既知のpositiveクラスだけでなく、学習時に与えた負例をNoneとして識別できるようになる
- ただし、Noneクラスを追加しても、あらゆる未知入力を識別できるわけではない
- 学習に使用した負例や、それに近いOODには有効だが、まったく異なる未知入力に対して誤って高い確信度を出す可能性は残る
- Noneは全体の負例クラス用のメタクラスであるため、実質的にはNoneの1-Recallこそが本来のFPRになる
- Noneクラスのrecall(Noneを見逃さなかった割合)は、そのまま通常クラスのprecisionに対応する
- つまり、見逃さずに正確に処理できた通常クラスの評価につながる
- Noneクラスの性能が下がれば、当然通常クラスの性能にも影響が出る
既知の弱点をあらかじめ加味する
- 例えばNLPでは、否定表現において精度が下がりやすいという既知の弱点がある
- 特徴が似ているにもかかわらず、クラス領域が外れてしまうことが原因
- こうした既知の弱点については、あらかじめデータセットのバランスを調整して対処できる
Negationの明確化
- 特にnegationが絡む場合に有効な手法
- 例えば、Moveクラスの反対がDon’t MoveなのかStopクラスなのか、AIが迷うケースがある
- その場合は、意味を明確化するために、MoveクラスのスロットにNegationを持たせ、Move(negated=True)のように表現する
- すると、メタクラスであるNone以外の否定表現は、Negationスロットで対応できるようになる
- 結果として「動かない」と「Stop」が同一視されなくなり、精度が上がる
- これはデータセットの無矛盾性とも関連する
ラベルの信頼度: GoldとSilver
データセットのラベルは、どうやって付与されたかによって信頼度が異なる。この信頼度をGold・Silverという段階で区別して管理しておくことも重要。
Gold(ゴールド)ラベル
- 人の手で検証・確認されたラベル
- 品質は高いが、作成コストが高く量を確保しにくい
Silver(シルバー)ラベル
- モデルやルールベース処理などで自動生成されたラベル
- 量は確保しやすいが、ゴールドに比べてノイズが混ざりやすい
段階的なティア管理
- 単純な二値の区分だけでは不十分なことも多く、信頼度をさらに細かい段階に分けて管理すると扱いやすい
- 例: 読みが一意で人手検証済み(gold_verified)、人手検証済みだが本質的に複数の正解がありうる(gold_free_variation)、まだ判断がついていない自動生成ラベル(silver_ambiguous)
- ティアごとに、機械的なクロスチェックを先に流し、意見が割れたものを優先的に人手レビュー(Silver→Goldへの昇格)に回す、という段階的な運用と組み合わせるとよい
- 詳しくはフリガナデータをクレンジングする時に直した項目のメモや分布外データの対処方法でも扱っている
用途による使い分け
- Trainには、SilverをGoldと混ぜて量を確保しつつ使うことが多い。多少のラベルノイズは学習の過程である程度吸収されやすい
- Diag・Testのような、性能を正しく測定するためのデータには、なるべくGoldを使うべき
- ラベル自体にノイズがあると、性能の低さがモデルの問題なのかラベルのノイズなのかを区別できなくなり、機械学習におけるデータとデータソースの再考のデータ品質QAの意味が薄れてしまう
ラベル・属性の管理方法
データセット、特にTrainデータセットを作る際には、サンプルが持つ属性をどう区分・管理するかという問題もある。属性の性質によって、適した管理方法が異なる。
直交する属性: フォルダ管理
- クラス・サブクラス・カテゴリー・ID/OOD・Positive/Negative・Easy/Hardのような属性は、互いに直交する(1サンプルにつき各軸で1つの値だけを持ち、軸同士も独立している)
- こうした属性は、フォルダ階層でそのまま表現できる
| |
- ディレクトリ構造自体がそのままデータの分類を表すため、追加のマスターファイルが無くても直感的に管理できる
- 特にID(In-Distribution)とOOD(Out-of-Distribution)は、機械学習におけるデータとデータソースの再考のDiagで扱う「スコープの境界」を直接反映する軸でもあり、他の軸と同様にきちんと分けて管理しておくことが重要
- 他にも、以下のような軸がフォルダ管理に向いている
- spec/seed(データを生成・収集する前提となる設計書やtaxonomy)
- self/others(自分で作ったデータか、他所のデータか)
- real/generated・third_party(データの出自)
- sampling_weight(学習時のサンプリング重み別)
- case(特定のケース別)
- calibration(確信度キャリブレーション用)
- generalization dataset(いわゆるOOD dataset。汎化性能を客観的に測るために別途用意しておく必要がある)
直交しない属性: Tag.jsonでの管理
- UseCase・FailurePatternのような属性は、クラスのように均等に分布せず、1サンプルが複数の値を同時に持つこともある多対多の関係になる
- こうした属性をフォルダで表現しようとすると、同じサンプルを複数の場所に置く必要が出てきて破綻する
- 代わりに、
Tag.jsonのようなマスターファイルで、サンプルIDとタグの対応表として管理する方がよい
| |
対称的な属性: Pair.jsonでの管理
- Dyad(対)になるような、表現がわずかに違うだけの対応関係を持つサンプルもある
- この対応関係自体が情報を持つため、
pair_idを振り、Pair.jsonのようなマスターファイルでどのサンプル同士が対になっているかを管理する
| |
まとめると
| 属性の性質 | 例 | 管理方法 |
|---|---|---|
| 直交する | クラス・カテゴリー・Positive/Negative・Easy/Hard | フォルダ階層 |
| 直交しない | UseCase・FailurePattern | Tag.json(多対多のマスター管理) |
| 対称的 | Dyad・minimal pair | Pair.json(pair_idによる対応管理) |
具体的なデータセット定義例
多クラス分類の例
- まずdataについて、種となるデータ(seeds)と生成されたデータ(generated)を分ける
data/{seeds, generated}のような形にする- さらに
data/seeds/grade1/class_name/{positive,negative}/subclass_name/{def.md, seed.csv}のように切る - gradeは難易度を表し、grade1からgrade6程度まで定義する
- gradeを定義する理由は、うまくいかなかった時に、どこまでうまくいっているのかを測れるようにするため
- それぞれの$\text{grade} \times \text{class} \times \text{subclass}$について、分割統治法のように解いていくイメージ
| |
二値分類の例
以下は、ある名前を対象にした二値分類のクラス設計の実例。
- グレードをトップで分けるのではなく、まず
real/syntheticというsourceの軸で分ける - その後にgrade分け(難易度分け)をクラスに落とし込み、クラス単位で難易度を教える
- この例では単純な二値分類ではなく、negativeの内訳を細分化して5クラス分類にしている
- 対象クラスのフォルダ以外はすべてnegativeケースになる
- 最後に、サブクラス単位でさらに分割している
| |
まとめ
- 分類クラスの設計には、完全性は目指さず無矛盾性を目指すという原則があり、seedとタクソノミーというデータ仮説、サブデータセットによる分割統治で実現しやすくなる
- 評価用データはgrade別に難易度設計しておくと、基礎能力への悪影響やholdout過信を避けられる
- クラスの範囲を絞り境界を太くするGeometric Class Designや、コア(意味軸)とサーフェス(表現軸)の分離によって、クラスの幾何学的な領域を設計できる
- 特に意味の近いクラス同士は、inner-class・inter-classでの一貫性チェックと、境界専用データセットが有効
- shifted positive・adversarial negatives・Truncated Negative・Hidden Negativeなど、hard caseの作り方には複数の手法があり、組み合わせ数を数えることでデータのかさ増し効果も見積もれる
- NoneクラスやNegationスロットの設計によって、明示的な負例の識別や否定表現の混同を防げる
- ラベルにはGold(人手検証済み、高品質・高コスト)とSilver(自動生成、大量・ノイズあり)の信頼度差があり、Trainは混ぜて量を確保、Diag・Testはなるべく Goldを使うという使い分けが重要
- クラス・属性の管理は、直交する(フォルダ管理)・直交しない(Tag.json)・対称的(Pair.json)という性質ごとに、適した方法を使い分ける
- 実際のフォルダ構成例として、grade×class×subclassの多クラス分類と、source軸を起点にした二値分類の2パターンを示した
