深度学习入门:基于Python的理论与实现笔记

深度学习入门:基于Python的理论与实现 - 学习笔记


第1章 Python入门

核心思想: 掌握Python基础语法和NumPy、Matplotlib库,为深度学习实现做好准备。

1.1 Python是什么

是什么? 简单、易读、开源的编程语言,适合数据科学和深度学习。

为什么需要? 深度学习框架(TensorFlow、PyTorch等)都提供Python接口。

作用? 实现深度学习算法,进行数值计算和数据可视化。


1.2 NumPy

是什么? 用于数值计算的Python库,提供高效的数组操作。

为什么需要? 深度学习需要大量矩阵运算,NumPy提供优化实现。

作用? 实现向量、矩阵运算,支持广播机制。

对应代码:

python 复制代码
import numpy as np

# 生成NumPy数组
x = np.array([1.0, 2.0, 3.0])

# 算术运算(element-wise)
x = np.array([1.0, 2.0, 3.0])
y = np.array([2.0, 4.0, 6.0])
x + y  # array([3., 6., 9.])
x * y  # array([2., 8., 18.])

# 广播
A = np.array([[1, 2], [3, 4]])
A * 10  # array([[10, 20], [30, 40]])

# 矩阵乘法
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
np.dot(A, B)  # array([[19, 22], [43, 50]])

1.3 Matplotlib

是什么? Python的绘图库。

为什么需要? 可视化训练过程和结果。

对应代码:

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

# 绘制sin函数
x = np.arange(0, 6, 0.1)
y = np.sin(x)
plt.plot(x, y)
plt.show()

# 绘制多条曲线
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y1, label="sin")
plt.plot(x, y2, linestyle="--", label="cos")
plt.legend()
plt.show()

第2章 感知机

核心思想: 感知机是神经网络的起源,通过权重和偏置实现逻辑电路,但单层感知机无法解决非线性问题。

2.1 感知机是什么

是什么? 接收多个输入信号,输出一个信号的算法。

数学表达式:

