《Web安全之机器学习入门》笔记:第十五章 15.6 TensorFlow DNN识别验证码(三)

该博客介绍了如何运用深度神经网络(DNN)识别MNIST数据集中的验证码。通过配置3层隐藏层和ReLU激活函数,建立多层感知机模型,并利用交叉熵作为损失函数,采用Adagrad进行优化。经过10轮训练,初始准确率为16.41%,调整学习率和训练轮数后,准确率提升至92.89%。优化过程探讨了学习率和训练轮数对模型性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 系列目录

《Web安全之机器学习入门》笔记:第十五章 15.4 TensorFlow识别验证码(一)

《Web安全之机器学习入门》笔记:第十五章 15.5 TensorFlow多层感知机识别验证码(二)

《Web安全之机器学习入门》笔记:第十五章 15.6 TensorFlow DNN识别验证码(三)

《Web安全之机器学习入门》笔记:第十五章 15.7与15.8 TensorFlow识别垃圾邮件

目录

一、DNN

二、数据集

三、代码

1、DNN原理图

2、定义DNN

(1)输入层

(2)隐藏层(共 3 层,均为全连接层)

(3)输出层

(4)参数初始化

3、完整代码

4、运行结果

5、程序优化


本章节根据《Web安全之机器学习入门》第15章神经网络来完成笔记,本小节通过DNN识别验证码(MNIST数据集)。

一、DNN

深度神经网络(DNN)是深度学习领域的重要模型。它由多个隐藏层组成,相比浅层神经网络,能学习到数据更复杂、抽象的特征表示。在结构上,包含输入层接收原始数据,多个隐藏层进行特征提取与变换,输出层给出最终结果。训练时,借助反向传播算法,根据预测值与真实值的误差调整各层权重,优化模型。在图像识别中,可提取图像的纹理、形状等深层特征实现精准分类;在语音识别里,能对语音信号进行特征建模以准确转写文字;在自然语言处理方面,可处理文本语义理解等任务。

二、数据集

MNIST数据集是机器学习领域的经典基准数据集,主要用于手写数字识别任务。该数据集由美国国家标准与技术研究院(NIST)整理,包含70,000张28×28像素的灰度图像,涵盖0-9共10个类别,其中60,000张为训练样本,10,000张为测试样本

三、代码

1、DNN原理图

2、定义DNN

模型是一个含三层隐藏层的多层感知机(MLP),专为 MNIST 手写数字分类设计,整体结构呈 “输入层→隐藏层 1→隐藏层 2→隐藏层 3→输出层” 的链式传递,各层参数与运算逻辑如下所示。

(1)输入层
  • 输入维度:784 维(对应 MNIST 图像 28×28 像素展平后的特征向量)
  • 占位符定义x = tf.placeholder("float", [None, 784])None表示支持任意批量的样本输入,784 固定为特征维度。
(2)隐藏层(共 3 层,均为全连接层)

每层均由 “线性变换 + ReLU 激活” 组成,通过全连接方式传递特征,逐步提取高层抽象特征:

  • 隐藏层 1

    • 神经元数量:300 个
    • 线性变换layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
      • 权重weights['h1']:维度[784, 300],连接输入层与隐藏层 1
      • 偏置biases['b1']:维度[300],为每个神经元添加偏置
    • 激活函数:ReLU(tf.nn.relu(layer_1)),引入非线性,增强特征表达能力
  • 隐藏层 2

    • 神经元数量:200 个
    • 线性变换layer_2 = tf.add(tf.matmul(layer_1, weights['h2']), biases['b2'])
      • 权重weights['h2']:维度[300, 200],连接隐藏层 1 与隐藏层 2
      • 偏置biases['b2']:维度[200]
    • 激活函数:ReLU,进一步提取非线性特征
  • 隐藏层 3

    • 神经元数量:100 个
    • 线性变换layer_3 = tf.add(tf.matmul(layer_2, weights['h3']), biases['b3'])
      • 权重weights['h3']:维度[200, 100],连接隐藏层 2 与隐藏层 3
      • 偏置biases['b3']:维度[100]
    • 激活函数:ReLU,继续压缩特征维度,提炼核心模式
