🦔

理論も理解しないでデータ解析するんですか??(機械学習チートシート)

に公開

機械学習チートシート

対象読者:機械学習に関する講義を履修済みの大学生や社会人の方
数式の導出過程に重きを置いていますが、細かい説明や背景は省いているので、これを最初の学習用としないでください
参考までにPythonでのデータ解析用コードを記しています


概要

教師あり学習

  • 入力データと出力データから関数のパラメータを予測

教師なし学習

  • 入力データだけから関数のパラメータを予測

強化学習

  • 与えられた状態において報酬を最大化する行動を推定

データ前処理

標準化

  • 平均が0、標準偏差が1となるように変換
  • 単位や尺度の影響を取り除く
z = \frac{x - \mu}{\sigma}
from sklearn.preprocessing import StandardScaler
import numpy as np

X = np.array([[10, 20], [30, 40], [50, 60]])
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print("標準化前:\n", X)
print("標準化後:\n", X_scaled)

多重共線性

  • 説明変数同士の相関関係が高く、パラメータの推定が不安定になる

過学習

  • 学習データに過剰に適合し、汎化性能が低下する

回帰(Regression)

最小二乗法

  • 以下の損失関数を最小化
L(\mathbf{w}) = \| \mathbf{y} - X \mathbf{w} \|^2
L(\mathbf{w}) = (\mathbf{y} - X \mathbf{w})^\top (\mathbf{y} - X \mathbf{w}) = \mathbf{y}^\top \mathbf{y} - 2 \mathbf{w}^\top X^\top \mathbf{y} + \mathbf{w}^\top X^\top X \mathbf{w}
\frac{\partial L}{\partial \mathbf{w}} = -2 X^\top \mathbf{y} + 2 X^\top X \mathbf{w} = 0
X^\top X \mathbf{w} = X^\top \mathbf{y}
\mathbf{w} = (X^\top X)^{-1} X^\top \mathbf{y}

X^\top X が正則である必要がある。多重共線性があると解が不安定になる

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_regression

X, y = make_regression(n_samples=100, n_features=1, noise=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

model = LinearRegression()
model.fit(X_train, y_train)

print("係数:", model.coef_)
print("切片:", model.intercept_)
print("決定係数 R2:", model.score(X_test, y_test))

正則化回帰

  • 訓練データへの過剰な適合を防ぐため、パラメータの大きさにペナルティを与える

Ridge回帰(L2正則化)

L(\mathbf{w}) = \| \mathbf{y} - X \mathbf{w} \|^2 + \lambda \| \mathbf{w} \|^2_2
\frac{\partial L}{\partial \mathbf{w}} = -2 X^\top \mathbf{y} + 2 X^\top X \mathbf{w} + 2 \lambda \mathbf{w} = 0
(X^\top X + \lambda I) \mathbf{w} = X^\top \mathbf{y}
\mathbf{w} = (X^\top X + \lambda I)^{-1} X^\top \mathbf{y}
  • 単位行列は正則化するパラメータに対応する対角成分のみ1とする
  • 対角成分を足してランク落ちを防ぐことで、逆行列を安定に計算

Lasso回帰(L1正則化)

L(\mathbf{w}) = \| \mathbf{y} - X \mathbf{w} \|^2 + \lambda \| \mathbf{w} \|_1
  • \mathbf{w} の一部を0にする(特徴量選択)
  • 解析的に解けないため、数値計算を行う

# Ridge回帰
from sklearn.linear_model import Ridge

ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
print("Ridge回帰 R2:", ridge.score(X_test, y_test))

# Lasso回帰
from sklearn.linear_model import Lasso

lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)
print("Lasso回帰 R2:", lasso.score(X_test, y_test))
print("Lassoで選択された特徴量:", lasso.coef_)


評価指標

MSE(Mean Squared Error)

\text{MSE} = \frac{1}{N} \sum_{n=1}^{N} (y_n - \hat{y}_n)^2

MAE(Mean Absolute Error)

\text{MAE} = \frac{1}{N} \sum_{n=1}^{N} |y_n - \hat{y}_n|

R^2 スコア(決定係数)

R^2 = 1 - \frac{\sum^N _{n-1} (y_i - \hat{y}_i)^2}{\sum^N _{n-1} (y_i - \bar{y})^2}
  • R^2 = 1:y_i=\hat{y}_i
    完全に説明できている
  • R^2 = 0:\hat{y}_i=\bar{y}
    平均を使うのと同等

