「ニューラルネットワークって聞くけど、どうやって学習してるの?」
「活性化関数って何?なんで必要なの?」
「ReLUとかシグモイドとか、種類が多すぎて分からない…」
機械学習やディープラーニングを勉強していると、必ず出会うのが「活性化関数」という概念です。
実は、活性化関数がなければ、ニューラルネットワークは単純な一次関数にしかなりません。複雑なパターンを学習できるのは、活性化関数のおかげなんです。この記事では、活性化関数の基本から使い分けまで、初心者の方にも分かりやすく解説します。
読み終わる頃には、AIの「知性の源」が理解できますよ!
活性化関数とは?ニューロンの「スイッチ」

活性化関数とは、ニューラルネットワークの各ニューロン(神経細胞)で、入力信号を変換して出力する関数のこと。
英語では「Activation Function」と呼ばれます。
ニューロンの仕組み
ニューラルネットワークは、脳の神経細胞を模した構造です。
ニューロンの動作:
- 複数の入力を受け取る
- 各入力に重み(重要度)を掛けて合計する(重み付き和)
- 活性化関数に通す
- 結果を次のニューロンに渡す
実例:
入力1 × 重み1 = 0.5
入力2 × 重み2 = 0.3
入力3 × 重み3 = 0.2
合計 = 1.0
↓ 活性化関数(例:ReLU)を通す
出力 = 1.0(そのまま)
活性化関数は、ステップ3で登場します。
生物学的な類似
実際の脳のニューロンも、入力信号がある閾値を超えると「発火」(信号を送る)します。
活性化関数は、この「発火するかどうか」を決める仕組みを数学的に表現したものなんです。
なぜ活性化関数が必要なのか?
「単純に足し算と掛け算だけじゃダメなの?」と思いますよね。実は、ダメなんです。
理由1:非線形性の導入
活性化関数がないと、ニューラルネットワークは線形変換の組み合わせになります。
問題点:
線形変換をいくら重ねても、結局は一つの線形変換にまとまってしまいます。
実例:
f(x) = 2x
g(x) = 3x
g(f(x)) = g(2x) = 3(2x) = 6x
これは単純な「6x」と同じです。複雑な層を重ねても意味がありません。
活性化関数があると:
非線形な変換が可能になり、複雑なパターンを学習できます。
理由2:複雑な境界の表現
実世界の問題は、単純な直線では分類できません。
実例:
- 画像認識:「猫」と「犬」を区別
- 音声認識:複雑な音のパターン
- 自然言語処理:文章の意味理解
これらには、曲線的な複雑な境界が必要です。活性化関数が、この複雑さを実現します。
比喩で理解
活性化関数なし:
定規で直線しか引けない画家。複雑な絵は描けません。
活性化関数あり:
曲線も描ける画家。あらゆる形を表現できます。
主要な活性化関数の種類
それぞれの活性化関数の特徴を見ていきましょう。
1. Sigmoid(シグモイド関数)
数式:
σ(x) = 1 / (1 + e^(-x))
特徴:
- 出力範囲:0〜1
- S字カーブの形
- 確率として解釈しやすい
グラフの形:
1.0 | -------
| /
0.5 | /
| /
0.0 | ---/
|_________________
負 0 正
メリット:
- 出力が0〜1なので、確率として解釈できる
- 滑らかな曲線
デメリット:
- 勾配消失問題:入力が大きいまたは小さいと、勾配がほぼゼロになる
- 計算コストが高い(指数関数を使用)
- 出力が常に正の値(0〜1)
使用場面:
- 出力層(二値分類)
- 確率を求めたいとき
実装例(Python):
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 使用例
x = np.array([-2, -1, 0, 1, 2])
print(sigmoid(x))
# 出力: [0.119 0.269 0.5 0.731 0.881]
2. tanh(ハイパボリックタンジェント)
数式:
tanh(x) = (e^x - e^(-x)) / (e^x + e^(-x))
特徴:
- 出力範囲:-1〜1
- S字カーブ(Sigmoidと似ている)
- ゼロ中心(平均が0に近い)
グラフの形:
1.0 | -------
| /
0.0 |______/________
| /
-1.0 | ---/
|_________________
負 0 正
メリット:
- Sigmoidより勾配が強い
- ゼロ中心なので、学習が安定しやすい
デメリット:
- 勾配消失問題は依然として存在
- 計算コストが高い
使用場面:
- 隠れ層(中間層)
- RNN(再帰型ニューラルネットワーク)
実装例:
import numpy as np
def tanh(x):
return np.tanh(x)
# 使用例
x = np.array([-2, -1, 0, 1, 2])
print(tanh(x))
# 出力: [-0.964 -0.762 0. 0.762 0.964]
3. ReLU(Rectified Linear Unit)
数式:
ReLU(x) = max(0, x)
つまり、正の値はそのまま、負の値は0にする。
グラフの形:
| /
| /
| /
| /
| /
____|/___________
0
メリット:
- 計算が超高速(単純な比較だけ)
- 勾配消失問題が軽減される
- スパース性(多くのニューロンが0になる)
- 現在最も人気
デメリット:
- Dying ReLU問題:ニューロンが0を出力し続けて学習が止まる
- 負の入力で勾配が0
使用場面:
- 隠れ層(最も一般的)
- CNN(畳み込みニューラルネットワーク)
実装例:
import numpy as np
def relu(x):
return np.maximum(0, x)
# 使用例
x = np.array([-2, -1, 0, 1, 2])
print(relu(x))
# 出力: [0 0 0 1 2]
4. Leaky ReLU(リーキーReLU)
数式:
Leaky ReLU(x) = max(0.01x, x)
負の値を完全に0にせず、小さな傾きを持たせます。
グラフの形:
| /
| /
| /
| /
_/ / |/
0
メリット:
- Dying ReLU問題を軽減
- 負の入力でも勾配がある
デメリット:
- 係数(0.01など)の調整が必要
使用場面:
- ReLUで問題が起きたとき
- 画像生成モデル(GAN)
実装例:
import numpy as np
def leaky_relu(x, alpha=0.01):
return np.where(x > 0, x, alpha * x)
# 使用例
x = np.array([-2, -1, 0, 1, 2])
print(leaky_relu(x))
# 出力: [-0.02 -0.01 0. 1. 2. ]
5. ELU(Exponential Linear Unit)
数式:
ELU(x) = x (x > 0の場合)
ELU(x) = α(e^x - 1) (x ≤ 0の場合)
メリット:
- 負の値でも勾配がある
- ゼロ中心に近い出力
- Dying ReLU問題がない
デメリット:
- 計算コストがやや高い(指数関数使用)
実装例:
import numpy as np
def elu(x, alpha=1.0):
return np.where(x > 0, x, alpha * (np.exp(x) - 1))
# 使用例
x = np.array([-2, -1, 0, 1, 2])
print(elu(x))
# 出力: [-0.865 -0.632 0. 1. 2. ]
6. Swish(SiLU)
数式:
Swish(x) = x × sigmoid(x)
特徴:
- Googleが提案した比較的新しい関数
- 滑らかな曲線
- ReLUより性能が良いことが多い
メリット:
- 多くのタスクでReLUを上回る性能
- 滑らかで微分可能
デメリット:
- 計算コストがやや高い
実装例:
import numpy as np
def swish(x):
return x * (1 / (1 + np.exp(-x)))
# 使用例
x = np.array([-2, -1, 0, 1, 2])
print(swish(x))
# 出力: [-0.238 -0.269 0. 0.731 1.762]
7. Softmax(ソフトマックス)
数式:
Softmax(xi) = e^xi / Σ(e^xj)
特徴:
- 出力の合計が1になる
- 多クラス分類の出力層で使用
実例:
入力: [2.0, 1.0, 0.1]
↓
出力: [0.659, 0.242, 0.099]
合計 = 1.0
これは「65.9%の確率でクラス1、24.2%でクラス2…」と解釈できます。
使用場面:
- 出力層(多クラス分類)
実装例:
import numpy as np
def softmax(x):
exp_x = np.exp(x - np.max(x)) # 数値安定性のため
return exp_x / exp_x.sum()
# 使用例
x = np.array([2.0, 1.0, 0.1])
print(softmax(x))
# 出力: [0.659 0.242 0.099]
活性化関数の選び方