y={0(w1x1+w2x2≤θ)1(w1x1+w2x2>θ)y = \begin{cases} 0 & (w_1x_1 + w_2x_2 \leq \theta) \\ 1 & (w_1x_1 + w_2x_2 > \theta) \end{cases}y={01(w1x1+w2x2≤θ)(w1x1+w2x2>θ)

或等价形式:

y={0(b+w1x1+w2x2≤0)1(b+w1x1+w2x2>0)y = \begin{cases} 0 & (b + w_1x_1 + w_2x_2 \leq 0) \\ 1 & (b + w_1x_1 + w_2x_2 > 0) \end{cases}y={01(b+w1x1+w2x2≤0)(b+w1x1+w2x2>0)

其中 bbb 为偏置,w1,w2w_1, w_2w1,w2 为权重。

对应代码:

python 复制代码
import numpy as np

def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w * x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

2.2 感知机的局限性

是什么? 单层感知机无法表示异或门(XOR)。

为什么? 异或门是非线性问题,单层感知机只能表示线性空间。

局限? 无法用一条直线将异或门的输出分开。

[由此引出:多层感知机]

→ 通过叠加层(多层感知机)可以解决非线性问题

→ 理论上2层感知机可以表示任意函数


2.3 多层感知机

是什么? 叠加了多层的感知机。

为什么需要? 单层感知机无法解决非线性问题。

作用? 通过组合与门、与非门、或门实现异或门。

对应代码:

python 复制代码
def XOR(x1, x2):
    s1 = NAND(x1, x2)
    s2 = OR(x1, x2)
    y = AND(s1, s2)
    return y

真值表验证:

x1 x2 s1(NAND) s2(OR) y(AND)
0 0 1 0 0
0 1 1 1 1
1 0 1 1 1
1 1 0 1 0

第3章 神经网络

核心思想: 神经网络通过平滑的激活函数(如sigmoid)替代阶跃函数,实现可学习的非线性映射。

3.1 激活函数

是什么? 将输入信号的总和转换为输出信号的函数。

为什么需要? 决定如何激活输入信号的总和,引入非线性。

作用? 使神经网络能够学习复杂的非线性模式。

对比表格:

特性 阶跃函数 Sigmoid函数 ReLU函数
表达式 h(x)={0x≤01x>0h(x)=\begin{cases}0&x\leq0\\1&x>0\end{cases}h(x)={01x≤0x>0 h(x)=11+e−xh(x)=\frac{1}{1+e^{-x}}h(x)=1+e−x1 h(x)={xx>00x≤0h(x)=\begin{cases}x&x>0\\0&x\leq0\end{cases}h(x)={x0x>0x≤0
平滑性 不连续 平滑连续 连续(原点不可导)
输出范围 {0, 1} (0, 1) [0, +∞)
导数 几乎处处为0 h(x)(1−h(x))h(x)(1-h(x))h(x)(1−h(x)) {1x>00x≤0\begin{cases}1&x>0\\0&x\leq0\end{cases}{10x>0x≤0
梯度消失 严重 可能 缓解(负半轴)

[由此引出:激活函数的选择]

→ 使用ReLU缓解梯度消失

→ 使用Batch Normalization稳定梯度分布

→ 使用残差连接构建捷径

对应代码:

python 复制代码
import numpy as np

# 阶跃函数
def step_function(x):
    return np.array(x > 0, dtype=np.int)

# Sigmoid函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# ReLU函数
def relu(x):
    return np.maximum(0, x)

3.2 为什么激活函数必须是非线性的

是什么? 激活函数不能使用线性函数。

为什么? 使用线性函数时,多层网络等价于单层网络。

证明: 假设 h(x)=cxh(x) = cxh(x)=cx,则3层网络:

y(x)=h(h(h(x)))=c⋅c⋅c⋅x=c3xy(x) = h(h(h(x))) = c \cdot c \cdot c \cdot x = c^3xy(x)=h(h(h(x)))=c⋅c⋅c⋅x=c3x

这等价于单层网络 y(x)=axy(x) = axy(x)=ax(其中 a=c3a = c^3a=c3)。


3.3 3层神经网络的实现

对应代码:

python 复制代码
def init_network():
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])
    return network

def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)
    return y

3.4 输出层的设计

是什么? 根据问题类型选择不同的输出层激活函数。

对比表格:

问题类型 输出层激活函数 损失函数
回归问题 恒等函数 均方误差
二分类问题 Sigmoid函数 交叉熵误差
多分类问题 Softmax函数 交叉熵误差

Softmax函数:

yk=eak∑i=1neaiy_k = \frac{e^{a_k}}{\sum_{i=1}^{n}e^{a_i}}yk=∑i=1neaieak

Softmax实现(含溢出对策):

python 复制代码
def softmax(a):
    c = np.max(a)  # 溢出对策
    exp_a = np.exp(a - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

Softmax特征: 输出值在0.0~1.0之间,总和为1,可解释为概率。


3.5 手写数字识别(MNIST)

对应代码:

python 复制代码
import sys, os
sys.path.append(os.pardir)
from dataset.mnist import load_mnist

# 加载数据
(x_train, t_train), (x_test, t_test) = load_mnist(
    normalize=True, flatten=True, one_hot_label=False)

# 神经网络推理
def predict(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = softmax(a3)
    return y

# 批处理
batch_size = 100
for i in range(0, len(x), batch_size):
    x_batch = x[i:i+batch_size]
    y_batch = predict(network, x_batch)
    p = np.argmax(y_batch, axis=1)

第4章 神经网络的学习

核心思想: 神经网络通过损失函数评估性能,利用梯度下降法自动更新权重参数,从数据中学习最优解。

4.1 从数据中学习

是什么? 由数据自动决定权重参数的值。

为什么需要? 人工决定成千上万个参数是不可能的。

作用? 避免人为介入,实现端到端学习。

训练数据与测试数据:

  • 训练数据:用于学习,调整权重参数
  • 测试数据:用于评估泛化能力
  • 泛化能力:处理未被观察过的数据的能力

4.2 损失函数

是什么? 表示神经网络性能的"恶劣程度"的指标。

为什么需要? 为神经网络学习提供优化目标。

作用? 以损失函数为基准,找出使它的值达到最小的权重参数。

[由此引出:为什么不能用识别精度作为指标]

→ 识别精度对微小参数变化不敏感(离散值)

→ 绝大多数地方导数为0,无法更新参数

→ 损失函数是连续值,可以计算梯度


4.3 均方误差

是什么? 计算神经网络输出与监督数据各元素之差的平方和。

公式:

E=12∑k(yk−tk)2E = \frac{1}{2}\sum_{k}(y_k - t_k)^2E=21k∑(yk−tk)2

对应代码:

python 复制代码
def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t)**2)

4.4 交叉熵误差

是什么? 计算正确解标签对应的输出的自然对数。

公式:

E=−∑ktklog⁡(yk)E = -\sum_{k}t_k\log(y_k)E=−k∑tklog(yk)

对应代码:

python 复制代码
def cross_entropy_error(y, t):
    delta = 1e-7  # 防止log(0)
    return -np.sum(t * np.log(y + delta))

# mini-batch版本
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

4.5 数值微分与梯度

是什么? 利用微小差分求导数的方法。

为什么需要? 计算损失函数对权重参数的梯度。

作用? 梯度指示损失函数值减小最多的方向。

数值微分(中心差分):

python 复制代码
def numerical_diff(f, x):
    h = 1e-4  # 0.0001
    return (f(x + h) - f(x - h)) / (2 * h)

梯度:

python 复制代码
def numerical_gradient(f, x):
    h = 1e-4
    grad = np.zeros_like(x)
    for idx in range(x.size):
        tmp_val = x[idx]
        x[idx] = tmp_val + h
        fxh1 = f(x)
        x[idx] = tmp_val - h
        fxh2 = f(x)
        grad[idx] = (fxh1 - fxh2) / (2 * h)
        x[idx] = tmp_val
    return grad

4.6 梯度下降法

是什么? 沿着梯度方向更新参数,逐渐减小函数值的方法。

公式:

x0=x0−η∂f∂x0x_0 = x_0 - \eta\frac{\partial f}{\partial x_0}x0=x0−η∂x0∂f
x1=x1−η∂f∂x1x_1 = x_1 - \eta\frac{\partial f}{\partial x_1}x1=x1−η∂x1∂f

其中 η\etaη 为学习率。

对应代码:

python 复制代码
def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x
    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
    return x

超参数: 学习率等需要人工设定的参数。


4.7 神经网络的学习算法实现

对应代码:

python 复制代码
class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, 
                 weight_init_std=0.01):
        self.params = {}
        self.params['W1'] = weight_init_std * \
            np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * \
            np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)
    
    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        return y
    
    def loss(self, x, t):
        y = self.predict(x)
        return cross_entropy_error(y, t)
    
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy
    
    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        grads = {}
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        return grads

学习过程:

python 复制代码
for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    grad = network.numerical_gradient(x_batch, t_batch)
    
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]

[由此引出:数值微分的缺点]

→ 计算量大,耗时长

→ 需要更高效的方法:误差反向传播法


第5章 误差反向传播法

核心思想: 通过计算图和链式法则,高效地计算神经网络中各层参数的梯度。

5.1 计算图

是什么? 将计算过程用图形表示,通过节点和边表示。

为什么需要? 直观理解计算过程,高效计算导数。

作用? 通过正向传播计算结果,通过反向传播计算导数。

局部计算: 无论全局多么复杂,各个节点只需进行与自己相关的简单计算。


5.2 链式法则

是什么? 复合函数的导数等于各函数导数的乘积。

公式:

如果 z=f(g(x))z = f(g(x))z=f(g(x)),则
∂z∂x=∂z∂g⋅∂g∂x\frac{\partial z}{\partial x} = \frac{\partial z}{\partial g} \cdot \frac{\partial g}{\partial x}∂x∂z=∂g∂z⋅∂x∂g

计算图中的反向传播: 将上游传来的导数乘以局部导数,传递给下游。


5.3 加法节点和乘法节点的反向传播

加法节点: 将上游的值原封不动地传给下游

∂z∂x=1,∂z∂y=1\frac{\partial z}{\partial x} = 1, \quad \frac{\partial z}{\partial y} = 1∂x∂z=1,∂y∂z=1

乘法节点: 将上游的值乘以正向传播时的"翻转值"

∂z∂x=y,∂z∂y=x\frac{\partial z}{\partial x} = y, \quad \frac{\partial z}{\partial y} = x∂x∂z=y,∂y∂z=x

对应代码:

python 复制代码
class MulLayer:
    def __init__(self):
        self.x = None
        self.y = None
    
    def forward(self, x, y):
        self.x = x
        self.y = y
        out = x * y
        return out
    
    def backward(self, dout):
        dx = dout * self.y  # 翻转x和y
        dy = dout * self.x
        return dx, dy

class AddLayer:
    def __init__(self):
        pass
    
    def forward(self, x, y):
        out = x + y
        return out
    
    def backward(self, dout):
        dx = dout * 1
        dy = dout * 1
        return dx, dy

5.4 激活函数层的实现

ReLU层:

python 复制代码
class Relu:
    def __init__(self):
        self.mask = None
    
    def forward(self, x):
        self.mask = (x <= 0)
        out = x.copy()
        out[self.mask] = 0
        return out
    
    def backward(self, dout):
        dout[self.mask] = 0
        dx = dout
        return dx

Sigmoid层:

python 复制代码
class Sigmoid:
    def __init__(self):
        self.out = None
    
    def forward(self, x):
        out = 1 / (1 + np.exp(-x))
        self.out = out
        return out
    
    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out
        return dx

5.5 Affine层(全连接层)

是什么? 实现矩阵乘积和偏置加法的层。

正向传播: Y=X⋅W+BY = X \cdot W + BY=X⋅W+B

反向传播:

∂L∂X=∂L∂Y⋅WT\frac{\partial L}{\partial X} = \frac{\partial L}{\partial Y} \cdot W^T∂X∂L=∂Y∂L⋅WT
∂L∂W=XT⋅∂L∂Y\frac{\partial L}{\partial W} = X^T \cdot \frac{\partial L}{\partial Y}∂W∂L=XT⋅∂Y∂L
∂L∂B=∑i∂L∂Yi\frac{\partial L}{\partial B} = \sum_{i}\frac{\partial L}{\partial Y_i}∂B∂L=i∑∂Yi∂L

对应代码:

python 复制代码
class Affine:
    def __init__(self, W, b):
        self.W = W
        self.b = b
        self.x = None
        self.dW = None
        self.db = None
    
    def forward(self, x):
        self.x = x
        out = np.dot(x, self.W) + self.b
        return out
    
    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis=0)
        return dx

5.6 Softmax-with-Loss层

是什么? Softmax函数和交叉熵误差的组合层。

反向传播的"漂亮"结果:

∂L∂ak=yk−tk\frac{\partial L}{\partial a_k} = y_k - t_k∂ak∂L=yk−tk

这是Softmax输出与教师标签的差分,直接表示当前神经网络的误差。

对应代码:

python 复制代码
class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None
        self.t = None
    
    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        return self.loss
    
    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size
        return dx

5.7 误差反向传播法的实现

对应代码:

python 复制代码
class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, 
                 weight_init_std=0.01):
        self.params = {}
        self.params['W1'] = weight_init_std * \
            np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * \
            np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)
        
        self.layers = OrderedDict()
        self.layers['Affine1'] = \
            Affine(self.params['W1'], self.params['b1'])
        self.layers['Relu1'] = Relu()
        self.layers['Affine2'] = \
            Affine(self.params['W2'], self.params['b2'])
        self.lastLayer = SoftmaxWithLoss()
    
    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)
        return x
    
    def gradient(self, x, t):
        # forward
        self.loss(x, t)
        
        # backward
        dout = 1
        dout = self.lastLayer.backward(dout)
        
        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)
        
        grads = {}
        grads['W1'] = self.layers['Affine1'].dW
        grads['b1'] = self.layers['Affine1'].db
        grads['W2'] = self.layers['Affine2'].dW
        grads['b2'] = self.layers['Affine2'].db
        return grads

