8bit量子化と浮動小数点の罠——AIモデルの数値を比較・評価するときに見落としがちな2つの構造的な落とし穴
DOI 1.16と DOI 1.21の、 専門知識のない方向けの解説です。
これはこのプロジェクトの4モデルに限った特殊な話ではありません。 普通の8bit画像で学習・適用されているAIモデルは、下で説明する2つの 事実——1つは8bit画像の仕組みについて、もう1つはコンピュータの 演算の仕方について——の上に等しく乗っています。何をすべきかは 分野全体で判断すべき問いであり、私たち自身がここで結論を出そうと しているわけではありませんが、正確な記録として書き留めておく 価値があると考えています。
一言でまとめると:Part 1は「真の値がそもそも有限個しか ない」という話、Part 2は「その真の値が、 コンピュータ自身の浮動小数点演算によって汚染され——誤って 数えられてしまう」という話です。
Part 1:無関係な画像の一部が、なぜ全く同じ数字になるのか(DOI 1.16)
誕生日パラドックス
23人が集まった部屋を想像してください。誕生日が1年365通りも あるのだから、誰か2人の誕生日が一致するなんて、とても起こり そうにないと感じるかもしれません。しかし実際の確率は50%を 超えます。これが有名な「誕生日パラドックス」です——特定の2人が 一致するかではなく、グループ内のどの組み合わせでもよいので、 可能な「組」の数が人数よりずっと速く増えていくのです。
組み合わせの数は、要素の数よりもずっと速く増えていく——これが偶然の一致があっという間に起きやすくなる理由です。
これが画素の明るさにどう当てはまるか
8bit画像でも、上の誕生日の例と全く同じことが起きます——ただし 「部屋」がずっと大きいだけです。各画素の明るさは、任意の実数 ではなく、0〜255の256通りの整数のいずれかしか取れません。本 プロジェクトでは、画像の小さな正方形(「ブロック」)——8×8画素、 つまり64個の画素——ごとに、その64個全ての画素値から計算される、 明るさのばらつきを表すσgtという値(標準偏差に 近いもの)を測定しています。256通りの整数を64個組み合わせると、 256よりずっと多い種類の厳密な結果が生まれえます——しかし、その 64個の入力はあくまで0〜255の整数に限られているため(任意の実数 ではないため)、σgtとして取りうる出力の種類は、 どれだけ多くても、特定の・有限の・数えられる個数に収まります。 その数が実際には約230万通りです。この約230万という数字こそが、 このプロジェクトにおける「365通りしかない誕生日」に相当します ——256そのものではなく、256通りの入力を組み合わせた結果、行き 着く先の(ずっと多いとはいえ)限られた出力の種類数です。そして 23人どころ ではなく、約7900万個ものブロックがあります——だから上と同じ理屈で、 中身に何の関連性もないのに、偶然全く同じ値になるブロックが多数 出てきます。これはバグでも測定の壊れた兆候でもありません——画素の 明るさがそもそも256通りしかないことに加えて、「日数」(=σgt が取りうる種類数、約230万)よりずっと多い「人数」(=ブロック数、 約7900万)がいることから直接生じる、避けられない結果です。
64個の入力は、それぞれ256通りの値に限られていますが、組み合わさって1つの出力になります——大きいながらも有限で、数えられる結果の集合です。
実際にどれくらいの頻度で起きているか
DOI 1.16は、このプロジェクト自身のデータでこの偶然がどれほどの 頻度で実際に起きているかを測定しました:約7900万ブロックのうち、 異なるσgtの値はわずか約230万種類しか存在しません ——平均すると、34を超える無関係なブロックが、厳密に同じ1つの値を 共有していることになります。(この約230万という数字自体、実は コンピュータの浮動小数点演算の仕組みによってわずかに水増しされて いたことが、下のPart 2でわかります——真の値はもっと少ないのです。)
Part 2:コンピュータ自身の演算に潜む罠(DOI 1.21)
自分で動かして確かめられる簡単な例
ここからは、画像とは全く関係のない、もう1つ別の効果です——1番目の 効果の上に重なって生じます。Pythonのインタープリタで次を試して みてください:
>>> (0.1 + 0.2) + 0.3
0.6000000000000001
>>> 0.1 + (0.2 + 0.3)
0.6
どちらの式も、同じ3つの数を足し合わせています。数学的には、 どちらも厳密に0.6のはずです。しかし、コンピュータは小数点を 含む数(「浮動小数点」数)を、固定された有限個のビットで表現して いるため、日常的な小数の多くは完全な精度では表現できず、極めて 近い値で近似するしかありません。どちらの足し算を先に行うかに よって、このわずかな誤差の丸められ方がわずかに変わり、コンピュータ は数学的には全く同じはずの数に対して、技術的には異なる2つの ビットパターンを格納してしまいます。
同じσgtが、別々の値として数えられてしまう仕組み
これが重要になるのは、上のPart 1との組み合わせによってです: これほど多くの無関係なブロックが全く同じσgtに なるはずである以上、実際にそのソフトウェアが全く同じ順序の 足し算でそれぞれを計算したかどうかが、格納される値まで同じに なるかどうかを左右します。2つのブロックの計算がたまたまわずかに 異なる演算経路を通った場合、両方とも数学的には厳密に同じ σgtでありながら、技術的には最小単位だけ異なる 2つのビットパターンとして格納されてしまうことがあります——これを 私たちは「ghost duplication(影の重複)」と呼んでいます。「この列に 何種類の異なる値が現れるか」という素朴な数え方は、これらを1つでは なく2つの別々の値として数えてしまい、見かけ上の数を水増しして しまいます。
実データでの具体例:distinct値数はどれだけ水増しされていたか
このプロジェクト自身のデータで見つかった実例:1枚の画像内の 無関係な2つのブロックが、同じ真のσgt (≈0.0004863513439456968)を持ちながら、実際には 5.421010862427522e-20という差で格納されていました——これは ちょうど2-64、コンピュータが浮動小数点数を表現する 仕組みから直接導かれる綺麗なIEEE 754機械定数であって、ブロックの中身が 本当に違うわけではありません。DOI 1.21は、この罠がDOI 1.16の distinct値数をどれだけ 水増ししていたかを測定しました:σgtは約1.95倍 水増し(真の値は約118万、最初に報告された約230万ではない)、 関連する明るさの指標μgtは約4.2倍 水増し(真の値は16,320、最初に報告された68,649ではない)—— どちらも同じghost duplicationという仕組みで、水増しの度合いが 量ごとに違うだけです。
同じ真の値が、2通りの異なる演算経路を通ることで、技術的には異なる2つの数として格納されてしまう——直接見るには小さすぎる差。
なぜこれは1つのプロジェクトより大きな話なのか
Part 1(8bit量子化)は、普通の8bit画像で学習・評価されている あらゆるAIモデル——つまりほとんど全てのAIモデル——に当てはまります。 Part 2(浮動小数点のghost duplication)は、画像モデルに限らず、 浮動小数点演算から計算された厳密な異なる値の数を数えているあらゆる 分野のあらゆるソフトウェアに当てはまる、さらに広い範疇の話です。 モデルの挙動がどれだけ「離散化」されているかを測定する作業にも、 多数の計算結果にわたって厳密な値を比較する作業にも、ここで説明 した2つの構造的な効果が同じように関わってきます。
誰でも再実行できる動くコードとともに、これをはっきりと記録に 残しているのは、この問題をこの精度で記録として残しておく価値が あると考えているからです。これにどう対処すべきか——特定の用途に とって重要かどうか、もし重要ならどう扱うべきか——という判断は、 私たち自身で決着をつけたと主張するのではなく、広い研究コミュニティ に委ねています。
もっと詳しく知りたい方は
技術的な詳細(検証用SQL・画面録画・ファイルハッシュ)は DOI 1.16と DOI 1.21の Zenodoレコードに公開されています。クエリ単位の解説は DOI 1.21のSQLページ、用語レベルの 定義は用語集に あります。