シグモイド関数

article technology high #sigmoid#activation-function#machine-learning#deep-learning#logistic-regression#vanishing-gradient#mathematics
Created: 2026-05-20 Updated:

シグモイド関数 σ(x)=1/(1+e^{-x}) は値域 (0,1) のS字曲線で、ロジスティック回帰や二値分類の出力層で確率として解釈できる。隠れ層では勾配消失により ReLU へ置き換えられたが、ゲート機構や多ラベル分類では今も標準。

シグモイド関数

シグモイド関数 σ(x)=1/(1+ex)\sigma(x) = 1 / (1 + e^{-x}) は値域 (0, 1) のS字曲線で、任意の実数を確率として解釈できる値へ写す。1990 - 2000 年代にニューラルネットの隠れ層活性化関数の標準だったが、勾配消失問題により 2010 年代前半に ReLU へ主役を譲った。それでも二値分類の出力層、多ラベル分類、LSTM / GRU のゲート機構など、0 から 1 への滑らかなマッピングが本質的に必要な箇所では今も第一選択である。

数学的定義と基本性質

シグモイド関数(標準ロジスティック関数)は次式で定義される。

σ(x)=11+ex\sigma(x) = \frac{1}{1 + e^{-x}}

値域は開区間 (0, 1) で、両端には漸近線として 0 と 1 が存在するが、有限の x に対して厳密に 0 や 1 を取ることはない。実数全域で単調増加し、グラフはなめらかなS字曲線を描く。原点では σ(0)=1/(1+e0)=1/2\sigma(0) = 1/(1 + e^0) = 1/2 となり、対称性 σ(x)=1σ(x)\sigma(-x) = 1 - \sigma(x) が成立する。これは 1σ(x)=ex/(1+ex)=1/(1+ex)=σ(x)1 - \sigma(x) = e^{-x}/(1 + e^{-x}) = 1/(1 + e^x) = \sigma(-x) から直接導かれる。

導関数は次の自己出力依存形を持つ。

σ(x)=σ(x)(1σ(x))\sigma'(x) = \sigma(x) \cdot (1 - \sigma(x))

導出は商の微分から σ(x)=ex/(1+ex)2=y(1y)\sigma'(x) = e^{-x}/(1 + e^{-x})^2 = y \cdot (1 - y)(y=σ(x)y = \sigma(x))で得られる。この形は実装上きわめて有利である。順伝播で計算した yy をキャッシュしておけば、逆伝播時に入力 xx を再参照することなく勾配が計算できる。たとえば ReLU は勾配計算に入力の符号が必要なのに対し、sigmoid と tanh は出力値だけで勾配が確定する。PyTorch の autograd はこの性質を活用してメモリを節約する。

機械学習における用途

シグモイド関数の最も古典的かつ重要な用途は、ロジスティック回帰の出力層である。線形結合 z=wx+bz = w^\top x + bσ(z)\sigma(z) に通すことで、出力を「クラス 1 に属する確率」として解釈できる。これにより、回帰モデルに最尤推定の枠組みで二値分類を行わせることが可能になる。深層学習においても、二値分類タスクの最終層活性化関数として sigmoid は標準である。

PyTorch では torch.sigmoid(x) または torch.nn.Sigmoid を使う。torch.nn.functional.sigmoid も存在するが、公式ドキュメント上は非推奨警告が付いており、torch.sigmoid へ統一することが推奨されている。NumPy には組み込みのシグモイド関数がなく、SciPy の scipy.special.expit が正規の数値安定実装として提供されている。手書きの 1.0 / (1.0 + np.exp(-x)) は後述のオーバーフロー問題を抱えるため、本番コードでは expit を使うのが安全である。

二値分類で sigmoid を使う際の重要なパターンは、損失関数との組み合わせ方である。素朴な実装は「sigmoid で確率に変換 → BCE(Binary Cross-Entropy)で損失計算」だが、これは数値的に不安定である。PyTorch では torch.nn.BCEWithLogitsLoss(関数形は binary_cross_entropy_with_logits)を使うべきで、これは sigmoid と BCE を log-sum-exp 恒等式で融合し、max(x,0)xy+log(1+ex)\max(x, 0) - x \cdot y + \log(1 + e^{-|x|}) という形で安定計算する。logit が大きいときに σ(x)1.0\sigma(x) \approx 1.0 となり log(1.0)\log(1.0) が浮動小数点丸めで情報を失う問題を回避できる。

ロジスティック回帰は本質的に「sigmoid 活性化と交差エントロピー損失を持つ 1 層ニューラルネット」であり、古典統計と深層学習の橋渡しとして理解しておくと有用である。

ReLU に置き換えられた理由

シグモイドが隠れ層から姿を消した最大の理由は、勾配消失問題である。σ(x)=σ(x)(1σ(x))\sigma'(x) = \sigma(x)(1 - \sigma(x))x=0x = 0 で最大値 0.25 を取り、x|x| が大きくなるにつれて急速にゼロへ近づく。具体的には σ(5)0.9933\sigma(5) \approx 0.9933σ(5)0.9933×0.00670.00665\sigma'(5) \approx 0.9933 \times 0.0067 \approx 0.00665 で、x5|x| \gtrsim 5 の飽和領域では勾配が 0.007 以下となる。

