《鱼书》笔记

kkyljr 发布于 2026-04-08 184 次阅读


《鱼书》笔记

1. python基础

1.1 Numpy

​ Np的广播:

>>> x = np.array([1.0, 2.0, 3.0])
>>> x / 2.0
array([ 0.5,  1. ,  1.5])

​ 多维数组:

>>> A = np.array([[1, 2], [3, 4]])
>>> print(A)
[[1 2]
 [3 4]]
>>> A.shape  #多维数组每项长度一样否则报错
(2, 2)
>>> A.dtype  #矩阵元素的数据类型
dtype('int64')

>>> B = np.array([[3, 0],[0, 6]])
>>> A + B
array([[ 4,  2],
       [ 3, 10]])
>>> A * B     # *号为直接数组对应元素乘积
array([[ 3,  0],
       [ 0, 24]])

​ 访问操作:

>>> X = np.array([[51, 55], [14, 19], [0, 4]])
>>> X = X.flatten()       # 将X转换为一维数组, 即拉平
>>> print(X)
[51 55 14 19  0  4]
>>> X[np.array([0, 2, 4])] # 获取索引为0、2、4的元素
array([51, 14,  0])

​ 矩阵乘积(点乘):

>>> A = np.array([[1,2], [3,4]])
>>> A.shape
(2, 2)
>>> B = np.array([[5,6], [7,8]])
>>> B.shape
(2, 2)
>>> np.dot(A, B)
array([[19, 22],
       [43, 50]])

1.2 Matplotlib

import numpy as np
import matplotlib.pyplot as plt
# 生成数据
x = np.arange(0, 6, 0.1) # 以0.1为单位,生成0到6的数据
y = np.sin(x)
# 绘图
plt.plot(x, y)
plt.show()
x = np.arange(0, 6, 0.1) # 以0.1为单位,生成0到6的数据
y1 = np.sin(x)
y2 = np.cos(x)
# 绘制图形
plt.plot(x, y1, label="sin")
plt.plot(x, y2, linestyle = "--", label="cos") # 用虚线绘制
plt.xlabel("x") # x轴标签
plt.ylabel("y") # y轴标签
plt.title('sin & cos') # 标题
plt.legend()    #图例显示, 收集plot()中的label
plt.show()

​ 显示图像:

import matplotlib.pyplot as plt
from matplotlib.image import imread
img = imread('lena.png') # 读入图像(设定合适的路径!)
plt.imshow(img)
plt.show()

2. 感知机

2.1 什么是感知机

​ 感知机算法是美国学者Frank Rosenblatt在1957年提出来的, 是神经网络的起源算法.

​ 感知机接收多个输入信号, 输出一个信号. 在感知机中, ==输出信号==只有 0/1 两种取值. 为方便理解, 0对应"不传递信号", 1对应"传递信号".

image-20260403042632610.png

​ 其中x~1~, x~2~为输入信号, w~1~, w~2~为权重. 图中圆圈称为"神经元"或者"节点". 输入信号被送往神经元时, 会分别乘以固定的权重. 这些信号的总和超过阈值 θ 时, 才会输出1, 称之为"神经元被激活". 即:

image-20260403043809335.png

​ 令θ = -b, 则有image-20260407113837705.png

​ 把b成为偏置, 把w~1~, w~2~称为权重

​ w~1~, w~2~为控制输入信号重要性的参数, 偏置是调整神经元被激活的容易程度的参数.

2.2 感知机的局限性

​ 用上文中的感知机模型无法实现异或门, (w~1~, w~2~ + b> 0, 与w~1~ + w~2~ + b< 0矛盾)

2.2.1 线性与非线性

image-20260407114941700.png

image-20260407115018388.png

2.3 多层感知机 (异或门实现)

​ 感知机的叠加, 使得感知机能够实现更多的功能, 如下图: image-20260407115930480.png

image-20260407120101998.png

3.神经网络

​ 神经网络的出线, 可以自动地从数据中学习到合适的权重参数.

3.1 神经网络的结构

​ 输入层 ---- 隐藏层(中间层) ---- 输出层

image-20260407121406959.png

3.2 激活函数

激活函数: 将输入信号总和转化为输出信号的函数. 即下图中h(x):

image-20260407121746697.png

3.2.1 阶跃函数

前文中的激活函数称为阶跃函数, 一旦输入超过阈值, 就切换输出.

3.2.2 sigmoid函数

image-20260407123309684.png

激活函数必须使用非线性函数, 因为如果使用线性函数的话, 那么叠加层就没有意义了

3.2.3 ReLU(Rectified Linear Unit)函数

