深度学习入门:神经网络是如何"思考"的?
揭开神经网络的神秘面纱,用最直观的方式理解深度学习的核心原理。
前言
在上一篇文章中,我们了解了机器学习的基本概念。今天,我们将深入探索机器学习中最耀眼的技术——深度学习。
你可能好奇:为什么叫"深度"学习?神经网络是怎么"思考"的?它和人脑有什么关系?这篇文章将为你一一解答。
一、从人脑到人工神经网络
人脑的启示
人脑大约有 860亿个神经元,每个神经元通过突触与其他神经元相连,形成复杂的网络。当我们学习新知识时,神经元之间的连接强度会发生变化。
人脑神经元结构示意
树突(接收信号)
↓
┌───────────┐
│ 细胞体 │ ← 处理信息
└─────┬─────┘
│
轴突(传递信号)
│
↓
突触(连接其他神经元)
人工神经网络
人工神经网络是对人脑的简化模拟:
| 人脑神经元 | 人工神经元 |
|---|---|
| 树突 | 输入端 |
| 细胞体 | 计算单元 |
| 轴突 | 输出端 |
| 突触强度 | 权重(Weight) |
二、单个神经元的工作原理
一个神经元接收多个输入,进行加权求和,再经过激活函数输出结果。
数学表达
输入:x₁, x₂, x₃, ...
权重:w₁, w₂, w₃, ...
偏置:b
加权求和:z = w₁x₁ + w₂x₂ + w₃x₃ + ... + b
输出:y = 激活函数(z)
直观理解
想象你要决定周末是否去公园:
- 输入1:天气好(1)或不好(0)
- 输入2:朋友有空(1)或没空(0)
- 输入3:心情好(1)或不好(0)
不同的因素对你决策的影响不同:
天气权重 w₁ = 0.5 (天气很重要)
朋友权重 w₂ = 0.3 (朋友因素次之)
心情权重 w₃ = 0.2 (心情影响较小)
偏置 b = -0.4 (你本身有点宅)
决策计算:
z = 0.5×1 + 0.3×1 + 0.2×1 + (-0.4) = 0.6
如果激活函数是:输出 = 1 if z > 0 else 0
那么输出 = 1,决定去公园!
三、激活函数:神经网络的灵魂
为什么需要激活函数?如果没有它,无论多少层神经网络,最终都等价于一个线性变换,无法处理复杂问题。
常见激活函数
1. Sigmoid 函数
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
特点:将任意输入压缩到 (0, 1) 之间
1.0 ┤ ╭───────
│ ╭
0.5 ┤ ╭
│ ╭
0.0 ┤╭──────────────→ x
-4 -2 0 2 4
缺点:
- 梯度消失问题(两端梯度接近0)
- 输出不是以0为中心
2. ReLU(Rectified Linear Unit)
def relu(x):
return np.maximum(0, x)
特点:简单高效,是目前最流行的激活函数
│ ╱
│ ╱
│ ╱
0.0 ┼──────────────→ x
│
│
优点:
- 计算简单
- 缓解梯度消失
- 稀疏激活
3. 其他常见激活函数
| 函数 | 公式 | 特点 |
|---|---|---|
| Tanh | tanh(x) | 输出在 (-1, 1) |
| Leaky ReLU | max(0.01x, x) | 解决ReLU"死亡"问题 |
| GELU | x·Φ(x) | BERT等模型使用 |
| Softmax | eˣᵢ/Σeˣⱼ | 多分类输出层 |
四、多层神经网络:深度学习的"深"
单层神经元只能解决简单的线性问题。要处理复杂任务,需要多层堆叠:
输入层 隐藏层 输出层
○ ○
○ ────→ ○ ────→ ○
○ ○
○ ○
特征提取 特征变换 最终预测
为什么"深"很重要?
层次化特征学习:
图像识别的层次特征:
第1层:边缘、线条
↓
第2层:纹理、简单形状
↓
第3层:部件(眼睛、耳朵、轮子)
↓
第4层:完整对象(人脸、汽车)
↓
输出层:分类结果
万能近似定理
一个具有足够多神经元的隐藏层的神经网络,理论上可以近似任何连续函数。这就是为什么深度学习能解决如此多的问题。
五、前向传播:信息流动
前向传播就是数据从输入层经过各层变换到达输出的过程。
代码实现
import numpy as np
class NeuralNetwork:
def __init__(self, layer_sizes):
"""
layer_sizes: 各层神经元数量,如 [2, 3, 1] 表示
输入2个神经元,隐藏层3个,输出1个
"""
self.weights = []
self.biases = []
# 随机初始化权重和偏置
for i in range(len(layer_sizes) - 1):
w = np.random.randn(layer_sizes[i], layer_sizes[i+1]) * 0.01
b = np.zeros((1, layer_sizes[i+1]))
self.weights.append(w)
self.biases.append(b)
def relu(self, z):
return np.maximum(0, z)
def sigmoid(self, z):
return 1 / (1 + np.exp(-z))
def forward(self, x):
"""前向传播"""
activation = x
for i in range(len(self.weights) - 1):
z = np.dot(activation, self.weights[i]) + self.biases[i]
activation = self.relu(z) # 隐藏层用ReLU
# 输出层用Sigmoid(二分类)
z = np.dot(activation, self.weights[-1]) + self.biases[-1]
output = self.sigmoid(z)
return output
# 使用示例
nn = NeuralNetwork([2, 4, 1]) # 2输入 -> 4隐藏 -> 1输出
x = np.array([[0.5, 0.3]])
print(nn.forward(x))
六、反向传播:神经网络如何学习
反向传播是神经网络学习的核心算法,它的本质是链式法则的应用。
核心思想
前向传播:输入 → 隐藏层 → 输出 → 预测值
反向传播:损失 ← 计算梯度 ← 更新权重
输入
↓
┌───────┐
│ 隐藏层 │ ←─── 反向传播梯度
└───┬───┘
↓
┌───────┐
│ 输出层 │ ←─── 计算损失
└───┬───┘
↓
预测值 ─── 与真实值比较 ──→ 损失函数
损失函数
衡量预测值与真实值之间的差距:
# 均方误差(回归问题)
def mse_loss(y_pred, y_true):
return np.mean((y_pred - y_true) ** 2)
# 交叉熵损失(分类问题)
def cross_entropy_loss(y_pred, y_true):
epsilon = 1e-15 # 防止log(0)
y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
return -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
梯度下降
根据梯度更新权重:
# 权重更新公式
w = w - learning_rate * ∂Loss/∂w
b = b - learning_rate * ∂Loss/∂b
学习率的重要性:
学习率太小:收敛太慢
────────────────────────→ 时间
╱╲ ╱╲ ╱╲ ╱╲
╱ ╲╱ ╲╱ ╲╱ ╲
学习率太大:可能发散
────────────────────────→ 时间
╱ ╲
╱ ╲
╱ ╲ 发散!
合适的学习率:平稳收敛
────────────────────────→ 时间
╲
╲
╲________________
七、完整训练示例:XOR问题
XOR(异或)问题是一个经典的非线性问题,单层感知器无法解决,但多层神经网络可以轻松搞定。
import numpy as np
# XOR数据
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])
class XORNetwork:
def __init__(self):
# 初始化权重
self.w1 = np.random.randn(2, 4) # 输入层到隐藏层
self.b1 = np.zeros((1, 4))
self.w2 = np.random.randn(4, 1) # 隐藏层到输出层
self.b2 = np.zeros((1, 1))
self.lr = 0.1
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(self, x):
return x * (1 - x)
def train(self, X, y, epochs=10000):
for epoch in range(epochs):
# 前向传播
z1 = np.dot(X, self.w1) + self.b1
a1 = self.sigmoid(z1)
z2 = np.dot(a1, self.w2) + self.b2
a2 = self.sigmoid(z2)
# 反向传播
error = y - a2
d2 = error * self.sigmoid_derivative(a2)
d1 = d2.dot(self.w2.T) * self.sigmoid_derivative(a1)
# 更新权重
self.w2 += a1.T.dot(d2) * self.lr
self.b2 += np.sum(d2, axis=0, keepdims=True) * self.lr
self.w1 += X.T.dot(d1) * self.lr
self.b1 += np.sum(d1, axis=0, keepdims=True) * self.lr
if epoch % 1000 == 0:
loss = np.mean(error ** 2)
print(f"Epoch {epoch}, Loss: {loss:.4f}")
return a2
# 训练
nn = XORNetwork()
output = nn.train(X, y)
print("\n最终预测结果:")
for i in range(4):
print(f"{X[i]} -> {output[i][0]:.4f} (期望: {y[i][0]})")
输出:
Epoch 0, Loss: 0.2500
Epoch 1000, Loss: 0.1250
Epoch 2000, Loss: 0.0821
...
最终预测结果:
[0 0] -> 0.0231 (期望: 0)
[0 1] -> 0.9782 (期望: 1)
[1 0] -> 0.9784 (期望: 1)
[1 1] -> 0.0217 (期望: 0)
八、深度学习框架:让训练更简单
实际项目中,我们很少手写神经网络,而是使用成熟的框架:
PyTorch 示例
import torch
import torch.nn as nn
# 定义模型
class SimpleNN(nn.Module):
def __init__(self):
super().__init__()
self.layer1 = nn.Linear(2, 4)
self.layer2 = nn.Linear(4, 1)
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
def forward(self, x):
x = self.relu(self.layer1(x))
x = self.sigmoid(self.layer2(x))
return x
# 创建模型
model = SimpleNN()
criterion = nn.BCELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# 训练数据
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [1], [1], [0]])
# 训练
for epoch in range(1000):
optimizer.zero_grad()
outputs = model(X)
loss = criterion(outputs, y)
loss.backward()
optimizer.step()
if epoch % 200 == 0:
print(f"Epoch {epoch}, Loss: {loss.item():.4f}")
# 预测
print("\n预测结果:")
print(model(X).detach().numpy())
九、经典网络架构
1. MLP(多层感知器)
最基础的神经网络,全连接结构。
输入层 → 隐藏层1 → 隐藏层2 → ... → 输出层
○ ○ ○ ○
○ → ○ → ○ → ... ○
○ ○ ○
应用:表格数据分类、回归任务
2. CNN(卷积神经网络)
专为图像设计,通过卷积核提取局部特征。
输入图像 → 卷积层 → 池化层 → 卷积层 → 全连接层 → 输出
[图片] [特征图] [压缩] [高级特征] [分类]
关键组件:
- 卷积层:提取局部特征
- 池化层:降维,减少计算
- 卷积核:可学习的特征检测器
3. RNN(循环神经网络)
处理序列数据,具有"记忆"能力。
时刻 t-1 时刻 t 时刻 t+1
○ → ○ → ○
↓ ↓ ↓
输出 输出 输出
应用:文本处理、语音识别、时间序列预测
十、深度学习为什么成功?
| 因素 | 说明 |
|---|---|
| 数据量 | 大数据为深度学习提供了充足的训练样本 |
| 算力 | GPU并行计算让训练深层网络成为可能 |
| 算法 | ReLU、BatchNorm、Adam等技巧解决了训练难题 |
| 架构 | CNN、RNN、Transformer等架构设计合理 |
| 开源生态 | PyTorch、TensorFlow降低了使用门槛 |
小结
让我们回顾今天学习的核心概念:
| 概念 | 一句话理解 |
|---|---|
| 神经元 | 加权求和 + 激活函数 |
| 激活函数 | 引入非线性,让网络能学习复杂模式 |
| 前向传播 | 数据从输入到输出的流动过程 |
| 反向传播 | 根据损失函数计算梯度,更新权重 |
| 深度 | 网络层数越多,能学习的特征越抽象、越高级 |
| 学习率 | 控制参数更新的步长 |
思考与练习
-
思考题:
- 为什么激活函数必不可少?如果去掉会怎样?
- 深度神经网络为什么比浅层网络更强大?
-
动手练习:
- 修改XOR网络的隐藏层神经元数量,观察训练效果
- 尝试用PyTorch构建一个MNIST手写数字识别模型
-
延伸阅读:
下期预告
下一篇文章,我们将探讨:从RNN到Transformer:序列建模的演进之路
会解答这些问题:
- RNN如何处理变长序列?
- LSTM如何解决长距离依赖?
- Transformer为什么能取代RNN?
- 注意力机制的原理是什么?
关注专栏,不错过后续更新!
作者:ECH00O00 本文首发于掘金专栏《AI科普实验室》 欢迎评论区交流讨论,点赞收藏就是最大的鼓励 ❤️