我一直觉得TensorFlow的深度神经网络代码非常困难且繁琐,对TensorFlow搭建模型也十分困惑,所以我近期阅读了大量的神经网络代码,终于找到了搭建神经网络的规律,各位要是觉得我的文章对你有帮助不妨点一个关注

  我个人把深度学习分为以下步骤:数据处理 --> 模型搭建 --> 构建损失 --> 模型训练 --> 模型评估

我先把代码放出来,然后一点一点来讲

  1. # Author:凌逆战
  2. # -*- encoding:utf-8 -*-
  3. # 修改时间:2020年5月31日
  4. import time
  5. from tensorflow.examples.tutorials.mnist import input_data
  6. from nets.my_alex import alexNet
  7. from ops import *
  8.  
  9. tf.flags.DEFINE_integer('batch_size', 50, 'batch size, default: 1')
  10. tf.flags.DEFINE_integer('class_num', 10, 'batch size, default: 1')
  11. tf.flags.DEFINE_integer('epochs', 10, 'batch size, default: 1')
  12. tf.flags.DEFINE_float('learning_rate', 1e-4, '初始学习率, 默认: 0.0002')
  13. tf.flags.DEFINE_string('checkpoints_dir', "checkpoints", '保存检查点的地址')
  14. FLAGS = tf.flags.FLAGS
  15.  
  16. # 从MNIST_data/中读取MNIST数据。当数据不存在时,会自动执行下载
  17. mnist = input_data.read_data_sets('./data', one_hot=True, reshape=False)
  18. # reshape=False (None, 28,28,1) # 用于第一层是卷积层
  19. # reshape=False (None, 784) # 用于第一层是全连接层
  20.  
  21. # 我们看一下数据的shape
  22. print(mnist.train.images.shape) # 训练数据图片(55000, 28, 28, 1)
  23. print(mnist.train.labels.shape) # 训练数据标签(55000, 10)
  24. print(mnist.test.images.shape) # 测试数据图片(10000, 28, 28, 1)
  25. print(mnist.test.labels.shape) # 测试数据图片(10000, 10)
  26. print(mnist.validation.images.shape) # 验证数据图片(5000, 28, 28, 1)
  27. print(mnist.validation.labels.shape) # 验证数据图片(5000, 784)
  28.  
  29. def train():
  30. batch_size = FLAGS.batch_size # 一个batch训练多少个样本
  31. batch_nums = mnist.train.images.shape[0] // batch_size # 一个epoch中应该包含多少batch数据
  32. class_num = FLAGS.class_num # 分类类别数
  33. epochs = FLAGS.epochs # 训练周期数
  34. learning_rate = FLAGS.learning_rate # 初始学习率
  35.  
  36. ############ 保存检查点的地址 ############
  37. checkpoints_dir = FLAGS.checkpoints_dir # checkpoints
  38. # 如果检查点不存在,则创建
  39. if not os.path.exists(checkpoints_dir):
  40. os.makedirs(FLAGS.checkpoints_dir)
  41.  
  42. ######################################################
  43. # 创建图 #
  44. ######################################################
  45. graph = tf.Graph() # 自定义图
  46. # 在自己的图中定义数据和操作
  47. with graph.as_default():
  48. inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
  49. labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
  50. # 看个人喜欢,有的人在初始化定义中就定义了learning_rate,有的人喜欢通过feed传learning_rate
  51. learning_rate = tf.placeholder("float", None, name='learning_rate')
  52. # 如果网络结构有dropout层,需要定义keep_probn,如果没有则不需要
  53. # 训练的时候需要,测试的时候需要设置成1
  54. keep_prob = tf.placeholder(dtype="float", name='keep_prob')
  55. ############ 搭建模型 ############
  56. logits = alexNet(inputs, class_num, keep_prob=keep_prob) # 使用placeholder搭建模型
  57. ############ 损失函数 ############
  58. loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
  59. tf.add_to_collection('losses', loss)
  60. total_loss = tf.add_n(tf.get_collection("loss")) # total_loss=模型损失+权重正则化损失
  61. ############ 模型精度 ############
  62. predict = tf.argmax(logits, 1) # 模型预测结果
  63. accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, 1)), tf.float32))
  64. ############ 优化器 ############
  65. variable_to_train = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES) # 可训练变量列表
  66. # 创建优化器,更新网络参数,最小化loss,
  67. global_step = tf.Variable(0, trainable=False)
  68. learning_rate = tf.train.exponential_decay(learning_rate=learning_rate, # 初始学习率
  69. global_step=global_step,
  70. decay_steps=batch_nums, # 多少步衰减一次
  71. decay_rate=0.1, # 衰减率
  72. staircase=True) # 以阶梯的形式衰减
  73. # 移动平均值更新参数
  74. # train_op = moving_average(loss, learning_rate, global_step)
  75. # adam优化器,adam算法好像会自动衰减学习率,
  76. train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss=total_loss,
  77. global_step=global_step,
  78. var_list=variable_to_train)
  79. ############ TensorBoard可视化 summary ############
  80. summary_writer = tf.summary.FileWriter(logdir="./logs", graph=graph) # 创建事件文件
  81. tf.summary.scalar(name="losses", tensor=total_loss) # 收集损失值变量
  82. tf.summary.scalar(name="acc", tensor=accuracy) # 收集精度值变量
  83. tf.summary.scalar(name='learning_rate', tensor=learning_rate)
  84. merged_summary_op = tf.summary.merge_all() # 将所有的summary合并为一个op
  85. ############ 模型保存和恢复 Saver ############
  86. saver = tf.train.Saver(max_to_keep=5)
  87.  
  88. ######################################################
  89. # 创建会话 #
  90. ######################################################
  91. max_acc = 0.
  92. config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
  93. with tf.Session(config=config, graph=graph) as sess:
  94. # 加载模型,如果模型存在返回 是否加载成功和训练步数
  95. could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
  96. if could_load:
  97. print(" [*] 模型加载成功")
  98. else:
  99. print(" [!] 模型加载失败")
  100. try:
  101. tf.global_variables_initializer().run()
  102. except:
  103. tf.initialize_all_variables().run()
  104.  
  105. for epoch in range(epochs):
  106. for i in range(batch_nums):
  107. start_time = time.time()
  108. # batch_images = data_X[i * batch_size:(i + 1) * batch_size]
  109. # batch_labels = data_y[i * batch_size:(i + 1) * batch_size]
  110. train_batch_x, train_batch_y = mnist.train.next_batch(batch_size)
  111.  
  112. # 使用真实数据填充placeholder,运行训练模型和合并变量操作
  113. _, summary, loss, step = sess.run([train_op, merged_summary_op, total_loss, global_step],
  114. feed_dict={inputs: train_batch_x,
  115. labels: train_batch_y,
  116. keep_prob: 0.5})
  117. if step % 100 == 0:
  118. summary_writer.add_summary(summary, step) # 将每次迭代后的变量写入事件文件
  119. summary_writer.flush() # 强制summary_writer将缓存中的数据写入到日志文件中(可选)
  120.  
  121. ############ 可视化打印 ############
  122. print("Epoch:[%2d] [%4d/%4d] time:%4.4f,loss:%.8f" % (
  123. epoch, i, batch_nums, time.time() - start_time, loss))
  124.  
  125. # 打印一些可视化的数据,损失...
  126. if step % 100 == 0:
  127. acc = sess.run(accuracy, feed_dict={inputs: mnist.validation.images,
  128. labels: mnist.validation.labels,
  129. keep_prob: 1.0})
  130. print("Epoch:[%2d] [%4d/%4d] accuracy:%.8f" % (epoch, i, batch_nums, acc))
  131. ############ 保存模型 ############
  132. if acc > max_acc:
  133. max_acc = acc
  134. save_path = saver.save(sess,
  135. save_path=os.path.join(checkpoints_dir, "model.ckpt"),
  136. global_step=step)
  137. tf.logging.info("模型保存在: %s" % save_path)
  138. print("优化完成!")
  139.  
  140. def main(argv=None):
  141. train()
  142.  
  143. if __name__ == '__main__':
  144. # logging.basicConfig(level=logging.INFO)
  145. tf.logging.set_verbosity(tf.logging.INFO)
  146. tf.app.run()