​ ReLU函数, 输入大于0, 直接输出该值; 输入小于等于0时, 输出0.image-20260407131826555.png

3.3 3层神经网络的实现

image-20260407192502411.png

image-20260407192508426.png

​ 第一层的加权和可以表示为:image-20260407192519727.png

​ 上述操作计算出了加权信号与偏置之和, 然后还要通过之前学习的激活函数转换为输出信号.

代码实现如下:

def step_function(x):
    return np.array(x &gt; 0, dtype=int)

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def relu(x):
    return np.maximum(0, x)

def identity_function(x):   #恒等函数
    return x

def init_network():     #三层神经网络
        network = {}
        network[&#039;W1&#039;] = np.array([[0.1,0.3,0.5], [0.2, 0.4, 0.6]])
        network[&#039;b1&#039;] = np.array([0.1, 0.2, 0.3])
        network[&#039;W2&#039;] = np.array([[0.1,0.4], [0.2, 0.5], [0.3, 0.6]])
        network[&#039;b2&#039;] = np.array([0.1, 0.2])
        network[&#039;W3&#039;] = np.array([[0.1,0.3], [0.2, 0.4]])
        network[&#039;b3&#039;] = np.array([0.1, 0.2])

        return network

def forward(network, x):
    W1, W2, W3 = network[&#039;W1&#039;], network[&#039;W2&#039;], network[&#039;W3&#039;]
    b1, b2, b3 = network[&#039;b1&#039;], network[&#039;b2&#039;], network[&#039;b3&#039;]

    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

network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)

3.4 输出层设计

​ 一般来说, 回归问题用恒等函数, 分类问题用softmax函数

3.4.1 softmax函数

image-20260407230328377.png

由于在计算机中, exp容易溢出, 所以需要对softmax函数进行改进

image-20260407230802351.png

​ 可以观察到, y~k~的和为1, 我们可以把softmax的输出解释为概率, 所以一般用于分类模型中, 一般而言, 神经网络只把输出值最大的神经元对应的类别作为识别结果. 且exp为递增函数, 故在进行推理阶段时, softmax函数可以省略.

3.5 MNIST数字识别

​ 略

4. 神经网络的学习

​ 机器学习的最终目标是获得泛化能力, 泛化能力是指处理未被观察过的数据的能力.

如果只对特定数据集处理能力好, 称为过拟合

4.1 损失函数

​ 神经网络以某个指标为线索寻找最优的权重参数, 神经网络的学习中这个指标称为损失函数

损失函数 是表示神经网络性能的"恶劣程度"的指标, 即当前的神经网络对监督数据在多大程度上不拟合, 不一致.

4.1.1 均方误差

image-20260408182701400.png

4.1.2 交叉熵误差

image-20260408183302997.png

​ 在one-hot表示中, t~k~只有正确解的标签为1, 所以实际上交叉熵误差的值由正确解标签所对应的输出结果决定.

​ 在代码实现中, 为了防止 ln0 爆Inf, 所以可以添加一个微小值进行保护:

def cross_entropy_error(y, t):
    delta = 1e-7
    return -np.sum(t * np.log(y + delta))

4.1.3 mini-batch学习

​ 上述函数均为针对单个数据的损失函数, 如果要求所有训练数据的损失函数的总和, 以交叉熵误差为例, 可以写成下式.

image-20260408184125519.png

​ 如果遇到数据量大的情况, 计算全部数据的误差和是不现实的. 因此, 我们可以从全部数据中选出一部分, 作为全部数据的"近似". 神经网络的学习也是从训练数据中选出一批数据(称为mini-batch, 小批量), 然后对每个mini-batch进行学习. 这种方式称为mini-batch学习.

image-20260408184939680.png

4.2 梯度

​ 机器学习中优化问题最常用的方法就是梯度下降法, 用于减小损失函数的值.

image-20260408192726909.png

4.3 学习算法的实现

image-20260409042846462.png

​ 上图为书中初始化权重的函数, 可以发现在生成权重w时在随机生成后还乘以了一个weight_init_std, 这是由于sigmoid函数的特性, 在0和1处无法训练的问题.

超参数: 需要先手动设定的参数, 如权重, lr, 循环次数等

5. 误差反向传播法

5.1 反向传播链式法则

5.1.1 计算图

image-20260409052535111.png

​ 计算图可以集中精力于局部计算, 通过传递局部计算的结果, 可以获得全局的复杂计算结果

5.1.2 反向传播

image-20260409054030314.png

5.1.3 Affine层实现

image-20260409064355312.png

5.1.4 Softmax-with-Loss层

image-20260409070713504.png

image-20260409070728877.png