ニューラルネットワークと機械学習の基礎:概念からPyTorchによる実装まで
【概要】 ニューラルネットワークは,入力データの重みづけ処理,合計とバイアス調整,活性化関数の適用を行うニューロンがネットワークを形成する機械学習モデルである.PyTorchを活用した実装では,大規模なデータセットを用いた学習により,ニューロン間の結合の重みとバイアスを自動的に最適化し,データの特徴やパターンを獲得する.特に,バックプロパゲーションによる誤差の逆伝播計算と,勾配降下法による誤差の最小化が,学習プロセスにおいて重要な役割を果たす.
【目次】
1. Python のインストールと必要なPythonライブラリのインストール(Windows上)
- Python のインストール
注:既にPython(バージョン3.12を推奨)がインストール済みの場合は,この手順は不要である.
winget(Windowsパッケージマネージャー)を使用してインストールを行う
- Windowsで,コマンドプロンプトを管理者権限で起動する(例:Windowsキーを押し,「cmd」と入力し,「管理者として実行」を選択)
- winget(Windowsパッケージマネージャー)が利用可能か確認する:
winget --version
- Pythonのインストール(下のコマンドにより Python 3.12 がインストールされる).
- 必要なPythonライブラリのインストール
【関連する外部ページ】
【サイト内の関連ページ】
2. ニューラルネットワークの基本構造と仕組み
ニューラルネットワークは,入力データの重みづけ,合計とバイアス,活性化関数の適用を行うニューロンから構成される高度な学習システムである.各ニューロンは複数の入力信号を受け取り,重み付け処理と合計,バイアス調整を行った後,活性化関数によって最終的な出力値を決定する.この出力は,次層のニューロンへの入力として伝播される.
ニューロンの基本処理:
- 入力の重みづけ:各入力信号に対応する重み係数を乗算して重要度を調整する
- 合計とバイアス:重みづけされた入力値の総和にバイアス値を加算して閾値を調整する
- 活性化関数の適用:ReLU活性化関数により,入力が0以下の場合は0,それ以外は入力値をそのまま出力してニューロンの活性度を決定する
Pythonスクリプト例(ニューロンの処理)
# ニューラルネットワークの単一ニューロンの順伝播計算
# 入力、重み、バイアスから活性化値を計算
# 入力値
inputs = [0.3, -0.5, 0.2]
# 重み
weights = [0.1, 0.8, -0.5]
# バイアス
bias = 0.2
# 重み付き和の計算
weighted_sum = 0
# 各入力に対応する重みを掛けて合計
for i in range(len(inputs)):
weighted_sum += inputs[i] * weights[i]
# バイアスを加える
weighted_sum += bias
# ReLU活性化関数による出力計算
# 0以下の場合は0、そうでなければweighted_sumをそのまま出力
if weighted_sum > 0:
output = weighted_sum
else:
output = 0
# 結果を表示
print(f"{inputs} -> {output}")

3. 活性化関数とその役割
活性化関数は,ニューロンの出力特性を決定する重要な要素である.入力信号の重みづけ処理と合計,バイアス調整の結果に適用され,ニューロンの最終的な活性度を決定する.代表的な活性化関数として,ReLUやシグモイド関数が広く使用されている.
特に,ReLU(Rectified Linear Unit)は,以下の優れた特徴を持つ革新的な活性化関数である:
- 入力信号が0未満の場合は出力を0に抑制する
- 入力信号が0以上の場合は,その値をそのまま出力として伝播する
- シンプルな構造でありながら,優れた学習性能を実現する
- 現代のディープラーニングにおいて,標準的な活性化関数として採用されている
Pythonスクリプト例(ReLUとシグモイド)
import math
def relu(x):
"""
ReLU活性化関数
入力が0より大きい場合はそのまま返し、0以下の場合は0を返す
"""
return max(0, x)
def sigmoid(x):
"""
シグモイド活性化関数
入力を0-1の範囲に変換する
"""
return 1 / (1 + math.exp(-x))
# 入力値の設定
x1 = 1
x2 = -1
x3 = 0
# ReLU関数による出力計算
relu_out1 = relu(x1)
relu_out2 = relu(x2)
# シグモイド関数による出力計算
sigmoid_out = sigmoid(x3)
# 結果の表示
print(f"{x1} -> {relu_out1}") # 正の入力
print(f"{x2} -> {relu_out2}") # 負の入力
print(f"{x3} -> {sigmoid_out}") # シグモイド

