Open24

生成AIを使ってAIを学ぶ(コードが合ってるかは検証してない)

nixgemnixgem

※自分用メモ、何の話かは何となくわかる人にはわかるはず。

ベイズ推定とマルコフ決定過程(MDP)は異なる目的や応用範囲を持つ統計および機械学習の手法である。

ベイズ推定

ベイズ推定は、データに基づいて確率分布やパラメータを推定するための手法です。ベイズの定理を基礎にしており、事前分布(先験的な信念)と観測データから得られる尤度を組み合わせて事後分布を計算する。

nixgemnixgem

マルコフ決定過程(MDP)

マルコフ決定過程は、意思決定のための数学的フレームワークで、エージェントが一連の行動を選択しながら環境と相互作用するプロセスをモデル化する。
MDPは、以下の要素で構成される。

  • State
  • Action
  • 遷移確率 Transition Probability
  • 報酬関数 Reward
    MDPでは、各状態での行動選択が次の状態や報酬にどのような影響を与えるかをモデル化し、最適な方策(ポリシー)を見つけることが目的
nixgemnixgem

MDPとMCMCとの違い

MCMCは、複雑な確率分布からサンプリングを行うための計算手法です。特に、直接解析的に計算することが困難な事後分布からサンプルを得るために使用する。

あくまでMCMCはツールである。

新しいサンプルは現在の状態に依存する形で生成され、連鎖的に生成される。

モンテカルロ法
乱数を使ったサンプリング手法

MDPとMCMC

遷移確率や報酬関数が不確実である場合、ベイズ推定を使ってこれらの不確実性を扱うことがある
→遷移確率や報酬関数の事後分布をサンプリングして最適んなポリシーを導出する

強化学習

MCMCを使って方策最適化やモデルパラメータの推定を行うことがある。

nixgemnixgem

ナイーブベイズ

確率に基づいた分類アルゴリズムの一つ

UseCase

  • テキスト分類
  • スパムフィルタリング
事後確率=P(A|B)=\dfrac{P(B|A) \cdot P(A)}{P(B)}=\dfrac{尤度 \cdot 事前確率}{事象Bが起こる確率}

Example: spam mail

テキストだけで判定しているわけもなく、送信者や件名などから総合的に判断してるらしい(?)

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB

# トレーニングデータとラベル
texts = ["I love this movie", "This movie is terrible", "I like this film", "This film is awful"]
labels = [1, 0, 1, 0]  # 1: positive, 0: negative

# テキストをベクトルに変換
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(texts)

# ナイーブベイズモデルの訓練
model = MultinomialNB()
model.fit(X, labels)

# 新しいテキストの分類
new_texts = ["I enjoy this movie", "This film is bad"]
new_X = vectorizer.transform(new_texts)
predictions = model.predict(new_X)

print(predictions)  # 出力: [1, 0]
nixgemnixgem

Kullback-Leibler Divergence

ダイバージェンスは、確率分布間の差異を測る指標で、主に情報理論や統計学で使用される。
KLダイバージェンスは、ある確率分布
Pが他の確率分布Q とどれだけ異なるかを測定する

性質として
非対称性と非負性
例)
情報損失の測定。真の分布への近さ
予測分布と真の分布の差異を最小化したい

import numpy as np
from scipy.stats import entropy

P = [0.4, 0.6]
Q = [0.5, 0.5]

kl_divergence = entropy(P, Q)
print("KL Divergence:", kl_divergence)
nixgemnixgem

Jensen-Shannon Divergence Generalization

JSダイバージェンスは分布の類似性を測るための対称的な指標

import numpy as np
from scipy.spatial.distance import jensenshannon

# 仮のテーブルデータのカテゴリカル分布
data1 = [50, 30, 20]  # カテゴリ A, B, C の出現数
data2 = [40, 35, 25]  # 別の期間のカテゴリ A, B, C の出現数

# 分布を確率に変換
p = np.array(data1) / np.sum(data1)
q = np.array(data2) / np.sum(data2)

# JSダイバージェンスの計算
js_divergence = jensenshannon(p, q)
print("JS Divergence:", js_divergence)
nixgemnixgem