(3)输出层
  • 输出维度:10 维(对应 0-9 共 10 个数字类别)
  • 线性变换out_layer = tf.matmul(layer_3, weights['out']) + biases['out']
    • 权重weights['out']:维度[100, 10],连接隐藏层 3 与输出层
    • 偏置biases['out']:维度[10],为每个类别添加偏置
  • 无激活函数:输出为原始 logits(未归一化的得分),需后续结合softmax计算概率(代码中通过tf.nn.softmax_cross_entropy_with_logits隐式处理)。
(4)参数初始化
  • 权重(weights):所有权重均用tf.random_normal初始化(服从正态分布的随机值),维度随层间连接关系动态调整(如[784, 300][300, 200]等)。
  • 偏置(biases):所有偏置同样用tf.random_normal初始化,维度与对应层神经元数量一致(如隐藏层 1 偏置为[300])。
n_hidden_1 = 300
n_hidden_2 = 200
n_hidden_3 = 100
n_input = 784
n_classes = 10

x = tf.placeholder("float",[None,784])
y = tf.placeholder("float",[None,n_classes])


def multilayer_perceptron(x,weights,biases):
    layer_1 = tf.add(tf.matmul(x,weights['h1']),biases['b1'])
    layer_1 = tf.nn.relu(layer_1)

    layer_2 = tf.add(tf.matmul(layer_1,weights['h2']),biases['b2'])
    layer_2 = tf.nn.relu(layer_2)

    layer_3 = tf.add(tf.matmul(layer_2,weights['h3']),biases['b3'])
    layer_3 = tf.nn.relu(layer_3)

    out_layer = tf.matmul(layer_3,weights['out']) + biases['out']
    #out_layer = tf.matmul(layer_2, weights['out']) + biases['out']
    return out_layer

weigths = {
    'h1': tf.Variable(tf.random_normal([n_input,n_hidden_1])),
    'h2': tf.Variable(tf.random_normal([n_hidden_1,n_hidden_2])),
    'h3': tf.Variable(tf.random_normal([n_hidden_2,n_hidden_3])),
    'out': tf.Variable(tf.random_normal([n_hidden_3,n_classes]))
    #'out': tf.Variable(tf.random_normal([n_hidden_2,n_classes]))
}

biases = {
    'b1': tf.Variable(tf.random_normal([n_hidden_1])),
    'b2': tf.Variable(tf.random_normal([n_hidden_2])),
    'b3': tf.Variable(tf.random_normal([n_hidden_3])),
    'out': tf.Variable(tf.random_normal([n_classes]))
}

pred = multilayer_perceptron(x,weigths,biases)

衰减函数则是使用交叉熵,使用Adagrad自使用调节

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred,labels=y))
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

3、完整代码

本文使用 TensorFlow 构建三层隐藏层的多层感知机(MLP)识别 MNIST 数字。加载数据并设超参数,网络含 3 个隐藏层(300、200、100 神经元,均用 ReLU 激活)和输出层,随机初始化权重偏置;以交叉熵为损失,梯度下降(学习率 0.001)训练 10 轮(每批 100 样本),输出每轮平均损失,最终测试准确率,实现较浅层模型更强的特征提取能力。主要处理逻辑如下所示。

  • 数据准备:使用TensorFlow内置的MNIST数据加载器,自动下载和管理数据集。

  • 网络结构:构建了一个4层神经网络(3个隐藏层+1个输出层),每层使用ReLU激活函数。

  • 训练过程:采用小批量梯度下降法,每轮遍历所有批次数据,计算并优化损失。

  • 评估指标:使用分类准确率作为模型性能评估标准。 

原书配套源码修改为可运行后,基于python3的完整源码如下所示:

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow.compat.v1 as tf  # 使用TensorFlow 1.x的API

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 屏蔽TensorFlow的非错误警告信息

# 加载MNIST数据集,one_hot表示标签是否采用独热编码格式
mnist = input_data.read_data_sets("../data/mnist", one_hot=True)

# 定义超参数
learning_rate = 0.001  # 学习率
training_epochs = 10    # 训练轮数
batch_size = 100        # 每批数据量
display_step = 1        # 每隔多少轮显示一次训练信息

# 网络结构参数
n_hidden_1 = 300  # 第一隐藏层神经元数量
n_hidden_2 = 200  # 第二隐藏层神经元数量
n_hidden_3 = 100  # 第三隐藏层神经元数量
n_input = 784     # MNIST数据输入维度(28x28=784)
n_classes = 10    # MNIST分类类别数(0-9共10类)