main(global_step)

  1. # Author:凌逆战
  2. # -*- encoding:utf-8 -*-
  3. # 修改时间:2020年5月31日
  4. import time
  5. from tensorflow.examples.tutorials.mnist import input_data
  6. from nets.my_vgg import VGG16Net
  7. from ops import *
  8.  
  9. tf.flags.DEFINE_integer('batch_size', 100, 'batch size, default: 1')
  10. tf.flags.DEFINE_integer('class_num', 10, 'batch size, default: 1')
  11. tf.flags.DEFINE_integer('epochs', 10, 'batch size, default: 1')
  12. tf.flags.DEFINE_float('learning_rate', 2e-4, '初始学习率, 默认: 0.0001')
  13. tf.flags.DEFINE_string('checkpoints_dir', "checkpoint", '保存检查点的地址')
  14. FLAGS = tf.flags.FLAGS
  15.  
  16. # 从MNIST_data/中读取MNIST数据。当数据不存在时,会自动执行下载
  17. mnist = input_data.read_data_sets('./MNIST_data', one_hot=True, reshape=False)
  18. # reshape=False (None, 28,28,1) # 用于第一层是卷积层
  19. # reshape=False (None, 784) # 用于第一层是全连接层
  20.  
  21. # 我们看一下数据的shape
  22. print(mnist.train.images.shape) # 训练数据图片(55000, 28, 28, 1)
  23. print(mnist.train.labels.shape) # 训练数据标签(55000, 10)
  24. print(mnist.test.images.shape) # 测试数据图片(10000, 28, 28, 1)
  25. print(mnist.test.labels.shape) # 测试数据图片(10000, 10)
  26. print(mnist.validation.images.shape) # 验证数据图片(5000, 28, 28, 1)
  27. print(mnist.validation.labels.shape) # 验证数据图片(5000, 784)
  28.  
  29. def train():
  30. batch_size = FLAGS.batch_size
  31. batch_nums = mnist.train.images.shape[0] // batch_size # 一个epoch中应该包含多少batch数据
  32. class_num = FLAGS.class_num
  33. epochs = FLAGS.epochs
  34. learning_rate = FLAGS.learning_rate
  35.  
  36. ############ 保存检查点的地址 ############
  37. checkpoints_dir = FLAGS.checkpoints_dir # checkpoints
  38. # 如果检查点不存在,则创建
  39. if not os.path.exists(checkpoints_dir):
  40. os.makedirs(FLAGS.checkpoints_dir)
  41.  
  42. ######################################################
  43. # 创建图 #
  44. ######################################################
  45. graph = tf.Graph() # 自定义图
  46. # 在自己的图中定义数据和操作
  47. with graph.as_default():
  48. inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
  49. labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
  50. ############ 搭建模型 ############
  51. logits = VGG16Net(inputs, class_num) # 使用placeholder搭建模型
  52. ############ 损失函数 ############
  53. # 计算预测值和真实值之间的误差
  54. loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
  55. tf.add_to_collection('losses', loss)
  56. total_loss = tf.add_n(tf.get_collection("loss")) # total_loss=模型损失+权重正则化损失
  57. ############ 模型精度 ############
  58. predict = tf.argmax(logits, axis=1)
  59. accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, axis=1)), tf.float32))
  60. ############ 优化器 ############
  61. variable_to_train = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES) # 可训练变量列表
  62. # 创建优化器,更新网络参数,最小化loss,
  63. train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss=total_loss,
  64. var_list=variable_to_train)
  65. ############ TensorBoard可视化 summary ############
  66. summary_writer = tf.summary.FileWriter("./logs", graph=graph) # 创建事件文件
  67. tf.summary.scalar(name="loss", tensor=total_loss) # 收集损失值变量
  68. tf.summary.scalar(name='accuracy', tensor=accuracy) # 收集精度值变量
  69. tf.summary.scalar(name='learning_rate', tensor=learning_rate)
  70. merged_summary_op = tf.summary.merge_all() # 将所有的summary合并为一个op
  71. ############ 模型保存和恢复 Saver ############
  72. saver = tf.train.Saver(max_to_keep=5)
  73.  
  74. ######################################################
  75. # 创建会话 #
  76. ######################################################
  77. max_acc = 0.
  78. config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
  79. with tf.Session(config=config, graph=graph) as sess:
  80. # 加载模型,如果模型存在返回 是否加载成功和训练步数
  81. could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
  82. if could_load:
  83. step = checkpoint_step
  84. print(" [*] 模型加载成功")
  85. else:
  86. print(" [!] 模型加载失败")
  87. try:
  88. tf.global_variables_initializer().run()
  89. except:
  90. tf.initialize_all_variables().run()
  91. step = 0
  92.  
  93. for epoch in range(epochs):
  94. for i in range(batch_nums):
  95. start_time = time.time() # 记录一下开始训练的时间
  96. # batch_images = data_X[i * batch_size:(i + 1) * batch_size]
  97. # batch_labels = data_y[i * batch_size:(i + 1) * batch_size]
  98. train_batch_x, train_batch_y = mnist.train.next_batch(batch_size)
  99.  
  100. # 使用真实数据填充placeholder,运行训练模型和合并变量操作
  101. _, summary, loss = sess.run([train_op, merged_summary_op, total_loss],
  102. feed_dict={inputs: train_batch_x,
  103. labels: train_batch_y})
  104. if step % 100 == 0:
  105. summary_writer.add_summary(summary, step) # 将每次迭代后的变量写入事件文件
  106. summary_writer.flush() # 强制summary_writer将缓存中的数据写入到日志文件中(可选)
  107.  
  108. ############ 可视化打印 ############
  109. print("Epoch:[%2d] [%4d/%4d] time:%4.4f,loss:%.8f" % (
  110. epoch, i, batch_nums, time.time() - start_time, loss))
  111.  
  112. # 打印一些可视化的数据,损失...
  113. # if np.mod(step, 100) == 1
  114. if step % 100 == 0:
  115. acc = sess.run(accuracy, {inputs: mnist.validation.images,
  116. labels: mnist.validation.labels})
  117. print("Epoch:[%2d] [%4d/%4d],acc:%.8f" % (epoch, i, batch_nums, acc))
  118. ############ 保存模型 ############
  119. if acc > max_acc:
  120. max_acc = acc
  121. save_path = saver.save(sess,
  122. save_path=os.path.join(checkpoints_dir, "model.ckpt"),
  123. global_step=step)
  124. # logging.info("模型保存在: %s" % save_path)
  125. tf.logging.info("模型保存在: %s" % save_path)
  126. step += 1
  127. print("优化完成!")
  128.  
  129. def main(argv=None):
  130. train()
  131.  
  132. if __name__ == '__main__':
  133. # logging.basicConfig(level=logging.INFO)
  134. tf.logging.set_verbosity(tf.logging.INFO)
  135. tf.app.run()

main(step)

数据处理

  数据处理因为每个专业领域的原因各不相同,而这不同点也是各位论文创新点的新方向。不同的我没法讲,但我总结了几点相同的地方——batch数据生成。因为深度学习模型需要一个batch一个batch的喂数据进行训练,所以我们的数据必须是batch的形式,这里衍生了三点问题

  1. 通过代码批量读取数据,
  2. 如何生成batch数据:由于篇幅过长,实在有很多地方要介绍和详述,我把这一块内容移到了这篇文章《TensorFlow读取数据的三种方法》中
  3. 数据的shape:我举两个例子让大家理解:图片数据为4维 (batch_size, height,width, channels),序列数据为3维 (batch_size, time_steps, input_size),
    • 不同的shape处理方法不同,选择神经网络模型单元也不同。我会在后面细讲

模型搭建

  阅读这一节我默认大家已经学会了数据的batch读取了。

  模型搭建这一步很像我们小时候玩的搭积木,我这里以经典神经网络模型VGG、Alex、ResNet、Google Inception Net为例讲解,大家看代码看多了也会很简单的就找到,当然我是有一点私心的,我想把这些经典的网络在这篇文章做一个tensorflow实现汇总,我细讲第一个,大家可能看一个例子就懂了,看懂了就直接往下看,看不懂就多看几个。

LeNet5模型

论文:1998_LeNet_Gradient-Based Learning Applied to Document Recognition

  下面我们定义一个LeNet5模型,我们先定义需要用到的神经网络单元,相同的代码尽量封装成函数的形式以节省代码量和简洁代码

  1. def conv(input, kernel_size, output_size, stride, init_bias=0.0, padding="SAME", name=None, wd=None):
  2. input_size = input.shape[-1]
  3. conv_weights = tf.get_variable(name='weights',
  4. shape=[kernel_size, kernel_size, input_size, output_size],
  5. initializer=tf.truncated_normal_initializer(stddev=0.1),
  6. dtype=tf.float32)
  7. conv_biases = tf.get_variable(name='biases',
  8. shape=[output_size],
  9. initializer=tf.constant_initializer(init_bias),
  10. dtype=tf.float32)
  11.  
  12. if wd is not None:
  13. # wd 0.004
  14. # tf.nn.l2_loss(var)=sum(t**2)/2
  15. weight_decay = tf.multiply(tf.nn.l2_loss(conv_weights), wd, name='weight_loss')
  16. tf.add_to_collection('losses', weight_decay)
  17.  
  18. conv_layer = tf.nn.conv2d(input, conv_weights, [1, stride, stride, 1], padding=padding, name=name) # 卷积操作
  19. conv_layer = tf.nn.bias_add(conv_layer, conv_biases) # 加上偏置项
  20. conv_layer = tf.nn.relu(conv_layer) # relu激活函数
  21.  
  22. return conv_layer
  23.  
  24. def fc(input, output_size, init_bias=0.0, activeation_func=True, wd=None):
  25. input_shape = input.get_shape().as_list()
  26. # 创建 全连接权重 变量
  27. fc_weights = tf.get_variable(name="weights",
  28. shape=[input_shape[-1], output_size],
  29. initializer=tf.truncated_normal_initializer(stddev=0.1),
  30. dtype=tf.float32)
  31. if wd is not None:
  32. # wd 0.004
  33. # tf.nn.l2_loss(var)=sum(t**2)/2
  34. weight_decay = tf.multiply(tf.nn.l2_loss(fc_weights), wd, name='weight_loss')
  35. tf.add_to_collection('losses', weight_decay)
  36. # 创建 全连接偏置 变量
  37. fc_biases = tf.get_variable(name="biases",
  38. shape=[output_size],
  39. initializer=tf.constant_initializer(init_bias),
  40. dtype=tf.float32)
  41.  
  42. fc_layer = tf.matmul(input, fc_weights) # 全连接计算
  43. fc_layer = tf.nn.bias_add(fc_layer, fc_biases) # 加上偏置项
  44. if activeation_func:
  45. fc_layer = tf.nn.relu(fc_layer) # rele激活函数
  46. return fc_layer

  然后利用我们搭建的神经网络单元,搭建LeNet5神经网络模型

  1. # 训练时:keep_prob=0.5
  2. # 测试时:keep_prob=1.0
  3. def leNet(inputs, class_num, keep_prob=0.5):
  4. # 第一层 卷积层 conv1
  5. with tf.variable_scope('layer1-conv1'):
  6. conv1 = conv(input=inputs, kernel_size=5, output_size=32, stride=1, init_bias=0.0, name="layer1-conv1",
  7. padding="SAME")
  8. # 第二层 池化层
  9. with tf.name_scope('layer2-pool1'):
  10. pool1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
  11. # 第三层 卷积层 conv2
  12. with tf.variable_scope('layer3-conv2'):
  13. conv2 = conv(input=pool1, kernel_size=5, output_size=64, stride=1, init_bias=0.0, name="layer3-conv2",
  14. padding="SAME")
  15. # 第四层 池化层
  16. with tf.name_scope('layer4-pool2'):
  17. pool2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
  18.  
  19. # 后面要做全连接,因此要把数据变成2维
  20. # pool_shape = pool2.get_shape().as_list()
  21. pool_shape = pool2.shape
  22. flatten = tf.reshape(pool2, [-1, pool_shape[1] * pool_shape[2] * pool_shape[3]])
  23. with tf.variable_scope('layer5-fcl'):
  24. fc1 = fc(input=flatten, output_size=512, init_bias=0.1, activeation_func=tf.nn.relu, wd=None)
  25. fc1 = tf.nn.dropout(fc1, keep_prob=keep_prob, name="dropout1")
  26. with tf.variable_scope('layer6-fc2'):
  27. logit = fc(input=fc1, output_size=class_num, init_bias=0.1, activeation_func=False, wd=None)
  28. return logit

Alex模型

论文:2012_Alex_ImageNet Classification with Deep Convolutional Neural Networks

  下面我们定义一个Alex模型,我们先定义需要用到的神经网络单元,相同的代码尽量封装成函数的形式以节省代码量和简洁代码

  1. def conv(input, kernel_size, output_size, stride, init_bias=0.0, padding="SAME", name=None, wd=None):
  2. input_size = input.shape[-1]
  3. conv_weights = tf.get_variable(name='weights',
  4. shape=[kernel_size, kernel_size, input_size, output_size],
  5. initializer=tf.random_normal_initializer(mean=0, stddev=0.01),
  6. dtype=tf.float32)
  7. if wd is not None:
  8. # wd 0.004
  9. # tf.nn.l2_loss(var)=sum(t**2)/2
  10. weight_decay = tf.multiply(tf.nn.l2_loss(conv_weights), wd, name='weight_loss')
  11. tf.add_to_collection('losses', weight_decay)
  12.  
  13. conv_biases = tf.get_variable(name='biases',
  14. shape=[output_size],
  15. initializer=tf.constant_initializer(init_bias),
  16. dtype=tf.float32)
  17. conv_layer = tf.nn.conv2d(input, conv_weights, [1, stride, stride, 1], padding=padding, name=name) # 卷积操作
  18. conv_layer = tf.nn.bias_add(conv_layer, conv_biases) # 加上偏置项
  19. conv_layer = tf.nn.relu(conv_layer) # relu激活函数
  20.  
  21. return conv_layer