UseCase

  • カテゴリカルデータの比較
  • モデルの評価
  • 異常検知
    (情報圧縮や伝送の過程での情報損失を評価するといったこともあるらしい。)

マーケティング戦略の効果を評価する
カテゴリに対するユーザの分布が時間とともに変化するかどうかを確認する

nixgemnixgem

注意点

  • 入力データが確率として正規化されてないとダメ
  • 0を含むとKLはおかしなことになるので、小さな値epsilonを加えることがあるとのこと
nixgemnixgem

情報理論には他にもいくつかの重要なエントロピーの概念がある。
エントロピーは情報理論の基本概念で、確率分布の不確実性を測る尺度。

エントロピーは、確率分布 P の不確実性を測定します。具体的には、次のように定義される

-\sum P(x) \log{P(x)}

条件付きエントロピーは、あるランダム変数Y が与えられたときのランダム変数X の不確実性を測定する。

結合エントロピーは、2つのランダム変数X,Yの共同の不確実性を測定

相互情報量は、2つのランダム変数 X と Y がどれだけ情報を共有しているかを測定する。

クロスエントロピー
真の分布Pと予測分布Qの間の不確実性

H(P,Q)=-\sum P \log Q
nixgemnixgem

理解するには
ある事象 x が発生する確率
P(x) が小さいほど、その事象が発生したときに得られる情報は多くなります。これは直感的に、「珍しい出来事は多くの情報をもたらす」という考えに基づいています。

エントロピーは、確率分布全体の不確実性を測るため、各事象の情報量の期待値として定義される

事象xが発生する確率Pの情報量は-log_2 P(x)

情報量の期待値がエントロピー

公平なコインのエントロぴーは1ビット

情報量

利点1 非負
P(x)は0から1の間を取るので、対数関数を使うと-logPが非負

利点2 加法性
対数の底は3つある
2だとビット
eだとナット(nat)→熱力学や統計力学
10はハートレー(hartley)→そもそも使われない

qubitを調べてみたら混乱したので省略しよう

nixgemnixgem

1948 A Mathematical Theory of Commnuication
ここでエントロピーの話が出てきた

ちなみに物理のエントロピーはちょっと別
系の無秩序さや不規則性の尺度らしい。
エネルギーや熱の散逸

情報量や不確実性に関連する情報理論のエントロピーとはなんか違う。

nixgemnixgem

エントロピーとダイバージェンスはどっちかでいいんじゃないかと聞いてみたら
相互に補完するといいだした
エントロピーってそもそも単一の分布
ダイバージェンスは2つの分布の差異や距離
だから全然ちゃうな。。。と

ちなみに3つもあるみたい。。。