4. ニューラルネットワークの構造と動作原理
基本構造:ニューラルネットワークは,複数の層から構成される階層的なアーキテクチャを持ち,各層は同種のニューロンで構成されている.個々のニューロンは,入力信号の重みづけ処理,合計とバイアス調整,活性化関数の適用という一連の計算を実行する.
フォワードプロパゲーション:入力データは入力層から出力層へと順方向(フォワード)に伝播する.各層のニューロンは,前層からの入力信号を処理し,その結果を次層のニューロンへと伝達する.
分類のための出力層構造:
- 出力層のニューロン数は,分類対象のクラス数に対応する(例:3クラス分類では3ニューロン)
- 各出力ニューロンの活性度は,0以上の実数値として表現される
- 出力層における活性度の相対的な大小関係により,最終的な分類結果が決定される
分類結果の決定:最も高い活性度を示すニューロンに対応するクラスが,システムの最終的な分類結果として出力される.
プログラムの構成:
- 入力層:2個のニューロンによる入力処理(入力値0.2と0.8を使用)
- 出力層:3個のニューロンによる3クラス分類の実現
- 重み行列:2×3の行列により,各入力から各出力への結合強度を表現
- バイアス:出力層の各ニューロンに対して個別に設定(全て0.1に初期化)
処理の流れ:
- 入力層の各ニューロンの値に重みを掛けて,出力層の各ニューロンへ伝達する
- 出力層の各ニューロンで,入力の重み付き和とバイアスを計算する
- ReLU関数により活性化を行い,負の値を0に変換する
- 最大の出力値を持つニューロンのインデックスが,最終的な分類結果となる
# ニューラルネットワークによる3クラス分類の実装
# 入力層(2ニューロン)から出力層(3ニューロン)への順伝播計算を行う
inputs = [0.2, 0.8] # 入力値
# 入力層から出力層への重み係数(2×3行列)
layer_weights = [
[0.1, 0.4, 0.7], # 入力1からの重み
[0.2, 0.5, 0.8] # 入力2からの重み
]
layer_bias = [0.1, 0.1, 0.1] # 出力層の各ニューロンのバイアス
# 出力層の各ニューロンの出力を計算
output = [0] * 3 # 出力用配列を初期化
for j in range(3): # 出力層の各ニューロンについて
sum = 0
for i in range(2): # 入力層の各ニューロンからの入力を合計
sum += inputs[i] * layer_weights[i][j]
sum += layer_bias[j] # バイアスを加算
output[j] = max(0, sum) # ReLU関数による活性化
print(f"入力: {inputs}")
print(f"出力: {output}")
print(f"分類結果: {output.index(max(output))}") # 最大出力を持つニューロンのインデックスを取得

PyTorchによる実装
PyTorchによる実装は,上記の基本プログラムと同等の計算を行い,同じ結果を効率的に導出する.PyTorchの行列演算機能と組み込みのReLU関数を活用している.
# ニューラルネットワークの3クラス分類プログラム
import torch
# 入力データ(2個のニューロン)
inputs = torch.tensor([0.2, 0.8])
# 重み行列(入力2×出力3の行列、転置して使用)
layer_weights = torch.tensor([
[0.1, 0.4, 0.7], # 1番目の入力からの重み
[0.2, 0.5, 0.8] # 2番目の入力からの重み
]).T # 行列を転置して各出力ニューロンへの重みを行方向に配置
# バイアス(出力層の3ニューロン分)
layer_bias = torch.tensor([0.1, 0.1, 0.1])
# フォワードプロパゲーション
# 1. 入力と重みの行列積で重み付き和を計算
# 2. バイアスを加算
# 3. ReLU関数で活性化(max(0,x))
output = torch.relu(torch.matmul(inputs, layer_weights.T) + layer_bias)
# 結果出力
print(f"入力: {inputs.tolist()}")
print(f"出力: {output.tolist()}")
print(f"分類結果: {torch.argmax(output).item()}") # 最大値を持つインデックスが分類結果

