Strong bias arising from extremely difficult regression problems
予測問題におけるバイアス
きっかけは@JMLさんのツイートです
これに対して@yoshiso44さんがこんな反応をしていました。
マーケットデータ等ラベルが非常に予測困難な問題、特に0平均で分布している場合は、予測が0であることが非常に強力な正解へのバイアスになる
基本的に特徴量がラベルに対して持つ情報量が少ないほど、より尖度の高い分布になるはず
このstatementを見て、私はなるほどなーと思っていました。
直観的には正しそうです。しかし、本当にそうでしょうか?
ある性質を持った確率変数特有の現象なのか、どういうときにこの現象が観察できるのか。
定量的に検証することで、何かヒントを得られるかもしれません。
この記事は回帰問題において上記の現象を検証してみようというものです。
(先行研究があるかは調べていないので、あったら教えてほしいです)
検証
手順
- 機械学習モデルにとって簡単な予測問題を定義する。機械学習モデルがその問題をちゃんと解けることを確認する。
- 問題のS/N比を下げることで難易度を上げていくと、バイアスが強くなっていくかを確認する。
特徴量の準備
つまり、
この特徴量はi.i.d.であるとします。これは
ここでは
import numpy as np
import pandas as pd
np.random.seed(42)
df = pd.DataFrame(np.random.normal(size=[10000, 10]), columns=[f"feat_{i}" for i in range(10)])
df[["feat_0"]].hist(bins=100, density=True)
簡単な予測問題
1.機械学習モデルにとって簡単な低S/N比の予測問題を定義する。機械学習モデルがその問題をちゃんと解けることを確認する。
簡単なターゲットラベルの作成
さて、特徴量は用意できたので、次はターゲットラベル
「簡単な問題」ではターゲットラベルはpredictableであってほしいので、なにかしらの関数
少しトリッキーですが、ここでは
そうすると、学習を行う際に同じ構造を持ったNNを用いればperfectな予測が可能なはずです。
(スケール変換している分はLinearレイヤーで吸収できるはず。)
また、このターゲットラベルを予測する問題はS/N比が0の問題になっています。
今回はtensorflowを用いて実装してみます。
import tensorflow as tf
import random
random.seed(42)
tf.random.set_seed(42)
f = tf.keras.models.Sequential()
f.add(tf.keras.layers.Dense(100, input_dim=10, activation='tanh', use_bias=False))
f.add(tf.keras.layers.Dense(1, activation='linear', use_bias=False))
y = pd.Series(f.predict(df).flatten())
y /= y.std() # normalize
y.plot(kind="hist", bins=100, density=True, title="y")
ここでbiasをtanh
にすることで、
また、あとでノイズを加える際にターゲットラベルのスケールを固定するために、標準偏差が1になるようにスケール変換しています。
ちなみに非線形な活性化関数を使っているので、ターゲットラベルは正規分布ではなくなっているはずです。[1]
簡単な問題に対する学習
学習を実行してみます。
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(100, input_dim=10, activation='tanh'))
model.add(tf.keras.layers.Dense(1))
model.compile(loss="mean_squared_error", optimizer="adam")
history = model.fit(df, y, validation_split=0.25, epochs=200, batch_size=64)
損失関数の減少を確認
import matplotlib.pyplot as plt
plt.plot(history.history["loss"], label="training")
plt.plot(history.history["val_loss"], label="validation")
plt.ylabel("MSE")
plt.xlabel("epoch")
plt.yscale('log')
plt.show()
縦軸が対数であることに注意。
ハイパーパラメータの設定次第では際限なく損失が減少して0に到達するはずですが、今回はある程度のところで止めています。
学習済みモデルの出力の分布を確認
pred = pd.Series(model.predict(df).flatten())
def plot_dist(y, pred):
y.plot(kind="hist", bins=100, density=True, label="y")
pred.plot(kind="hist", bins=100, density=True, label="pred")
plt.legend()
plt.show()
plot_dist(y, pred)
ここで学習したのはS/N比が0の簡単な問題なので、ちゃんと学習できることを確認できました。
予測困難な問題
- 問題のS/N比を上げることで難易度を上げていくと、バイアスが強くなっていくかを確認する。
予測困難なターゲットラベルの作成
ここではターゲットラベルに正規分布でノイズを乗せることによってS/N比を大きくし、予測が困難な問題を作っていきます。
ノイズレベル
先程作ったターゲットラベルに標準偏差が
ターゲットラベルの標準偏差はもともと
noise_levels = range(1, 101, 10)
noisy_y = {l: y + np.random.normal(size=y.shape, scale=l * 0.1) for l in noise_levels}
noisy_y = {k: v / v.std() for k, v in noisy_y.items()}
ここでもターゲットラベルのスケールを調整して標準偏差が
非線形な変換をはさんでいるので一般にはターゲットラベルは正規分布にならないですが、ターゲットラベルの尖度はノイズレベルによらずほぼ0であり、ほぼ(標準)正規分布のようなものになっています。
ノイズレベル
target mean: 0.009, std: 1.000, kurtosis: -0.020
ノイズレベル
target mean: 0.005, std: 1.000, kurtosis: -0.035
予測困難な問題の学習
先程作ったノイズありのラベルに対して、各ノイズレベルごとに学習を行います。
def create_model():
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(100, input_dim=10, activation='tanh'))
model.add(tf.keras.layers.Dense(1))
model.compile(loss="mean_squared_error", optimizer="adam")
return model
for l in noise_levels:
model = create_model()
history = model.fit(df, noisy_y[l], validation_split=0.25, epochs=200, batch_size=64, verbose=0)
pred = pd.Series(model.predict(df, verbose=0).flatten())
print(f"noise level: {l}")
print(f"MSE: {np.mean((pred - noisy_y[l])**2):.3f}")
print(f"target mean: {noisy_y[l].mean():.3f}, std: {noisy_y[l].std():.3f}, kurtosis: {noisy_y[l].kurtosis():.3f}")
print(f"pred mean: {pred.mean():.3f}, std: {pred.std():.3f}, kurtosis: {pred.kurtosis():.3f}")
plot_dist(noisy_y[l], pred)
ノイズレベル
noise level: 10
MSE: 0.478
target mean: 0.009, std: 1.000, kurtosis: -0.020
pred mean: 0.010, std: 0.750, kurtosis: -0.080
ノイズレベル
noise level: 100
MSE: 0.955
target mean: 0.005, std: 1.000, kurtosis: -0.035
pred mean: 0.038, std: 0.282, kurtosis: 0.554
実験結果からノイズレベルが大きいほど、
- (当然のことですが)MSEが大きい
- 予測の分散が小さい
- 予測の尖度(kurtosis)が大きい
ということが確認できました。
まとめ
人工データでターゲットラベルのS/N比を変化させることで、S/N比と予測の分布の関係を検証しました。
今回の設定では予測モデルからの出力はノイズレベルが大きくなるほど尖度が大きくなります。
この実験で@yoshiso44さんの
マーケットデータ等ラベルが非常に予測困難な問題、特に0平均で分布している場合は、予測が0であることが非常に強力な正解へのバイアスになる
基本的に特徴量がラベルに対して持つ情報量が少ないほど、より尖度の高い分布になるはず
というstatementを定量的に検証することができました。
ノイズが乗ったターゲットラベルが性質の悪い分布[2]ではなく正規分布っぽい分布であったとしても予測の分布の尖度が大きくなることは一つ面白いポイントです。
もっと一般的な状況であっても回帰問題だと上記のような強いバイアスが発生するかと思われます。
この問題を回避するためになにかしらの分類問題に置き換えたりすることが考えられそうです。
質問・コメント等大歓迎です、是非よろしくお願いします!
参考: 分類問題への置き換えについて
Discussion