手搓一个简单的神经网络识别猫猫图像
基本流程
加载数据 –> 训练模型找出 w,b –> 将 w,b 代入预测函数 –> 预测
实现
数据加载
数据是给好的hd5文件低像素图片
导入库 –> 加载数据集 –> 数据重塑
1 | import numpy as np # 导入NumPy库,用于科学计算 |
我们可以模拟一个简单的 HDF5 数据集结构,并使用它来测试数据加载和处理功能
1 | import numpy as np |
1 | [0, 1] |
现在打印 train_set_x_orig 和 train_set_y_orig 的形状,观察数据的结构
1 | # 加载数据集 |
1 | train_set_x_orig shape: (209, 64, 64, 3) |
train_set_x_orig shape: (209, 64, 64, 3): 这表示训练集特征数据的形状。具体来说:
209 是样本数量,表示有 209 张图片。
64 是图片的高度和宽度,表示每张图片是 64x64 像素的正方形。
3 是通道数,表示每张图片是彩色的(RGB)。
train_set_y_orig shape: (1, 209): 这表示训练集标签数据的形状。具体来说:
1 是标签的维度,表示每个样本只有一个标签。
209 是样本数量,表示每个样本对应一个标签。
解释一下维度
标量: 没有维度,因为它是一个单一的数值。a=1
向量: 只有一个维度,表示为一个列或行。a=[1,2,3]
矩阵: 有两个维度,表示为行和列。a=[[1,2,3],[1,2,3]]
张量: 有三个或更多维度,可以看作是多个矩阵的集合。a=[[[1]],[[2]],[[3]]]
1 | scalar = np.array(1) # 标量,0维 |
解释一下重塑
- 原始的 test_set_y_orig 可能是一维数组,形状为 (样本数量,)。将其重塑为(1,样本数量)使得后续的矩阵运算更加方便和一致,尤其是在与其他二维数组(如特征矩阵)进行运算时。
(1, 样本数量) 表示一个行向量,其中有 样本数量 个元素。
1 | import numpy as np |
1 | 转换前: |
数据处理
1 | m_train = train_set_x_orig.shape[0] |
数据展平
操作
reshape(train_set_x_orig.shape[0], -1) 将每张图片展平成一个一维向量。
-1 表示自动计算展平后的维度。对于一张 64x64 的彩色图片,展平后会变成一个长度为 12288 的向量(64 * 64 * 3)。
.T 是转置操作,将数据从 (样本数量, 特征数) 转换为 (特征数, 样本数量),这在机器学习中是一个常见的格式。
为什么
展平操作将每张图片的像素值展平为一个一维向量,使得每个样本都可以用一个向量表示。
这种格式便于输入到机器学习模型中进行训练。
数据标准化
操作
将展平后的数据除以 255,将像素值缩放到 [0, 1] 的范围内。
这一步是为了加速模型的训练过程,并提高模型的稳定性。为什么标准化:
为什么
标准化可以使特征具有相同的尺度,避免某些特征对模型的影响过大。
通过缩放到 [0, 1],可以加速梯度下降的收敛。
模型初始化
对于线性模型,我们通常需要初始化权重和偏置。
1 | def initialize_with_zeros(dim): |
1 | import numpy as np |
前向传播和反向传播
1 | def propagate(w, b, X, Y): |
这里前向传播和反向传播直接带的公示,现在简要讲解一下原理
前向传播是指将输入数据通过神经网络传递,计算输出的过程。其主要目的是计算模型的预测值。
输入层:
- 输入数据 XX 被传递到网络的第一层。
隐藏层(如果有):
每个神经元接收输入,计算加权和,并通过激活函数得到输出。
公式:a[l]=σ(W[l]a[l−1]+b[l])a[l]=σ(W[l]a[l−1]+b[l])
其中,W[l]W[l] 是权重矩阵,b[l]b[l] 是偏置,σσ 是激活函数。
输出层:
- 最后一层的输出即为模型的预测值 Y^Y^。
损失计算:
- 计算预测值与真实值之间的差异,通常使用损失函数(如均方误差、交叉熵等)。
反向传播是指通过计算损失函数的梯度,更新模型参数的过程。其主要目的是最小化损失函数。
损失函数的梯度:
- 计算损失函数对输出层的梯度。
链式法则:
- 使用链式法则计算每一层的梯度。
参数更新:
- 使用梯度下降法更新权重和偏置。
简单来说,前向传播就是输入数据,计算损失;反向传播就是根据损失,调整参数。
模型优化
1 | def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost=False): |
模型预测函数
1 | def predict(w, b, X): |
构建和训练模型
我们将使用一个函数来整合所有步骤,包括初始化参数、优化参数、预测结果,并评估模型的性能。
1 | def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False): |
运行模型
运行之前,看一下数据集中的图片怎么样
1 | index = 30 |
1 | 标签为[0], 这是一个'non-cat' 图片. |
也是能够正常展示
1 | # 运行模型 |
==》
1 | 迭代的次数: 0, 误差值: 0.693147 |
我可以打印出成本的变化情况,即每次调整参数实际值与预测值的误差,应该是下降的。
1 | # 从字典 d 中提取成本列表,并去除不必要的维度,就是把二维的转成一维的,便于绘图 |
接着,我们可以看看基于损失函数,学习率对模型造成的影响。(一个好的学习率,能使结果更加准确)
1 | learning_rates = [0.01, 0.001, 0.0001] |
1 | 学习率为: 0.01时 |
这里选定学习率为 0.01
测试
通过模型训练我们找到了合适的 w,b,下一步就只需要拿这个 w,b 带入预测函数去测试图片了。
1 | # 读取图像文件并将其转换为 NumPy 数组 |
但是对真实图片来说,效果真的很差,可能因为数据集是像素图像,训练次数不够,并且这是一个单神经元网络。
没办法,最后再测一下测试数据里的内容。
1 | # 选择测试集中的一个图像索引 |
代码
1 | import numpy as np |
像素数据在库里。
后记
感受了一波半自动写模型,无奈菜的没边,各种问题最后都会铺面而来。
对于数据集的处理,模型逻辑代码,测试功能的编写都有待欠缺。等着下一次优化,一定能准确识别猫猫。
为了不让自己太过难堪,决定先去 py 一下别人的猫识别程序,不过他们的可能就不仅仅是猫识别了,QAQ。