conv函数

  1. def fc(input, output_size, init_bias=0.0, activeation_func=True, wd=None):
  2. input_shape = input.get_shape().as_list()
  3. # 创建 全连接权重 变量
  4. fc_weights = tf.get_variable(name="weights",
  5. shape=[input_shape[-1], output_size],
  6. initializer=tf.random_normal_initializer(mean=0.0, stddev=0.01),
  7. dtype=tf.float32)
  8. if wd is not None:
  9. # wd 0.004
  10. # tf.nn.l2_loss(var)=sum(t**2)/2
  11. weight_decay = tf.multiply(tf.nn.l2_loss(fc_weights), wd, name='weight_loss')
  12. tf.add_to_collection('losses', weight_decay)
  13.  
  14. # 创建 全连接偏置 变量
  15. fc_biases = tf.get_variable(name="biases",
  16. shape=[output_size],
  17. initializer=tf.constant_initializer(init_bias),
  18. dtype=tf.float32)
  19.  
  20. fc_layer = tf.matmul(input, fc_weights) # 全连接计算
  21. fc_layer = tf.nn.bias_add(fc_layer, fc_biases) # 加上偏置项
  22. if activeation_func:
  23. fc_layer = tf.nn.relu(fc_layer) # rele激活函数
  24. return fc_layer

fc函数

  1. def LRN(input, depth_radius=2, alpha=0.0001, beta=0.75, bias=1.0):
  2. """Local Response Normalization 局部响应归一化"""
  3. return tf.nn.local_response_normalization(input, depth_radius=depth_radius, alpha=alpha,
  4. beta=beta, bias=bias)

LRN函数

  然后利用我们搭建的神经网络单元,搭建Alex神经网络模型

  1. def alexNet(inputs, class_num, keep_prob=0.5):
  2. # 第一层卷积层 conv1
  3. with tf.variable_scope("conv1"):
  4. conv1 = conv(input=inputs, kernel_size=7, output_size=96, stride=3, init_bias=0.0, name="conv1", padding="SAME")
  5. conv1 = LRN(conv1)
  6. conv1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name="pool1")
  7. # 第二层卷积层 conv2
  8. with tf.variable_scope("conv2"):
  9. conv2 = conv(input=conv1, kernel_size=7, output_size=96, stride=3, init_bias=1.0, name="conv2", padding="SAME")
  10. conv2 = LRN(conv2)
  11. conv2 = tf.nn.max_pool(conv2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name="pool2")
  12. # 第三层卷积层 conv3
  13. with tf.variable_scope("conv3"):
  14. conv3 = conv(input=conv2, kernel_size=7, output_size=96, stride=3, init_bias=0.0, name="conv3", padding="SAME")
  15. # 第四层卷积层 conv4
  16. with tf.variable_scope("conv4"):
  17. conv4 = conv(input=conv3, kernel_size=7, output_size=96, stride=3, init_bias=1.0, name="conv4", padding="SAME")
  18. # 第五层卷积层 conv5
  19. with tf.variable_scope("conv5"):
  20. conv5 = conv(input=conv4, kernel_size=3, output_size=256, stride=1, init_bias=1.0, name="conv5")
  21. conv5 = tf.nn.max_pool(conv5, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name="pool5")
  22. conv5_shape = conv5.shape # 后面做全连接,所以要把shape改成2维
  23. # shape=[batch, dim]
  24. flatten = tf.reshape(conv5, [-1, conv5_shape[1] * conv5_shape[2] * conv5_shape[3]])
  25. # 第一层全连接层 fc1
  26. with tf.variable_scope("fc1"):
  27. fc1 = fc(input=flatten, output_size=4096, init_bias=1.0, activeation_func=tf.nn.relu, wd=None)
  28. fc1 = tf.nn.dropout(fc1, keep_prob=keep_prob, name="dropout1")
  29. # 第一层全连接层 fc2
  30. with tf.variable_scope("fc2"):
  31. fc2 = fc(input=fc1, output_size=4096, init_bias=1.0, activeation_func=tf.nn.relu, wd=None)
  32. fc2 = tf.nn.dropout(fc2, keep_prob=keep_prob, name="dropout1")
  33. # 第一层全连接层 fc3
  34. with tf.variable_scope("fc3"):
  35. logit = fc(input=fc2, output_size=class_num, init_bias=1.0, activeation_func=False, wd=None)
  36.  
  37. return logit # 模型输出

VGG模型

论文:2014_VGG_Very Deep Convolutional Networks for Large-Scale Image Recognition

VGG有两个比较有名的网络:VGG16、VGG19,我在这里搭建VGG16,有兴趣的朋友可以按照上面的模型结构自己用TensorFlow搭建VGG19模型

  下面我们定义一个VGG16模型,和前面一样,我们先定义需要用到的神经网络单元,相同的代码尽量封装成函数的形式以节省代码量和简洁代码

  因为模型中同一个变量域中包含多个卷积操作,因此在卷积函数中套一层变量域

  1. def conv(inputs, scope_name, kernel_size, output_size, stride, init_bias=0.0, padding="SAME", wd=None):
  2. input_size = int(inputs.get_shape()[-1])
  3. with tf.variable_scope(scope_name):
  4. conv_weights = tf.get_variable(name='weights',
  5. shape=[kernel_size, kernel_size, input_size, output_size],
  6. dtype=tf.float32,
  7. initializer=tf.truncated_normal_initializer(mean=0.0, stddev=1e-1))
  8. if wd is not None:
  9. # tf.nn.l2_loss(var)=sum(t**2)/2
  10. weight_decay = tf.multiply(tf.nn.l2_loss(conv_weights), wd, name='weight_loss')
  11. tf.add_to_collection('losses', weight_decay)
  12.  
  13. conv_biases = tf.get_variable(name='biases',
  14. shape=[output_size],
  15. dtype=tf.float32,
  16. initializer=tf.constant_initializer(init_bias))
  17. conv_layer = tf.nn.conv2d(inputs, conv_weights, [1, stride, stride, 1], padding=padding, name=scope_name)
  18. conv_layer = tf.nn.bias_add(conv_layer, conv_biases)
  19. conv_layer = tf.nn.relu(conv_layer)
  20. return conv_layer

conv函数

  1. def fc(inputs, scope_name, output_size, init_bias=0.0, activeation_func=True, wd=None):
  2. input_shape = inputs.get_shape().as_list()
  3. with tf.variable_scope(scope_name):
  4. # 创建 全连接权重 变量
  5. fc_weights = tf.get_variable(name="weights",
  6. shape=[input_shape[-1], output_size],
  7. dtype=tf.float32,
  8. initializer=tf.truncated_normal_initializer(mean=0.0, stddev=1e-1))
  9. if wd is not None:
  10. # wd 0.004
  11. # tf.nn.l2_loss(var)=sum(t**2)/2
  12. weight_decay = tf.multiply(tf.nn.l2_loss(fc_weights), wd, name='weight_loss')
  13. tf.add_to_collection('losses', weight_decay)
  14.  
  15. # 创建 全连接偏置 变量
  16. fc_biases = tf.get_variable(name="biases",
  17. shape=[output_size],
  18. dtype=tf.float32,
  19. initializer=tf.constant_initializer(init_bias),
  20. trainable=True)
  21.  
  22. fc_layer = tf.matmul(inputs, fc_weights) # 全连接计算
  23. fc_layer = tf.nn.bias_add(fc_layer, fc_biases) # 加上偏置项
  24. if activeation_func:
  25. fc_layer = tf.nn.relu(fc_layer) # rele激活函数
  26. return fc_layer