5. バックプロパゲーションと学習メカニズム
バックプロパゲーションは,1986年にRumelhartらによって確立された画期的な学習アルゴリズムである.ネットワークの出力誤差を基に,出力層から入力層へと逆方向に誤差を伝播させ,各層の結合重みとバイアスを最適化する効率的な学習メカニズムを実現する.
- 訓練データを用いてニューラルネットワークを動作させ,出力を得る
- 出力結果と教師信号を比較し,二乗誤差を計算する
- 計算された誤差の勾配を基に,ニューロン間の結合重みとバイアスを最適化し,誤差を段階的に低減する
- 同一の訓練データを反復使用することで,さらなる誤差の低減を実現する
プログラムの構成と動作説明:
- 入力層:2個のニューロンによる特徴量の入力処理(入力値:0.2,0.8)
- 出力層:3個のニューロンによる3クラス分類の実現
- 学習率:0.1(重みの更新幅を制御するパラメータ)
- 教師信号:one-hotベクトル[1,0,0]による正解クラスの指定
- 初期重み:[[0.1, 0.4, 0.7], [0.2, 0.5, 0.8]]による結合強度の初期設定
- 初期バイアス:[0.1, 0.1, 0.1]による閾値の初期設定
処理の流れ:
- フォワード計算でReLU活性化関数を適用し,ネットワークの出力を生成する
- 出力と教師信号の二乗誤差を計算し,損失関数として定義する
- 計算された誤差を基に,重みとバイアスを最適な方向に更新する
- この学習プロセスを繰り返し実行し,ネットワークの性能を向上させる
2つのプログラムは,同一のニューラルネットワーク学習を実現しているが,その実装アプローチが異なる.プログラム1では,重みとバイアスの更新において,ReLUの勾配(出力が正のとき1,負のとき0)を明示的に計算し,forループで処理を行う.一方,プログラム2では,PyTorchのbackward()関数による自動微分で勾配を計算し,効率的な行列演算(torch.matmul)を活用している.この結果,プログラム2はより簡潔で保守性の高い実装を実現している.
プログラム1:単純な実装
"""
ニューラルネットワークの単純な学習実装
入力層(2)→出力層(3)の順伝播型ネットワーク
ReLU活性化関数を使用し、二乗誤差による学習を行う
"""
inputs = [0.2, 0.8]
target = [1, 0, 0] # 正解ラベル(3クラス分類の1番目)
learning_rate = 0.1
# 初期重みとバイアス
layer_weights = [
[0.1, 0.4, 0.7], # 入力1から各出力への重み
[0.2, 0.5, 0.8] # 入力2から各出力への重み
]
layer_bias = [0.1, 0.1, 0.1] # 各出力ノードのバイアス
# フォワード計算:入力値と重みの積和にバイアスを加え、ReLU関数で活性化
output = [0, 0, 0]
for j in range(3): # 各出力ノードについて
sum = 0
for i in range(2): # 各入力との重み付き和を計算
sum += inputs[i] * layer_weights[i][j]
sum += layer_bias[j]
output[j] = max(0, sum) # ReLU関数による活性化
# 誤差計算:教師信号と出力の差
errors = [target[j] - output[j] for j in range(3)]
# 重みとバイアスの更新:勾配降下法による調整
for j in range(3):
for i in range(2):
if output[j] > 0: # ReLUの勾配は出力が正の時のみ1
layer_weights[i][j] += learning_rate * errors[j] * inputs[i]
if output[j] > 0: # バイアスも同様に更新
layer_bias[j] += learning_rate * errors[j]
print(f"誤差: {errors}")
print(f"更新後の重み: {layer_weights}")