from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

y_pred = model.predict(X_test)
print("MSE:", mean_squared_error(y_test, y_pred))
print("MAE:", mean_absolute_error(y_test, y_pred))
print("R2:", r2_score(y_test, y_pred))


ホールドアウト法

  • データを訓練用と検証用にランダムに分割し、汎化性能を検証
from sklearn.model_selection import train_test_split

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)

交差検証法(Cross Validation)

  • 元のデータから一つずつ検証用データとして選び、すべてのデータが訓練・検証に一度ずつ使われるように評価する

K-fold交差検証法

  • データをK個の等しいサイズのサブセットに分割し、各サブセットを1回ずつ検証用データとし、残りを訓練用データに使ってK回モデルを評価
from sklearn.model_selection import KFold, cross_val_score
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression

iris = load_iris()
X, y = iris.data, iris.target == 0

kf = KFold(n_splits=5, shuffle=True, random_state=1)
model = LogisticRegression()

scores = cross_val_score(model, X, y, cv=kf)
print("各Foldのスコア:", scores)
print("平均スコア:", scores.mean())

混同行列(Confusion Matrix)

真値\識別 P N
P TP(True Positive) FN(False Negative)
N FP(False Positive) TN(True Negative)
  • TP: 正しく陽性と判定された数(真陽性)
  • TN: 正しく陰性と判定された数(真陰性)
  • FP: 本当は陰性なのに陽性と判定された数(偽陽性)
  • FN: 本当は陽性なのに陰性と判定された数(偽陰性)

Recall(再現率)

\text{Recall} = \frac{TP}{TP + FN}
  • 実際に陽性だったもののうち、陽性と正しく予測された割合

Precision(適合率)

\text{Precision} = \frac{TP}{TP + FP}
  • 陽性と予測したもののうち、実際に陽性だった割合

Accuracy(正解率)

\text{Accuracy} = \frac{TP + TN}{TP + TN + FP + FN}
  • 全体のうち、正しく分類できた割合。

F1 スコア

F1 = \frac{2 \cdot \text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}}
  • Precision と Recall の調和平均

from sklearn.metrics import confusion_matrix, classification_report
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

iris = load_iris()
X, y = iris.data, iris.target
# 2クラスに簡略化 (class 0 vs rest)
y_binary = (y == 0).astype(int)

X_train, X_test, y_train, y_test = train_test_split(X, y_binary, random_state=42)
model = LogisticRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))
print("Classification Report:\n", classification_report(y_test, y_pred))


ROC曲線・AUC

  • ROC(Receiver Operating Characteristic)
    横軸:False Positive Rate(FPR)
    縦軸:True Positive Rate(TPR)
  • AUC:(Area Under the Curve)
    ROC曲線の下の面積
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc

y_prob = model.predict_proba(X_test)[:,1]
fpr, tpr, thresholds = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)

plt.plot(fpr, tpr, label=f'ROC curve (area = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], linestyle='--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend()
plt.show()


ロジスティック回帰

  • y \in \{0,1\} に対して、事後確率をシグモイド関数で表現:
P(\mathbf{x}) = \frac{1}{1 + e^{-(w_0 + \mathbf{w}^T \mathbf{x})}}
L(\mathbf{w}) = \prod_{n=1} ^N P(\mathbf{x}) ^{y_n} (1 - P(\mathbf{x})) ^{1 - y_n}
\log L(\mathbf{w}) = \sum_{n=1}^N \left[ y_n \log P(\mathbf{x}) + (1 - y_n) \log (1 - P(\mathbf{x})) \right]
\mathcal{L}(\mathbf{w}) = -\sum_{n=1}^N \left[ y_n \log P(\mathbf{x}) + (1 - y_n) \log (1 - P(\mathbf{x})) \right]

from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
model.fit(X_train, y_train)

y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]

識別

最近傍法

\hat{y} = \arg\min_y (\min_n d(\mathbf{x}-\mathbf{x^{(y)}_n}))
  • データのノイズに強く影響する

k-NN(k近傍法)

  • 入力データに最も近い k 個のサンプルを選び、多数決でクラスを決定
  • 過学習を防止
from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
print("k-NN 正解率:", knn.score(X_test, y_test))

サポートベクトルマシン(SVM)

ハードマージン

決定境界:

\mathbf{w}^T \mathbf{x} + w_0 = 0

ご分類なしの場合、ラベル y_i \in \{-1, +1\}に対して以下の式が成り立つ:

y_i(\mathbf{w}^T \mathbf{x}_i + w_0) \geq 1 \quad

サポートベクトル \mathbf{x}_i から決定境界への距離:

M = \frac{y_i (\mathbf{w}^T \mathbf{x}_i + w_0)}{\|\mathbf{w}\|}

Mの最大化は\mathbf{w}の最小化と同値である

\min_{\mathbf{w}, w_0} \|\mathbf{w}\|^2 , y_i (\mathbf{w}^T \mathbf{x}_i + w_0) \geq 1 \quad

ソフトマージン

現実のデータは完全に線形分離できないので、スラック変数 \xi_i を導入:

\begin{align} \min_{\mathbf{w}, w_0, \boldsymbol{\xi}} \quad & \frac{1}{2} \|\mathbf{w}\|^2 + C \sum_{i=1}^N \xi_i , y_i(\mathbf{w}^T \mathbf{x}_i + w_0) \geq 1 - \xi_i \end{align}

カーネルトリック(非線形分離)

入力 \mathbf{x} を非線形写像 \phi(\mathbf{x}) で高次元空間に写像:

K(\mathbf{x}_i, \mathbf{x}_j) = \phi(\mathbf{x}_i)^T \phi(\mathbf{x}_j)

双対問題の内積をカーネルに置き換えれば非線形SVMが得られる:

f(\mathbf{x}) = \sum_{i=1}^{N} \alpha_i y_i K(\mathbf{x}_i, \mathbf{x}) + b

代表的なカーネル:

  • 線形カーネル:
    K(\mathbf{x_i}, \mathbf{x_j}) = \mathbf{x_i}^T \mathbf{x_j}
  • 多項式カーネル:
    K(\mathbf{x_i}, \mathbf{x_j}) = (\mathbf{x_i}^T \mathbf{x_j} + c)^d
  • RBFカーネル:
    K(\mathbf{x_i}, \mathbf{x_j}) = \exp\left(-\gamma{\|\mathbf{x_i} - \mathbf{x_j}\|^2}\right)
from sklearn.svm import SVC

svm = SVC(kernel='rbf', C=1.0, gamma='scale')
svm.fit(X_train, y_train)
print("SVM 正解率:", svm.score(X_test, y_test))

決定木

  • 木構造を用いて、ルールに従った分類または回帰を行う
  • \log_2N回の分岐でどのような入力データも分類可能

ジニ不純度(Gini Imprity)

  • ある領域に相当するノードtにおいて誤分類する確率
  • 誤分類がないとき0で最小、異なるクラスで同じ数だけ誤分類されるとき最大
G(t) = 1 - \sum_{k=1}^{K} P^2(C_k\mid t)
P^2(C_k\mid t) = \frac{N_k(t)}{N(t)}
P^2(C_k\mid t):ノードtでk番目のクラスが選ばれる確率
  • ジニ不純度の差分が最大となる境界値で分割
  • 左右それぞれのノードにおけるジニ不純度を G(t_L), G(t_R) とすると、
\Delta G(t) = G(t)-\left( \frac{N(t_L)}{N(t)} G(t_L) + \frac{N(t_R)}{N(t)} G(t_R) \right)

剪定(Pruning)

  • 決定木の部分木をいくつか削除することで過学習を防止

  • 以下のコスト複雑度を最小化

G_\alpha(T) = G(T) + \alpha |T|

G(T): 木 T による誤分類率
|T|: 葉ノードの数(木のサイズ)
\alpha: 複雑度に対するペナルティ係数

from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
import matplotlib.pyplot as plt

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(X_train, y_train)

plt.figure(figsize=(12,8))
tree.plot_tree(dt, filled=True, feature_names=iris.feature_names, class_names=['Not class0','Class0'])
plt.show()

バイアス・バリアンス分解

\mathbb{E} \left[ \|\hat{\mathbf{y}} - \mathbf{y} \|^2 \right] =\mathbb{E}\left[\|\hat{\mathbf{y}} - \mathbb{E}[\hat{\mathbf{y}}]\|^2\right]+\|\mathbb{E}[\hat{\mathbf{y}}] - \mathbf{y}\|^2
  • 第1項はバリアンス
  • 第2項はバイアスの二乗
  • バリアンスとバイアスはトレードオフの関係

アンサンブル学習

  • 複数のモデル(弱学習器)を組み合わせて、精度の向上や過学習の抑制を図る