どの活性化関数を使えばいいのでしょうか?
隠れ層(中間層)での推奨
第一選択:ReLU
- 最も一般的
- 高速で効果的
- まず試すべき関数
ReLUで問題が起きたら:
- Leaky ReLU
- ELU
- Swish
出力層での推奨
二値分類(0か1か):
- Sigmoid
多クラス分類(複数のクラスから一つ):
- Softmax
回帰問題(数値予測):
- 活性化関数なし(線形)
- または、出力範囲に応じてSigmoidやtanh
タスク別の推奨
画像認識(CNN):
- 隠れ層:ReLU、Leaky ReLU
- 出力層:Softmax(分類)
自然言語処理(RNN、Transformer):
- 隠れ層:tanh、ReLU、GELU
- 出力層:Softmax
生成モデル(GAN):
- 生成器:Leaky ReLU、tanh
- 識別器:Leaky ReLU
勾配消失問題と勾配爆発問題
活性化関数を選ぶ上で重要な概念です。
勾配消失問題(Vanishing Gradient)
問題:
ニューラルネットワークが深くなると、誤差の勾配(微分値)が徐々に小さくなり、初期層の学習が進まなくなる現象。
原因:
Sigmoidやtanhでは、入力が大きい・小さいときに勾配がほぼ0になります。
実例:
層10の勾配: 0.8
層9の勾配: 0.8 × 0.8 = 0.64
層8の勾配: 0.64 × 0.8 = 0.51
...
層1の勾配: ほぼ0(学習が進まない)
解決策:
- ReLUファミリーを使う
- Batch Normalizationを導入
- 残差接続(ResNet)を使う
勾配爆発問題(Exploding Gradient)
問題:
勾配が指数関数的に大きくなり、重みが発散してしまう現象。
解決策:
- 勾配クリッピング(勾配の上限を設定)
- 適切な重みの初期化
- Batch Normalization
PyTorchでの実装例
実際のディープラーニングフレームワークでの使い方です。
基本的な使い方
import torch
import torch.nn as nn
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.fc1 = nn.Linear(784, 128)
self.fc2 = nn.Linear(128, 64)
self.fc3 = nn.Linear(64, 10)
# 活性化関数の定義
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
def forward(self, x):
x = self.fc1(x)
x = self.relu(x) # ReLUを適用
x = self.fc2(x)
x = self.relu(x) # ReLUを適用
x = self.fc3(x)
# 出力層(多クラス分類なのでSoftmaxは損失関数側で)
return x
様々な活性化関数
# ReLU系
relu = nn.ReLU()
leaky_relu = nn.LeakyReLU(negative_slope=0.01)
elu = nn.ELU(alpha=1.0)
# Sigmoid、tanh
sigmoid = nn.Sigmoid()
tanh = nn.Tanh()
# Swish(SiLU)
silu = nn.SiLU()
# Softmax
softmax = nn.Softmax(dim=1)
関数形式での使用
import torch.nn.functional as F
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.fc1 = nn.Linear(784, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = F.relu(self.fc1(x)) # 関数形式
x = self.fc2(x)
return x
よくある誤解
活性化関数について、よくある勘違いを解説します。
誤解1:活性化関数は一つだけ使う
真実:
層ごとに異なる活性化関数を使えます。実際、出力層と隠れ層では別の関数を使うことが一般的です。
誤解2:ReLUが常に最善
真実:
ReLUは万能ではありません。タスクやデータによっては、他の関数の方が良い結果を出すこともあります。
誤解3:新しい関数ほど良い
真実:
SwishやMishなどの新しい関数は、特定のタスクでは優れていますが、常にReLUより良いわけではありません。計算コストとのトレードオフを考える必要があります。
実験:活性化関数の比較

簡単な実験で違いを見てみましょう。
問題設定
XOR問題(非線形な問題)を解く
データ:
入力: (0,0) → 出力: 0
入力: (0,1) → 出力: 1
入力: (1,0) → 出力: 1
入力: (1,1) → 出力: 0
コード例
import torch
import torch.nn as nn
import torch.optim as optim
# データ
X = torch.tensor([[0,0], [0,1], [1,0], [1,1]], dtype=torch.float32)
y = torch.tensor([[0], [1], [1], [0]], dtype=torch.float32)
# モデル(ReLU使用)
class XORNet(nn.Module):
def __init__(self):
super(XORNet, self).__init__()
self.fc1 = nn.Linear(2, 4)
self.fc2 = nn.Linear(4, 1)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.sigmoid(self.fc2(x))
return x
# 学習
model = XORNet()
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters())
for epoch in range(1000):
optimizer.zero_grad()
output = model(X)
loss = criterion(output, y)
loss.backward()
optimizer.step()
# テスト
with torch.no_grad():
predictions = model(X)
print(predictions)
活性化関数を変えて、学習速度や精度を比較してみてください。
よくある質問
Q1. 活性化関数を使わないとどうなる?
ニューラルネットワークが線形変換の組み合わせになり、単純な線形回帰と同じになってしまいます。複雑なパターンを学習できません。
Q2. 隠れ層でSoftmaxを使ってもいい?
技術的には可能ですが、一般的には推奨されません。Softmaxは出力が確率分布になるため、出力層での使用が適しています。
Q3. 自作の活性化関数を作れる?
はい、可能です。ただし、勾配が計算できる(微分可能)必要があります。
Q4. ReLUの「Dying」問題はどれくらい深刻?
実用上は大きな問題にならないことが多いです。問題が起きたら、Leaky ReLUやELUに変更してみましょう。
まとめ:活性化関数はAIの「個性」を作る
活性化関数は、ニューラルネットワークに非線形性を与え、複雑なパターン学習を可能にする重要な要素です。
活性化関数の重要ポイント:
- ニューロンの出力を変換する関数
- 非線形性を導入し、複雑な問題を解けるようにする
- 層ごとに異なる関数を使い分ける
主要な活性化関数:
- Sigmoid:0〜1の出力、二値分類の出力層
- tanh:-1〜1の出力、RNN
- ReLU:最も一般的、隠れ層の第一選択
- Leaky ReLU:ReLUの改良版
- Swish:新しい高性能関数
- Softmax:多クラス分類の出力層
選び方のガイドライン:
- 隠れ層:まずReLU、問題があればLeaky ReLU
- 出力層:タスクに応じてSigmoid、Softmax、線形
- 迷ったらReLUから始める
重要な問題:
- 勾配消失問題:Sigmoid、tanhで発生しやすい
- Dying ReLU:ReLUで発生する可能性
- 解決策:適切な活性化関数の選択
活性化関数の選択は、モデルの性能に大きく影響します。まずは基本のReLUから始めて、タスクに応じて最適な関数を見つけていきましょう!
楽しいディープラーニングライフを!

コメント