BioinfoにおけるPandas,Matplotlibの基礎
この記事は、Pythonで実践 生命科学データの機械学習 (https://www.yodosha.co.jp/yodobook/book/9784758122634/) の内容を含んでいます。
私は現在バイオインフォマティクス研究室に所属する学生です。
勉強した事をアウトプットする場として用いていますため、何卒ご理解のほどよろしくお願いいたします。
(>人<;)
PyTorchでニューラルネットワークを構築する
⇧前回の記事では、深層学習の基本知識に深掘りを行ないました。
この知識を踏まえて、今回は実際にPuTorchを扱ってみました。
ベースとなる進め方は、
- モデル構築
- 訓練データセットで学習
- 検証データセットで過学習の確認
- データセットのスコアの確認
この手順になっていきます。
以下は学習段階で疑問に思ったこと、より調べたくなったことを記載していきます!
最初に行ったこと、
1️⃣ データ読み込み
2️⃣ クラスラベル追加
3️⃣ データ分割(学習・検証・テスト)
4️⃣ 特徴量・ラベルの分割
5️⃣ データ標準化
データセットの仕上げとして、データの標準化を行いました。
# 標準化する
from sklearn.preprocessing import StandardScaler
標準化(Standardization)の目的と具体的な処理
標準化の目的
標準化(Standardization)は、機械学習モデルの 学習を安定させる ために重要な前処理です。特に、異なるスケールの特徴量を持つデータを扱う際に役立ちます。
1. 学習の安定化
- 特徴量のスケールが異なると、モデルが適切に学習できず、特定の特徴量に偏った重みが学習される 可能性がある。
-
例:
- 身長(150〜180cm)
- 体重(50〜80kg)
- スケールが異なるため、大きな値の特徴(身長)が学習を支配してしまう。
2. 勾配降下法の最適化
- ニューラルネットワークや線形回帰などで使用される 勾配降下法(Gradient Descent) の収束を早める。
- スケールがバラバラだと、学習が非効率になり、最適解への収束が遅くなる。
3. モデルの精度向上
- 多くの機械学習アルゴリズム(ロジスティック回帰・SVM・k-NN・ニューラルネットワークなど)は、データのスケールに敏感。
- 標準化を行うことで、モデルの性能が向上する可能性が高い。
具体的に何をしているのか?
① 平均を 0、標準偏差を 1 にする
標準化では、各特徴量を以下の式に従って変換します:
$$
X' = \frac{X - \mu}{\sigma}
$$
- $(X)$:元の特徴量
- $(\mu) $:その特徴量の平均
- $(\sigma) $:その特徴量の標準偏差
- $(X') $:標準化後の特徴量
② Python(scikit-learn)での標準化の実装
Pythonでは、StandardScaler
を使って簡単に標準化できます。
from sklearn.preprocessing import StandardScaler
sc = StandardScaler() # StandardScalerのインスタンスを作成
# 学習データの平均と標準偏差を計算
sc.fit(X_train)
# トレーニングデータの標準化
X_train_std = sc.transform(X_train)
# 検証データ・テストデータにも同じ変換を適用
X_val_std = sc.transform(X_val)
X_test_std = sc.transform(X_test)
具体例
例:標準化前と標準化後の比較
標準化前
身長 (cm) | 体重 (kg)
---------------------
170 | 65
160 | 55
180 | 75
問題点
身長と体重のスケールが異なる
大きい値(身長)が学習に大きな影響を与える可能性がある
標準化後
身長 (標準化) | 体重 (標準化)
---------------------
0.0 | 0.0
-1.0 | -1.0
1.0 | 1.0
すべての特徴量のスケールが揃い、学習が安定!
標準化が必要なアルゴリズム
- 標準化が重要なモデル
- ロジスティック回帰
- SVM(サポートベクターマシン)
- k近傍法(k-NN)
- ニューラルネットワーク
- 主成分分析(PCA)
- 線形回帰(勾配降下法を用いる場合)
標準化が不要なモデル
- 決定木(Decision Tree)
- ランダムフォレスト(Random Forest)
- XGBoost, LightGBM(勾配ブースティング系)
- k-means(ただし、特徴量のスケールが大きく異なる場合は必要)
コードの再現性と乱数
# コードに再現性を持たせるために乱数を固定
torch.manual_seed(42)
torch.cuda.manual_seed(42)
torch.backends.cudnn.deterministic = True
torch.use_deterministic_algorithms = True
PyTorch で乱数を固定する方法とその目的
なぜ乱数を固定するのか?
機械学習・ディープラーニングのモデルをトレーニングする際、以下の理由から 乱数の固定(シード設定) は重要です:
1. 再現性の確保
同じコードを実行しても、常に同じ結果が得られるようにする。
モデルの学習結果の一貫性を保ち、デバッグや比較を容易にする。
2. 実験の公平性
複数のモデルを比較する際、ランダムな初期値による影響を排除し、公平な比較を可能にする。
3. バグの発見
結果が毎回変わると、予期しない挙動が起きても原因を特定しづらい。
乱数を固定することで、問題の切り分けがしやすくなる。
次に、PyTorchを学ぶ上での基本文法を示す。
PyTorchのDatasetを使ってデータを管理する
1. Dataset
クラスとは?
PyTorchのDataset
クラスを継承して、独自のデータセットを作成します。
これにより、データを簡単に管理でき、DataLoader
を使ってバッチ単位でデータを取得できます。
2. クラスの詳細説明
① 訓練 & 検証データ (TrainValData
)
class TrainValData(Dataset):
def __init__(self, X_data, y_data):
self.X_data = X_data
self.y_data = y_data
def __getitem__(self, index):
return self.X_data[index], self.y_data[index]
def __len__(self):
return len(self.X_data)
X_data
(特徴量) と y_data
(ラベル) を受け取る
__getitem__
で index
番目のデータを取得
__len__
でデータの総数を返す
② テストデータ (TestData
)
class TestData(Dataset):
def __init__(self, X_data):
self.X_data = X_data
def __getitem__(self, index):
return self.X_data[index]
def __len__(self):
return len(self.X_data)
y_data
(ラベル) を持たない
X_data
のみを管理
テストデータを誤って訓練に使用しないための対策
3. データセットの作成
train_data = TrainValData(torch.FloatTensor(X_train_std), torch.FloatTensor(y_train))
val_data = TrainValData(torch.FloatTensor(X_val_std), torch.FloatTensor(y_val))
test_data = TestData(torch.FloatTensor(X_test_std))
torch.FloatTensor(...)
に変換し、PyTorchで扱いやすい形に
train_data
→ 訓練用
val_data
→ 検証用
test_data
→ テスト用(ラベルなし)
PyTorch の学習ステップ
PyTorchを用いた学習プロセスは 5 ステップの繰り返し です!
PyTorch における学習の流れ
機械学習の学習ステップは、次の 5つのステップ に分かれます。
- 順伝播(forward propagation)
- 損失計算(loss calculation)
- 勾配の初期化(zero gradients)
- 誤差逆伝播(backpropagation)
- パラメータ更新(update parameters)
それぞれ わかりやすく 解説していきます!
ステップ1:順伝播(Forward Propagation)
何をするの?
モデルに入力データを与え、ニューラルネットワークを通して 予測値 を計算します。
イメージ
人間の脳に例えると、「問題(入力)」を見て「答え(出力)」を考えるステップです。
PyTorchコード
outputs = model(inputs) # モデルにデータを入力し、出力を得る
ポイント
-
model(inputs)
で、ニューラルネットワークがデータを処理し、予測値を出す。 - 「前回の学習結果をもとに、どのように予測するか」をニューラルネットワークが考える。
ステップ2:損失計算(Loss Calculation)
何をするの?
モデルの予測 (outputs
) と正解ラベル (targets
) を比べて、どれだけ間違っているか(損失) を計算します。
イメージ
テストの答案を採点して、「何点間違えたか?」を測るステップ。
PyTorchコード
loss = loss_function(outputs, targets) # 損失関数で誤差を計算
ポイント
-
loss_function
は、例えば MSE(平均二乗誤差) や クロスエントロピー損失 を使う。 - 目標は 損失(誤差)を小さくすること。
例
もし猫の画像を入力したとき、モデルが 「犬」 と予測したら 損失は大きく なります。
逆に 「猫」 と正しく予測したら、損失は 小さく なります。
ステップ3:勾配の初期化(Zero Gradients)
何をするの?
前回の学習の影響を消して、新しく勾配を計算できるようにします。
イメージ
ホワイトボードに前回の計算式が残っていたら、新しい計算ができませんよね?
だから、一旦ホワイトボードを消す ステップです。
PyTorchコード
optimizer.zero_grad() # 勾配を初期化
ポイント
- PyTorch は 勾配を累積 する性質があるので、毎回リセットが必要!
-
zero_grad()
を忘れると、前の計算の影響で 間違った学習 になる。
ステップ4:誤差逆伝播(Backpropagation)
💡 何をするの?
損失を小さくするために、どの重み(パラメータ)をどれくらい調整すればよいか? を計算します。
イメージ
試験の点数が悪かったとき、「どの問題を間違えたか?」を分析し、次に何を勉強すれば点数が上がるか? を考えるステップ。
PyTorchコード
loss.backward() # 誤差逆伝播で勾配を計算
ポイント
-
.backward()
で、各パラメータが どれくらい損失に影響しているか を計算。 - これにより、「どの重みをどれくらい変更すればよいか」が分かる。
ステップ5:パラメータ更新(Update Parameters)
何をするの?
計算した勾配を使って、モデルのパラメータ(重み)を更新し、より良い予測ができるようにします。
イメージ
間違えた問題を復習して、次は より良い回答ができるように改善 するステップ。
PyTorchコード
optimizer.step() # パラメータ更新
ポイント
-
.step()
を実行すると、学習率 (lr
) に基づいて、パラメータが調整される。 - これにより、次回の予測が より正しくなる可能性 が高まる。
まとめ:PyTorch の学習プロセス
for epoch in range(num_epochs): # 学習を複数回繰り返す
outputs = model(inputs) # (1) 順伝播
loss = loss_function(outputs, targets) # (2) 損失計算
optimizer.zero_grad() # (3) 勾配初期化
loss.backward() # (4) 誤差逆伝播
optimizer.step() # (5) パラメータ更新
PyTorchでニューラルネットワークを作る方法
1. どんなニューラルネットワークを作るの?
今回は 2値分類(Binary Classification) を行う ニューラルネットワーク を定義します!
具体的には、以下の構造を持つ 4層のモデル になります。
層 | 入力特徴量 | 出力特徴量 | 処理内容 |
---|---|---|---|
入力層 | 13 | 32 | 線形変換 + Batch Normalization + ReLU |
隠れ層1 | 32 | 128 | 線形変換 + Batch Normalization + ReLU |
隠れ層2 | 128 | 64 | 線形変換 + Batch Normalization + ReLU |
出力層 | 64 | 1 | 線形変換(シグモイドは不要) |
特徴
-
nn.Sequential
を使って、レイヤーを 簡潔に定義! -
BatchNorm1d
を追加して、学習の安定化! -
ReLU
を使って 活性化関数 を適用! -
Binary Classification
のため、出力は1つの値(0 or 1 の確率)!
2. ニューラルネットワークの定義
では、PyTorchでニューラルネットワークを定義 してみましょう!
torch.nn.Module
を継承した BinaryClassificationNet
クラスを作成します。
import torch.nn as nn
# 各層のノード数を定義
num_layers = 3
num_features = [32, 128, 64]
# ニューラルネットワークの定義
class BinaryClassificationNet(nn.Module):
def __init__(self):
super(BinaryClassificationNet, self).__init__()
# 入力層(13 -> 32)
self.layers1 = nn.Sequential(
nn.Linear(in_features=13, out_features=num_features[0]),
nn.BatchNorm1d(num_features[0]), # バッチ正規化
nn.ReLU(), # 活性化関数
)
# 隠れ層1(32 -> 128)
self.layers2 = nn.Sequential(
nn.Linear(in_features=num_features[0], out_features=num_features[1]),
nn.BatchNorm1d(num_features[1]),
nn.ReLU(),
)
# 隠れ層2(128 -> 64)
self.layers3 = nn.Sequential(
nn.Linear(in_features=num_features[1], out_features=num_features[2]),
nn.BatchNorm1d(num_features[2]),
nn.ReLU(),
)
# 出力層(64 -> 1)
self.layers_out = nn.Linear(in_features=num_features[2], out_features=1)
# 順伝播の処理を定義
def forward(self, x):
x = self.layers1(x)
x = self.layers2(x)
x = self.layers3(x)
x = self.layers_out(x)
return x
コードのポイント
-
__init__()
で 各層を定義 -
forward()
で データを順番に流す処理を記述 -
nn.Sequential
を使って、簡潔に記述
3. まとめ
-
nn.Module
を継承してニューラルネットワークを定義する方法! -
nn.Sequential
を使って コードを簡潔にするテクニック! -
2値分類用のモデル構築 に必要なレイヤー(
Linear
,BatchNorm1d
,ReLU
)の役割! - 順伝播(forward)でデータを流す処理を記述する方法!
学習率0.001のAdamオプティマイザとは?
Adamオプティマイザとは?
Adam(Adaptive Moment Estimation)は、機械学習・深層学習で広く使われている最適化アルゴリズムです。
勾配降下法の一種で、学習の進み方を適応的に調整 する特徴があります。
Adamの主なメリット
- 学習率の調整が不要(自動的に適応)
- SGD(確率的勾配降下法)より収束が速い
- 慣性(Momentum)と適応学習率(Adaptive Learning Rate)を組み合わせている
学習率(Learning Rate)とは?
学習率(lr)は、ニューラルネットワークのパラメータ(重み)をどれくらい更新するかを決めるハイパーパラメータです。
学習率 | 特徴 |
---|---|
大きすぎる(例: 0.1) | 収束が早いが、最適解を飛び越えてしまい、精度が安定しない可能性がある。 |
小さすぎる(例: 0.00001) | 収束が遅くなり、学習に時間がかかる。最適解にたどり着かないことも。 |
適切(例: 0.001) | 速く安定して学習できる。一般的に推奨される値。 |
optim.Adam(model.parameters(), lr=0.001)
の意味
LEARNING_RATE = 0.001
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)
このコードは、以下のような意味を持ちます。
-
model.parameters()
:モデルのパラメータ(重み)を最適化の対象とする -
optim.Adam(...)
:Adamオプティマイザを使用する -
lr=0.001
:学習率を 0.001 に設定(一般的な初期値)
なぜ0.001なのか?
- Adamオプティマイザのデフォルトの学習率が 0.001 であり、一般的に良い結果が得られるため。
- 多くの研究・実験で 最適な初期値 として使われている。
- 必要に応じて
0.0001
や0.01
などに変更してチューニング可能。