バギング

  • バリアンスが大きく、バイアスが小さい弱学習器を集めてモデルを作成
  • 無相関な決定木の多数決や平均により予測
  • 元の訓練データから重複ありの復元抽出を行うブートストラップ法を行う
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier

bagging = BaggingClassifier(base_estimator=DecisionTreeClassifier(), n_estimators=10, random_state=42)
bagging.fit(X_train, y_train)
print("バギング 正解率:", bagging.score(X_test, y_test))


ブースティング

  • バイアスが大きく、バリアンスが小さい弱学習器を集めてモデルを作成
from sklearn.ensemble import AdaBoostClassifier

ada = AdaBoostClassifier(n_estimators=50, random_state=42)
ada.fit(X_train, y_train)
print("AdaBoost 正解率:", ada.score(X_test, y_test))

ランダムフォレスト(Random Forest)

  • バギングに説明変数のランダムサンプリングを加えることで、バリアンスを抑え、過学習を防ぐ
  • 各決定木の分岐時に説明変数p個からランダムに\sqrt{p} 個だけ選ぶ
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
print("ランダムフォレスト 正解率:", rf.score(X_test, y_test))

クラスタリング

k-meansクラスタリング

  • 各データ点 \mathbf{x}_i を K 個のクラスタに分類する手法

以下の損失関数を最小化:
$$
L(\mu_k) = \sum_{k=1}^{K} \sum_{\mathbf{x}_n \in C_k} | \mathbf{x}_i - \boldsymbol{\mu}_k |^2
$$

\mathbf{\mu_k} = \frac{1}{|C_k|} \sum^N_{n=1,\mathbf{x_n} \in C_k} \mathbf{x_n}
  • C_k: クラスタ k
  • \boldsymbol{\mu}_k: クラスタ k の中心(Centroid)
  • ランダムな初期値に依存するため、局所解に陥ることがある
from sklearn.cluster import KMeans
import numpy as np

X = np.array([[1, 2], [1, 4], [1, 0],
              [4, 2], [4, 4], [4, 0]])

kmeans = KMeans(n_clusters=2, random_state=42)
kmeans.fit(X)

print("クラスタ割当:", kmeans.labels_)
print("クラスタ中心:", kmeans.cluster_centers_)

エルボー法

  • 最適なクラスタ数 K を選ぶ方法
  • クラスタ数の増加に伴う損失関数の減少度合いが緩やかになるKを選択する
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs

# サンプルデータ作成
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)

# SSE (Within-Cluster Sum of Squares) の計算
sse = []
k_range = range(1, 11)
for k in k_range:
    kmeans = KMeans(n_clusters=k, random_state=0)
    kmeans.fit(X)
    sse.append(kmeans.inertia_)  # inertia_ はSSE

# プロット
plt.plot(k_range, sse, 'bx-')
plt.xlabel('クラスタ数 k')
plt.ylabel('SSE (Within-cluster sum of squares)')
plt.title('エルボー法によるクラスタ数決定')
plt.show()

生成モデル

  • 観測データxの母集団の確率分布をモデル化する
  • モデルの表現力向上のため、潜在変数を導入

EMアルゴリズム(Expectation-Maximization Algorithm)

  • 潜在変数を含む確率モデルのパラメータ推定に用いられる反復最適化手法
  • Eステップ:隠れ変数の分布の期待値を計算
  • Mステップ:期待値で得られた分布を用いてパラメータを最適化
  • 局所最適に収束するが、大域最適とは限らない

\begin{aligned}
\ln p(\mathbf{x};\theta)
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln p(\mathbf{x};\theta) \\
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln  \frac{p(\mathbf{x}, \mathbf{z};\theta)}{p(\mathbf{z}|\mathbf{x};\theta)} \\
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln  \frac{p(\mathbf{x}, \mathbf{z};\theta)}{q(\mathbf{z})} \cdot \frac{q(\mathbf{z})}{p(\mathbf{z}|\mathbf{x};\theta)}  \\
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln \frac{p(\mathbf{x}, \mathbf{z};\theta)}{q(\mathbf{z})} + \sum_{\mathbf{z}} q(\mathbf{z}) \ln \frac{q(\mathbf{z})}{p(\mathbf{z}|\mathbf{x};\theta)} \\
&= \underbrace{\mathcal{L}(q,\theta)}_{\text{ELBO}} + \underbrace{D(q\|p)}_{\text{KL - divergence}}
\end{aligned}

