トレーニングにまつわるあれこれを掲載しているブログではありますが,都合によりこのような記事を掲載いたします.
現在一般社団法人ディープラーニング協会のE資格を取得するため,ラビットチャレンジなるプログラムを受講しています.本プログラムにおいてレポート公開が必須になっていることから,こちらのブログにてレポートします.
機械学習
線形回帰
複数の変数と
の関係を以下のような式で表現したものを線形回帰と呼ぶ.
一般に以下のような行列の形で表現される.
これを踏まえて,線形回帰モデルは以下のように表現される.
以下のようなイメージ.パラメータxと重みwの内積でyは表現される.NNモデルの最終層と同じような印象.
なお,真値との誤差
は以下のように表現される.
xとyの組み合わせ(学習データ)と,重みwの関係は以下のように書ける
この誤差を最小二乗法で最小化するようなを探索する問題と整理することができる.
最小二乗法の式は以下.
は以下のように式展開して求められる.
非線形回帰
複数の変数に基底関数を適用して,非線形化したものを非線形回帰と呼ぶ.線形回帰は恒等写像関数を適用したものと考えることができる.
よく使われるのは,恒等写像関数(=線形回帰),
多項式,
ガウス型基底,
ガウス型基底は多項式より柔軟な設定ができそうだが,調整するパラメータが多くて使うのが難しいそうな印象を受けた.
非線形回帰における過学習と未学習
表現力が不足していることで,学習データ・テストデータともに誤差が大きいことを未学習(underfitting)と呼ぶ.
また,表現力が高すぎることで,学習データでは小さい誤差が得られるものの,テストデータに対しては誤差が大きい
ことを,過学習(overfitting)と呼ぶ.
未学習に対する対策としては,
- 基底関数を追加するなどして,表現力を高める
過学習に対する対策としては,
- 学習データを増やす
- 不要な基底関数を削減するなどして,表現力を抑制する
- 正則化項を設ける
が挙げられる.正則化項Rは以下のように使われる.
ただしはn行k列の基底関数
このとき,
をRidge推定量と呼ぶ.
ロジスティック回帰
ロジスティック回帰は分類問題を解くための機械学習モデル.線形結合をシグモイド関数に入力することで,0 or 1に分類する.
シグモイド関数は以下
NNモデルの最終層に使われたりするので,馴染み深い.
ロジスティック回帰モデルは以下のように表現される.
このとき,や
は既知で,
を求めることになる.
を求めるために,尤度関数を用いて,最尤推定を行う.すなわち,
で,このようなpが得られるようなwを求める.最尤推定の詳細や勾配降下法は割愛.
主成分分析
主成分分析は多変量データの情報をより少数個の変数に圧縮する手法.
この線形変換するについて,
ただし,
となる最適化問題を解けば良い.
K近傍法
割愛
K Means
これも割愛
SVM
SVMは分類問題で用いられる手法のひとつ.ここでは線形SVMについて述べる.
学習データが線形分離可能なときに,なるべくその距離が大きくなるように,2 つのクラスのデータを分離するような
2 つの平行な超平面を選択することができる.2 つの超平面の間はマージン,2 つの超平面の中間に位置する超平面は
最大マージン超平面と呼ぶ.また,マージン上のサンプルをサポートベクターと呼ぶ.
検証や最適化
検証
回帰モデルにおける検証方法として,ホールドアウト法とクロスバリデーションがある.
ホールドアウト法では有限のデータを学習用とテスト用の2つに分割し、「予測精度」や「誤り率」を推定する為に一度だけ使用する.
簡易な方法ではあるが,分割方法で性能評価がばらつき,データが大量にない場合は良い性能評価が得られない場合がある.
クロスバリデーションではデータをk分割して,k-1つを学習用,1つをテスト用として評価する行為をk回実施,その平均を性能評価とする.
分割による影響を抑えることができ,より一般的に利用されている検証方法.
最適化
ハイパーパラメータの最適化手法として,グリッドサーチやランダムサーチ,ベイズ最適化がある.
コード演習
以下にロジスティック回帰についてのコード演習を掲載する.scikit learnを使用した実装は実施経験があるので,今回はnumpyでの実装について確認した.
まずはimport
%matplotlib inline import numpy as np import matplotlib.pyplot as plt
つぎに訓練データを生成するためのコード.
gen_dataは標準偏差を使って,平均0・分散1のデータと,平均1・分散1のデータを生成する関数.
n_sample = 100 half_n_sample = 50 var = .2 def gen_data(n_sample, half_n_sample): x0 = np.random.normal(size=n_sample).reshape(-1, 2) - 1. x1 = np.random.normal(size=n_sample).reshape(-1, 2) + 1. x_train = np.concatenate([x0, x1]) y_train = np.concatenate([np.zeros(half_n_sample), np.ones(half_n_sample)]).astype(np.int) return x_train, y_train def plt_data(x_train, y_train): plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train, facecolor="none", edgecolor="b", s=50, label="training data") plt.legend()
gen_dataを使ってデータ生成.グラフで生成データを確認.
#データ作成 x_train, y_train = gen_data(n_sample, half_n_sample) #データ表示 plt_data(x_train, y_train)
いい感じにばらついている.
定数項に合わせて1で埋めた行列を追加する関数と,シグモイド関数,最適化手法としてSGD(最急降下法)を準備.
def add_one(x): return np.concatenate([np.ones(len(x))[:, None], x], axis=1) def sigmoid(x): return 1 / (1 + np.exp(-x)) def sigmoid(x): return 1 / (1 + np.exp(-x)) def sgd(X_train, y_train, max_iter, eta): w = np.zeros(X_train.shape[1]) for _ in range(max_iter): w_prev = np.copy(w) sigma = sigmoid(np.dot(X_train, w)) grad = np.dot(X_train.T, (sigma - y_train)) w -= eta * grad if np.allclose(w, w_prev): return w return w
そして学習開始.学習率は0.01,イテレーションは100.
X_train = add_one(x_train) max_iter=100 eta = 0.01 w = sgd(X_train, max_iter, eta)
最後にテストデータを作って学習結果を可視化する.
meshgridで-5~5の範囲で,10000サンプル生成.
probabilityを計算して,0.5より大きいのものを1,0.5以下を0とした.
xx0, xx1 = np.meshgrid(np.linspace(-5, 5, 100), np.linspace(-5, 5, 100)) xx = np.array([xx0, xx1]).reshape(2, -1).T X_test = add_one(xx) proba = sigmoid(np.dot(X_test, w)) y_pred = (proba > 0.5).astype(np.int)
下記でコンター作成.
plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train) plt.contourf(xx0, xx1, proba.reshape(100, 100), alpha=0.2, levels=np.linspace(0, 1, 3))
scikit learnで実行した結果が以下.同じ結果が得られていることを確認した.
ちなみに学習データに対する正解率は0.92
from sklearn import metrics proba = sigmoid(np.dot(X_train, w)) y_pred = (proba > 0.5).astype(np.int) metrics.accuracy_score(y_train, y_pred) >>0.92
from sklearn.linear_model import LogisticRegression model=LogisticRegression(fit_intercept=True) model.fit(x_train, y_train) proba = model.predict_proba(xx) y_pred = (proba > 0.5).astype(np.int) plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train) plt.contourf(xx0, xx1, proba[:, 0].reshape(100, 100), alpha=0.2, levels=np.linspace(0, 1, 3))