# 定义占位符
x = tf.placeholder("float", [None, 784])  # 输入数据占位符
y = tf.placeholder("float", [None, n_classes])  # 标签占位符

# 定义多层感知机模型
def multilayer_perceptron(x, weights, biases):
    # 第一隐藏层:矩阵乘法 + 偏置 + ReLU激活
    layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
    layer_1 = tf.nn.relu(layer_1)
    
    # 第二隐藏层
    layer_2 = tf.add(tf.matmul(layer_1, weights['h2']), biases['b2'])
    layer_2 = tf.nn.relu(layer_2)
    
    # 第三隐藏层
    layer_3 = tf.add(tf.matmul(layer_2, weights['h3']), biases['b3'])
    layer_3 = tf.nn.relu(layer_3)
    
    # 输出层(无激活函数)
    out_layer = tf.matmul(layer_3, weights['out']) + biases['out']
    return out_layer

# 定义权重和偏置变量
weights = {
    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),    # 输入层到第一隐藏层
    'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])), # 第一到第二隐藏层
    'h3': tf.Variable(tf.random_normal([n_hidden_2, n_hidden_3])), # 第二到第三隐藏层
    'out': tf.Variable(tf.random_normal([n_hidden_3, n_classes]))  # 第三隐藏层到输出层
}

biases = {
    'b1': tf.Variable(tf.random_normal([n_hidden_1])),  # 第一隐藏层偏置
    'b2': tf.Variable(tf.random_normal([n_hidden_2])),  # 第二隐藏层偏置
    'b3': tf.Variable(tf.random_normal([n_hidden_3])),  # 第三隐藏层偏置
    'out': tf.Variable(tf.random_normal([n_classes]))    # 输出层偏置
}

# 构建模型
pred = multilayer_perceptron(x, weights, biases)

# 定义损失函数和优化器
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))  # 交叉熵损失
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)  # 梯度下降优化器

# 初始化所有变量
init = tf.global_variables_initializer()

# 开始训练
with tf.Session() as sess:
    sess.run(init)  # 初始化变量
    
    # 按轮次训练
    for epoch in range(training_epochs):
        avg_cost = 0.  # 平均损失
        total_batch = int(mnist.train.num_examples / batch_size)  # 计算总批次数
        
        # 遍历所有批次
        for i in range(total_batch):
            batch_x, batch_y = mnist.train.next_batch(batch_size)  # 获取下一批数据
            # 运行优化器和损失计算
            _, c = sess.run([train_step, cost], feed_dict={x: batch_x, y: batch_y})
            avg_cost += c / total_batch  # 计算平均损失
        
        # 显示训练信息
        if epoch % display_step == 0:
            print("Epoch:", '%04d' % (epoch+1), "cost=", "{:.9f}".format(avg_cost))
    
    # 测试模型准确率
    correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))  # 比较预测和真实标签
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))     # 计算准确率
    print("Accuracy:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))  # 评估测试集

4、运行结果

运行结果如下所示,很明显0.2左右的准确率显示模型训练效果极差,存在明显问题,。

Epoch: 0001 cost= 160.255845963
Epoch: 0002 cost= 3.702655527
Epoch: 0003 cost= 2.998886849
Epoch: 0004 cost= 2.768014714
Epoch: 0005 cost= 2.632289400
Epoch: 0006 cost= 2.541885174
Epoch: 0007 cost= 2.471330396
Epoch: 0008 cost= 2.419655328
Epoch: 0009 cost= 2.382263158
Epoch: 0010 cost= 2.350417513
Accuracy: 0.1641

5、程序优化

(1)参照书中内容,将学习率由代码中的0.0001改为0.3,效果无明显增长

再将epoch轮数有10改为100,运行结果如下

test_accuracy= 0.8123

(2)更改train_step参数,同时修改学习率

train_step = tf.train.AdamOptimizer(1e-4).minimize(cost)

设置10轮效果如下所示。

test_accuracy= 0.8571

设置100轮效果如下所示。

test_accuracy= 0.9289

这里之所以要简单改一下,是因为运行作者配套源码时出现了准确率过低的问题,实际上就是神经网络中学习率以及损失函数等优化问题,大家可以自己调一调,作者这里选择了最简单的入门级的MNIST图片数据集,命名为验证码,也只是举个应用实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mooyuan天天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值