D(q\|p)=0よりq(\mathbf{z}) = p(\mathbf{z}|\mathbf{x}; \theta)

\mathcal{L}(q, \theta) = \sum_{\mathbf{z}} p(\mathbf{z}|\mathbf{x}; \theta) \ln p(\mathbf{x}, \mathbf{z}; \theta) - \sum_{\mathbf{z}} p(\mathbf{z}|\mathbf{x}; \theta) \ln q(\mathbf{z})

第二項は定数と見なせるため、第一項(完全データ対数尤度の期待値)を最大化する:

Q(\theta, \theta^{\text{old}}) = p(\mathbf{z}|\mathbf{x}; \theta) \ln p(\mathbf{x}, \mathbf{z}; \theta)

混合ガウス分布(GMM)

p(\mathbf{x}) = \sum_{k=1}^{K} \pi_k \mathcal{N}(\mathbf{x} \mid \boldsymbol{\mu}_k, \boldsymbol{\Sigma}_k)
  • \pi_k: 混合比 \sum_{k=1}^{K} \pi_k =1
  • \mathcal{N}: 多変量正規分布
import numpy as np
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture
from sklearn.datasets import make_blobs

# データ作成
X, y_true = make_blobs(n_samples=400, centers=3, cluster_std=0.60, random_state=42)

# GMM モデルの作成と学習
gmm = GaussianMixture(n_components=3, covariance_type='full', random_state=42)
gmm.fit(X)

# 各データ点のクラスタ予測
labels = gmm.predict(X)

# 結果の可視化
plt.scatter(X[:, 0], X[:, 1], c=labels, s=40, cmap='viridis')
plt.title("Gaussian Mixture Model (EMアルゴリズム)によるクラスタリング")
plt.show()

階層的クラスタリング(Hierarchical Clustering)

  • クラスタ間距離が最も近いクラスタを段階的に統合

全てのペア (i,j) に対して距離を計算し、n \times n の距離行列 \mathbf{D} を得る:

\mathbf{D}_{ij} = d(\mathbf{x}_i, \mathbf{x}_j)

クラスタ間距離

単連結(Single Linkag)

D(C_i, C_j) = \min_{x \in C_i, y \in C_j} d(x_i, y_j)

完全連結(Complete Linkage)

D(C_i, C_j) = \max_{x \in C_i, y \in C_j} d(x_i, y_j)

平均連結(Average Linkage)

D(C_i, C_j) = \frac{1}{|C_i||C_j|} \sum_{x \in C_i,y \in C_j} d(x_i, y_j)

ウォード連結(Ward Linkage)

D(C_i, C_j) = \sum_{x \in C_i \cup C_j} ( x - \mu_{C_i \cup C_j} )^2 - \left( \sum_{x \in C_i} ( x - \mu_{C_i} )^2 + \sum_{x \in C_j} ( x - \mu_{C_j} )^2 \right)

系統樹(dendrogram)

  • 階層的クラスタリングにおける統合過程を視覚化
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
import numpy as np

X = np.array([[1, 2], [3, 4], [5, 6], [8, 8]])
Z = linkage(X, 'ward')

plt.figure(figsize=(6, 4))
dendrogram(Z)
plt.show()


主成分分析(Principal Component Analysis: PCA)

  • 多次元データをより少ない次元に射影して、元のデータの分散をできるだけ保持する次元削減

中心化(平均0)したデータの\mathbf{w}への射影の二乗が最大になるような\mathbf{w}を求める:

\|\mathbf{Xw}\|^2 = (\mathbf{Xw})^T\mathbf{Xw}=\mathbf{w^T X^T}\mathbf{Xw}
\|\mathbf{w}\|^2 = \mathbf{w^T w} = 1

Lagrange未定乗数を導入:

L(\mathbf{w}, \lambda) = \mathbf{w}^T \mathbf{X}^T \mathbf{X} \mathbf{w} - \lambda (\mathbf{w}^T \mathbf{w} - 1)

このラグランジュ関数を \mathbf{w} で偏微分してゼロとおくと、

\frac{L}{\partial \mathbf{w}} = 2 \mathbf{X}^T \mathbf{X} \mathbf{w} - 2 \lambda \mathbf{w} = \mathbf{0}
\mathbf{X}^T \mathbf{X} \mathbf{w} = \lambda \mathbf{w}