fc函数

  然后利用我们搭建的神经网络单元,搭建VGG16神经网络模型

  1. def VGG16Net(inputs, class_num):
  2. with tf.variable_scope("conv1"):
  3. # conv1_1 [conv3_64]
  4. conv1_1 = conv(inputs=inputs, scope_name="conv1_1", kernel_size=3, output_size=64, stride=1,
  5. init_bias=0.0, padding="SAME")
  6. # conv1_2 [conv3_64]
  7. conv1_2 = conv(inputs=conv1_1, scope_name="conv1_2", kernel_size=3, output_size=64, stride=1,
  8. init_bias=0.0, padding="SAME")
  9. pool1 = tf.nn.max_pool(conv1_2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool1')
  10. with tf.variable_scope("conv2"):
  11. # conv2_1
  12. conv2_1 = conv(inputs=pool1, scope_name="conv2_1", kernel_size=3, output_size=128, stride=1,
  13. init_bias=0.0, padding="SAME")
  14. # conv2_2
  15. conv2_2 = conv(inputs=conv2_1, scope_name="conv2_2", kernel_size=3, output_size=128, stride=1,
  16. init_bias=0.0, padding="SAME")
  17. pool2 = tf.nn.max_pool(conv2_2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool2')
  18. with tf.variable_scope("conv3"):
  19. # conv3_1
  20. conv3_1 = conv(inputs=pool2, scope_name="conv3_1", kernel_size=3, output_size=256, stride=1,
  21. init_bias=0.0, padding="SAME")
  22. # conv3_2
  23. conv3_2 = conv(inputs=conv3_1, scope_name="conv3_2", kernel_size=3, output_size=256, stride=1,
  24. init_bias=0.0, padding="SAME")
  25. # conv3_3
  26. conv3_3 = conv(inputs=conv3_2, scope_name="conv3_3", kernel_size=3, output_size=256, stride=1,
  27. init_bias=0.0, padding="SAME")
  28. pool3 = tf.nn.max_pool(conv3_3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool3')
  29. with tf.variable_scope("conv4"):
  30. # conv4_1
  31. conv4_1 = conv(inputs=pool3, scope_name="conv4_1", kernel_size=3, output_size=512, stride=1,
  32. init_bias=0.0, padding="SAME")
  33. # conv4_2
  34. conv4_2 = conv(inputs=conv4_1, scope_name="conv4_2", kernel_size=3, output_size=512, stride=1,
  35. init_bias=0.0, padding="SAME")
  36. # conv4_3
  37. conv4_3 = conv(inputs=conv4_2, scope_name="conv4_3", kernel_size=3, output_size=512, stride=1,
  38. init_bias=0.0, padding="SAME")
  39. pool4 = tf.nn.max_pool(conv4_3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool4')
  40. with tf.variable_scope("conv5"):
  41. # conv5_1
  42. conv5_1 = conv(inputs=pool4, scope_name="conv4_1", kernel_size=3, output_size=512, stride=1,
  43. init_bias=0.0, padding="SAME")
  44. # conv5_2
  45. conv5_2 = conv(inputs=conv5_1, scope_name="conv4_2", kernel_size=3, output_size=512, stride=1,
  46. init_bias=0.0, padding="SAME")
  47. # conv5_3
  48. conv5_3 = conv(inputs=conv5_2, scope_name="conv4_3", kernel_size=3, output_size=512, stride=1,
  49. init_bias=0.0, padding="SAME")
  50. pool5 = tf.nn.max_pool(conv5_3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool4')
  51. input_shape = pool5.get_shape().as_list() # 后面做全连接,所以要把shape改成2维
  52. # shape=[batch, dim]
  53. flatten = tf.reshape(pool5, [-1, input_shape[1] * input_shape[2] * input_shape[3]])
  54. fc1 = fc(inputs=flatten, scope_name="fc1", output_size=4096, init_bias=1.0, activeation_func=True)
  55. fc2 = fc(inputs=fc1, scope_name="fc2", output_size=4096, init_bias=1.0, activeation_func=True)
  56. fc3 = fc(inputs=fc2, scope_name="fc3", output_size=class_num, init_bias=1.0, activeation_func=True)
  57.  
  58. return fc3

上图中有一个softmax层,我们也可以定义出来

  1. class_num = 1000
  2. # placeholder 定义
  3. inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 3], name='inputs')
  4. labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
  5. learning_rate = tf.placeholder("float", None, name='learning_rate')
  6.  
  7. logits = VGG16Net(inputs)
  8. probs = tf.nn.softmax(logits)

ResNet模型

论文

  ResNet的网络结构如下图所示

我们先定义需要用到的神经网络单元

  1. def batch_normalization(inputs, output_size):
  2. mean, variance = tf.nn.moments(inputs, axes=[0, 1, 2]) # 计算均值和方差
  3. beta = tf.get_variable('beta', output_size, tf.float32, initializer=tf.zeros_initializer)
  4. gamma = tf.get_variable('gamma', output_size, tf.float32, initializer=tf.ones_initializer)
  5. bn_layer = tf.nn.batch_normalization(inputs, mean, variance, beta, gamma, 0.001)
  6.  
  7. return bn_layer

batch_normalization函数

  1. def conv(input, kernel_size, output_size, stride, padding="SAME", wd=None):
  2. input_size = input.shape[-1]
  3. conv_weights = tf.get_variable(name='weights',
  4. shape=[kernel_size, kernel_size, input_size, output_size],
  5. dtype=tf.float32,
  6. initializer=tf.truncated_normal_initializer(mean=0.0, stddev=0.1),
  7. regularizer=tf.contrib.layers.l2_regularizer(0.00004)) # 正则损失衰减率0.000004
  8.  
  9. conv_layer = tf.nn.conv2d(input, conv_weights, [1, stride, stride, 1], padding=padding) # 卷积操作
  10. batch_norm = batch_normalization(conv_layer, output_size)
  11. conv_output = tf.nn.relu(batch_norm) # relu激活函数
  12. return conv_output

conv函数

  1. def fc(input, output_size, activeation_func=True):
  2. input_shape = input.shape[-1]
  3. # 创建 全连接权重 变量
  4. fc_weights = tf.get_variable(name="weights",
  5. shape=[input_shape, output_size],
  6. initializer=tf.truncated_normal_initializer(stddev=0.01),
  7. dtype=tf.float32,
  8. regularizer=tf.contrib.layers.l2_regularizer(0.01))
  9. # 创建 全连接偏置 变量
  10. fc_biases = tf.get_variable(name="biases",
  11. shape=[output_size],
  12. initializer=tf.zeros_initializer,
  13. dtype=tf.float32)
  14.  
  15. fc_layer = tf.matmul(input, fc_weights) # 全连接计算
  16. fc_layer = tf.nn.bias_add(fc_layer, fc_biases) # 加上偏置项
  17. if activeation_func:
  18. fc_layer = tf.nn.relu(fc_layer) # rele激活函数
  19. return fc_layer

fc函数

  1. def block(input, n, output_size, change_first_stride, bottleneck):
  2. if n == 0 and change_first_stride:
  3. stride = 2
  4. else:
  5. stride = 1
  6. if bottleneck:
  7. with tf.variable_scope('a'):
  8. conv_a = conv(input=input, kernel_size=1, output_size=output_size, stride=stride, padding="SAME")
  9. conv_a = batch_normalization(conv_a, output_size)
  10. conv_a = tf.nn.relu(conv_a)
  11. with tf.variable_scope('b'):
  12. conv_b = conv(input=conv_a, kernel_size=3, output_size=output_size, stride=1, padding="SAME")
  13. conv_b = batch_normalization(conv_b, output_size)
  14. conv_b = tf.nn.relu(conv_b)
  15.  
  16. with tf.variable_scope('c'):
  17. conv_c = conv(input=conv_b, kernel_size=1, output_size=output_size * 4, stride=1, padding="SAME")
  18. output = batch_normalization(conv_c, output_size * 4)
  19. else:
  20. with tf.variable_scope('A'):
  21. conv_A = conv(input=input, kernel_size=3, output_size=output_size, stride=stride, padding="SAME")
  22. conv_A = batch_normalization(conv_A, output_size)
  23. conv_A = tf.nn.relu(conv_A)
  24.  
  25. with tf.variable_scope('B'):
  26. conv_B = conv(input=conv_A, kernel_size=3, output_size=output_size, stride=1, padding="SAME")
  27. output = batch_normalization(conv_B, output_size)
  28.  
  29. if input.shape == output.shape:
  30. with tf.variable_scope('shortcut'):
  31. shortcut = input # shortcut
  32. else:
  33. with tf.variable_scope('shortcut'):
  34. shortcut = conv(input=input, kernel_size=1, output_size=output_size * 4, stride=1, padding="SAME")
  35. shortcut = batch_normalization(shortcut, output_size * 4)
  36.  
  37. return tf.nn.relu(output + shortcut)

block函数

  然后我们定义神经网络框架

  1. def inference(inputs, class_num, num_blocks=[3, 4, 6, 3], bottleneck=True):
  2. # data[1, 224, 224, 3]
  3.  
  4. # 我们尝试搭建50层ResNet
  5. with tf.variable_scope('conv1'):
  6. conv1 = conv(input=inputs, kernel_size=7, output_size=64, stride=2, padding="SAME")
  7. conv1 = batch_normalization(inputs=conv1, output_size=64)
  8. conv1 = tf.nn.relu(conv1)
  9.  
  10. with tf.variable_scope('conv2_x'):
  11. conv_output = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')
  12. for n in range(num_blocks[0]):
  13. with tf.variable_scope('block%d' % (n + 1)):
  14. conv_output = block(conv_output, n, output_size=64, change_first_stride=False, bottleneck=bottleneck)
  15.  
  16. with tf.variable_scope('conv3_x'):
  17. for n in range(num_blocks[1]):
  18. with tf.variable_scope('block%d' % (n + 1)):
  19. conv_output = block(conv_output, n, output_size=128, change_first_stride=True, bottleneck=bottleneck)
  20.  
  21. with tf.variable_scope('conv4_x'):
  22. for n in range(num_blocks[2]):
  23. with tf.variable_scope('block%d' % (n + 1)):
  24. conv_output = block(conv_output, n, output_size=256, change_first_stride=True, bottleneck=bottleneck)
  25.  
  26. with tf.variable_scope('conv5_x'):
  27. for n in range(num_blocks[3]):
  28. with tf.variable_scope('block%d' % (n + 1)):
  29. conv_output = block(conv_output, n, output_size=512, change_first_stride=True, bottleneck=bottleneck)
  30.  
  31. output = tf.reduce_mean(conv_output, reduction_indices=[1, 2], name="avg_pool")
  32. with tf.variable_scope('fc'):
  33. output = fc(output, class_num, activeation_func=False)
  34.  
  35. return output

Google Inception Net模型

  Inception Net模型 以后再更新吧,如果这篇文章对大家有用,欢迎大家催促我。

RNN模型

  Tensorflow中的CNN变数很少,而RNN却丰富多彩,不仅在RNN Cell上有很多种、在实现上也有很多种,在用法上更是花样百出。

五个基本的RNN CellRNNCellBasicRNNCellLSTMCellBasicLSTMCellGRUCell

RNN Cell的封装和变形MultiRNNCell(多层RNN)、DropoutWrapperResidualWrapperDeviceWrapper

四种架构 (static+dynamic)*(单向+双向)=4:static_rnn(静态RNN)、dynamic_rnn(动态RNN)、static_bidirectional_rnn(静态双向RNN)、bidirectional_dynamic_rnn(动态双向RNN)

五种手法 (one+many)*(one+many) +1=5:

  1. one to one(1 vs 1):输入一个,输出一个。其实和全连接神经网络并没有什么区别,这一类别算不得是 RNN。
  2. one to many(1 vs N):输入一个,输出多个。图像标注,输入一个图片,得到对图片的语言描述
  3. many to one(N vs 1):输入多个,输出一个。序列分类,把序列压缩成一个向量
  4. many to many(N vs N):输入多个,输出多个。两者长度可以不一样。翻译任务
  5. many to many(N vs N):输入多个,输出多个。两者长度一样。char RNN

我们先定义需要用到的神经网络单元

全连接层

  1. def fc(input, output_size, activeation_func=tf.nn.relu):
  2. input_shape = input.shape[-1]
  3. # 创建 全连接权重 变量
  4. fc_weights = tf.get_variable(name="weights",
  5. shape=[input_shape, output_size],
  6. initializer=tf.truncated_normal_initializer(stddev=0.01),
  7. dtype=tf.float32,
  8. regularizer=tf.contrib.layers.l2_regularizer(0.01))
  9. # 创建 全连接偏置 变量
  10. fc_biases = tf.get_variable(name="biases",
  11. shape=[output_size],
  12. initializer=tf.zeros_initializer,
  13. dtype=tf.float32)
  14.  
  15. fc_layer = tf.matmul(input, fc_weights) # 全连接计算
  16. fc_layer = tf.nn.bias_add(fc_layer, fc_biases) # 加上偏置项
  17. if activeation_func:
  18. fc_layer = activeation_func(fc_layer) # rele激活函数
  19. return fc_layer

单层 静态/动态 LSTM/GRU

  1. #######################################
  2. # 单层 静态/动态 LSTM/GRU #
  3. #######################################
  4. # 单层静态LSTM
  5. def single_layer_static_lstm(input_x, time_steps, hidden_size):
  6. """
  7. :param input_x: 输入张量 形状为[batch_size, n_steps, input_size]
  8. :param n_steps: 时序总数
  9. :param n_hidden: LSTM单元输出的节点个数 即隐藏层节点数
  10. """
  11. # 把输入input_x按列拆分,并返回一个有n_steps个张量组成的list
  12. # 如batch_sizex28x28的输入拆成[(batch_size,28),((batch_size,28))....]
  13. # 如果是调用的是静态rnn函数,需要这一步处理 即相当于把序列作为第一维度
  14. input_x1 = tf.unstack(input_x, num=time_steps, axis=1)
  15. lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size) # 创建LSTM_cell
  16. # 静态rnn函数传入的是一个张量list 每一个元素都是一个(batch_size,input_size)大小的张量
  17. output, states = tf.nn.static_rnn(cell=lstm_cell, inputs=input_x1, dtype=tf.float32) # 通过cell类构建RNN
  18.  
  19. return output, states
  20.  
  21. # 单层静态gru
  22. def single_layer_static_gru(input, time_steps, hidden_size):
  23. """
  24. :param input: 输入张量 形状为[batch_size, n_steps, input_size]
  25. :param n_steps: 时序总数
  26. :param n_hidden: gru单元输出的节点个数 即隐藏层节点数
  27. :return: 返回静态单层GRU单元的输出,以及cell状态
  28. """
  29. # 把输入input_x按列拆分,并返回一个有n_steps个张量组成的list
  30. # 如batch_sizex28x28的输入拆成[(batch_size,28),((batch_size,28))....]
  31. # 如果是调用的是静态rnn函数,需要这一步处理 即相当于把序列作为第一维度
  32. input_x = tf.unstack(input, num=time_steps, axis=1)
  33. gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size) # 创建GRU_cell
  34. # 静态rnn函数传入的是一个张量list 每一个元素都是一个(batch_size,input_size)大小的张量
  35. output, states = tf.nn.static_rnn(cell=gru_cell, inputs=input_x, dtype=tf.float32) # 通过cell类构建RNN
  36.  
  37. return output, states
  38.  
  39. # 单层动态LSTM
  40. def single_layer_dynamic_lstm(input, time_steps, hidden_size):
  41. """
  42. :param input_x: 输入张量 形状为[batch_size, time_steps, input_size]
  43. :param time_steps: 时序总数
  44. :param hidden_size: LSTM单元输出的节点个数 即隐藏层节点数
  45. :return: 返回动态单层LSTM单元的输出,以及cell状态
  46. """
  47. lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size) # 创建LSTM_cell
  48. # 动态rnn函数传入的是一个三维张量,[batch_size,time_steps, input_size] 输出也是这种形状
  49. output, states = tf.nn.dynamic_rnn(cell=lstm_cell, inputs=input, dtype=tf.float32) # 通过cell类构建RNN
  50. output = tf.transpose(output, [1, 0, 2]) # 注意这里输出需要转置 转换为时序优先的
  51. return output, states
  52.  
  53. # 单层动态gru
  54. def single_layer_dynamic_gru(input, time_steps, hidden_size):
  55. """
  56. :param input: 输入张量 形状为[batch_size, time_steps, input_size]
  57. :param time_steps: 时序总数
  58. :param hidden_size: GRU单元输出的节点个数 即隐藏层节点数
  59. :return: 返回动态单层GRU单元的输出,以及cell状态
  60. """
  61. gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size) # 创建GRU_cell
  62. # 动态rnn函数传入的是一个三维张量,[batch_size,n_steps,input_size] 输出也是这种形状
  63. output, states = tf.nn.dynamic_rnn(cell=gru_cell, inputs=input, dtype=tf.float32) # 通过cell类构建RNN
  64. output = tf.transpose(output, [1, 0, 2]) # 注意这里输出需要转置 转换为时序优先的
  65. return output, states

