Tensorflow卷积神经网络[转]

Tensorflow卷积神经网络

卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络, 在计算机视觉等领域被广泛应用. 本文将简单介绍其原理并分析Tensorflow官方提供的示例.

关于神经网络与误差反向传播的原理可以参考作者的另一篇博文BP神经网络与Python实现.

工作原理

卷积是图像处理中一种基本方法. 卷积核是一个nxn的矩阵通常n取奇数, 这样矩阵就有了中心点和半径的概念.

对图像中每个点取以其为中心的n阶方阵, 将该方阵与卷积核中对应位置的值相乘, 并用它们的和作为结果矩阵中对应点的值.

下面的动图展示了卷积的计算过程:

上述操作处理图像得到新图像的操作称为卷积, 卷积得到的结果矩阵被称为特征图(Feature Map). 灰度图使用一个矩阵便能表示, RGB图像则需要3个矩阵. 也就是说, 1个RGB图像使用一个卷积核卷积会得到3个Feature Map.

若卷积核中各元素和为1则图像亮度不变, 若小于1则变暗, 大于1则会变亮.

卷积核的中心无法对准原图像中边缘的像素点(与边缘距离小于卷积核半径), 若要对边缘的点进行计算必须填充(padding)外部缺少的点使卷积核的中心可以对准它们. 常用的填充策略有:

  • 使用中心点的值代替缺失的点
  • 使用中心点邻域的均值代替缺失的点
  • 填充为0

特殊的卷积核可以实现特殊的效果:

  • 锐化

                 

  • 提取边缘

         

  • 浮雕

          

下面四张图片分别为:

  • A: 原图
  • B: 锐化
  • C: 边缘检测
  • D: 浮雕

图片来源, 该文章对卷积进行了更生动地介绍

卷积数学定义可以参考卷积总结我对卷积的理解

局部感知

一般认为人的视觉认知是从局部到全局的,而图像的空间联系也是局部的像素联系较为紧密,而距离较远的像素相关性则较弱.

同理, 每个神经元其实没有必要对全局图像进行感知, 只需要与局部图像建立连接. 在网络的更深层将神经元的局部感知进一步综合就可以了解到全局信息.

采用局部感知的方法减少了需要训练的权值数. 在实际应用中图像的分辨率和训练迭代次数都是有限的, 更少的权值数通常会带来更高精度.

权值共享

在卷积神经网络中对于同一个卷积核, 所有卷积层神经元和图像输入层的连接使用同一个权值矩阵.

权值共享进一步减少了所需训练的权值数, 一个卷积层的权值数变为了卷积核中元素个数.

权值共享隐含的原理是: 图像的一部分的统计特性与其他部分是一样的, 在图像某一部分学习到的特征也能应用到其它部分上.

从上文关于特殊卷积核的描述中可以得知, 一种卷积核通常只能提取图像中的一种特征. 且权值共享使得连接可以训练的权值数大为减少. 为了充分提取特征通常采用使用多个卷积核的方法.

池化

通过卷积学习到的图像特征仍然数量巨大, 不便直接进行分类. 池化层便用于减少特征数量.

池化操作非常简单, 比如我们使用一个卷积核对一张图片进行过滤得到一个8x8的方阵, 我们可以将方阵划分为16个2x2方阵, 每个小方阵称为邻域.

用16个小方阵的均值组成一个4x4方阵便是均值池化, 类似地还有最大值池化等操作. 均值池化对保留背景等特征较好, 最大值池化对纹理提取更好.

随机池化则是根据像素点数值大小赋予概率(权值), 然后按其加权求和.

TensorFlow实现

TensorFlow的文档Deep MNIST for Experts介绍了使用CNN在MNIST数据集上识别手写数字的方法.

完整代码可以在GitHub上找到, 本文将对其进行简单分析. 源码来自tensorflow-1.3.0版本示例.

主要有3条引入:

import tempfile
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