\mathbf{w} は 共分散行列\mathbf{X}^T \mathbf{X} の固有ベクトル、\lambda は対応する固有値となる
この固有値問題を解いて、最大の固有値に対応する固有ベクトルが第一主成分の射影方向


寄与率(Explained Variance Ratio)

  • 各主成分がデータ全体の分散のうちどれだけを説明しているかを示す
\frac{\lambda_i}{\sum_{i=1}^p \lambda_i}

累積寄与率(Cumulative Explained Variance Ratio)

\frac{\sum_{i=1}^{p'}\lambda_i}{\sum_{i=1}^p \lambda_i}\quad (q'\leq q)
from sklearn.decomposition import PCA
import numpy as np

X = np.random.rand(100, 5)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)

print("寄与率:", pca.explained_variance_ratio_)
print("変換後データ形状:", X_pca.shape)

ニューラルネットワーク(Neural Networks)

  • 多層のノードと活性化関数で構成されるモデル

活性化関数

  • ReLU
    $$
    f(x) = \max(0, x)
    $$
  • Sigmoid
    $$
    f(x) = \frac{1}{1 + e^{-x}}
    $$
    出力は0から1の範囲
    勾配消失問題あり
  • tanh
    $$
    f(x) = \tanh(x) = \frac{e^{x} - e^{-x}}{e^{x} + e^{-x}}
    $$
    出力範囲は -1 から 1
import torch
import torch.nn as nn
import torch.optim as optim

class SimpleNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 5)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(5, 1)

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = SimpleNN()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# ダミーデータ
x = torch.randn(3, 10)
y = torch.randn(3, 1)

# 学習ステップ例
optimizer.zero_grad()
output = model(x)
loss = criterion(output, y)
loss.backward()
optimizer.step()

勾配降下法

  • パラメータ w を損失関数 L(w) の勾配に沿って更新:
w \leftarrow w - \eta \nabla L(w)

\eta:学習率


誤差伝播法

  • 多層ネットワークで出力層から入力層へ誤差を逆伝播し、各パラメータの勾配を効率的に計算
\frac{\partial y}{\partial x} = \frac{\partial y}{\partial y} \cdot \frac{\partial y}{\partial a} \cdot \frac{\partial a}{\partial b} \cdot \frac{\partial b}{\partial x}
\delta_j^{(l)} = \sum_k \delta_k^{(l+1)} \frac{\partial u_k^{(l+1)}}{\partial u_j^(l)}

確率勾配降下法

  • データの一部をランダムにバッチとして選び、バッチを用いて勾配降下法を行う
  • 局所解に陥ることを防ぐ

スキップ接続

  • 深いネットワークで勾配消失を防ぐために、層をまたいで入力を後の層に直接渡す
  • 出力 y = F(x) + x

Dropout

  • 過学習防止のため、学習時にランダムに一部のニューロンの結合を削除

CNN(畳み込みニューラルネットワー)

  • 画像や時系列データなどの局所特徴抽出に適したネットワーク

畳み込み演算(Convolution)

入力画像 I とフィルタ K の畳み込み:

S(i,j) = (I * K)(i,j) = \sum_m \sum_n I(i-m, j-n) K(m,n)

パディング

  • 畳み込み時に画像の端を拡張し、ゼロパディングなどを施すことで出力サイズを調整

ストライド

  • フィルタをスライドさせる移動幅
  • 出力サイズの調整や計算効率の効率化を行う

プーリング

  • 特徴マップの空間サイズを縮小し、計算負荷を削減
  • 最大値プーリング、平均値プーリングなどが用いられる

VAE(変分オートエンコーダ)

  • 入力 x を潜在変数 z にエンコードし、デコードする生成モデル

損失関数:

ELBO(x;\theta,\phi) = -\frac{1}{2}\sum^D_{d=1}(x_d-\hat{x_d})^2 + \frac{1}{2}\sum^H_{h=1}(1+\log\delta_n^2-\mu_h^2-\delta_n^2)+condt

第一項:再構成誤差
第二項:正則化項


ベイズ推論

  • パラメータ \theta に対する事後確率を計算して推論を行う:
P(\theta|D) = \frac{P(D|\theta) P(\theta)}{P(D)}

P(D|\theta):尤度
P(\theta):事前確率
P(D):エビデンス


import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)
        self.relu = nn.ReLU()
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.fc = nn.Linear(16 * 16 * 16, 10)  # 例: 32x32画像の場合

    def forward(self, x):
        x = self.pool(self.relu(self.conv1(x)))
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

Discussion