多层 静态/动态 LSTM/GRU

  1. #######################################
  2. # 多层 静态/动态 LSTM/GRU #
  3. #######################################
  4. # 多层静态LSTM网络
  5. def multi_layer_static_lstm(input, time_steps, hidden_size):
  6. """
  7. :param input: 输入张量 形状为[batch_size,time_steps,input_size]
  8. :param time_steps: 时序总数
  9. :param n_hidden: LSTM单元输出的节点个数 即隐藏层节点数
  10. :return: 返回静态多层LSTM单元的输出,以及cell状态
  11. """
  12. # 把输入input_x按列拆分,并返回一个有n_steps个张量组成的list
  13. # 如batch_sizex28x28的输入拆成[(batch_size,28),((batch_size,28))....]
  14. # 如果是调用的是静态rnn函数,需要这一步处理 即相当于把序列作为第一维度
  15. input_x1 = tf.unstack(input, num=time_steps, axis=1)
  16.  
  17. # 多层RNN的实现 例如cells=[cell1,cell2,cell3],则表示一共有三层
  18. mcell = tf.nn.rnn_cell.MultiRNNCell(
  19. [tf.nn.rnn_cell.LSTMCell(num_units=hidden_size) for _ in range(3)])
  20.  
  21. # 静态rnn函数传入的是一个张量list 每一个元素都是一个(batch_size,input_size)大小的张量
  22. output, states = tf.nn.static_rnn(cell=mcell, inputs=input_x1, dtype=tf.float32)
  23.  
  24. return output, states
  25.  
  26. # 多层静态GRU
  27. def multi_layer_static_gru(input, time_steps, hidden_size):
  28. """
  29. :param input_x: 输入张量 形状为[batch_size,n_steps,input_size]
  30. :param time_steps: 时序总数
  31. :param hidden_size: gru单元输出的节点个数 即隐藏层节点数
  32. :return: 返回静态多层GRU单元的输出,以及cell状态
  33. """
  34. # 把输入input_x按列拆分,并返回一个有n_steps个张量组成的list
  35. # 如batch_sizex28x28的输入拆成[(batch_size,28),((batch_size,28))....]
  36. # 如果是调用的是静态rnn函数,需要这一步处理 即相当于把序列作为第一维度
  37. input_x = tf.unstack(input, num=time_steps, axis=1)
  38.  
  39. # 多层RNN的实现 例如cells=[cell1,cell2,cell3],则表示一共有三层
  40. mcell = tf.nn.rnn_cell.MultiRNNCell(
  41. [tf.nn.rnn_cell.GRUCell(num_units=hidden_size) for _ in range(3)])
  42.  
  43. # 静态rnn函数传入的是一个张量list 每一个元素都是一个(batch_size,input_size)大小的张量
  44. output, states = tf.nn.static_rnn(cell=mcell, inputs=input_x, dtype=tf.float32)
  45.  
  46. return output, states
  47.  
  48. # 多层静态GRU和LSTM 混合
  49. def multi_layer_static_mix(input, time_steps, hidden_size):
  50. """
  51. :param input: 输入张量 形状为[batch_size,n_steps,input_size]
  52. :param time_steps: 时序总数
  53. :param hidden_size: gru单元输出的节点个数 即隐藏层节点数
  54. :return: 返回静态多层GRU和LSTM混合单元的输出,以及cell状态
  55. """
  56. # 把输入input_x按列拆分,并返回一个有n_steps个张量组成的list
  57. # 如batch_sizex28x28的输入拆成[(batch_size,28),((batch_size,28))....]
  58. # 如果是调用的是静态rnn函数,需要这一步处理 即相当于把序列作为第一维度
  59. input_x = tf.unstack(input, num=time_steps, axis=1)
  60.  
  61. # 可以看做2个隐藏层
  62. lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=hidden_size)
  63. gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size * 2)
  64.  
  65. # 多层RNN的实现 例如cells=[cell1,cell2],则表示一共有两层,数据经过cell1后还要经过cells
  66. mcell = tf.nn.rnn_cell.MultiRNNCell(cells=[lstm_cell, gru_cell])
  67.  
  68. # 静态rnn函数传入的是一个张量list 每一个元素都是一个(batch_size,input_size)大小的张量
  69. output, states = tf.nn.static_rnn(cell=mcell, inputs=input_x, dtype=tf.float32)
  70.  
  71. return output, states
  72.  
  73. # 多层动态LSTM
  74. def multi_layer_dynamic_lstm(input, time_steps, hidden_size):
  75. """
  76. :param input: 输入张量 形状为[batch_size,n_steps,input_size]
  77. :param time_steps: 时序总数
  78. :param hidden_size: LSTM单元输出的节点个数 即隐藏层节点数
  79. :return: 返回动态多层LSTM单元的输出,以及cell状态
  80. """
  81. # 多层RNN的实现 例如cells=[cell1,cell2],则表示一共有两层,数据经过cell1后还要经过cells
  82. mcell = tf.nn.rnn_cell.MultiRNNCell(
  83. [tf.nn.rnn_cell.LSTMCell(num_units=hidden_size) for _ in range(3)])
  84.  
  85. # 动态rnn函数传入的是一个三维张量,[batch_size,n_steps,input_size] 输出也是这种形状
  86. output, states = tf.nn.dynamic_rnn(cell=mcell, inputs=input, dtype=tf.float32)
  87.  
  88. # 注意这里输出需要转置 转换为时序优先的
  89. output = tf.transpose(output, [1, 0, 2])
  90. return output, states
  91.  
  92. # 多层动态GRU
  93. def multi_layer_dynamic_gru(input, time_steps, hidden_size):
  94. """
  95. :param input: 输入张量 形状为[batch_size,n_steps,input_size]
  96. :param time_steps: 时序总数
  97. :param hidden_size: gru单元输出的节点个数 即隐藏层节点数
  98. :return: 返回动态多层GRU单元的输出,以及cell状态
  99. """
  100. # 多层RNN的实现 例如cells=[cell1,cell2],则表示一共有两层,数据经过cell1后还要经过cells
  101. mcell = tf.nn.rnn_cell.MultiRNNCell(
  102. [tf.nn.rnn_cell.GRUCell(num_units=hidden_size) for _ in range(3)])
  103.  
  104. # 动态rnn函数传入的是一个三维张量,[batch_size,n_steps,input_size] 输出也是这种形状
  105. output, states = tf.nn.dynamic_rnn(cell=mcell, inputs=input, dtype=tf.float32)
  106.  
  107. # 注意这里输出需要转置 转换为时序优先的
  108. output = tf.transpose(output, [1, 0, 2])
  109. return output, states
  110.  
  111. # 多层动态GRU和LSTM 混合
  112. def multi_layer_dynamic_mix(input, time_steps, hidden_size):
  113. """
  114. :param input: 输入张量 形状为[batch_size,n_steps,input_size]
  115. :param time_steps: 时序总数
  116. :param hidden_size: gru单元输出的节点个数 即隐藏层节点数
  117. :return: 返回动态多层GRU和LSTM混合单元的输出,以及cell状态
  118. """
  119. # 可以看做2个隐藏层
  120. gru_cell = tf.nn.rnn_cell.GRUCell(num_units=hidden_size * 2)
  121. lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=hidden_size)
  122.  
  123. # 多层RNN的实现 例如cells=[cell1,cell2],则表示一共有两层,数据经过cell1后还要经过cells
  124. mcell = tf.nn.rnn_cell.MultiRNNCell(cells=[lstm_cell, gru_cell])
  125.  
  126. # 动态rnn函数传入的是一个三维张量,[batch_size,n_steps,input_size] 输出也是这种形状
  127. output, states = tf.nn.dynamic_rnn(cell=mcell, inputs=input, dtype=tf.float32)
  128.  
  129. # 注意这里输出需要转置 转换为时序优先的
  130. output = tf.transpose(output, [1, 0, 2])
  131. return output, states