5.8 梯度确认

是什么? 比较数值微分和误差反向传播法的结果,确认实现是否正确。

为什么需要? 误差反向传播法实现复杂,容易出错。

对应代码:

python 复制代码
grad_numerical = network.numerical_gradient(x_batch, t_batch)
grad_backprop = network.gradient(x_batch, t_batch)

for key in grad_numerical.keys():
    diff = np.average(np.abs(grad_backprop[key] - grad_numerical[key]))
    print(key + ":" + str(diff))

第6章 与学习相关的技巧

核心思想: 通过优化参数更新方法、合理设置权重初始值、使用正则化技术,提高神经网络的学习效率和泛化能力。

6.1 参数的更新方法

对比表格:

方法 特点 优点 缺点
SGD 沿梯度方向更新 简单、易实现 非均向函数效率低
Momentum 引入速度概念 加速收敛,减少振荡 需要额外参数
AdaGrad 自适应学习率 适合稀疏数据 学习率可能过小
Adam Momentum + AdaGrad 综合优点,效果好 需要更多超参数

SGD:

python 复制代码
class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr
    
    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]

Momentum:

python 复制代码
class Momentum:
    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None
    
    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)
        
        for key in params.keys():
            self.v[key] = self.momentum * self.v[key] - self.lr * grads[key]
            params[key] += self.v[key]