共通情報
Mutual Information
多変量相関
KLの一般化(特定の応用領域
JSの一般化
etc..

nixgemnixgem

バイアスとバリアンス(分散)は、モデルの性能を評価し、過学習(overfitting)と過少学習(underfitting)のトレードオフを理解するための重要な概念です。これらは、汎化誤差(generalization error)を分解して、モデルの誤差の原因を詳細に分析するために使用されます。

汎化誤差は
バイアスの2乗+バリアンス+Irreducible(ノイズ)

バイアス

モデルが真のデータ生成過程をどれだけ近似しているかを示す指標です。バイアスが大きいと、モデルはデータ生成過程をうまく捉えられていないため、過少学習(underfitting)の状態にあります。

バリアンス

モデルがトレーニングデータに対してどれだけ敏感かを示す指標です。バリアンスが大きいと、モデルはトレーニングデータのノイズにも適合しやすくなり、過学習(overfitting)の状態にあります。

不確実性(Irreducible Error):

モデルで捉えることができないデータ自体のノイズや偶然の要素による誤差です。この部分はどんなモデルでも減らすことができません。

モデルの複雑さが増すと、バイアスは減少しますが、バリアンスが増加する傾向にあります。一方、モデルの複雑さが減ると、バイアスは増加しますが、バリアンスが減少します。この関係を「バイアス・バリアンスのトレードオフ」と呼びます。

単純なモデル
→バイアスとバリアンスのバランスをとる
→正則化を使ってバリアンスを減らす
→クロスバリデーションによって汎化性能を評価する
→バギングやブースティングを使ってバリアンスとバイアスどっちも減らしてロバスト

nixgemnixgem

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
from sklearn.metrics import mean_squared_error

# データ生成
np.random.seed(0)
n_samples = 30
X = np.sort(np.random.rand(n_samples))
y = np.sin(2 * np.pi * X) + np.random.normal(scale=0.1, size=n_samples)

# トレーニングデータとテストデータに分割
X_train, X_test = X[:n_samples // 2], X[n_samples // 2:]
y_train, y_test = y[:n_samples // 2], y[n_samples // 2:]

# モデルのトレーニングと予測
degrees = [1, 3, 10]
plt.figure(figsize=(15, 5))

for i, degree in enumerate(degrees):
    model = make_pipeline(PolynomialFeatures(degree), LinearRegression())
    model.fit(X_train[:, np.newaxis], y_train)
    y_pred = model.predict(X_test[:, np.newaxis])

    # プロット
    plt.subplot(1, len(degrees), i + 1)
    plt.scatter(X_train, y_train, label='Train data')
    plt.scatter(X_test, y_test, label='Test data')
    plt.plot(X_test, y_pred, label=f'Degree {degree} prediction')
    plt.title(f'Degree {degree}\nMSE: {mean_squared_error(y_test, y_pred):.2f}')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()

plt.tight_layout()
plt.show()
nixgemnixgem

リッジ回帰、ラッソ回帰

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
from sklearn.metrics import mean_squared_error

# データ生成
np.random.seed(0)
n_samples = 30
X = np.sort(np.random.rand(n_samples))
y = np.sin(2 * np.pi * X) + np.random.normal(scale=0.1, size=n_samples)

# トレーニングデータとテストデータに分割
X_train, X_test = X[:n_samples // 2], X[n_samples // 2:]
y_train, y_test = y[:n_samples // 2], y[n_samples // 2:]

# モデルのトレーニングと予測
degrees = [1, 3, 10]
plt.figure(figsize=(15, 5))

for i, degree in enumerate(degrees):
    model = make_pipeline(PolynomialFeatures(degree), LinearRegression())
    model.fit(X_train[:, np.newaxis], y_train)
    y_pred = model.predict(X_test[:, np.newaxis])

    # プロット
    plt.subplot(1, len(degrees), i + 1)
    plt.scatter(X_train, y_train, label='Train data')
    plt.scatter(X_test, y_test, label='Test data')
    plt.plot(X_test, y_pred, label=f'Degree {degree} prediction')
    plt.title(f'Degree {degree}\nMSE: {mean_squared_error(y_test, y_pred):.2f}')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()

plt.tight_layout()
plt.show()
nixgemnixgem

アンサンブル学習

  • Bootstrap Aggregating => バギング
  1. トレーニングデータからブートストラップサンプリング(重複を許したランダムサンプリング)によって複数のデータセットを作成します。
  2. 各サブデータセットで同じモデル(例えば、決定木)をトレーニングします。
  3. すべてのモデルの予測結果を集約(例えば、分類では多数決、回帰では平均)して最終的な予測を行います。
    バギングはモデルのバリアンスを減少させる効果があります。個々のモデルが過学習しやすい場合でも、バギングにより全体の予測が安定する傾向にあります。
    各モデルの学習は独立して行われるため、並列計算が可能です。

ランダムフォレスト

決定木をベースとしたもの

  1. バギングの手法で、ブートストラップサンプリングを使って複数のデータセットを作成します。
  2. 各サブデータセットで決定木をトレーニングしますが、各ノードの分岐条件を選ぶ際に、全ての特徴量の中からランダムに選ばれた一部の特徴量だけを使って分岐を決定します。
  3. すべての決定木の予測結果を集約(多数決や平均)して最終的な予測を行います。

特徴量のランダムサブセットを使用することで、モデルの多様性を増やし、バリアンスをさらに減らすことができます。

過学習のリスクを抑えつつ、強力な予測性能を持つモデルが構築可能です。

ブースティング

手順:
最初のモデルをトレーニングし、予測を行います。
次のモデルは、前のモデルが間違えたデータポイントに対してより重みを置いてトレーニングします(誤分類されたデータに対するペナルティを強化)。
このプロセスを繰り返し、最終的に全てのモデルの結果を加重平均などで統合して予測を行います。

特長:
ブースティングは主にバイアスを減少させる効果があります。各ステップで前のモデルの誤りを修正していくため、全体として高い予測精度を達成します。
過学習のリスクが高い場合もありますが、慎重に調整することで非常に高性能なモデルを作成できます。

nixgemnixgem

ベースとしないバギングというのは結局
SVM, knn, 線形回帰, ニューラルネットワーク, ナイーブベイズ
などがあるらしい。

nixgemnixgem

パーセプトロンの基礎
パーセプトロンは、1950年代後半にフランク・ローゼンブラット(Frank Rosenblatt)によって提案された、最も単純なタイプのニューラルネットワークモデルです。主に次のような特徴があります:

線形分類:

パーセプトロンは、入力データを線形境界で分類するモデルです。出力は通常、バイナリ(0か1)です。
単一層の構造:

パーセプトロンは単一の計算ユニット(ニューロン)で構成され、入力に対して重み付き和を計算し、その結果に基づいて出力を決定します。
収束定理:

パーセプトロンの収束定理は、線形に分離可能なデータセットに対して、適切な重みを見つけることができると保証するものです。ただし、これは線形分離可能な場合にのみ適用されます。
マージン:

マージンとは、データポイントと決定境界(線形境界)との距離を指します。大きなマージンは、より安定した分類器を意味しますが、パーセプトロン自体はマージンを最大化するように設計されていません。
現代のニューラルネットワークにおける位置付け
パーセプトロンの概念は、より複雑なニューラルネットワークモデル(例えば、マルチレイヤーパーセプトロン(MLP)やディープニューラルネットワーク)の基礎を形成しますが、以下の点で現代の深層学習において直接的には使われません:

1非線形性の導入:
パーセプトロンは線形分類器であり、線形に分離可能な問題にのみ適用されます。現代のニューラルネットワークでは、非線形活性化関数(ReLUやシグモイドなど)を使用することで、より複雑な関係を学習することができます。

2収束定理の限定性:
収束定理は線形に分離可能なデータに対してのみ適用されます。深層学習では、非線形関数や多層構造を用いるため、このような定理は直接適用されません。

3マージンの最大化:
サポートベクターマシン(SVM)のようなアルゴリズムでは、マージンの最大化が重要な役割を果たしますが、パーセプトロンではそれが目的ではありません。現代のニューラルネットワークでは、正則化やドロップアウトのような技法を用いて、過学習を防ぎ、より良い汎化性能を持つモデルを作成します。

nixgemnixgem

SVDの使い所
次元削減(PCA)
モデル圧縮(重み行列の分解)
モデルのパラメータ行列を正則化
レコメンドシステムにおける評価行列の補完

nixgemnixgem

PCA=主成分分析とFA=因子分析は構造解析、次元削減
(なんか次元を減らす話ばかりだなぁ。。。)

因子分析は、観測データから潜在因子を学習する過程があり、これは機械学習における学習プロセスと多くの共通点があります。単なる行列計算ではなく、データの背後にある構造を理解し、モデルに適合させるための反復的なプロセスを含む点で、より学習に近い方法

nixgemnixgem

SHAP

import torch
import torch.nn as nn
import torch.optim as optim

# シンプルなニューラルネットワークの定義
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(10, 5)
        self.fc2 = nn.Linear(5, 1)

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

# モデルのインスタンス作成
model = SimpleNN()

# モデルの学習などを行う
# optimizer = optim.SGD(model.parameters(), lr=0.01)
# loss_fn = nn.MSELoss()
# ...
import shap

# モデルをSHAPのDeepExplainerに渡す
explainer = shap.DeepExplainer(model, background_data)

# 入力データに対してSHAP値を計算
shap_values = explainer.shap_values(input_data)

# SHAP値を可視化
shap.summary_plot(shap_values, input_data)
nixgemnixgem

敵対的ドメイン適応

import torch
import torch.nn as nn
import torch.optim as optim

class FeatureExtractor(nn.Module):
    def __init__(self):
        super(FeatureExtractor, self).__init__()
        # シンプルなCNNベースの特徴抽出ネットワーク
        self.conv = nn.Sequential(
            nn.Conv2d(1, 32, kernel_size=5),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 48, kernel_size=5),
            nn.ReLU(),
            nn.MaxPool2d(2),
        )
        self.fc = nn.Sequential(
            nn.Linear(48 * 4 * 4, 100),
            nn.ReLU(),
        )

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

class Classifier(nn.Module):
    def __init__(self):
        super(Classifier, self).__init__()
        self.fc = nn.Sequential(
            nn.Linear(100, 50),
            nn.ReLU(),
            nn.Linear(50, 10),
        )

    def forward(self, x):
        return self.fc(x)

class DomainDiscriminator(nn.Module):
    def __init__(self):
        super(DomainDiscriminator, self).__init__()
        self.fc = nn.Sequential(
            nn.Linear(100, 50),
            nn.ReLU(),
            nn.Linear(50, 1),
            nn.Sigmoid()
        )

    def forward(self, x):
        return self.fc(x)
# モデルの初期化
feature_extractor = FeatureExtractor()
classifier = Classifier()
domain_discriminator = DomainDiscriminator()

# オプティマイザーの定義
optimizer_feature = optim.Adam(feature_extractor.parameters(), lr=0.001)
optimizer_classifier = optim.Adam(classifier.parameters(), lr=0.001)
optimizer_discriminator = optim.Adam(domain_discriminator.parameters(), lr=0.001)

# 損失関数の定義
criterion_classifier = nn.CrossEntropyLoss()
criterion_discriminator = nn.BCELoss()

# 訓練ループ
for epoch in range(num_epochs):
    for (source_data, source_labels), (target_data, _) in zip(source_loader, target_loader):
        # ステップ1: ソースドメインでの特徴抽出と分類
        features = feature_extractor(source_data)
        outputs = classifier(features)
        loss_classifier = criterion_classifier(outputs, source_labels)

        # ステップ2: ドメイン判別器の訓練
        domain_labels = torch.cat([torch.ones(source_data.size(0)), torch.zeros(target_data.size(0))])
        features_combined = torch.cat([features, feature_extractor(target_data)])
        domain_outputs = domain_discriminator(features_combined.detach())
        loss_discriminator = criterion_discriminator(domain_outputs, domain_labels)

        # ステップ3: 特徴抽出ネットワークの訓練(逆伝播)
        loss_domain_adv = criterion_discriminator(domain_discriminator(features), torch.zeros(source_data.size(0)))

        # オプティマイザーのステップ
        optimizer_feature.zero_grad()
        optimizer_classifier.zero_grad()
        optimizer_discriminator.zero_grad()

        loss_classifier.backward(retain_graph=True)
        optimizer_classifier.step()

        loss_discriminator.backward()
        optimizer_discriminator.step()

        loss_domain_adv.backward()
        optimizer_feature.step()

    print(f'Epoch {epoch}/{num_epochs}, Classifier Loss: {loss_classifier.item()}, Discriminator Loss: {loss_discriminator.item()}')
nixgemnixgem

エッジコンピューティング

  • ネットワーク
  • 分散システム

クラウドコンピューティング

  • Docker/K8S
  • CloudPlatformとの統合
nixgemnixgem

枝刈り

(決定木のものは過学習対策になるが、NNでは計算量削減のほうが目的)
Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman Coding

  • sparse
  • 剪定アルゴリズム

蒸留

Distilling the Knowledge in a Neural Network

  • cross entropy loss
  • softmax 温度スケーリング
    • ソフトマックスの出力に温度とよばれるパラメータ

量子化

  • 固定小数点・浮動小数点
  • 量子化誤差とその影響