main(_)函数负责网络的构建:

def main(_):
  # 导入MNIST数据集
  # FLAGS.data_dir是本地数据的路径, 可以用空字符串代替以自动下载数据集
  mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

  # x是输入层, 每个28x28的图像被展开为784阶向量
  x = tf.placeholder(tf.float32, [None, 784])

  # y_是训练集预标注好的结果, 采用one-hot的方法表示10种分类
  y_ = tf.placeholder(tf.float32, [None, 10])

  # deepnn方法构建了一个cnn, y_conv是cnn的预测输出
  # keep_prob是dropout层的参数, 下文再讲
  y_conv, keep_prob = deepnn(x)

  # 计算预测y_conv和标签y_的交叉熵作为损失函数
  with tf.name_scope(‘loss‘):
    cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_,
                                                            logits=y_conv)
  cross_entropy = tf.reduce_mean(cross_entropy)

  # 使用Adam优化算法, 以最小化损失函数为目标
  with tf.name_scope(‘adam_optimizer‘):
    train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

  # 计算精确度(正确分类的样本数占测试样本数的比例), 用于评估模型效果
  with tf.name_scope(‘accuracy‘):
    correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
    correct_prediction = tf.cast(correct_prediction, tf.float32)
  accuracy = tf.reduce_mean(correct_prediction)

main函数与其它tensorflow神经网络并无二致, 关键分析deepnn方法如何构建cnn:

def deepnn(x):
  # x的结构为[n, 784], 将其展开成[n, 28, 28]
  # 第四维表示图像的特征, 当前为灰度图故为1. 也就是说每个像素点需要一个值来描述
  # 类似地, RGB图像为3, RDBA图像为4
  with tf.name_scope(‘reshape‘):
    x_image = tf.reshape(x, [-1, 28, 28, 1])

  # 第一个卷积层将28x28灰度图使用32个卷积核进行卷积
  with tf.name_scope(‘conv1‘):
    # 初始化连接权值, 为了避免梯度消失权值使用正则分布进行初始化
    # 使用5x5大小的卷积核, 使用32个卷积核, 从原图中提取出32个特征(产生32个Feature-Map)
    W_conv1 = weight_variable([5, 5, 1, 32])

    # 初始化偏置值, 这里使用的是0.1
    b_conv1 = bias_variable([32])

    # conv2d实现: tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding=‘SAME‘)
    # strides是卷积核移动的步幅
    # padding有两个取值: SAME:表示卷积之后Feature-Map的长宽与x_image相同; VALID则表示忽略边缘像素, Feature-Map比x_image小
    # h_conv1的结构为[n, 28, 28, 32]
    h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

  # 第一个池化层, 将2x2方阵最大值池化为一个特征, 池化为14x14矩阵
  with tf.name_scope(‘pool1‘):
    h_pool1 = max_pool_2x2(h_conv1)

  # 第二个卷积层, 将第一个卷积层提取32个特征使用64个卷积核提取64个特征
  with tf.name_scope(‘conv2‘):
    # 这里的卷积核是3维的, 有32个5*5的二维卷积核, 每个二维卷积核与一个14x14Feature-Map进行卷积
    # 将这32个14x14结果矩阵累加起来便得到一个新的Feature-Map
    # 64个三维卷积核得到64个新Feature-Map
    W_conv2 = weight_variable([5, 5, 32, 64])
    b_conv2 = bias_variable([64])
    # h_conv2的结构为[n, 14, 14, 64]
    h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)

  # 第二个池化层, 将2x2方阵最大值池化为一个特征, 池化为7x7矩阵
  with tf.name_scope(‘pool2‘):
    # h_pool2的结构为[n, 7, 7, 64]
    h_pool2 = max_pool_2x2(h_conv2)

  # 第一个全连接层, 将[7, 7, 64]特征矩阵用全连接层映射到1024各特征
  with tf.name_scope(‘fc1‘):
    W_fc1 = weight_variable([7 * 7 * 64, 1024])
    b_fc1 = bias_variable([1024])
    h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
    h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

  # 使用dropout层避免过拟合
  # 即在训练过程中的一次迭代中, 随机选择一定比例的神经元不参与此次迭代
  # 参与迭代的概率值由keep_prob指定, keep_prob=1.0为使用整个网络
  with tf.name_scope(‘dropout‘):
    keep_prob = tf.placeholder(tf.float32)
    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

  # 第二个全连接层, 将1024个特征映射到10个特征, 即10个分类的one-hot编码
  # one-hot编码是指用 `100`代替1, `010`代替2, `001`代替3... 的编码方式
  with tf.name_scope(‘fc2‘):
    W_fc2 = weight_variable([1024, 10])
    b_fc2 = bias_variable([10])
    y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2

  return y_conv, keep_prob

