モデルの過学習を防ぐテクニック | モデルの評価と改善 | Pythonによる機械学習を学ぶ

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
ad. 価格範囲を指定して商品を探せます

モデルの過学習を防ぐテクニック(正則化、ドロップアウト)

過学習(オーバーフィッティング)とは、モデルが訓練データに適合しすぎてしまい、未知のデータに対する予測性能が低下する状態です。訓練データでは高い精度を示していても、テストデータや実際の運用データで性能が落ちる場合は、過学習が疑われます。

過学習を防ぐためには、モデルの複雑さを抑え、特定のデータに依存しすぎないようにすることが重要です。代表的な方法として、正則化とドロップアウトがあります。

過学習を防ぐ仕組みを図で理解する

過学習を防ぐ仕組みを図で理解する

過学習とは

過学習は、モデルが訓練データの細かいノイズや偶然のパターンまで覚えてしまう状態です。

  • 訓練データでは高い精度になる
  • テストデータでは精度が下がる
  • 未知のデータに弱くなる
  • モデルが複雑すぎる場合に起こりやすい

正則化とは

正則化は、モデルの重みが大きくなりすぎないように制約を加える方法です。重みが大きくなりすぎると、モデルが訓練データに過度に適合しやすくなります。

正則化を行うことで、モデルを適度に単純に保ち、未知のデータに対する汎化性能を高めやすくなります。

L1正則化(Lasso)

L1正則化は、重みの絶対値にペナルティを加える方法です。不要な特徴量の重みを0にしやすいため、特徴量選択の効果もあります。

  • 不要な特徴量を除外しやすい
  • モデルをシンプルにできる
  • 特徴量選択にも使える

Lasso回帰の実装例

from sklearn.linear_model import Lasso
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split

# データのロード
data = load_diabetes()
X = data.data
y = data.target

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42
)

# Lassoモデルの作成
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)

# モデルの性能評価
train_score = lasso.score(X_train, y_train)
test_score = lasso.score(X_test, y_test)

print(f"訓練データのスコア: {train_score:.3f}")
print(f"テストデータのスコア: {test_score:.3f}")

alphaは正則化の強さを表します。値が大きいほど強い正則化がかかります。

L2正則化(Ridge)

L2正則化は、重みの二乗にペナルティを加える方法です。L1正則化のように重みを0にしやすいわけではありませんが、全体の重みを小さく抑えることで、モデルを安定させます。

  • 重みの極端な大きさを抑える
  • すべての特徴量を活かしやすい
  • モデルを安定させやすい

Ridge回帰の実装例

from sklearn.linear_model import Ridge

# Ridgeモデルの作成
ridge = Ridge(alpha=0.1)
ridge.fit(X_train, y_train)

# モデルの性能評価
train_score = ridge.score(X_train, y_train)
test_score = ridge.score(X_test, y_test)

print(f"訓練データのスコア: {train_score:.3f}")
print(f"テストデータのスコア: {test_score:.3f}")

Ridge回帰では、特徴量を残したまま重みを抑えるため、過学習を防ぎながら安定した予測を行いやすくなります。

L1正則化とL2正則化の違い

項目 L1正則化(Lasso) L2正則化(Ridge)
ペナルティ 重みの絶対値 重みの二乗
重みが0になるか なりやすい なりにくい
特徴量選択 できる 基本的にはできない
特徴 モデルをよりシンプルにしやすい モデルを安定させやすい

ドロップアウトとは

ドロップアウトは、主にニューラルネットワークで使われる過学習防止の手法です。学習中に一部のニューロンをランダムに無効化し、特定のニューロンに依存しすぎないようにします。

これにより、ネットワーク全体がより汎用的な特徴を学習しやすくなります。

  • 学習中に一部のニューロンを無効化する
  • 特定の経路への依存を防ぐ
  • ニューラルネットワークの過学習を抑える
  • 複数の弱いモデルを組み合わせるような効果がある

ドロップアウトの実装例

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical

# データのロード
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# データの前処理
X_train = X_train.reshape(-1, 28 * 28) / 255.0
X_test = X_test.reshape(-1, 28 * 28) / 255.0

y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

# モデルの作成
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(28 * 28,)))
model.add(Dropout(0.5))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

# モデルのコンパイル
model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    metrics=['accuracy']
)

# モデルの学習
model.fit(
    X_train,
    y_train,
    epochs=10,
    batch_size=128,
    validation_split=0.2
)

Dropout(0.5)は、学習中に50%のニューロンをランダムに無効化する設定です。

正則化とドロップアウトの違い

項目 正則化 ドロップアウト
主な対象 回帰モデル、線形モデル、ニューラルネットワーク ニューラルネットワーク
考え方 重みに制約を加える 一部のニューロンを無効化する
目的 モデルの複雑さを抑える 特定のニューロンへの依存を防ぐ
代表例 L1正則化、L2正則化 Dropout層

正則化の強さを調整する

正則化の効果は、alphaなどのハイパーパラメータによって変わります。強すぎるとアンダーフィッティングになり、弱すぎると過学習を防ぎきれないことがあります。

GridSearchCVによる調整例

from sklearn.model_selection import GridSearchCV

# 探索するalphaの候補
param_grid = {
    'alpha': [0.01, 0.1, 1.0, 10.0]
}

# グリッドサーチ
grid_search = GridSearchCV(
    Lasso(),
    param_grid,
    cv=5
)

grid_search.fit(X_train, y_train)

print("最適なalpha:", grid_search.best_params_)

複数の候補を比較することで、データに合った正則化の強さを選びやすくなります。

過学習を防ぐその他の方法

  • データを増やす: 学習データを増やすことで、汎化性能を高めやすくなります。
  • 早期終了: 検証データの性能が悪化し始めた時点で学習を止めます。
  • モデルを単純にする: パラメータ数や層の数を減らします。
  • 交差検証: 複数の分割で性能を確認し、過学習を見つけやすくします。