一、激活函数(Activation Functions)

为什么需要激活函数?
神经网络的基本单元是神经元,每个神经元的输出是输入的加权和(线性变换)。如果没有激活函数,无论堆叠多少层神经元,输出始终是输入的线性组合,无法拟合复杂的非线性关系(比如图像中的边缘、纹理等)。激活函数的作用就是引入非线性变换,让网络具备“学习复杂模式”的能力。

1. 常见激活函数及PyTorch实现

(1)ReLU(Rectified Linear Unit)
  • 公式y = max(0, x)
  • 当输入x > 0时,输出等于输入;当x ≤ 0时,输出为0。
  • 特点:计算简单,解决了传统Sigmoid/Tanh的梯度消失问题,训练速度快,是目前最常用的激活函数。
  • PyTorch实现
  import torch
  import torch.nn as nn

  # 创建ReLU激活函数实例
  relu = nn.ReLU()

  # 测试:输入一个张量
  x = torch.tensor([-1.0, 0.0, 1.5, -0.3])
  y = relu(x)
  print("ReLU输出:", y)  # 输出:tensor([0.0000, 0.0000, 1.5000, 0.0000])
(2)Sigmoid函数
  • 公式y = 1 / (1 + exp(-x))
  • 输出范围在(0, 1)之间,常用于二分类问题的输出层(将结果转为概率)。
  • 特点:输出是概率值,但当x很大或很小时,梯度趋近于0,容易出现梯度消失,深层网络训练困难。
  • PyTorch实现
  sigmoid = nn.Sigmoid()
  x = torch.tensor([-2.0, 0.0, 2.0])
  y = sigmoid(x)
  print("Sigmoid输出:", y)  # 输出:tensor([0.1192, 0.5000, 0.8808])
(3)Tanh函数
  • 公式y = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
  • 输出范围在(-1, 1)之间,均值为0,理论上比Sigmoid更易训练。
  • 特点:仍存在梯度消失问题,应用场景较少,主要用于RNN等序列模型的隐藏层。
  • PyTorch实现
  tanh = nn.Tanh()
  x = torch.tensor([-1.0, 0.0, 1.0])
  y = tanh(x)
  print("Tanh输出:", y)  # 输出:tensor([-0.7616, 0.0000, 0.7616])

二、卷积层(Convolutional Layers)

卷积层是什么?
卷积层是CNN(卷积神经网络)的核心,通过滑动一个“滤镜”(卷积核)在输入数据上,提取局部特征(如边缘、纹理)。例如,用不同的卷积核可以识别图像中的“边缘”“条纹”等模式。

1. 卷积操作的基本概念
  • 输入:假设输入是一张灰度图像(单通道,二维矩阵),形状为(H, W)
  • 卷积核(Filter/Kernel):一个小矩阵(如3x3),用于特征提取。
  • 步长(Stride):卷积核每次滑动的像素数(默认1)。
  • 填充(Padding):在输入边缘添加0,控制输出尺寸(避免特征丢失)。

简单示例
输入:3x3矩阵(像素值)

[[1, 2, 3],
 [4, 5, 6],
 [7, 8, 9]]

卷积核:2x2矩阵

[[a, b],
 [c, d]]

输出计算:每个位置是卷积核覆盖区域的像素乘积之和
- 左上角:1*a + 2*b + 4*c + 5*d
- 右上角:2*a + 3*b + 5*c + 6*d
- 左下角:4*a + 5*b + 7*c + 8*d
- 右下角:5*a + 6*b + 8*c + 9*d

2. PyTorch中的卷积层(nn.Conv2d)

在PyTorch中,卷积层通过nn.Conv2d实现,用于处理二维图像数据(如RGB图像)。输入形状(batch_size, in_channels, height, width),其中:
- batch_size:批量样本数(如一次处理16张图像);
- in_channels:输入通道数(RGB图像为3,灰度图为1);
- height/width:图像高度和宽度。

关键参数
- in_channels:输入通道数;
- out_channels:输出通道数(卷积核数量,决定特征图复杂度);
- kernel_size:卷积核大小(如3表示3x3);
- stride:步长(默认1);
- padding:填充(默认0)。

输出形状计算
输出高度/宽度 = (输入高度/宽度 + 2*padding - kernel_size) // stride + 1

代码示例
假设输入是一张RGB图像(batch=1,通道数=3,尺寸=28x28),用3x3卷积核,输出16个通道:

# 1. 导入库
import torch
import torch.nn as nn

# 2. 创建输入张量(batch=1, 通道=3, 高=28, 宽=28)
x = torch.randn(1, 3, 28, 28)  # 随机生成数据

# 3. 定义卷积层
conv = nn.Conv2d(
    in_channels=3,     # 输入3个通道(RGB)
    out_channels=16,   # 输出16个通道(16个卷积核)
    kernel_size=3,     # 3x3卷积核
    stride=1,          # 步长1
    padding=1          # 填充1,保持输出尺寸不变
)

# 4. 前向传播(应用卷积)
y = conv(x)

# 5. 打印输入和输出形状
print("输入形状:", x.shape)    # 输出:torch.Size([1, 3, 28, 28])
print("输出形状:", y.shape)    # 输出:torch.Size([1, 16, 28, 28])
3. 卷积层 + 激活函数实战

通常卷积层后接激活函数(如ReLU),形成“卷积→激活”的基本单元:

# 创建卷积层+ReLU
conv_relu = nn.Sequential(
    nn.Conv2d(3, 16, 3, 1, 1),  # 卷积层
    nn.ReLU()                   # 激活函数
)

y = conv_relu(x)
print("卷积+ReLU输出:", y.shape)  # 仍为torch.Size([1, 16, 28, 28])

总结:激活函数让神经网络引入非线性,卷积层通过滑动窗口提取图像特征。两者结合是CNN模型的核心结构,后续可进一步学习池化层(如MaxPooling)和全连接层,构建完整的图像识别模型。

小练习:尝试修改卷积核大小(如kernel_size=5)或步长(stride=2),观察输出形状变化,理解各参数对特征提取的影响。

小夜