单层/多层 双向 静态/动态 LSTM/GRU

  1. #######################################
  2. # 单层/多层 双向 静态/动态 LSTM/GRU #
  3. #######################################
  4. # 单层静态双向LSTM
  5. def single_layer_static_bi_lstm(input, time_steps, hidden_size):
  6. """
  7. :param input: 输入张量 形状为[batch_size,time_steps,input_size]
  8. :param time_steps: 时序总数
  9. :param hidden_size: LSTM单元输出的节点个数 即隐藏层节点数
  10. :return: 返回单层静态双向LSTM单元的输出,以及cell状态
  11. """
  12. # 把输入input_x按列拆分,并返回一个有n_steps个张量组成的list
  13. # 如batch_sizex28x28的输入拆成[(batch_size,28),((batch_size,28))....]
  14. # 如果是调用的是静态rnn函数,需要这一步处理 即相当于把序列作为第一维度
  15. input_x = tf.unstack(input, num=time_steps, axis=1)
  16. lstm_fw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size) # 正向
  17. lstm_bw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size) # 反向
  18.  
  19. # 静态rnn函数传入的是一个张量list 每一个元素都是一个(batch_size,input_size)大小的张量
  20. # 这里的输出output是一个list 每一个元素都是前向输出,后向输出的合并
  21. output, fw_state, bw_state = tf.nn.static_bidirectional_rnn(cell_fw=lstm_fw_cell,
  22. cell_bw=lstm_bw_cell,
  23. inputs=input_x,
  24. dtype=tf.float32)
  25. print(type(output)) # <class 'list'>
  26. print(len(output)) #
  27. print(output[0].shape) # (?, 256)
  28.  
  29. return output, fw_state, bw_state
  30.  
  31. # 单层动态双向LSTM
  32. def single_layer_dynamic_bi_lstm(input, time_steps, hidden_size):
  33. """
  34. :param input: 输入张量 形状为[batch_size,time_steps,input_size]
  35. :param time_steps: 时序总数
  36. :param hidden_size: gru单元输出的节点个数 即隐藏层节点数
  37. :return: 返回单层动态双向LSTM单元的输出,以及cell状态
  38. """
  39. lstm_fw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size) # 正向
  40. lstm_bw_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size) # 反向
  41.  
  42. # 动态rnn函数传入的是一个三维张量,[batch_size,time_steps,input_size] 输出是一个元组 每一个元素也是这种形状
  43. output, state = tf.nn.bidirectional_dynamic_rnn(cell_fw=lstm_fw_cell,
  44. cell_bw=lstm_bw_cell,
  45. inputs=input,
  46. dtype=tf.float32)
  47. print(type(output)) # <class 'tuple'>
  48. print(len(output)) #
  49. print(output[0].shape) # (?, 28, 128)
  50. print(output[1].shape) # (?, 28, 128)
  51.  
  52. output = tf.concat(output, axis=2) # 按axis=2合并 (?,28,128) (?,28,128)按最后一维合并(?,28,256)
  53. output = tf.transpose(output, [1, 0, 2]) # 注意这里输出需要转置 转换为时序优先的
  54.  
  55. return output, state
  56.  
  57. # 多层静态双向LSTM
  58. def multi_layer_static_bi_lstm(input, time_steps, hidden_size):
  59. """
  60. :param input: 输入张量 形状为[batch_size,time_steps,input_size]
  61. :param time_steps: 时序总数
  62. :param hidden_size: LSTM单元输出的节点个数 即隐藏层节点数
  63. :return: 返回多层静态双向LSTM单元的输出,以及cell状态
  64. """
  65. # 把输入input_x按列拆分,并返回一个有n_steps个张量组成的list
  66. # 如batch_sizex28x28的输入拆成[(batch_size,28),((batch_size,28))....]
  67. # 如果是调用的是静态rnn函数,需要这一步处理 即相当于把序列作为第一维度
  68. input_x = tf.unstack(input, num=time_steps, axis=1)
  69.  
  70. stacked_fw_rnn = []
  71. stacked_bw_rnn = []
  72. for i in range(3):
  73. stacked_fw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)) # 正向
  74. stacked_bw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)) # 反向
  75.  
  76. # 静态rnn函数传入的是一个张量list 每一个元素都是一个(batch_size,input_size)大小的张量
  77. # 这里的输出output是一个list 每一个元素都是前向输出,后向输出的合并
  78. output, fw_state, bw_state = tf.contrib.rnn.stack_bidirectional_rnn(stacked_fw_rnn,
  79. stacked_bw_rnn,
  80. inputs=input_x,
  81. dtype=tf.float32)
  82. print(type(output)) # <class 'list'>
  83. print(len(output)) #
  84. print(output[0].shape) # (?, 256)
  85.  
  86. return output, fw_state, bw_state
  87.  
  88. # 多层动态双向LSTM
  89. def multi_layer_dynamic_bi_lstm(input, time_steps, hidden_size):
  90. """
  91. :param input: 输入张量 形状为[batch_size,n_steps,input_size]
  92. :param time_steps: 时序总数
  93. :param hidden_size: gru单元输出的节点个数 即隐藏层节点数
  94. :return: 返回多层动态双向LSTM单元的输出,以及cell状态
  95. """
  96. stacked_fw_rnn = []
  97. stacked_bw_rnn = []
  98. for i in range(3):
  99. stacked_fw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)) # 正向
  100. stacked_bw_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(num_units=hidden_size)) # 反向
  101.  
  102. # 动态rnn函数传入的是一个三维张量,[batch_size,n_steps,input_size] 输出也是这种形状,
  103. # input_size变成了正向和反向合并之后的 即input_size*2
  104. output, fw_state, bw_state = tf.contrib.rnn.stack_bidirectional_dynamic_rnn(stacked_fw_rnn,
  105. stacked_bw_rnn,
  106. inputs=input,
  107. dtype=tf.float32)
  108. print(type(output)) # <class 'tensorflow.python.framework.ops.Tensor'>
  109. print(output.shape) # (?, 28, 256)
  110.  
  111. output = tf.transpose(output, [1, 0, 2]) # 注意这里输出需要转置 转换为时序优先的
  112.  
  113. return output, fw_state, bw_state

然后我们定义神经网络框架

  1. def RNN_inference(inputs, class_num, time_steps, hidden_size):
  2. """
  3. :param inputs: [batch_size, n_steps, input_size]
  4. :param class_num: 类别数
  5. :param time_steps: 时序总数
  6. :param n_hidden: LSTM单元输出的节点个数 即隐藏层节点数
  7. """
  8. #######################################
  9. # 单层 静态/动态 LSTM/GRU #
  10. #######################################
  11. # outputs, states = single_layer_static_lstm(inputs, time_steps, hidden_size) # 单层静态LSTM
  12. # outputs, states = single_layer_static_gru(inputs, time_steps, hidden_size) # 单层静态gru
  13. # outputs, states = single_layer_dynamic_lstm(inputs, time_steps, hidden_size) # 单层动态LSTM
  14. # outputs, states = single_layer_dynamic_gru(inputs, time_steps, hidden_size) # 单层动态gru
  15. #######################################
  16. # 多层 静态/动态 LSTM/GRU #
  17. #######################################
  18. # outputs, states = multi_layer_static_lstm(inputs, time_steps, hidden_size) # 多层静态LSTM网络
  19. # outputs, states = multi_layer_static_gru(inputs, time_steps, hidden_size) # 多层静态GRU
  20. # outputs, states = multi_layer_static_mix(inputs, time_steps, hidden_size) # 多层静态GRU和LSTM 混合
  21. # outputs, states = multi_layer_dynamic_lstm(inputs, time_steps, hidden_size) # 多层动态LSTM
  22. # outputs, states = multi_layer_dynamic_gru(inputs, time_steps, hidden_size) # 多层动态GRU
  23. # outputs, states = multi_layer_dynamic_mix(inputs, time_steps, hidden_size) # 多层动态GRU和LSTM 混合
  24. #######################################
  25. # 单层/多层 双向 静态/动态 LSTM/GRU #
  26. #######################################
  27. # outputs, fw_state, bw_state = single_layer_static_bi_lstm(inputs, time_steps, hidden_size) # 单层静态双向LSTM
  28. # outputs, state = single_layer_dynamic_bi_lstm(inputs, time_steps, hidden_size) # 单层动态双向LSTM
  29. # outputs, fw_state, bw_state = multi_layer_static_bi_lstm(inputs, time_steps, hidden_size) # 多层静态双向LSTM
  30. outputs, fw_state, bw_state = multi_layer_dynamic_bi_lstm(inputs, time_steps, hidden_size) # 多层动态双向LSTM
  31.  
  32. # output静态是 time_step=28个(batch=128, output=128)组成的列表
  33. # output动态是 (time_step=28, batch=128, output=128)
  34. print('hidden:', outputs[-1].shape) # 最后一个时序的shape(128,128)
  35.  
  36. # 取LSTM最后一个时序的输出,然后经过全连接网络得到输出值
  37. fc_output = fc(input=outputs[-1], output_size=class_num, activeation_func=tf.nn.relu)
  38.  
  39. return fc_output

设置全局变量和超参数

  在模型训练之前我们首先会定义一些超参数:batch_size、batch_nums、class_num、epochs、learning_rate

  1. batch_size = FLAGS.batch_size
  2. batch_nums = mnist.train.images.shape[0] // batch_size # 一个epoch中应该包含多少batch数据
  3. class_num = FLAGS.class_num
  4. epochs = FLAGS.epochs
  5. learning_rate = FLAGS.learning_rate

保存检查点的地址

  1. ############ 保存检查点的地址 ############
  2. checkpoints_dir = FLAGS.checkpoints_dir # checkpoints
  3. # 如果检查点不存在,则创建
  4. if not os.path.exists(checkpoints_dir):
  5. os.makedirs(FLAGS.checkpoints_dir)

创建图

  这一步可以不设置,因为tensorflow有一个默认图,我们定义的操作都是在默认图上的,当然我们也可以定义自己的,方便管理。

  1. ######################################################
  2. # 创建图 #
  3. ######################################################
  4. graph = tf.Graph() # 自定义图
  5. # 在自己的图中定义数据和操作
  6. with graph.as_default():