请重点关注第二个卷积层的实现

整个网络暴露的接口有3个:

  • 输入层x[n, 784]
  • 输出层y_conv[n, 10]
  • dropout保留比例keep_prob[1]

现在可以继续关注main方法了, 完成网络构建之后main先将网络结构缓存到硬盘:

graph_location = tempfile.mkdtemp()
print(‘Saving graph to: %s‘ % graph_location)
train_writer = tf.summary.FileWriter(graph_location)
train_writer.add_graph(tf.get_default_graph())

接下来初始化tf.Session()进行训练:

with tf.Session() as sess:
    # 初始化全局变量
    sess.run(tf.global_variables_initializer())
    for i in range(10000):
        # 每次取训练数据集中50个样本, 分10000次取出
        # batch[0]为特征集, 结构为[50, 784]即50组784阶向量
        # batch[1]为标签集, 结构为[50, 10]即50个采用one-hot编码的标签
        batch = mnist.train.next_batch(50)
        # 每进行100次迭代评估一次精度
        if i % 100 == 0:
            train_accuracy = accuracy.eval(feed_dict={
                x: batch[0], y_: batch[1], keep_prob: 1.0})
            print(‘step %d, training accuracy %g‘ % (i, train_accuracy))
        # 进行训练, dropout keep prob设为0.5
        train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

    # 评估最终精度, dropout keep prob设为1.0即使用全部网络
    print(‘test accuracy %g‘ % accuracy.eval(feed_dict={
        x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

启动代码会处理命令行参数和选项:

if __name__ == ‘__main__‘:
    parser = argparse.ArgumentParser()
    parser.add_argument(‘--data_dir‘, type=str,
                        default=‘/tmp/tensorflow/mnist/input_data‘,
                        help=‘Directory for storing input data‘)
    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)
时间: 2024-10-28 14:21:10

Tensorflow卷积神经网络[转]的相关文章

AI相关 TensorFlow -卷积神经网络 踩坑日记之一

上次写完粗浅的BP算法 介绍 本来应该继续把 卷积神经网络算法写一下的 但是最近一直在踩 TensorFlow的坑.所以就先跳过算法介绍直接来应用场景,原谅我吧. TensorFlow 介绍 TF是google开源出来的人工智能库,由python语言写的 官网地址:http://www.tensorflow.org/   请用科学上网访问 中文地址:http://www.tensorfly.cn/ 当然还有其他AI库,不过大多数都是由python 写的 .net 的AI库叫 Accord.net

TensorFlow 卷积神经网络--卷积层

之前我们已经有一个卷积神经网络识别手写数字的代码,执行下来正确率可以达到96%以上. 若是再优化下结构,正确率还可以进一步提升1~2个百分点. 卷积神经网络在机器学习领域有着广泛的应用.现在我们就来深入了解下卷积神经网络的细节. 卷积层,听名字就知道,这是卷积神经网络中的重要部分. 这个部分被称为过滤器(filter)或者内核(kernel) Tensorflow的官方文档中称这个部分为过滤器(filter). 在一个卷积层总,过滤器所处理的节点矩阵的长和宽都是由人工指定的,这个节点矩阵的尺寸也

深度学习原理与框架-Tensorflow卷积神经网络-神经网络mnist分类

使用tensorflow构造神经网络用来进行mnist数据集的分类 相比与上一节讲到的逻辑回归,神经网络比逻辑回归多了隐藏层,同时在每一个线性变化后添加了relu作为激活函数, 神经网络使用的损失值为softmax概率损失值,即为交叉熵损失值 代码:使用的是mnist数据集作为分类的测试数据,数据的维度为50000*784 第一步:载入mnist数据集 第二步:超参数的设置,输入图片的大小,分类的类别数,迭代的次数,每一个batch的大小 第三步:使用tf.placeholder() 进行输入数

tensorflow 卷积神经网络预测手写 数字

# coding=utf8 import tensorflow as tffrom tensorflow.examples.tutorials.mnist import input_datafrom PIL import Image def imageprepare(file_name): """ This function returns the pixel values. The imput is a png file location. ""&quo

Tensorflow卷积神经网络实现手写字符识别

# -*- coding:utf-8 -*- import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data import os import argparse import sys DATA_DIR = os.path.join('.', 'mnist_link') # ======================================= # COMMON OPERATIONS #

跟我学算法- tensorflow 卷积神经网络训练验证码

使用captcha.image.Image 生成随机验证码,随机生成的验证码为0到9的数字,验证码有4位数字组成,这是一个自己生成验证码,自己不断训练的模型 使用三层卷积层,三层池化层,二层全连接层来进行组合 第一步:定义生成随机验证码图片 number = ['0','1','2','3','4','5','6','7','8','9'] # alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',

【原创 深度学习与TensorFlow 动手实践系列 - 3】第三课:卷积神经网络 - 基础篇

提纲: 1. 链式反向梯度传到 2. 卷积神经网络 - 卷积层 3. 卷积神经网络 - 功能层 4. 实例:卷积神经网络MNIST分类 期待目标: 1. 清楚神经网络优化原理,掌握反向传播计算. 2. 掌握卷积神经网络卷积层的结构特点,关键参数,层间的连接方式. 3. 了解不同卷积神经网络功能层的作用,会进行简单的卷积神经网络结构设计. 4. 能够运行TensorFlow卷积神经网络 MNIST.  f(x, y, z) = (x + y) * z (3.00 + 1.00) * -2.00 =

TensorFlow框架(4)之CNN卷积神经网络详解

1. 卷积神经网络 1.1 多层前馈神经网络 多层前馈神经网络是指在多层的神经网络中,每层神经元与下一层神经元完全互连,神经元之间不存在同层连接,也不存在跨层连接的情况,如图 11所示. 图 11 对于上图中隐藏层的第j个神经元的输出可以表示为: 其中,f是激活函数,bj为每个神经元的偏置. 1.2 卷积神经网络 1.2.1 网络结构 卷积神经网络与多层前馈神经网络的结构不一样,其每层神经元与下一层神经元不是全互连,而是部分连接,即每层神经层中只有部分的神经元与下一层神经元有连接,但是神经元之间

深度学习之卷积神经网络CNN及tensorflow代码实现示例

一.CNN的引入 在人工的全连接神经网络中,每相邻两层之间的每个神经元之间都是有边相连的.当输入层的特征维度变得很高时,这时全连接网络需要训练的参数就会增大很多,计算速度就会变得很慢,例如一张黑白的 28×28 的手写数字图片,输入层的神经元就有784个,如下图所示: 若在中间只使用一层隐藏层,参数 w 就有 784×15=11760 多个:若输入的是28×28 带有颜色的RGB格式的手写数字图片,输入神经元就有28×28×3=2352 个-- .这很容易看出使用全连接神经网络处理图像中的需要训