AdaGrad:

python 复制代码
class AdaGrad:
    def __init__(self, lr=0.01):
        self.lr = lr
        self.h = None
    
    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)
        
        for key in params.keys():
            self.h[key] += grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

6.2 权重的初始值

是什么? 神经网络学习开始前权重的初始赋值。

为什么重要? 关系到学习能否成功进行。

[由此引出:权重初始化的关键问题]

→ 权重不能设为0(会导致对称性问题)

→ 权重不能太大(会导致梯度消失)

→ 权重不能太小(会导致表现力受限)

对比表格:

初始值 适用激活函数 公式
Xavier Sigmoid、Tanh 1n\sqrt{\frac{1}{n}}n1
He ReLU 2n\sqrt{\frac{2}{n}}n2

Xavier初始值:

python 复制代码
node_num = 100  # 前一层的节点数
w = np.random.randn(node_num, node_num) / np.sqrt(node_num)

He初始值:

python 复制代码
node_num = 100  # 前一层的节点数
w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num)

6.3 Batch Normalization

是什么? 对每层的激活值进行正规化的技术。

为什么需要? 使各层拥有适当的广度,加速学习。

作用?

  • 使学习快速进行(可增大学习率)
  • 不那么依赖初始值
  • 抑制过拟合

算法:

