正規化 標準化(機械学習)の理由,必要性,メリットと元に戻す(逆変換)方法をPythonで解説【ディープラーニング,ニューラルネットワーク】

テスト作業の工数見積もりを行うAIのプログラムについて、前回ご紹介いたしました。

AIプログラミング(Pythonサンプル):工数見積りする学習・予測プログラムを自作してみた【ラズパイ・機械学習・ディープラーニング】 | 9が好きな人のブログ

自作の拙作AIですが使えそうでしょうかね?(苦笑)
今回は、サンプルプログラムのあるポイントについて、補足説明します。これは地味に重要なポイントで、ちょっと苦労した点でもあります。

それは「データ前処理・標準化」です。

データ前処理とは

AI(ディープラーニング)などの機械学習においては、学習データに対して予め「前処理」というものがしばしば行われます。前処理とは、何らかの方法で、学習データ(説明変数、目的変数)の値を、機械学習上の計算で扱いやすいように変形しておくことです。

前処理で代表的なのが、学習データの値の範囲(スケール)を小さくしておくことです。

身長[cm]などでいえば、
[160,165,170,175,180]
のようなデータが5つあったとき、これらを最大値の180で割り算して
[0.888888889,0.916666667,0.944444444,0.972222222,1.0]
のように、1.0以下の値に収めるようなことです。

AIの学習データ(説明変数、目的変数)に対し、これを行うことで、以下の効果が得られ、学習スピードが向上します。

・説明変数の値が小さくなることで、ニューラルネットワークの重み更新の振れ幅が抑えられ、重みが収束しやすくなる
・目的変数の値が小さくなることで、損失関数の値も小さくなり、誤差が収束しやすくなる

たとえていえば、プラモデルがいい例かもしれません。現物そのままのサイズで、プラモを作ったり修繕しようとするのはとても大変で、手間も時間もコストもすごくかかります。

実際に1/1スケールのガンプラなど出回ってませんよねw(お台場のガンダムくらい?)出回っているプラモデルは、扱いやすいよう100分の1程度のスケールに小さくされています。AIの学習データの前処理を行う目的もそれと似たような理由です。

データの標準化とは

さて、前処理の手法としてよく用いられるのがデータの「正規化」とよばれるものです。正規化とは、計算・解析において扱いやすいように、データをある規則に従って整形することをいいます。例えば、画像認識AIにおいては、学習データに使用する画素値を最大値(255)で割っておくことで、データ値を[0,1]の範囲に収めるという手法が用いられます。

正規化の手法の中でも、特に以下のような特性を持つデータセットに変形することを「標準化」といいます。

・平均値=0
・標準偏差=1

標準偏差など、いきなり数学的な用語が出てきましたが、これらは統計学で使用される重要な概念です。また、上記の特性を満たすものは、「正規分布」と呼ばれる自然界でよくみられる形のデータ群です。

これらの概念については、以下のサイトなどが参考になります。

14-3. 標準化したデータの使い方 | 統計学の時間 | 統計WEB

6-2. データを標準化してみよう | 統計学の時間 | 統計WEB

標準化の計算は、それほど複雑ではありません。

・データ値:x
・データセットの平均値:u
・データセットの標準偏差:σ
・標準化データ値:X

とすると、以下の式で定義されます。

X = (x-u)/σ

試しに先ほどの身長のデータセット [160,165,170,175,180] に対し、標準化を行ってみると以下のようになります。

[-1.414213562, -0.707106781, 0, 0.707106781, 1.414213562]

かなり小さい値になりましたね。

AIにおけるデータ標準化のメリットの一つは、データのスケールを小さくして、学習速度を上げることです。それ以外にも、スケールの異なる複数の説明変数(身長、体重など)を正規化する場合にも使用されます。各説明変数間のスケールが大きく異なる場合、スケールの大きい変数が学習に影響を与えてしまうため、標準化を用いてこれを是正できます。

機械学習における標準化の目的、メリットについては、以下のサイトなども参考になります。

Feature Scalingはなぜ必要? - Qiita

以下のディープラーニング本でも正規化、標準化について言及されており、参考になります。




必要な数学だけでわかる ディープラーニングの理論と実装
秀和システム (2019-06-05)
売り上げランキング: 169,082

学習時の標準化

前回のAIサンプルプログラムにおいて、標準化によるデータ前処理は、学習プログラム、予測プログラム、プロットプログラムいずれにも実装されています。予測、プロットにおいては、標準化された出力データを、元のスケールに戻す標準化の逆変換も実装しています。

サンプルプログラムは↓のGitHub上にあります。
https://github.com/kotetsu99/deep_regression