逆伝播では層ごとに σ\sigma' が掛け合わされるため、LL 層を積むと勾配は (0.007)L(0.007)^L オーダーで縮小する。10 層なら 3×10213 \times 10^{-21}、入力側の重みは事実上更新されない。これが多層パーセプトロンが「3 - 4 層を超えると訓練が止まる」原因として 2000 年代に長く認識されていた壁である。

転機は 2010 年前後にやってきた。Nair & Hinton (2010) “Rectified Linear Units Improve Restricted Boltzmann Machines” が ReLU f(x)=max(0,x)f(x) = \max(0, x) を提案し、Krizhevsky, Sutskever, Hinton (2012) の AlexNet が ImageNet で ReLU を採用して優勝した。AlexNet 論文は ReLU が tanh ネットより数倍速く訓練できると報告しており、その理由として「非飽和非線形性」を挙げている。ReLU は正の領域で勾配が恒等的に 1、計算コストも比較関数 1 回と極めて低い。

ただし ReLU には負の領域で勾配がゼロになる「dead ReLU 問題」があり、この欠点は Leaky ReLU、ELU、GELU、SiLU などの後継関数で順次緩和されてきた。重要なのは、活性化関数の選択は層ごとに判断すべきという原則である。隠れ層では ReLU 系が支配的でも、二値分類や多ラベル分類の出力層では sigmoid が依然として正しい選択肢である。

数値的注意点

sigmoid の素朴な実装 1/(1+exp(x))1 / (1 + \exp(-x)) は、xx が大きな負の値のときに破綻する。例えば x=1000x = -1000 なら x=1000-x = 1000 で、np.exp(1000) は float64 の最大値(およそ 1.8×103081.8 \times 10^{308})を超えてオーバーフローし、結果として NaN を返す。本来このケースの出力は 0 に近い値であるべきなのに、計算結果が定義不能になる。

逆に xx が大きな正の値のときは np.exp(-1000) がアンダーフローして 0 になり、1/(1+0)=1.01 / (1 + 0) = 1.0 となる。これは数学的に正しい極限であり問題ない。つまり病的なのは「x0x \ll 0」のケースである。

安定実装は xx の符号で分岐する次のパターンが標準的である。

import numpy as np

def stable_sigmoid(x):
    return np.where(
        x >= 0,
        1.0 / (1.0 + np.exp(-x)),
        np.exp(x) / (1.0 + np.exp(x)),
    )

x<0x < 0 の枝では exp(x)\exp(x)(xx は負なので exp(x)<1\exp(x) < 1)を計算することで、大きな指数を避けられる。x0x \geq 0 の枝は元の式そのままだが、このとき exp(x)1\exp(-x) \leq 1 なので安全である。

ベクトル入力に対しては np.where でマスク選択を使う実装が一般的だが、scipy.special.expit は同じロジックを C / Cython で実装しており、ベクトル化された安定演算を提供している。本番コードでは自前実装より expit を選ぶべきである。

さらに浮動小数点丸めにより、x|x| がきわめて大きい(x±50x \approx \pm 50 程度以上)場合は結果が厳密に 0.0 または 1.0 に飽和する。この値を直接 log\log に通すと log(0)=\log(0) = -\infty あるいは log(1)=0\log(1) = 0 で勾配情報が失われるため、損失計算は前述の BCEWithLogitsLoss のようなロジット直接受け取り型 API を使うのが安全策となる。

代替関数との比較

sigmoid と関連の深い活性化関数を、選択指針とともに整理する。

tanh(双曲線正接)tanh(x)=(exex)/(ex+ex)\tanh(x) = (e^x - e^{-x})/(e^x + e^{-x}) で定義され、sigmoid とは tanh(x)=2σ(2x)1\tanh(x) = 2\sigma(2x) - 1 の関係を持つ。値域は (-1, 1) でゼロ中心化されている。sigmoid の出力はすべて正なので、次層への入力ベクトルも全要素正となり、重み更新が同符号にバイアスされ「ジグザグ最適化」が起きる。tanh の出力平均はおよそゼロに保たれ、この問題を緩和する。LeCun ら (1998) “Efficient BackProp” がこの議論の出典である。ReLU が登場する前は、隠れ層では tanh が sigmoid より優先される慣行があった。

softmax は多クラス分類における sigmoid の一般化である。クラス数 K=2K = 2 のとき、softmax は P(y=1x)=ew1x/(ew0x+ew1x)=σ((w1w0)x)P(y=1|x) = e^{w_1^\top x} / (e^{w_0^\top x} + e^{w_1^\top x}) = \sigma((w_1 - w_0)^\top x) となり、パラメータ化の自由度を除いて sigmoid に帰着する。二値分類で softmax(2 ロジット)と sigmoid(1 ロジット)のどちらを使うかは表現力では等価だが、パラメータ数が少なく実装が単純な sigmoid が好まれる。