μB←1m∑i=1mxi\mu_B \leftarrow \frac{1}{m}\sum_{i=1}^{m}x_iμB←m1i=1∑mxi
σB2←1m∑i=1m(xi−μB)2\sigma^2_B \leftarrow \frac{1}{m}\sum_{i=1}^{m}(x_i - \mu_B)^2σB2←m1i=1∑m(xi−μB)2
x^i←xi−μBσB2+ϵ\hat{x}_i \leftarrow \frac{x_i - \mu_B}{\sqrt{\sigma^2_B + \epsilon}}x^i←σB2+ϵ xi−μB
yi←γx^i+βy_i \leftarrow \gamma\hat{x}_i + \betayi←γx^i+β


6.4 正则化

是什么? 抑制过拟合的技术。

为什么需要? 防止模型过度拟合训练数据,提高泛化能力。

[由此引出:过拟合的原因]

→ 模型拥有大量参数、表现力强

→ 训练数据少

6.4.1 权值衰减

是什么? 对大的权重进行惩罚。

公式:

L=L0+12λW2L = L_0 + \frac{1}{2}\lambda W^2L=L0+21λW2

其中 λ\lambdaλ 是控制正则化强度的超参数。

6.4.2 Dropout

是什么? 随机删除神经元的方法。

为什么有效? 可以理解为集成学习的近似实现。

对应代码:

python 复制代码
class Dropout:
    def __init__(self, dropout_ratio=0.5):
        self.dropout_ratio = dropout_ratio
        self.mask = None
    
    def forward(self, x, train_flg=True):
        if train_flg:
            self.mask = np.random.rand(*x.shape) > self.dropout_ratio
            return x * self.mask
        else:
            return x * (1.0 - self.dropout_ratio)
    
    def backward(self, dout):
        return dout * self.mask

6.5 超参数的验证

是什么? 寻找最优超参数值的过程。

超参数包括:

  • 各层神经元数量
  • batch大小
  • 学习率
  • 权值衰减系数

验证数据: 专门用于评估超参数性能的数据,不能用测试数据。

最优化步骤:

  1. 设定超参数的范围(对数尺度)
  2. 从范围内随机采样
  3. 使用采样值进行学习,通过验证数据评估
  4. 重复步骤2-3,根据结果缩小范围

对应代码:

python 复制代码
# 对数尺度随机采样
weight_decay = 10 ** np.random.uniform(-8, -4)
lr = 10 ** np.random.uniform(-6, -2)

第7章 卷积神经网络(CNN)

核心思想: CNN通过卷积层和池化层保持数据的空间结构,高效提取图像特征。

7.1 整体结构

是什么? 新增了卷积层(Convolution层)和池化层(Pooling层)的神经网络。

为什么需要? 全连接层忽视了数据的形状,无法利用空间信息。

典型结构:

Conv → ReLU → Pooling → Conv → ReLU → Pooling → Affine → ReLU → Affine → Softmax