学習のサンプルコード「deep_regression_train.py」では、学習用のcsvファイル読み込んだ後、学習データセットの標準化を実装しています。データセット(ベクトル)の標準化はPythonの計算ライブラリである、scipyを使用することで、簡単に実装できます。

x = scipy.stats.zscore(x)

これを利用して、データセットの標準化を行っているのが以下のサブルーチンです。

 66 def load_csv(csvfile):
 67     # csvをロードし、変数に格納
 68     df = pd.read_csv(csvfile)
 69     dfv = df.values.astype(np.float64)
 70     n_dfv = dfv.shape[1]
 71
 72     # 学習データをシャッフル
 73     np.random.shuffle(dfv)
 74
 75     # 特徴量のセットを変数xに、ターゲットを変数yに格納
 76     x = dfv[:, np.array(range(0, (n_dfv-1)))]
 77     y = dfv[:, np.array([(n_dfv-1)])]
 78
 79     # データの標準化
 80     x = scipy.stats.zscore(x)
 81     y = scipy.stats.zscore(y)
 82
 83     return x, y

説明変数x(テスト項目数)、目的変数y(消化日数)をcsvから読み込み、1列目=x、2列目=yとなる行列を生成。これを行をランダムに入れ替えてシャッフルした後、x,yを別々のベクトルとして格納、最後にそれぞれに対して標準化処理を行っています。標準化処理自体は、scipyを使えば簡単にできます。

余談になりますが、学習データセットをシャッフルしているのは、モデルの学習に使用するデータに偏りを持たせないためです。モデルの学習には、KerasのModel クラスのfit関数を使用しています。

 53     # モデルの学習
 54     history = dnn_model.fit(X, y, epochs=nb_epochs, validation_split=0.1, batch_size=n    _bs, verbose=2)


ここで学習に使うデータは最初の9割で、残りの1割は学習に使わずモデルの精度(損失関数の大きさ)を評価するデータとして使用されます。

validation_split=0.1

という設定がそれです。

学習データをシャッフルせずに学習させた場合、データセットの後尾部分(x:テスト項目数 が大きい値の箇所)が学習に使われないため、そのレンジに対する予測精度が落ちてしまいます。このため、学習データをシャッフルで対処しています。
# そもそも評価用にデータを割かないのであればシャッフルは不要ですが……

予測・プロット時の標準化および逆変換

予測のサンプルコード「deep_regression_predict.py」においては、標準化および標準化されたデータを元のスケールに戻す逆変換を実装しています。

使用する学習済モデルは標準化された変数(x:テスト項目数)を、入力として使用します。このため予測プログラムに引数として渡すxに対し、標準化を行う必要があります。標準化に用いる、平均値と標準偏差ですが、これは学習データのものを用います。これを実施しているのが以下のサブルーチンです。

 68 def input_normalization(X, x):
 69     # 入力ベクトルの各要素値を、対応する学習データの各列ベクトルで標準化
 70     n = X.shape[1]
 71     for i in range(n):
 72         t = x[:,i]
 73         X[:,i] = (X[:,i] - t.mean()) / t.std()
 74     return X

↑のサブルーチンを用いて、入力データ(テスト項目数)を標準化し、学習モデルに入力して予測値(消化日数)を得ます。

 40     # 入力データ標準化
 41     X = input_normalization(X, x)
 42
 43     # 予測結果の取得
 44     result = dnn_model.predict_on_batch(X)
 45
 46     # 予測結果に対し標準化の逆変換
 47     Y = result * y.std() + y.mean()

ここで予測に使用している学習済モデルは、学習時に標準化された正解値(消化日数)を用いて訓練しています。そのため出力「result」が標準化されたスケールで出てきます。

予測したいのは、標準化されたスケールの予測値(消化日数)ではないため、これを元のスケールに戻す必要があります。そのため、予測結果に対し標準化の逆変換を行います。これは標準化の式を変形すれば簡単に計算できます。

標準化の式;X = (x-u)/σ
逆変換の式:x = X*σ + u

・データ値:x
・データセットの平均値:u
・データセットの標準偏差:σ
・標準化データ値:X

平均値uと標準偏差σは、学習データ(消化日数)のものを用います。これにより、元のスケールで予測値を得ることができます。

プロットサンプルコード「deep_regression_plot.py」についても、標準化・逆変換処理の要領は、予測プログラムとほぼ同じです。標準化・逆変換処理をかける入力値・出力値がスカラーからベクトルに変わっただけですね。

AI(ディープラーニング)をはじめとする機械学習において、標準化等の正規化によるデータ前処理は頻繁に利用されます。その実装方法について、本記事が参考になれば幸いです。

スポンサーリンク