GELU(Gaussian Error Linear Unit) は Hendrycks & Gimpel (2016) が提案した GELU(x)=xΦ(x)\text{GELU}(x) = x \cdot \Phi(x)(Φ\Phi は標準正規分布の累積分布関数)で、BERT (Devlin et al. 2018) や GPT-2 (Radford et al. 2019) 以降の Transformer 系言語モデルで広く採用されている。

Swish / SiLU(Sigmoid Linear Unit) は Ramachandran ら (2017) が自動探索で発見した Swish(x)=xσ(βx)\text{Swish}(x) = x \cdot \sigma(\beta x)β=1\beta = 1 のとき SiLU =xσ(x)= x \cdot \sigma(x) である。EfficientNet (Tan & Le, 2019) や近年の大規模言語モデルのフィードフォワードブロックで使われる。SiLU は x1.3x \approx -1.3 付近に小さなくぼみを持つ非単調関数で、負の値も出力できる。「入力を自身の確信度でスケールする soft gate」と解釈できる。

2020 年代以降、隠れ層活性化の事実上の標準は GELU と SiLU で、生の sigmoid を多層に積む構成は研究文献ではほぼ見ない。ただし以下に述べる通り、特定の場面では sigmoid 自体が今でも最適である。

今でも sigmoid が正解な場面

隠れ層から退いた sigmoid だが、設計上 0 から 1 への滑らかなマッピングが本質的に必要な場面では今も標準として残っている。

二値分類の出力層 が最も明確な用例である。クラス 1 の事後確率 P(y=1x)P(y = 1 | x) そのものを出力として返したい場合、sigmoid 以外の選択肢は実質ない。前述の通り、損失計算は BCEWithLogitsLoss を使い、モデル本体は sigmoid を含まない logit を出力する形が数値的に最適である。

多ラベル分類 では、各ラベルが独立に true / false を取りうるため、softmax(相互排他を仮定)は不適切である。KK 個の出力ノードそれぞれを独立に sigmoid に通し、各ラベルごとに二値分類問題として扱う。画像のマルチラベル分類(「犬」「屋外」「夕方」が同時に true)やテキストのマルチタグ分類で標準のパターンである。

LSTM / GRU のゲート機構 は sigmoid なしには成立しない。LSTM の input gate、forget gate、output gate はすべて sigmoid を通って 0 から 1 の値を出力し、「情報をどれだけ通すか」を表現する。0 なら完全遮断、1 なら完全通過、中間値は連続的な減衰である。GRU の update gate / reset gate も同様である。これらは「ゲート」という意味論を持つため、出力が 0 から 1 にスケールされていることが本質的に必要で、tanh や ReLU で代替できない。

Hard sigmoid は推論効率を重視するモバイル向けモデル(MobileNetV3、EfficientNet-Lite など)で使われる区分線形近似 max(0,min(1,(x+3)/6))\max(0, \min(1, (x + 3) / 6)) である。指数関数を回避できるため、CPU や組み込みハードウェアで高速に評価できる。同じ動機で Hard Swish も提案されている。

確率較正(Platt scaling) では、SVM などの非確率的分類器のスコアを確率に変換するため、追加で sigmoid を学習させる。これは Platt (1999) の手法で、現代でもキャリブレーション手段として使われる。

二言語用語対照表

日本語English
シグモイド関数Sigmoid function
ロジスティック関数Logistic function
活性化関数Activation function
勾配消失Vanishing gradient
二値分類Binary classification
多ラベル分類Multi-label classification
クロスエントロピーCross-entropy
ゼロ中心化Zero-centered
ゲート機構Gating mechanism
飽和Saturation
ロジットLogit
確率較正Probability calibration

参考文献

  • Goodfellow, I., Bengio, Y., Courville, A. (2016). Deep Learning. MIT Press. Ch. 6(活性化関数の節)
  • Krizhevsky, A., Sutskever, I., Hinton, G. (2012). “ImageNet Classification with Deep Convolutional Neural Networks” (AlexNet), NeurIPS 2012
  • Nair, V., Hinton, G. (2010). “Rectified Linear Units Improve Restricted Boltzmann Machines”, ICML 2010
  • LeCun, Y., Bottou, L., Orr, G. B., Müller, K.-R. (1998). “Efficient BackProp”, Neural Networks: Tricks of the Trade
  • Hendrycks, D., Gimpel, K. (2016). “Gaussian Error Linear Units (GELUs)”, arXiv:1606.08415
  • Ramachandran, P., Zoph, B., Le, Q. V. (2017). “Searching for Activation Functions” (Swish), arXiv:1710.05941
  • Tan, M., Le, Q. V. (2019). “EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks”, ICML 2019
  • Platt, J. (1999). “Probabilistic Outputs for Support Vector Machines and Comparisons to Regularized Likelihood Methods”
  • PyTorch documentation: torch.sigmoid, torch.nn.Sigmoid, torch.nn.BCEWithLogitsLoss, torch.nn.functional.binary_cross_entropy_with_logits
  • SciPy documentation: scipy.special.expit

Local graph