占位符

  一般我们会把input和label做成placeholder,方便我们使用把不同的batch数据传入网络,一些其他的超参数也可以做成placeholder,比如learning_rate、dorpout_keep_prob。一般在搭建模型的时候把placeholder的变量传入模型,在训练模型sess.run(train_op, feed_dict)的时候通过参数feed_dict={input:真实数据,label:真实标签} 把真实的数据传入神经网络。

  1. inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
  2. labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
  3. # 看个人喜欢,有的人在初始化定义中就定义了learning_rate,有的人喜欢通过feed传learning_rate
  4. learning_rate = tf.placeholder("float", None, name='learning_rate')
  5. # 如果网络结构有dropout层,需要定义keep_probn,如果没有则不需要
  6. # 训练的时候需要,测试的时候需要设置成1
  7. keep_prob = tf.placeholder(dtype="float", name='keep_prob')

搭建模型

  传进入的都是placeholder数据,不是我们之前整理好的batch数据。

  1. ############ 搭建模型 ############
  2. logits = alexNet(inputs, class_num, keep_prob=keep_prob) # 使用placeholder搭建模型

构建损失

  分类任务一般输出的是每个类别的概率向量,因此模型输出最后都要经过softmax转换成概率。一般经过softmax的输出损失函数都是交叉熵损失函数,tensorflow有将以上两步合在一起的现成函数 tf.nn.softmax_cross_entropy_with_logits

  1. ############ 损失函数 ############
  2. loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
  3. tf.add_to_collection('losses', loss)
  4. total_loss = tf.add_n(tf.get_collection("loss")) # total_loss=模型损失+权重正则化损失

自定义损失

  以后更新,欢迎大家催我。

模型精度

  在测试数据集上的精度

  1. ############ 模型精度 ############
  2. predict = tf.argmax(logits, 1) # 模型预测结果
  3. accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, 1)), tf.float32))

自定义度量

  以后更新,欢迎大家催我。

优化器

  创建优化器,更新网络参数,最小化loss

  优化器的种类有很多种,但是用法都差不多,常用的优化器有:

  • tf.train.AdamOptimizer
  • tf.train.GradientDescentOptimizer

  • tf.train.RMSPropOptimizer

下面以Adam优化器为例

  1. ############ 优化器 ############
  2. variable_to_train = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES) # 可训练变量列表
  3. global_step = tf.Variable(0, trainable=False) # 训练step
  4. # 设置学习率衰减
  5. learning_rate = tf.train.exponential_decay(learning_rate=learning_rate, # 初始学习率
  6. global_step=global_step,
  7. decay_steps=batch_nums, # 多少步衰减一次
  8. decay_rate=0.1, # 衰减率
  9. staircase=True) # 以阶梯的形式衰减
  10. # 创建Adam优化器,更新模型参数,最小化损失函数
  11. train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss=total_loss,  # 损失函数
  12. global_step=global_step,
  13. var_list=variable_to_train)  # 通过训练需要更新的参数列表

讲解

  • variable_to_train:上面的代码定义了可训练变量,我只是把列出了模型默认的可训练变量,这一个步是tensorflow默认的,如果不设置也没有关系。我写出来的原因是,有的大牛会这么写,对不同的可训练变量分别进行不同的优化,希望大家看到我的代码,下次看到别人的不会觉得陌生。
  • global_step:大多数人会用step=0,然后在训练的时候step+=1的方式更新step,但是本文介绍的是另一种方式,以tf.Variable的方式定义step,在模型训练的时候传入sess.run,global_step会自动+1更新
  • learning_rate:本文还设置了学习率衰减,大家也可以不设置,以固定的学习率训练模型,但是对于大型项目,还是推荐设置。

移动平均值更新参数

采用移动平均值的方式更新损失值和模型参数

  1. def train(total_loss, global_step):
  2. lr = tf.train.exponential_decay(0.01, global_step, decay_steps=350, decay_rate=0.1, staircase=True)
  3. # 采用滑动平均的方法更新损失值
  4. loss_averages = tf.train.ExponentialMovingAverage(decay=0.9, name='avg')
  5. losses = tf.get_collection('losses') # losses的列表
  6. loss_averages_op = loss_averages.apply(losses + [total_loss]) # 计算损失值的影子变量op
  7.  
  8. # 计算梯度
  9. with tf.control_dependencies([loss_averages_op]): # 控制计算指定,只有执行了括号中的语句才能执行下面的语句
  10. opt = tf.train.GradientDescentOptimizer(lr) # 创建优化器
  11. grads = opt.compute_gradients(total_loss) # 计算梯度
  12.  
  13. # 应用梯度
  14. apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)
  15.  
  16. # 采用滑动平均的方法更新参数
  17. variable_averages = tf.train.ExponentialMovingAverage(0.999, num_updates=global_step)
  18. variables_averages_op = variable_averages.apply(tf.trainable_variables())
  19.  
  20. with tf.control_dependencies([apply_gradient_op, variables_averages_op]):
  21. # tf.no_op()表示执行完apply_gradient_op, variable_averages_op操作之后什么都不做
  22. train_op = tf.no_op(name='train')
  23.  
  24. return train_op

TensorBoard可视化 summary

  1. ############ TensorBoard可视化 summary ############
  2. summary_writer = tf.summary.FileWriter(logdir="./logs", graph=graph) # 创建事件文件
  3. tf.summary.scalar(name="losses", tensor=total_loss) # 收集损失值变量
  4. tf.summary.scalar(name="acc", tensor=accuracy) # 收集精度值变量
  5. tf.summary.scalar(name='learning_rate', tensor=learning_rate)
  6. merged_summary_op = tf.summary.merge_all() # 将所有的summary合并为一个op

模型保存和恢复 Saver

  1. saver = tf.train.Saver(max_to_keep=5)  # 保存最新的5个检查点

创建会话

配置会话

  在创建会话之前我们一般都要配置会话,比如使用GPU还是CPU,用多少GPU等等。

我们一般使用 tf.ConfigProto()配置Session运行参数&&GPU设备指定

  1. config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
  2. config.gpu_options.per_process_gpu_memory_fraction = 0.4 # 占用40%显存 sess = tf.Session(config=config)
  3. # 或者
  4. config = tf.ConfigProto()
  5. config.allow_soft_placement = True
  6. config.log_device_placement = True
  7.  
  8. with tf.Session(config=config) as sess:
  9. # 或者
  10. sess = tf.Session(config=config)

tf.ConfigProto(log_device_placement=True):记录设备指派情况

  设置tf.ConfigProto()中参数log_device_placement = True,获取 operations 和 Tensor 被指派到哪个设备(几号CPU或几号GPU)上运行,会在终端打印出各项操作是在哪个设备上运行的。

tf.ConfigProto(allow_soft_placement=True):自动选择运行设备

  在TensorFlow中,通过命令 "with tf.device('/cpu:0'):",允许手动设置操作运行的设备。如果手动设置的设备不存在或者不可用,就会导致tf程序等待或异常,为了防止这种情况,可以设置tf.ConfigProto()中参数allow_soft_placement=True,自动选择一个存在并且可用的设备来运行操作。

config.gpu_options.allow_growth = True

当使用GPU时候,Tensorflow运行自动慢慢达到最大GPU的内存

tf.test.is_built_with_cuda():返回是否能够使用GPU进行运算

  为了加快运行效率,TensorFlow在初始化时会尝试分配所有可用的GPU显存资源给自己,这在多人使用的服务器上工作就会导致GPU占用,别人无法使用GPU工作的情况。这时我们需要限制GPU资源使用,详细实现方法请参考我的另一篇博客 tensorflow常用函数 Ctrl+F搜索“限制GPU资源使用”

创建会话Session

  Session有两种创建方式:

  1. sess = tf.Session(config=config, graph=graph)
  2. # 或通过with的方式创建Session
  3. with tf.Session(config=config, graph=graph) as sess:

  如果我们之前自定义了graph,则在会话中也要配置graph,如果之前没有自定义graph,使用的是tensorflow默认graph,则在会话不用自己去定义,tensorflow会自动找到默认图。

  在训练模型之前我们首先要设置一个高级一点的东西,那就是检查是否有之前保存好的模型,如果有着接着前面的继续训练,如果没有则从头开始训练模型。

恢复/重新训练

  定义一个检查模型是否存在的函数,为了美观,可以把这个函数放在最上面,或者其他脚本中,通过import导入。

  1. def load_model(sess, saver, checkpoint_dir):
  2. """加载模型,看看还能不能加一个功能,必须现在的检查检点是1000,但是我的train是100,要报错
  3. 还有就是读取之前的模型继续训练的问题
  4. checkpoint_dir = checkpoint"""
  5.  
  6. # 通过checkpoint找到模型文件名
  7. ckpt = tf.train.get_checkpoint_state(checkpoint_dir=checkpoint_dir)
  8. if ckpt and ckpt.model_checkpoint_path:
  9. ckpt_name = os.path.basename(ckpt.model_checkpoint_path) # 返回最新的chechpoint文件名 model.ckpt-1000
  10. print("新的chechpoint文件名", ckpt_name) # model.ckpt-2
  11. saver.restore(sess, os.path.join(checkpoint_dir, ckpt_name))
  12. # 现在不知道checkpoint文件名时怎样的,因此不知道里面如何运行
  13. counter = int(next(re.finditer("(\d+)(?!.*\d)", ckpt_name)).group(0)) #
  14. print(" [*] 成功模型 {}".format(ckpt_name))
  15. return True, counter
  16. else:
  17. print(" [*] 找不到checkpoint")
  18. return False, 0

  如果大家之前用的是global_step = tf.Variable(0, trainable=False),则使用下面diamante

  1. # 加载模型,如果模型存在返回 是否加载成功和训练步数
  2. could_load, checkpoint_step = load_model(sess, saver, "./log")
  3. if could_load:
  4. print(" [*] 加载成功")
  5. else:
  6. print(" [!] 加载失败")
  7. try:
  8. tf.global_variables_initializer().run()
  9. except:
  10. tf.initialize_all_variables().run()

  如果大家想使用step=0,step+=1,则可以使用下面代码

  1. # 加载模型,如果模型存在返回 是否加载成功和训练步数
  2. could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
  3. if could_load:
  4. step = checkpoint_step
  5. print(" [*] 模型加载成功")
  6. else:
  7. print(" [!] 模型加载失败")
  8. try:
  9. tf.global_variables_initializer().run()
  10. except:
  11. tf.initialize_all_variables().run()
  12. step = 0