プログラム2:PyTorchによる実装
import torch
# 入力データと教師信号の設定
inputs = torch.tensor([0.2, 0.8], requires_grad=True)
target = torch.tensor([1.0, 0.0, 0.0]) # 3クラス分類の正解ラベル
learning_rate = 0.1 # 学習率
# 重みとバイアスの初期化(requires_gradを設定して勾配計算を有効化)
layer_weights = torch.tensor([
[0.1, 0.4, 0.7],
[0.2, 0.5, 0.8]
], requires_grad=True)
layer_bias = torch.tensor([0.1, 0.1, 0.1], requires_grad=True)
# フォワード計算:入力値と重みの行列積にバイアスを加算し、ReLU関数で活性化
output = torch.relu(torch.matmul(inputs, layer_weights) + layer_bias)
# 二乗誤差による損失計算
loss = torch.sum((target - output) ** 2)
# 誤差逆伝播による勾配計算
loss.backward()
# 勾配降下法による重みとバイアスの更新
with torch.no_grad(): # 更新時は勾配計算不要
layer_weights -= learning_rate * layer_weights.grad
layer_bias -= learning_rate * layer_bias.grad
# 次回の学習のために勾配をクリア
layer_weights.grad.zero_()
layer_bias.grad.zero_()
# 学習結果の出力
print(f"誤差: {(target - output).tolist()}")
print(f"更新後の重み: {layer_weights.tolist()}")

6. 機械学習の概要
機械学習は,訓練データを用いて学習し,その結果として知的能力が向上する.訓練データの追加により,さらに知的能力が向上する可能性がある.
機械学習における訓練データの役割:訓練データは,機械学習の学習に使用されるデータである.データを用いた学習により,コンピュータは分類や予測などの知的な能力を獲得する.例えば,画像分類では分類済みの大量のデータを使用する.
- データの準備(目的に応じた訓練データを準備する)
- 学習の実行(データを用いてパターンを学習し,モデルを構築する)
- タスクの実行(新しいデータを処理する)
例えば,画像分類では分類済みの大量のデータを使用する.データの例として,訓練用画像60,000枚,テスト用画像10,000枚がある.
機械学習の特徴は:
- データを用いて知的能力を向上させること
- 自動でデータのパターンを抽出すること
- さまざまなタスクを自動実行すること
応用事例は,画像理解,自然言語処理,予測など多数ある.
機械学習によるプロセスは,基本構造として:
- 入力(28×28ピクセルの画像データを784次元のベクトルに変換)
- 処理(3層ニューラルネットワーク(784-128-64-10)による学習と予測)
- 出力(0から9までの数字の予測)
特徴として,機械学習では,訓練データから自動的にパターンや関連性を学習し,学習結果のモデルを利用して,新しいデータ(未知のデータ)に対してタスクが実行され,人手による規則の記述が不要であることが挙げられる.
MNISTデータセットの概略:
- 手書き数字(0〜9)の画像データセット
- 訓練用60,000枚,テスト用10,000枚
- 各画像は28×28ピクセルのグレースケール
- 画素値は0〜1に正規化
- 各画像に正解ラベル(0〜9)が付属
- 機械学習の入門用データセットとして広く使用
- Yann LeCunらが作成し,1998年に公開
import torch
from torch import nn, optim
from torchvision import datasets, transforms
# デバイスの設定
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# データセットの準備(MNIST)
transform = transforms.Compose([transforms.ToTensor()])
train_data = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_data = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
# データローダーの設定
train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=64, shuffle=False)
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(28*28, 128)
self.fc2 = nn.Linear(128, 64)
self.fc3 = nn.Linear(64, 10)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
# モデルをデバイスに移動
model = SimpleNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
# 学習の実行
epochs = 5
for epoch in range(epochs):
model.train() # 訓練モードの設定
running_loss = 0.0
for images, labels in train_loader:
# データをデバイスに移動
images = images.view(images.shape[0], -1).to(device)
labels = labels.to(device)
optimizer.zero_grad()
output = model(images)
loss = criterion(output, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
# メモリ解放
del loss
if torch.cuda.is_available():
torch.cuda.empty_cache()
print(f"エポック {epoch+1}/{epochs}, 訓練損失: {running_loss/len(train_loader):.4f}")
# モデルの評価
model.eval() # 評価モードの設定
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images = images.view(images.shape[0], -1).to(device)
labels = labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"テストデータにおける正解率: {100 * correct / total:.2f}%")

