CIFAR-10识别模型

版权声明:博主原创文章属私人所有,未经允许 不可转发和使用 https://blog.csdn.net/a1066196847/article/details/85204361

import tensorflow as tf

#通过tf.variable_scope函数控制tf.get_variable函数来获取以及创建过的变量
with tf.variable_scope("zyy"):#zyy的命名空间
        v=tf.get_variable("v",[1],initializer=tf.constant_initializer(1.0))  #在zyy的命名空间内创建名字为v的变量

with tf.variable_scope("zyy"):
        v = tf.get_variable("v", [1])  # 通过tf.get_variable函数创建v的变量,则会失败,由于在zyy空间中已经生成了一个v的变量

with tf.variable_scope("zyy", reuse=True):
        v = tf.get_variable("v", [1], initializer=tf.constant_initializer(1.5))

# -- * -- * -- * -- * -- * -- * -- * -- * -- * -- * -- * -- * -- * -- * --

def inference(images):
  """
  输入参数:训练图像
  Returns:最终每个图像的种类
  我们使用tf.get_variable(),而不是实例化所有变量tf.Variable(),
  以便在多个GPU训练运行中共享变量。如果我们只在单个GPU上运行此模型,
  我们可以简化此功能通过用tf.Variable()替换tf.get_variable()的所有实例。
  """
  # 建立第一层卷积层。使用tf.variable_scope是为了定义命名空间
  with tf.variable_scope('conv1') as scope:
    # 第一层卷积层的权重,5*5的filter,有3个通道,同时有64个这样的filter。stddev wd参数都是在初始化权重的时候 一些必须的截断正太的参数
    kernel = _variable_with_weight_decay('weights',
                                         shape=[5, 5, 3, 64],
                                         stddev=5e-2,
                                         wd=0.0)
    # 使用tf.nn.conv2d进行卷积,[1, 1, 1, 1]第一个和第四个1代表在batch上和channel上,不予特殊操作。中间两个1代表在height width
    # 维度上,划窗的长度是1。padding='SAME'代表此次卷积需要保证输出和输入的shape保持一致,所以会在保持一致的前提下,进行外圈补0。具体
    # 的计算,我会在代码后续进行详解
    conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME')
    # 进行完卷积后,还需要有个bias偏执项进行相加
    biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0))
    pre_activation = tf.nn.bias_add(conv, biases)
    # 经过激励层
    conv1 = tf.nn.relu(pre_activation, name=scope.name)
    # summary是指将输出报告到Tensorboard
    _activation_summary(conv1)

  # pool1
  # pool层会变换图像的shape,具体的计算放在下面详解
  pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                         padding='SAME', name='pool1')
  # norm1
  # 这是局部响应归一化层,现在的模型大多不采用
  norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
                    name='norm1')

  # conv2
  with tf.variable_scope('conv2') as scope:
    kernel = _variable_with_weight_decay('weights',
                                         shape=[5, 5, 64, 64],
                                         stddev=5e-2,
                                         wd=0.0)
    conv = tf.nn.conv2d(norm1, kernel, [1, 1, 1, 1], padding='SAME')
    biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.1))
    pre_activation = tf.nn.bias_add(conv, biases)
    conv2 = tf.nn.relu(pre_activation, name=scope.name)
    _activation_summary(conv2)

  # norm2
  norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
                    name='norm2')
  # pool2
  pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1],
                         strides=[1, 2, 2, 1], padding='SAME', name='pool2')

  # local3
  with tf.variable_scope('local3') as scope:
    # 铺平图像数据。因为这里不再是卷积计算了,需要把矩阵冲洗reshape成一个一维的向量
    # 在tensorflow官网进行 手写数字识别的时候,reshape的方法和下面的不一样
    # 那里面采用的reshape方法是:h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])。接着h_pool2_flat就直接可以和filter进行相乘
    # 下面这种reshape方法得到的返回结果 reshape 也可以直接和filter进行相乘
    reshape = tf.reshape(pool2, [FLAGS.batch_size, -1])
    dim = reshape.get_shape()[1].value # 8*8*64
    #这块的384这个数字和前面无关,是定义的 卷积核的个数,最终会输出384个特征
    weights = _variable_with_weight_decay('weights', shape=[dim, 384],
                                          stddev=0.04, wd=0.004)
    biases = _variable_on_cpu('biases', [384], tf.constant_initializer(0.1))
    local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)
    _activation_summary(local3)

  # local4
  with tf.variable_scope('local4') as scope:
    #因为上一层输出特征数是384,所以这块的shape第一维也是384
    weights = _variable_with_weight_decay('weights', shape=[384, 192],
                                          stddev=0.04, wd=0.004)
    biases = _variable_on_cpu('biases', [192], tf.constant_initializer(0.1))
    local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name)
    _activation_summary(local4)

  # linear layer(WX + b),
  # We don't apply softmax here because
  # tf.nn.sparse_softmax_cross_entropy_with_logits accepts the unscaled logits
  # and performs the softmax internally for efficiency.
  with tf.variable_scope('softmax_linear') as scope:
    weights = _variable_with_weight_decay('weights', [192, NUM_CLASSES],
                                          stddev=1/192.0, wd=0.0)
    biases = _variable_on_cpu('biases', [NUM_CLASSES],
                              tf.constant_initializer(0.0))
    softmax_linear = tf.add(tf.matmul(local4, weights), biases, name=scope.name)
    _activation_summary(softmax_linear)

  return softmax_linear

整个的模型代表就如上所示,两个卷积层+两个全连接层+最后的一个softmax层,最终得到每一幅图像的NUM_CLASSES个概率,再接一部处理就可以输出各个类别了。

下面详细的对从 batch_size, 32, 32的输入数据开始,经过每层时候的size大小进行计算

第一层卷积层:卷积层统一是使用SAME的方式,用全0去补全。所以padding会保证卷积操作不会影响图片大小。而我们的步长又设置成了1。所以在卷积层中,我们的图片size并没有减少。并且可以计算出来补0的圈数,padding的值(p) 必须要满足p = (f-1)/2,其中f是过滤器的大小,p = (5-1) / 2 = 2。

第一层池化层:上面卷积层输出为 [32, 32,3,64],前两维是height width,第三维是channel,第四维是filter个数。因为池化层虽然也有padding操作,但是以为滑动步长不为1,所以会改变图像size

padding的值(p) 必须要满足p = (f-1)/2 。其中f是过滤器的大小。 那么在我们这里就是padding的值就是p = (3-1) / 2 = 1。而图片的大小可以用这个公式计算:n = (n + 2p -f)/s +1 其中s是步长,n是图片大小。 我们的原始图片是32*32,那么刚才的公式就是(32 + 1*2 - 3)/2 +1 = 16.5,然后取整为16 。 这样经过第一个卷积+池化的时候,图片就变成了16*16

第二层卷积层:因为padding操作+步长为1,所以未改变图像size

第二层池化层:(16 + 1*2 - 3)/2 +1 = 8.5,然后取整为8

第一层全连接层:图像的size为8*8,又因为第二层卷积层输出的filter为64,所以在reshape成一维的时候,dim就位8*8*64,384是自己指定的当层为386个filter

第二层全连接层:上面的全连接层输出已经是1维386,那么这层的 参数项的shape 应为[384, 当层的filter数目 即192]

猜你喜欢

转载自blog.csdn.net/a1066196847/article/details/85204361