深度学习入门:神经网络基础

说实话,很多人一听到「神经网络」就觉得高深莫测。我当年刚接触时也一样,总觉得这玩意儿跟人脑一样复杂。其实没那么玄乎——它就是个数学函数,只不过参数多了点。

咱们这一章,就把神经网络最核心的几个概念掰开揉碎。你掌握了这些,后面那些花里胡哨的网络结构,说白了都是这些基础模块的排列组合。

感知机:一切开始的地方

感知机(Perceptron)是神经网络的老祖宗。1957年由Frank Rosenblatt提出,当时可是轰动一时。它的结构极其简单:输入 → 加权求和 → 激活 → 输出。

数学上就一句话:

y = sign(w·x + b)

其中sign是阶跃函数,大于0输出1,小于0输出0。w是权重,b是偏置。

我在项目中遇到过一件事:有同事想用单层感知机做图像分类,折腾了半天准确率就是上不去。为什么?因为单层感知机连异或(XOR)问题都解决不了。这是它的硬伤——只能处理线性可分的问题。

核心要点:感知机是线性分类器。它画出的决策边界是一条直线(或超平面)。

多层感知机:打破线性限制

既然单层不行,那就堆多层呗。多层感知机(MLP)就是在输入和输出之间加了若干隐藏层。每一层都是全连接的,层与层之间通过激活函数引入非线性。

你想想看,如果不用激活函数,多层线性变换叠加起来还是线性变换,那跟单层有啥区别?所以激活函数才是MLP的灵魂。

我习惯把MLP看作一个「万能函数逼近器」。理论上,只要隐藏层神经元够多,它能拟合任意复杂的函数。当然,实际中还得考虑过拟合、训练效率等问题。

下面这张图展示了MLP的基本结构:

多层感知机(MLP)结构图 x₁ x₂ x₃ x₄ 输入层 隐藏层1 隐藏层2 ŷ₁ ŷ₂ 输出层 全连接 全连接 + 激活 全连接

激活函数:非线性的来源

激活函数决定了神经元「要不要被激活」。我见过不少新手,一上来就堆层数,结果效果还不如浅层网络。问题往往出在激活函数选错了。

常用的就三种,咱们一个一个说。

Sigmoid

公式:σ(x) = 1 / (1 + e⁻ˣ)

输出范围在0到1之间。早期神经网络很喜欢用它,因为它有平滑的梯度。但有个致命问题——饱和区梯度几乎为0。什么意思?就是输入太大或太小时,梯度消失,网络学不动了。

避坑指南:我曾经在一个深层分类任务里用了Sigmoid,训练到第10轮loss就不降了。折腾了两天才发现是梯度消失。换成ReLU后,问题立刻解决。

Tanh

公式:tanh(x) = (eˣ - e⁻ˣ) / (eˣ + e⁻ˣ)

输出范围在-1到1之间。它解决了Sigmoid输出非零均值的问题,但梯度饱和问题依然存在。说白了,就是Sigmoid的升级版,但没质变。

ReLU

公式:ReLU(x) = max(0, x)

这是目前最常用的激活函数。简单粗暴——小于0就输出0,大于0就原样输出。好处是计算快,而且没有正半轴的梯度饱和问题。

但ReLU也有坑:神经元「死亡」问题。如果某个神经元一直输出负数,它的梯度永远是0,那它就再也活不过来了。

我的建议:新手入门先用ReLU。如果发现很多神经元死了,试试Leaky ReLU或者ELU。别一上来就搞花里胡哨的。

三种激活函数对比:

函数 输出范围 优点 缺点 常用场景
Sigmoid (0, 1) 平滑、可解释性强 梯度消失、非零均值 二分类输出层
Tanh (-1, 1) 零均值、比Sigmoid强 梯度消失依然存在 RNN、某些生成模型
ReLU [0, +∞) 计算快、无正半轴饱和 神经元死亡 CNN、MLP默认选择

损失函数:衡量模型好坏的标准

损失函数就是告诉模型「你错得有多离谱」。我习惯把它比作老师批改作业——分数越低,说明模型做得越好。

常见的损失函数有:

  • 均方误差(MSE):回归任务标配。计算预测值与真实值差的平方。
  • 交叉熵损失(Cross-Entropy):分类任务首选。配合Softmax使用效果最佳。
  • Huber损失:MSE的改良版,对异常点不那么敏感。

选损失函数有个简单原则:回归用MSE,分类用交叉熵。别问为什么,这是无数前辈踩坑踩出来的经验。

优化器:让模型学会更新参数

有了损失函数,接下来就是怎么让损失变小。优化器就是干这个的——它告诉模型该往哪个方向调整参数。

最基础的是随机梯度下降(SGD)。每次迭代用一个小批量数据计算梯度,然后更新参数。公式很简单:

w = w - lr * grad

其中lr是学习率。学习率设大了,模型震荡不收敛;设小了,训练慢得像蜗牛爬。

后来有了更聪明的优化器:

  • Momentum:给梯度加了个「惯性」,避免陷入局部最优。
  • Adam:自适应学习率,基本不用调参。我90%的项目都用它。
  • RMSprop:对梯度做指数加权平均,适合处理非平稳目标。

实战经验:我个人习惯先用Adam快速找到一个不错的解,然后换成SGD+Momentum做精细调优。这招在多个项目中都奏效。

下面是一个简单的MLP训练代码示例,用PyTorch实现:

import torch
import torch.nn as nn
import torch.optim as optim

# 定义一个简单的MLP
class SimpleMLP(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleMLP, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

# 初始化模型、损失函数、优化器
model = SimpleMLP(input_size=10, hidden_size=64, output_size=2)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练循环
for epoch in range(100):
    # 假设有数据dataloader
    for inputs, labels in dataloader:
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
    print(f'Epoch {epoch+1}, Loss: {loss.item():.4f}')

这段代码虽然简单,但包含了深度学习的完整流程:前向传播 → 计算损失 → 反向传播 → 参数更新。你把这个流程刻在脑子里,后面学什么网络结构都不怕。

小技巧:训练时记得打印loss。如果loss不降,先检查学习率是不是太大或太小。如果loss震荡,试试减小batch size或者加Momentum。

好了,这一章的内容就到这儿。神经网络的基础、感知机、多层感知机、激活函数、损失函数、优化器——这些概念你搞清楚了,后面学卷积、循环、Transformer都会轻松很多。记住,深度学习没有魔法,只有数学和工程。

专注资料整理