开始训练

  1. for epoch in range(epochs):
  2. for i in range(batch_nums):
  3. start_time = time.time()
  4. # batch_images = data_X[i * batch_size:(i + 1) * batch_size]
  5. # batch_labels = data_y[i * batch_size:(i + 1) * batch_size]
  6. train_batch_x, train_batch_y = mnist.train.next_batch(batch_size)
  7.  
  8. # 使用真实数据填充placeholder,运行训练模型和合并变量操作
  9. _, summary, loss, step = sess.run([train_op, merged_summary_op, total_loss, global_step],
  10. feed_dict={inputs: train_batch_x,
  11. labels: train_batch_y,
  12. keep_prob: 0.5})
  13. if step % 100 == 0:
  14. summary_writer.add_summary(summary, step) # 将每次迭代后的变量写入事件文件
  15. summary_writer.flush() # 强制summary_writer将缓存中的数据写入到日志文件中(可选)
  16.  
  17. ############ 可视化打印 ############
  18. print("Epoch:[%2d] [%4d/%4d] time:%4.4f,loss:%.8f" % (
  19. epoch, i, batch_nums, time.time() - start_time, loss))
  20.  
  21. # 打印一些可视化的数据,损失...
  22. if step % 100 == 0:
  23. acc = sess.run(accuracy, feed_dict={inputs: mnist.validation.images,
  24. labels: mnist.validation.labels,
  25. keep_prob: 1.0})
  26. print("Epoch:[%2d] [%4d/%4d] accuracy:%.8f" % (epoch, i, batch_nums, acc))
  27. ############ 保存模型 ############
  28. if acc > max_acc:
  29. max_acc = acc
  30. save_path = saver.save(sess,
  31. save_path=os.path.join(checkpoints_dir, "model.ckpt"),
  32. global_step=step)
  33. tf.logging.info("模型保存在: %s" % save_path)
  34. print("优化完成!")

模型评估

eval.py

模型评估的代码和模型训练的代码很像,只不过不需要对模型进行训练而已。

  1. from ops import *
  2. import tensorflow as tf
  3. from nets.my_alex import alexNet
  4. from tensorflow.examples.tutorials.mnist import input_data
  5.  
  6. tf.flags.DEFINE_integer('batch_size', 50, 'batch size, default: 1')
  7. tf.flags.DEFINE_integer('class_num', 10, 'batch size, default: 1')
  8. tf.flags.DEFINE_integer('epochs', 10, 'batch size, default: 1')
  9. tf.flags.DEFINE_string('checkpoints_dir', "checkpoints", '保存检查点的地址')
  10. FLAGS = tf.flags.FLAGS
  11.  
  12. # 从MNIST_data/中读取MNIST数据。当数据不存在时,会自动执行下载
  13. mnist = input_data.read_data_sets('./data', one_hot=True, reshape=False)
  14.  
  15. # 将数组张换成图片形式
  16. print(mnist.train.images.shape) # 训练数据图片(55000, 28, 28, 1)
  17. print(mnist.train.labels.shape) # 训练数据标签(55000, 10)
  18. print(mnist.test.images.shape) # 测试数据图片(10000, 28, 28, 1)
  19. print(mnist.test.labels.shape) # 测试数据图片(10000, 10)
  20. print(mnist.validation.images.shape) # 验证数据图片(5000, 28, 28, 1)
  21. print(mnist.validation.labels.shape) # 验证数据图片(5000, 10)
  22.  
  23. def evaluate():
  24. batch_size = FLAGS.batch_size
  25. batch_nums = mnist.train.images.shape[0] // batch_size # 一个epoch中应该包含多少batch数据
  26. class_num = FLAGS.class_num
  27. test_batch_size = 5000
  28. test_batch_num = mnist.test.images.shape[0] // test_batch_size
  29.  
  30. ############ 保存检查点的地址 ############
  31. checkpoints_dir = FLAGS.checkpoints_dir # checkpoints
  32. # 如果检查点不存在,则创建
  33. if not os.path.exists(checkpoints_dir):
  34. print("模型文件不存在,无法进行评估")
  35.  
  36. ######################################################
  37. # 创建图 #
  38. ######################################################
  39. graph = tf.Graph() # 自定义图
  40. # 在自己的图中定义数据和操作
  41. with graph.as_default():
  42. inputs = tf.placeholder(dtype="float", shape=[None, 28, 28, 1], name='inputs')
  43. labels = tf.placeholder(dtype="float", shape=[None, class_num], name='labels')
  44. ############ 搭建模型 ############
  45. logits = alexNet(inputs, FLAGS.class_num, keep_prob=1) # 使用placeholder搭建模型
  46. ############ 模型精度 ############
  47. predict = tf.argmax(logits, 1)
  48. accuracy = tf.reduce_mean(tf.cast(tf.equal(predict, tf.argmax(labels, 1)), tf.float32))
  49. ############ 模型保存和恢复 Saver ############
  50. saver = tf.train.Saver(max_to_keep=5)
  51.  
  52. ######################################################
  53. # 创建会话 #
  54. ######################################################
  55. config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
  56. with tf.Session(config=config, graph=graph) as sess:
  57. # 加载模型,如果模型存在返回 是否加载成功和训练步数
  58. could_load, checkpoint_step = load_model(sess, saver, FLAGS.checkpoints_dir)
  59. if could_load:
  60. print(" [*] 加载成功")
  61. else:
  62. print(" [!] 加载失败")
  63. raise ValueError("模型文件不存在,无法进行评估")
  64.  
  65. for i in range(test_batch_num):
  66. test_batch_x, test_batch_y = mnist.test.next_batch(test_batch_num)
  67. acc = sess.run(accuracy, feed_dict={inputs: test_batch_x,
  68. labels: test_batch_y})
  69. print("模型精度为:", acc)
  70. one_image = mnist.test.images[1].reshape(1, 28, 28, 1)
  71. predict_label = sess.run(predict, feed_dict={inputs: one_image})
  72. # print("123", tf.argmax(pre_yyy, 1).eval()) # [7]
  73. # print("123", tf.argmax(yyy, 1).eval()) # 7
  74.  
  75. def main(argv=None):
  76. evaluate()
  77.  
  78. if __name__ == '__main__':
  79. tf.app.run()

参考文献

CSDN_AlexNet神经网络结构

CSDN_【深度学习理论3】ALexNet模型的详解

github搜索tensorflow AlexNet

github_finetune_alexnet_with_tensorflow

github_AlexNet_with_tensorflow

github tensorflow vgg

ResNet详解与分析

tensorflow中使用tf.ConfigProto()配置Session运行参数&&GPU设备指定

用TensorFlow搭建一个万能的神经网络框架(持续更新)的更多相关文章

  1. 基于tensorflow搭建一个神经网络

    一,tensorflow的简介 Tensorflow是一个采用数据流图,用于数值计算的 开源软件库.节点在图中表示数字操作,图中的线 则表示在节点间相互联系的多维数据数组,即张量 它灵活的架构让你可以 ...

  2. iOS之github第三方框架(持续更新)

    1.MBProgressHUD MBProgressHUD是一个开源项目,实现了很多种样式的提示框 使用上简单.方便,并且可以对显示的内容进行自定义,功能很强大,很多项目中都有使用到. 到Github ...

  3. python日记:用pytorch搭建一个简单的神经网络

    最近在学习pytorch框架,给大家分享一个最最最最基本的用pytorch搭建神经网络并且训练的方法.本人是第一次写这种分享文章,希望对初学pytorch的朋友有所帮助! 一.任务 首先说下我们要搭建 ...

  4. Selenium+java - 手把手一起搭建一个最简单自动化测试框架

    写在前面 我们刚开始做自动化测试,可能写的代码都是基于原生写的代码,看起来特别不美观,而且感觉特别生硬. 来看下面一段代码,如下图所示: 从上面图片代码来看,具体特征如下: driver对象在测试类中 ...

  5. 搭建一个简单的mybatis框架

    一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以 ...

  6. 搭建一个简单的Struts2框架

    1  创建一个web项目. 2 导入必要的JAR文件. 放在WEB-INF下lib包里. 3 添加web.xml配置,添加启动配置. <?xml version="1.0" ...

  7. iOS 10中如何搭建一个语音转文字框架

    在2016WWDC大会上,Apple公司介绍了一个很好的语音识别的API,那就是Speech framework.事实上,这个Speech Kit就是Siri用来做语音识别的框架.如今已经有一些可用的 ...

  8. JDBC 学习笔记(十)—— 使用 JDBC 搭建一个简易的 ORM 框架

    1. 数据映射 当我们获取到 ResultSet 之后,显然这个不是我们想要的数据结构. 数据库中的每一个表,在 Java 代码中,一定会有一个类与之对应,例如: package com.gerrar ...

  9. Flutter学习三之搭建一个简单的项目框架

    上一篇文章介绍了Dart的语法的基本使用,从这篇文章开始,开发一个基于玩Android网站的app.使用的他们开放的api来获取网站数据. 根据网站的结构,我们app最外层框架需要添加一个底部导航栏, ...

随机推荐

  1. jQuery中的查找节点、创建节点、插入节点、删除节点、替换节点、复制节点操作方法

    jQuery操作节点我们可以分六点来讲,查找节点.创建节点.插入节点.删除节点.替换节点.复制节点. 一.查找节点 text() - 设置或返回所选元素的文本内容   ,html() - 设置或返回所 ...

  2. VSCode最强助攻

    VSCode最强助攻 VS Code是前端界必备的开发工具.页面仔小杨简单介绍几款高效.好用的插件,让原本单薄的VS Code如虎添翼,开发效率倍增. vscode-icons vscode-icon ...

  3. Spring官网阅读 | 总结篇

    接近用了4个多月的时间,完成了整个<Spring官网阅读>系列的文章,本文主要对本系列所有的文章做一个总结,同时也将所有的目录汇总成一篇文章方便各位读者来阅读. 下面这张图是我整个的写作大 ...

  4. vue-cli中浏览器图标的配置

    在VUE全家桶项目里面,这里给大家提供了2种方案,进行浏览器图标的配置. a):先把图片准备好,放在static文件夹下,再找到根目录下的index.html文件,并打开,在HTML文档的<he ...

  5. What?废柴, 模拟登陆,代码控制滑动验证真的很难吗?Are you kidding???

    1.简介 在前边的python接口自动化的时候,我们由于博客园的登录机制的改变,没有用博客园的登录测试接口.那么博客园现在变成了滑动验证登录,而且现在绝大多数的登录都变成这种滑动验证和验证码的登录验证 ...

  6. XSS挑战之旅(通过看代码解题)

    XSS 挑战之旅 level 1 没有什么过滤 payload: <script>alert(1)</script> level 2 php关键代码: echo "& ...

  7. zabbix server优化与迁移

    zabbix server优化与迁移 1. 概述 zabbix 系统其实分3个大部分,一个是server本身,另一个是php的httpd服务,第三个是非常需要优化的数据库.公司的zabbix监控主机在 ...

  8. vue中mixins的使用方法和注意点(详2)(异步请求的情况)

    当混合里面包含异步请求函数,而我们又需要在组件中使用异步请求函数的返回值时,我们会取不到此返回值,如下: mixin中 组件中 控制台 解决方案:不要返回结果而是直接返回异步函数 mixin中 组件中 ...

  9. Apache自定义404

    先用命令找到httpd.conf文件在哪 find -name 'httpd.conf' 默认配置文件: vim /etc/httpd/conf/httpd.conf 然后找到项目的路径 <Di ...

  10. MySQL表的CRUD及多表查询

    数据库表的增删改查操作: 增.删.改 查: 单表查询 简单查询.where约束.group by分组.聚合查询.having过滤.order by排序.limit限制.正则匹配 多表查询 连表查询:交 ...