7.2 卷积层

是什么? 对输入数据应用滤波器(卷积核)的层。

卷积运算: 滤波器在输入数据上滑动,计算乘积累加。

输出大小计算公式:

OH=H+2P−FHS+1OH = \frac{H + 2P - FH}{S} + 1OH=SH+2P−FH+1
OW=W+2P−FWS+1OW = \frac{W + 2P - FW}{S} + 1OW=SW+2P−FW+1

其中:H=输入高,W=输入宽,P=填充,S=步幅,FH=滤波器高,FW=滤波器宽

对比表格:

概念 说明
填充(Padding) 在输入数据周围填充0,调整输出大小
步幅(Stride) 滤波器应用的位置间隔
滤波器 卷积层的权重参数
偏置 加到滤波器应用结果上的固定值

7.3 池化层

是什么? 缩小高、长方向空间的层。

为什么需要? 减少参数数量,提高模型鲁棒性。

Max池化: 取目标区域的最大值

特点:

  • 没有要学习的参数
  • 通道数不发生变化
  • 对微小位置变化具有鲁棒性

7.4 im2col技巧

是什么? 将输入数据展开为适合矩阵乘积的形式。

为什么需要? 高效实现卷积运算。

对应代码(概念):

python 复制代码
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    # 将输入数据展开为2维数组
    # 便于使用矩阵乘法高效计算卷积
    pass

总结:深度学习核心概念图谱

复制代码
感知机(单层)
    ↓ [无法解决非线性问题]
多层感知机
    ↓ [激活函数不连续,无法学习]
神经网络(Sigmoid/ReLU)
    ↓ [需要高效计算梯度]
误差反向传播法
    ↓ [需要优化学习效率]
优化方法(SGD/Momentum/AdaGrad/Adam)
    ↓ [需要稳定训练]
权重初始化(Xavier/He)+ Batch Normalization
    ↓ [防止过拟合]
正则化(权值衰减/Dropout)
    ↓ [处理图像数据]
卷积神经网络(CNN)

重要公式汇总

激活函数:

Sigmoid: σ(x)=11+e−x\sigma(x) = \frac{1}{1 + e^{-x}}σ(x)=1+e−x1
ReLU: f(x)=max⁡(0,x)f(x) = \max(0, x)f(x)=max(0,x)
Softmax: yk=eak∑i=1neaiy_k = \frac{e^{a_k}}{\sum_{i=1}^{n}e^{a_i}}yk=∑i=1neaieak

损失函数:

均方误差: E=12∑k(yk−tk)2E = \frac{1}{2}\sum_{k}(y_k - t_k)^2E=21∑k(yk−tk)2
交叉熵误差: E=−∑ktklog⁡(yk)E = -\sum_{k}t_k\log(y_k)E=−∑ktklog(yk)

梯度下降:

W←W−η∂L∂WW \leftarrow W - \eta\frac{\partial L}{\partial W}W←W−η∂W∂L

权重初始化:

Xavier: 1n\sqrt{\frac{1}{n}}n1
He: 2n\sqrt{\frac{2}{n}}n2

卷积输出大小:

OH=H+2P−FHS+1OH = \frac{H + 2P - FH}{S} + 1OH=SH+2P−FH+1


笔记整理完成

相关推荐
FoldWinCard1 小时前
Python 第五次作业
linux·windows·python
Aliex_git1 小时前
gzip 压缩实践笔记
前端·网络·笔记·学习
China_Yanhy1 小时前
转型AI运维工程师·Day 10:拥抱“不确定性” —— 断点续训与 Spot 实例抢占
运维·人工智能·python
挖你家服务器电缆1 小时前
【深度学习系列学习总结】四大框架之一:cnn
人工智能·深度学习·cnn
花酒锄作田1 小时前
Flask - 常见应用部署方案
python·flask
宝贝儿好1 小时前
【强化学习】第九章:基于Action-Critic框架的强化学习
人工智能·python·深度学习·算法·动态规划
VXbishe1 小时前
基于web的校园失物招领管理系统-计算机毕设 附源码 24150
javascript·vue.js·spring boot·python·node.js·php·html5
小宋10212 小时前
Java 数据库访问 vs Python 数据库访问:JDBC vs ORM
java·数据库·python
秃了也弱了。2 小时前
python修复json神器:json-repair包(用于大模型返回json不规范)
python·json