卷积神经网络介绍
卷积神经网络结构
卷积层
激活函数
池化层
全连接层
Mnist数据集 -- 使用卷积神经网络、
1.卷积神经网络简介
1)与传统多层神经网络对比
2)发展历史
3)卷积神经网络在ImageNet比赛中的错误率
卷积神经网络原理--结构
卷积层
通过在原始图像上平移来提取特征
卷积核--filter--过滤器--模型参数
个数
大小
输入5*5*1 -- 核3*3 -- 每次移动一个所以步长为1
所以输出为3*3*1
步长
由自己设定,影响输出大小
零填充的大小
防止卷积核平移出图像的部分
总结--输出大小计算公式(重要)
多通道图片如何观察
输入图像:7*7*3 -- filter:3*3*3+bias 两个filter -- 步长为2 -- 输出3*3*2
思路:对于每一个卷积核进行三通道卷积,将三个通道的卷积结果进行加和并加上偏置得出来一个卷积后的数据,此时将他填入卷积后的矩阵中。如下得到一个3*3*1的矩阵,因为有两个卷积核所以得出两个矩阵
调用卷积层API:
小结
1、掌握filter要素的相关计算公式
2、filter大小
激活层
增加非线性得分割能力
激活函数:解决线性空间不能表达多维空间的缺陷
采用sigmoid不能达到很好的效果
如果取值相对较大时sigmoid的结果会很平缓,梯度即导数趋于零导致梯度消失
这里使用relu是针对图像来讲没有小于0的像素值所以可以采用,但是其他工程需要具体考虑。
使用playground可以展示不同的激活函数的作用和效果(www.playground.tensorflow.org)
API
注:卷积向下取整,池化向上取整
池化层(pooling layer)也叫做下采样(subsample)
降低模型复杂度,减少学习参数(防止过拟合)
也是相当与用一个核在图像上不断平移,不同的是池化不用卷积过程,如最大池化只取”核“框中的最大值。
利用了像素之间的联系
举例:池化层的计算
API
全连接层
进行最后得输出以及计算损失
将CNN想像为传统机器学习的话前面的卷积池化等相当于在做特征工程,而全连接层就相当于是“分类器”了。
总结
图像的识别大体可以用下图来表示过程
案例:CNN-Mnist手写数字识别
1、准备手写数字数据,可以通过tensorflow
2、实现前面设计的卷积网络结构:卷积,激活,池化(两层)
3、全连接层得到输出类别预测
4、计算损失值并优化
5、计算准确率
设计网络:
第一个卷积大层:
卷积层:32个filter(权重)5*5大小,1步,零填充SAME
激活:Relu
池化:2*2大小,2步
第二个卷积大层:
卷积层:64个filter(权重)5*5大小,1步,零填充SAME
激活:Relu
池化:2*2大小,2步
全连接
调参 - 提高准确率
调整学习率
随机初始化权重,偏置的值:修改标准差stddev
选择好用的优化器:一般用梯度优化,也有亚当优化等
网络的优化与改进
调整参数
使用改进版SGD算法
调整网络结构如使用 batc_normalization 或者 droopout 层
更高级的网络API模型的实现请参考
http://www.tensorflow.org/tutorials/layers
import tensorflow as tf # import tensorflow.compat.v1 as tf # import os from tensorflow.examples.tutorials.mnist import input_data __all__ = [tf] # tf.disable_v2_behavior() # 1.利用数据,在训练的时候实时提供数据 # mnist手写数字数据在运行时实时提供占位符 tf.app.flags.DEFINE_integer("is_train", 1, "指定是否是训练模型,还是拿数据去预测") FLAGS = tf.app.flags.FLAGS def create_weights(shape): # 定义一个用来修改权重形状的api方便后边使用 return tf.Variable(initial_value=tf.random_normal(shape=shape)) def create_model(x): # x为None行,784列 """ 构建卷积神经网络 :param x: :return: """ # 1.第一个卷积层 with tf.variable_scope("conv1"): # 卷积层 # 修改x变量的形状 input_x = tf.reshape(x, shape=[-1, 28, 28, 1]) # 样本数不明确所以为-1,其余为高,宽,通道数 # 定义filter和偏置 conv1_weights = create_weights(shape=[5, 5, 1, 32]) conv1_bias = create_weights(shape=[32]) conv1_x = tf.nn.conv2d(input=input_x, filter=conv1_weights, strides=[1, 1, 1, 1], padding="SAME") + conv1_bias # 激活层 relu1_x = tf.nn.relu(conv1_x) # 池化层 pool1_x = tf.nn.max_pool(value=relu1_x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME") # 2.第二个卷积层 with tf.variable_scope("conv2"): # 卷积层 # 定义filter和偏置 conv2_weights = create_weights(shape=[5, 5, 32, 64]) conv2_bias = create_weights(shape=[64]) conv2_x = tf.nn.conv2d(input=pool1_x, filter=conv2_weights, strides=[1, 1, 1, 1], padding="SAME") + conv2_bias # 激活层 relu2_x = tf.nn.relu(conv2_x) # 池化层 pool2_x = tf.nn.max_pool(value=relu2_x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME") # 3.全连接层 with tf.variable_scope("full_connection"): # [None,7,7,64] -> [None,7*7*64] # [None, 7*7*64] * [7*7*64, 10] = [None, 10] x_fc = tf.reshape(pool2_x, shape=[-1, 7*7*64]) # 这里-1指的就是None weights_fc = create_weights(shape=[7*7*64, 10]) bias_fc = create_weights(shape=[10]) # 结果输出 y_predict = tf.matmul(x_fc, weights_fc) + bias_fc return y_predict def full_connected_mnist(): """ 单层全连接神经网络识别手写数字图片 特征值:[None,784] 目标值:one_hot编码[None,10] :return: """ mnist = input_data.read_data_sets("./mnist_data/", one_hot=True) # 准备数据 # x[None, 784], y_true[None, 10] with tf.variable_scope("mnist_data"): x = tf.placeholder(tf.float32, [None, 784]) y_true = tf.placeholder(tf.int32, [None, 10]) y_predict = create_model(x) """ # 2.全连接层神经网络计算 # 类别:10个类别,全连接层:10个神经元 # 参数 w:[784, 10], b:[10] # 全连接层神经网络计算公式:[None, 784] * [784, 10] + [10] = [None, 10] # 随机初始化权重偏置参数,这些是优化的参数,必须用变量op去定义 with tf.variable_scope("fc_model"): weight = tf.Variable(tf.random.normal([784, 10]), name="w") bias = tf.Variable(tf.random.normal([10]), name="b") # fc层的计算 # y_predict [None, 10]输出结果供softmax使用 y_predict = tf.matmul(x, weight) + bias """ # 3.softmax回归以及交叉熵损失计算 with tf.variable_scope("softmax_crossentropy"): # labels 真实值 [None 10] one_hot # logits 全连层的输出[None, 10] # 返回每个样本损失组成的列表 loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=y_predict)) # 4.梯度下降损失优化 with tf.variable_scope("optimizer"): # 学习率 train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss) # 5.得出每次训练的准确率(通过真实值和预测值位置进行比较,每个样本都比较) with tf.variable_scope("accuracy"): equal_list = tf.equal(tf.argmax(y_true, 1), tf.argmax(y_predict, 1)) accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32)) # (2) 收集要显示的变量 # 先收集损失和准确率 tf.summary.scalar("losses", loss) tf.summary.scalar("acc", accuracy) """ # 收集权重和偏置 tf.summary.histogram("weights", weight) tf.summary.histogram("biases", bias) """ # 初始化变量op init_op = tf.global_variables_initializer() # (3) 合并所有变量op merged = tf.summary.merge_all() # 创建模型保存并加载 # saver = tf.train.Saver() # 开启会话去训练 with tf.Session() as sess: # 初始化变量 sess.run(init_op) # (1) 创建一个events文件实例 file_writer = tf.summary.FileWriter("./tmp/summary/", graph=sess.graph) # 加载模型 # if os.path.exists("./tmp/modelckpt/checkpoint"): # saver.restore(sess, "./tmp/modelckpt/fc_nn_model") if FLAGS.is_train == 1: # 循环步数去训练 for i in range(3000): # 获取数据,实时提供 # 每步提供50个样本训练 mnist_x, mnist_y = mnist.train.next_batch(50) # 运行训练op sess.run(train_op, feed_dict={x: mnist_x, y_true: mnist_y}) print("训练第%d步的准确率为:%f,损失为:%f" % ( i+1, sess.run(accuracy, feed_dict={x: mnist_x, y_true: mnist_y}), sess.run(loss, feed_dict={x: mnist_x, y_true: mnist_y}) ) ) # 运行合变量op,写入事件文件当中 summary = sess.run(merged, feed_dict={x: mnist_x, y_true: mnist_y}) file_writer.add_summary(summary, i) # if i % 100 == 0: # saver.save(sess, "./tmp/modelckpty/fc_nn_model") else: # 如果不是训练我们就去预测测试集数据 for i in range(100): # 每次拿一个样本 mnist_x, mnist_y = mnist.test.next_batch(1) print("训练第%d步的准确率为:%f,损失为:%f" % ( i + 1, sess.run(accuracy, feed_dict={x: mnist_x, y_true: mnist_y}), sess.run(loss, feed_dict={x: mnist_x, y_true: mnist_y}) ) ) return None if __name__ == "__main__": full_connected_mnist()