今日のプログラミングホラーのエピソードでは... random.seed() defのPythonドキュメントでは、 「aがint型の場合は直接使用されます。」[1] でも、シード値を3または-3にすると、実際には全く同じRNGオブジェクトが生成され、同じストリームが生成されます。(TIL)。nanochatでは、trainとtestの分割で異なるRNGシーケンスを生成するための(賢い方法だと思っていた)方法として符号を使っていました。そのため、train=testになってしまうので、厄介なバグが発生しています。 原因となっているCPythonコードはcpython/Modules/_randommodule.c [2]で見つかりました。321行目のコメントに次のような記述があります。 「このアルゴリズムは、数値が符号なしであることを前提としています。つまり、引数がPyLongの場合は、その絶対値を使用します。」 n = PyNumber_Absolute(引数); これは、シードに対して abs() を明示的に呼び出して正の値にし、符号ビットを破棄します。 しかし、このコメントも実際には誤り/誤解を招くものです。Pythonは内部的にメルセンヌツイスターMT19937アルゴリズムを呼び出しており、これは一般的に19937ビット(非ゼロ)の状態を持ちます。Pythonはint型(またはその他のオブジェクト)を受け取り、その情報をこれらのビットに「分散」します。原理的には、符号ビットを使って状態ビットを拡張することもできたはずです。このアルゴリズムには「符号なしの数値であること」を前提としている点は何もありません。符号ビットを組み込まないという決定がなされました(これは私の考えでは間違いでした)。簡単な例としては、n -> 2*abs(n) + int(n 同じシーケンス。 しかし、異なるシードが異なるシーケンスを生成するという保証はありません。つまり、Pythonは原則として、例えばseed(5)とseed(6)が異なる乱数ストリームであるとは保証しません(ただし、多くのアプリケーションでは暗黙的にこれが前提とされています)。実際、seed(5)とseed(-5)は同一のストリームです。そして、機械学習において訓練とテストの動作を分離するためにこれらを使用するべきではないでしょう。これは、最近私が遭遇したプログラミングの恐怖のフットガンの一つです。次回のエピソードでお会いしましょう。 [1] https://t.co/srv1ZBlDsi [2]
バグを発見してくれたgithubのericsilberstein1に感謝します。 https://t.co/github.com/karpathy/nanoc…なく、SpellingBee の総合タスク評価でのみ発生しますが)。
![今日のプログラミングホラーのエピソードでは...
random.seed() defのPythonドキュメントでは、
「aがint型の場合は直接使用されます。」[1]
でも、シード値を3または-3にすると、実際には全く同じRNGオブ](https://pbs.twimg.com/media/G7sc167aMAAuZi5.png)