7. 過学習の概念と対策
過学習の概念と特徴:過学習は,訓練データへの過剰適合により発生する.訓練データから,実在しない特徴やパターンを発見してしまうことが過学習の特徴である.特に訓練データが少ない場合に発生しやすくなる.
過学習の発生条件:
- 60,000枚ある訓練データから10枚だけを使用
- 784×10の大きな重み行列(7,840個のパラメータ)
- データ数に比べてパラメータ数が極端に多い
基本的対策:
- 訓練データの増加(それを可能にするコンピュータの高性能化)
- モデルの複雑さの抑制(層数やニューロン数の適切な設定)
- 検証データによる検証(過学習が無いことの確認)(実際の応用では必須)
技術的対策:(2009年以降に確立された重要技術)
- 非線形性の正規化 (Rectified Nonlinearity, 2009年):活性化関数の改良
- 活性化関数の ReLU (2011年):勾配消失問題の解決
- ドロップアウト:学習時にランダムにニューロンを無効化
- 正則化(L1,L2):重みの大きさに制約を加える
- 学習率の調整:最適な学習速度の制御
- He の初期化:重みの初期値を適切に設定
8. ディープラーニングを支える要素と応用と特徴
ディープラーニングは機械学習の一種であり,多層の人工ニューラルネットワークを使用してデータから学習し,複雑なタスクを実行する技術である.「ディープ」という名称は,多層のニューラルネットワークを使用することに由来する.
ディープラーニングは,画像認識,自然言語処理,音声認識など,多様なタスクで高い性能を発揮することから広く利用されている.これを支える要素には,活性化関数(ReLUなど),ドロップアウトや初期化手法,大規模データの活用,高性能コンピュータの発展,データ拡張技術などがある.
また,機械学習の3つの特徴は,情報の抽出(データからパターンや関係性を自動で抽出する能力),簡潔さ(従来は人間が設定していたルールを自動生成可能),限界の超越(従来手法では困難だった課題の解決が可能)である.
9. ニューラルネットワークの学習プロセスとまとめ
学習プロセスでは,訓練データによりニューラルネットを動作させる,結果と正解を照合し,誤差を得る,ニューロン間の結合の重みとバイアスを調整し,誤差を減らすという手順を実行する.
このとき,同じ訓練データを繰り返し使用することが重要である.なぜなら,訓練データを1回使っただけでは,学習不足の場合があるためである.同じ訓練データを繰り返し使用することで,誤差をさらに減らすことができ,1回,2回,3回,4回と進むにつれて誤差が減少することが期待できるという特徴がある.
ニューラルネットワークのまとめとして,単純な原理で動作し,ニューロンは複数の入力を受け取り,結合の重み,バイアス,活性化関数を用いた処理を行うという特徴がある.また,フォワードプロパゲーション:入力から出力の方向へ一方向にデータが流れるという性質を持ち,結合の重みとバイアスを調整して,望みの出力を実現する.これはデータを用いた学習により,結合の重みとバイアスを適切に調整することで達成される.