Sigmoid函数简介及其Python实现

文章目录

  • [一、Sigmoid 函数简介](#一、Sigmoid 函数简介)
    • [1. 数学公式](#1. 数学公式)
    • [2. 关键特性](#2. 关键特性)
    • [3. 应用场景](#3. 应用场景)
  • [二、Python 实现](#二、Python 实现)
    • [1. 使用 `math` 库 (适用于单个数值)](#1. 使用 math 库 (适用于单个数值))
    • [2. 使用 `numpy` 库 (适用于数值、列表、数组、矩阵)](#2. 使用 numpy 库 (适用于数值、列表、数组、矩阵))
    • [3. 使用 `scipy.special.expit` (数值稳定)](#3. 使用 scipy.special.expit (数值稳定))
  • 三、小结

一、Sigmoid 函数简介

Sigmoid 函数(也称为 Logistic 函数)是一个在数学、机器学习(尤其是在逻辑回归和早期神经网络中)广泛使用的函数。它的主要特点是将任意实数输入映射到 (0, 1) 这个开区间内。

1. 数学公式

Sigmoid 函数通常用希腊字母 σ (sigma) 表示,其数学表达式为:

σ ( x ) = 1 1 + e − x σ(x) = \frac{1}{1 + e^{-x}} σ(x)=1+e−x1

其中:

  • x 是函数的输入(一个实数)。
  • e 是自然对数的底(欧拉数,约等于 2.71828)。

2. 关键特性

(1) 输出范围 (0, 1): 这是 Sigmoid 最重要的特性之一。无论输入 x x x 是什么值(正无穷、负无穷或介于两者之间),输出值 σ ( x ) σ(x) σ(x) 总是严格大于 0 且严格小于 1。这使得它非常适合用来表示概率值,或者在二元分类问题中表示属于某个类别的可能性。

(2) S 形曲线: 函数的图形呈 "S" 形。当 x x x 趋近于负无穷时, e − x e^{-x} e−x 趋近于正无穷,分母变得非常大, σ ( x ) σ(x) σ(x) 趋近于 0。当 x x x 趋近于正无穷时, e − x e^{-x} e−x 趋近于 0,分母趋近于 1, σ ( x ) σ(x) σ(x) 趋近于 1。

(3) 单调递增: 函数在其整个定义域内是严格单调递增的,这意味着输入 x x x 越大,输出 σ ( x ) σ(x) σ(x) 也越大。

(4) 中心对称: 函数关于点 (0, 0.5) 中心对称。即 σ ( 0 ) = 1 / ( 1 + e 0 ) = 1 / ( 1 + 1 ) = 0.5 σ(0) = 1 / (1 + e^0) = 1 / (1 + 1) = 0.5 σ(0)=1/(1+e0)=1/(1+1)=0.5。

(5) 导数易于计算: Sigmoid 函数的导数可以用其自身来表示:
σ ′ ( x ) = σ ( x ) ∗ ( 1 − σ ( x ) ) σ'(x) = σ(x) * (1 - σ(x)) σ′(x)=σ(x)∗(1−σ(x))

这个特性在神经网络的反向传播算法中非常有用,因为计算梯度时可以直接利用前向传播计算出的 Sigmoid 值。

3. 应用场景

  • 逻辑回归 (Logistic Regression): Sigmoid 函数是逻辑回归模型的核心,用于将线性模型的输出转换为概率。
  • 神经网络激活函数: 在早期的神经网络中,Sigmoid 曾被广泛用作隐藏层和输出层的激活函数。
    • 输出层: 对于二元分类问题,输出层使用 Sigmoid 可以直接输出概率。
    • 隐藏层: 现在在深度神经网络的隐藏层中,Sigmoid 的使用已大大减少,主要因为梯度消失 (Vanishing Gradient) 问题。当输入 x 的绝对值很大时,Sigmoid 的导数趋近于 0,这会导致在反向传播过程中梯度逐层乘以接近 0 的数,使得深层网络的权重更新非常缓慢甚至停滞。ReLU 及其变种(如 Leaky ReLU, ELU)已成为更常用的隐藏层激活函数。
  • 概率建模: 任何需要将实数值压缩到 (0, 1) 区间以表示概率或置信度的场景。

缺点 (尤其是在深度学习隐藏层中):

  1. 梯度消失: 如上所述,饱和区域(输入绝对值大时)梯度接近 0。
  2. 输出非零中心 (Not Zero-Centered): Sigmoid 的输出恒大于 0。这会导致后续层接收到的输入总是正数,可能在梯度下降过程中引起参数更新的"之"字形抖动(Zigzagging dynamics),降低收敛速度。
  3. 计算复杂度: 相对于 ReLU 函数 (max(0, x)),指数运算 e^x 的计算成本稍高。

二、Python 实现

我们可以使用 Python 的 math 库(处理单个数值)或 numpy 库(处理数值或数组/向量/矩阵)来实现 Sigmoid 函数。在机器学习中,通常使用 numpy 因为它能高效地处理向量化运算。

1. 使用 math 库 (适用于单个数值)

python 复制代码
import math

def sigmoid_math(x):
  """
  计算单个数值的 Sigmoid 值。

  Args:
    x: 输入的实数。

  Returns:
    x 的 Sigmoid 值,范围在 (0, 1) 之间。
  """
  # 防止 e^(-x) 过大导致 OverflowError (当 x 是非常小的负数时)
  # Sigmoid(x) = 1 / (1 + exp(-x)) = exp(x) / (exp(x) + 1)
  # 当 x 非常小时,exp(x) 接近 0,Sigmoid(x) 接近 0
  # 当 x 非常大时,exp(-x) 接近 0,Sigmoid(x) 接近 1
  # 这里直接计算标准形式,对于极端值 math.exp 会处理或抛出异常
  try:
      result = 1 / (1 + math.exp(-x))
  except OverflowError:
      # 如果 exp(-x) 溢出,说明 -x 非常大,即 x 是非常小的负数
      # 此时 Sigmoid 值接近 0
      result = 0.0
  return result

# 示例
print(f"Sigmoid(0) = {sigmoid_math(0)}")
print(f"Sigmoid(10) = {sigmoid_math(10)}")
print(f"Sigmoid(-10) = {sigmoid_math(-10)}")
# 一个较大的正数,接近 1
print(f"Sigmoid(100) = {sigmoid_math(100)}")
# 一个较小的负数,接近 0
print(f"Sigmoid(-100) = {sigmoid_math(-100)}")

2. 使用 numpy 库 (适用于数值、列表、数组、矩阵)

这是在机器学习和数据科学中最常用的方式,因为 numpy 的函数可以对整个数组进行元素级 (element-wise) 操作,效率很高。

python 复制代码
import numpy as np

def sigmoid_numpy(x):
  """
  计算输入 x (可以是数值、列表、numpy 数组等) 的 Sigmoid 值。

  Args:
    x: 输入,可以是单个数值、列表、元组、numpy 数组等。

  Returns:
    与 x 相同形状的 numpy 数组,包含每个元素的 Sigmoid 值。
  """
  # np.exp() 可以直接处理数组
  # 对于非常大的负数 x, -x 很大, np.exp(-x) 可能溢出或得到 inf
  # 对于非常大的正数 x, -x 很小, np.exp(-x) 接近 0
  # Numpy 通常能较好地处理这些边界情况,例如 exp(很大负数) -> 0, exp(很大正数) -> inf
  # 1 / (1 + inf) -> 0. 这不是我们想要的,当 x 很大时,结果应为 1
  # Sigmoid(x) = 1 / (1 + exp(-x))
  # 为了数值稳定性,可以做一些处理,但通常 numpy 的标准实现足够健壮
  # 或者使用 scipy.special.expit(x) 是一个数值上更稳定的实现

  # 标准实现:
  x = np.array(x)  # 确保 x 是 numpy 数组
  return 1 / (1 + np.exp(-x))

# 示例
# 单个值
print(f"Sigmoid(0) = {sigmoid_numpy(0)}")

# 列表
input_list = [-10, -1, 0, 1, 10]
print(f"Sigmoid({input_list}) = {sigmoid_numpy(input_list)}")

# Numpy 数组
input_array = np.array([[-2, -0.5], [0.5, 2]])
print(f"Sigmoid(\n{input_array}\n) =\n{sigmoid_numpy(input_array)}")

# 极端值
print(f"Sigmoid(710) approx = {sigmoid_numpy(710)}") # np.exp(-710) 接近 0, 结果接近 1
# print(f"Sigmoid(800) = {sigmoid_numpy(800)}") # np.exp(-800) 可能下溢为 0,结果为 1
print(f"Sigmoid(-710) approx = {sigmoid_numpy(-710)}") # np.exp(710) 接近 inf, 1/(1+inf) -> 0
# print(f"Sigmoid(-800) = {sigmoid_numpy(-800)}") # np.exp(800) 可能溢出为 inf, 结果为 0

3. 使用 scipy.special.expit (数值稳定)

scipy 库提供了一个专门为 Sigmoid 函数优化的实现,通常在数值上更稳定。

python 复制代码
from scipy.special import expit # expit is the logistic sigmoid function

# 示例
print(f"Scipy Sigmoid(0) = {expit(0)}")
print(f"Scipy Sigmoid({input_list}) = {expit(input_list)}")
print(f"Scipy Sigmoid(\n{input_array}\n) =\n{expit(input_array)}")

# 处理极端值更稳健
print(f"Scipy Sigmoid(800) = {expit(800)}")
print(f"Scipy Sigmoid(-800) = {expit(-800)}")

图像绘制代码如下:

python 复制代码
import numpy as np
import matplotlib.pyplot as plt

def sigmoid(x):
  """计算 Sigmoid 函数值"""
  return expit(x) # 使用 scipy 的 expit 函数

# 1. 生成 x 值范围
# 我们需要一系列 x 值来绘制平滑的曲线
# np.linspace(start, stop, num) 在指定的间隔内返回均匀间隔的数字。
x = np.linspace(-10, 10, 200) # 生成从 -10 到 10 的 200 个点

# 2. 计算对应的 y 值 (Sigmoid 输出)
y = sigmoid(x)

# 3. 使用 matplotlib 绘图
plt.figure(figsize=(8, 5)) # 创建一个图形窗口,可以指定大小

plt.plot(x, y, label='Sigmoid Function', color='blue', linewidth=2) # 绘制曲线

# 4. 添加图形元素,使其更清晰
plt.title('Sigmoid Function: σ(x) = 1 / (1 + e^(-x))') # 图形标题
plt.xlabel('x') # x 轴标签
plt.ylabel('σ(x)') # y 轴标签

# 添加网格线
plt.grid(True, linestyle='--', alpha=0.6)

# 添加关键水平线和垂直线
plt.axhline(0.5, color='red', linestyle=':', linewidth=1, label='y = 0.5') # y=0.5 水平线
plt.axhline(1.0, color='gray', linestyle=':', linewidth=1, label='y = 1.0') # y=1.0 水平线
plt.axhline(0.0, color='gray', linestyle=':', linewidth=1, label='y = 0.0') # y=0.0 水平线
plt.axvline(0, color='gray', linestyle=':', linewidth=1) # x=0 垂直线

# 设置 y 轴范围,更清晰地显示 0 到 1 的区间
plt.ylim(-0.1, 1.1)

# 显示图例 (需要 plot 时指定了 label)
plt.legend()

# 5. 显示图形
plt.show()

三、小结

在实际的机器学习项目中,如果你使用了像 TensorFlowPyTorch 这样的深度学习框架,它们内部都已经内置了高效且数值稳定的 Sigmoid 函数实现,你通常会直接调用框架提供的函数。但理解其原理和基本的 Python 实现仍然很重要。

相关推荐
yangshuo12812 分钟前
家庭服务器IPV6搭建无限邮箱系统指南
运维·服务器·python
彷徨而立9 分钟前
【C++】频繁分配和释放会产生内存碎片
开发语言·c++
计算机徐师兄19 分钟前
基于Python Flask的深度学习电影评论情感分析可视化系统(2.0升级版,附源码)
python·深度学习·flask·电影评论情感分析·电影评论情感分析可视化系统·python电影评论情感分析·python电影情感分析系统
code_shenbing25 分钟前
C# 实现列式存储数据
开发语言·c#·存储
友莘居士1 小时前
特征工程四-2:使用GridSearchCV 进行超参数网格搜索(Hyperparameter Tuning)的用途
人工智能·机器学习·支持向量机·特征工程
Kairo_011 小时前
在 API 模拟阶段:Apipost vs. Faker.js vs. Postman —— 为什么 Apipost 是最优选择
开发语言·javascript·postman
囚~徒~1 小时前
django_rq
后端·python·django
Once_day1 小时前
研发效率破局之道阅读总结(4)个人效率
开发语言·研发效能·devops
痕5171 小时前
如何在idea中写spark程序。
开发语言
爱学习的capoo1 小时前
在TensorFlow中,`Dense`和`Activation`是深度学习模型构建里常用的层
人工智能·深度学习·tensorflow