系列目录
《Web安全之机器学习入门》笔记:第十五章 15.4 TensorFlow识别验证码(一)
《Web安全之机器学习入门》笔记:第十五章 15.5 TensorFlow多层感知机识别验证码(二)
《Web安全之机器学习入门》笔记:第十五章 15.6 TensorFlow DNN识别验证码(三)
《Web安全之机器学习入门》笔记:第十五章 15.7与15.8 TensorFlow识别垃圾邮件
目录
本章节根据《Web安全之机器学习入门》第15章神经网络来完成笔记,本小节目标是通过实例展示如何使用tensorflow识别验证码(MNIST图像)。
1、数据集
本小节仍然使用MNIST数据集,它包含70,000张28×28像素的手写数字灰度图像(0-9),其中60,000张用于训练,10,000张用于测试。每张图像都经过标准化和居中处理,并配有对应标签。该数据集由美国国家标准与技术研究院(NIST)整理发布,配套代码如下所示。
def load_data():
with gzip.open('../data/MNIST/mnist.pkl.gz') as fp:
training_data, valid_data, test_data = pickle.load(fp)
return training_data, valid_data, test_data
training_data, valid_data, test_dat=load_data()
x_training_data,y_training_data=training_data
x1,y1=test_dat
不过运行过程中会报错,具体如下所示。
Traceback (most recent call last):
File "C:/Users/xx/PycharmProjects/pythonProject/Web安全之机器学习入门/code/15-1.py", line 21, in <module>
training_data, valid_data, test_dat=load_data()
File "C:/Users/xx/PycharmProjects/pythonProject/Web安全之机器学习入门/code/15-1.py", line 18, in load_data
training_data, valid_data, test_data = pickle.load(fp)
UnicodeDecodeError: 'ascii' codec can't decode byte 0x90 in position 614: ordinal not in range(128)
将代码修改后可以跑通,具体如下所示。
def load_data():
with gzip.open('../data/MNIST/mnist.pkl.gz') as fp:
training_data, valid_data, test_data = pickle.load(fp, encoding="bytes")
return training_data, valid_data, test_data
2、label特征化
One-Hot编码是一种将分类变量转换为二进制向量的方法,每个类别对应向量中的一个位置。对于有N个类别的特征,One-Hot编码会生成一个长度为N的向量,其中只有对应类别的位置为1,其余为0。例如,数字3在0-9的分类中的One-Hot编码为[0,0,0,1,0,0,0,0,0,0]
。
特点:
-
消除类别间的数值大小关系,避免模型误解为有序数据
-
适用于类别数量较少的情况(避免维度爆炸)
这里使用one-hot法,具体如下所示。
y_training_data=get_one_hot(y_training_data)
y1=get_one_hot(y1)
3、源码修改
(1)报警信息1
Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
如果安装的是CPU版本(pip install tensorflow),在源码中加入如下代码,忽略警告
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
(2)报警信息2
Use `tf.global_variables_initializer` instead.
需要将如下源码进行修改。
tf.initialize_all_variables
修改后的代码如下所示。
tf.global_variables_initializer
(3)报警信息3
The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.
修改方法如下所示。
import tensorflow.compat.v1 as tf
4、训练过程
tensorflow的计算过程如下图所示。
5、完整代码
用 TensorFlow 构建简单神经网络识别 MNIST 手写数字。加载数据集后,将训练和测试标签转为 one-hot 编码;定义输入占位符(784 维特征)、权重(784×10)和偏置(10 维),通过 softmax 函数输出 10 类概率;以交叉熵为损失,用梯度下降(学习率 0.01)优化,按批量(100 样本)训练;最后计算测试集准确率,完成从数据预处理、模型搭建、训练到评估的完整流程,实现手写数字分类。具体步骤如下:
- 数据加载与预处理:加载 MNIST 数据集,并将标签转换为 one - hot 编码。
- 模型构建:定义输入层、权重、偏置和输出层,使用 softmax 函数进行分类。
- 损失函数与优化器:使用交叉熵损失函数和梯度下降优化器进行训练。
- 模型训练:按批量对模型进行训练。
- 模型评估:在测试数据上计算模型的准确率。
import tensorflow as tf
import pickle
import gzip
# 导入 TensorFlow 1.x 版本的兼容模块,以便使用旧版本的 API
import tensorflow.compat.v1 as tf
import os
# 设置 TensorFlow 的日志级别为 2,只显示错误信息,避免输出过多的警告和信息
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# 定义一个函数,用于将输入的标签列表转换为 one - hot 编码形式
def get_one_hot(x, size=10):
v = []
# 遍历输入的每个标签
for x1 in x:
# 初始化一个长度为 size 的零列表
x2 = [0] * size
# 将对应位置的元素设置为 1,这里假设标签从 1 开始计数
x2[(x1 - 1)] = 1
v.append(x2)
return v
# 定义一个函数,用于加载 MNIST 数据集
def load_data():
# 以二进制读取模式打开压缩文件
with gzip.open('../data/MNIST/mnist.pkl.gz') as fp:
# 从文件中加载训练数据、验证数据和测试数据
training_data, valid_data, test_data = pickle.load(fp, encoding="bytes")
return training_data, valid_data, test_data
# 调用 load_data 函数加载数据集
training_data, valid_data, test_dat = load_data()
# 从训练数据中分离出特征数据和标签数据
x_training_data, y_training_data = training_data
# 从测试数据中分离出特征数据和标签数据
x1, y1 = test_dat
# 将训练标签转换为 one - hot 编码
y_training_data = get_one_hot(y_training_data)
# 将测试标签转换为 one - hot 编码
y1 = get_one_hot(y1)
# 定义批量大小,即每次训练使用的样本数量
batch_size = 100
# 定义输入数据的占位符,形状为 [None, 784]
# None 表示样本数量不固定,784 是 MNIST 图像展平后的特征数量(28x28)
x = tf.placeholder("float", [None, 784])
# 定义权重矩阵的变量,初始值全为 0,形状为 [784, 10]
# 784 是输入特征数量,10 是输出类别数量(0 - 9 数字)
W = tf.Variable(tf.zeros([784, 10]))
# 定义偏置向量的变量,初始值全为 0,形状为 [10]
b = tf.Variable(tf.zeros([10]))
# 计算模型的预测输出
# 先进行矩阵乘法 x * W,再加上偏置 b,最后通过 softmax 函数转换为概率分布
y = tf.nn.softmax(tf.matmul(x, W) + b)
# 定义真实标签的占位符,形状为 [None, 10]
y_ = tf.placeholder("float", [None, 10])
# 计算交叉熵损失,用于衡量预测值和真实值之间的差异
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
# 定义优化器,使用梯度下降优化器,学习率为 0.01
# 目标是最小化交叉熵损失
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
# 初始化所有变量
init = tf.global_variables_initializer()
# 创建一个 TensorFlow 会话,用于执行计算图
sess = tf.Session()
# 运行初始化操作,初始化所有变量
sess.run(init)
# 开始训练循环,循环次数为训练数据总数除以批量大小
for i in range(int(len(x_training_data) / batch_size)):
# 从训练数据中取出一个批量的特征数据
batch_xs = x_training_data[(i * batch_size):((i + 1) * batch_size)]
# 从训练数据中取出一个批量的标签数据
batch_ys = y_training_data[(i * batch_size):((i + 1) * batch_size)]
# 运行训练步骤,传入批量数据
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
# 定义预测结果和真实标签是否相等的判断操作
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
# 计算准确率,将布尔值转换为浮点数并求平均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# 在测试数据上计算准确率,传入测试数据
print(sess.run(accuracy, feed_dict={x: x1, y_: y1}))
对源码进行详细分析, 重点关注模型架构和训练的配置参数,具体如下所示。
(1)模型架构
- 模型类型:单隐层神经网络(简化版逻辑回归),使用 softmax 激活函数实现多分类
- 输入层:784 个神经元(对应 28×28 像素的 MNIST 图像展平向量)
- 输出层:10 个神经元(对应数字 0-9 的类别概率分布)
- 权重矩阵:
W
维度为[784, 10]
,初始化为全零 - 偏置向量:
b
维度为[10]
,初始化为全零
(2)核心公式
- 线性变换:
z = x·W + b
- softmax 激活:
y = softmax(z)
,将线性输出转换为概率分布 - 损失函数:交叉熵损失
H(y', y) = -∑y'·log(y)
- 优化方法:梯度下降(Gradient Descent),学习率 0.01
(3)训练机制
- 批量训练:每次处理 100 个样本(batch_size=100)
- 迭代次数:
len(x_training_data) / batch_size
(约 600 次) - 参数更新:通过最小化交叉熵损失,迭代更新 W 和 b
(4)数据处理
- 标签转换:将数字标签(如 5)转为 one-hot 编码(如
[0,0,0,0,0,1,0,0,0,0]
) - 数据划分:使用原始测试集(10,000 样本)进行评估
(5)性能评估
- 准确率计算:
tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
- 评估指标:最终输出测试集上的分类准确率
6、运行结果
运行结果显示模型在 MNIST 测试集上的准确率为 90.97%。
0.9097