东方耀AI技术分享

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 4030|回复: 4
打印 上一主题 下一主题

[课堂笔记] 50、经典CNN网络LeNet实战:手写数字识别(分类)_笔记

[复制链接]

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14432
QQ
跳转到指定楼层
楼主
发表于 2019-1-9 20:50:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式


50、经典CNN网络LeNet实战:手写数字识别(分类)_笔记

第一步:导入数据# 手写数字识别的数据集主要包含三个部分:训练集(5.5w, mnist.train)、测试集(1w, mnist.test)、验证集(0.5w, mnist.validation)
# 手写数字图片大小是28*28*1像素的图片(黑白),也就是每个图片由784维的特征描述

第二步:设置超参并定义学习率调整策略
  1. def learn_rate_func(epoch):
  2.     """
  3.     根据给定的迭代批次,更新产生一个学习率的值 均匀分布策略
  4.     :param epoch:
  5.     :return:
  6.     """
  7.     return max(0.001, learn_rate_base * (0.9 ** int(epoch / 10)))

  8. # learn_rate = tf.train.exponential_decay() tf自带的学习率的
复制代码

第三步:开始构建模型 设置输入数据的占位符
第四步:构建LeNet网络(直接将网络结构翻译成为这个代码

  1. # 卷积
  2.         # conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC", name=None) => 卷积的API
  3.         # data_format: 表示的是输入的数据格式,两种:NHWC和NCHW,N=>样本数目,H=>Height, W=>Weight, C=>Channels
  4.         # use_cudnn_on_gpu:设置GPU加速
  5.         # name:设置操作的名字 与tf一样
  6.         # input:输入数据,必须是一个4维格式的图像数据,具体格式和data_format有关,如果data_format是NHWC的时候,input的格式为: [batch_size, height, width, channels] => [批次中的图片数目,图片的高度,图片的宽度,图片的通道数];如果data_format是NCHW的时候,input的格式为: [batch_size, channels, height, width] => [批次中的图片数目,图片的通道数,图片的高度,图片的宽度]
  7.         # filter: 卷积核或过滤器,是一个4维格式的数据,shape: [height, width, in_channels, out_channels] => [窗口的高度,窗口的宽度,输入的channel通道数(上一层图片的深度),输出的通道数(卷积核数目或深度,到底是几组w和b)]
  8.         # strides:步长,是一个4维的数据,每一维数据必须和data_format格式匹配,表示的是在data_format每一维上的移动步长,当格式为NHWC的时候,strides的格式为: [batch, in_height, in_width, in_channels] => [样本上的移动大小,高度的移动大小,宽度的移动大小,深度的移动大小],API要求在样本上和在深度通道上的移动必须是1;当格式为NCHW的时候,strides的格式为: [batch,in_channels, in_height, in_width]
  9.         # padding: 只支持两个参数"SAME", "VALID",当取值为SAME的时候,表示进行填充,"有个特例(特别强调):在TensorFlow中,如果步长为1,并且padding为SAME的时候,经过卷积之后的图像大小是不变的";当VALID的时候,表示多余的特征会丢弃;
  10.         w = get_variable('w', [5, 5, 1, 20])
复制代码

第五步:构建模型的损失函数
第六步:构建梯度下降的优化方法(一般用Adam 动量GD)
第七步:计算模型正确率
第八步:会话中执行阶段(模型的训练与迭代)



  1. # -*- coding: utf-8 -*-
  2. __author__ = 'dongfangyao'
  3. __date__ = '2019/1/9 下午9:05'
  4. __product__ = 'PyCharm'
  5. __filename__ = 'tf27'


  6. # 手写数字的图片数据 LeNet

  7. import tensorflow as tf
  8. from tensorflow.examples.tutorials.mnist import input_data

  9. # 手写数字的图片 数据
  10. mnist = input_data.read_data_sets('data/lenet', one_hot=True)
  11. # 55000
  12. print(mnist.train.num_examples)
  13. # (55000, 784)
  14. print(mnist.train.images.shape)
  15. # (55000, 10)
  16. print(mnist.train.labels.shape)
  17. # 7
  18. print(mnist.train.labels[0])

  19. print('测试集shape:{}'.format(mnist.test.images.shape))
  20. print('验证集shape:{}'.format(mnist.validation.images.shape))

  21. # 784 = 28*28*1 黑白
  22. train_img = mnist.train.images
  23. train_label = mnist.train.labels

  24. test_img = mnist.test.images
  25. test_label = mnist.test.labels

  26. train_sample_number = mnist.train.num_examples

  27. # 设置超参
  28. learn_rate_base = 0.1
  29. batch_size = 64
  30. display_step = 1

  31. input_dim = train_img.shape[1]
  32. n_classes = train_label.shape[1]

  33. # 1、设置占位符
  34. x = tf.placeholder(tf.float32, shape=[None, input_dim], name='x')
  35. y = tf.placeholder(tf.float32, shape=[None, n_classes], name='y')
  36. learn_rate = tf.placeholder(tf.float32, name='learn_rate')


  37. def learn_rate_func(epoch):
  38.     return max(0.001, learn_rate_base * (0.9 ** int(epoch / 10)))


  39. def get_variable(name, shape=None, dtype=tf.float32, initializer=tf.random_normal_initializer(mean=0, stddev=0.1)):
  40.     return tf.get_variable(name, shape, dtype, initializer)


  41. # 2、构建网络 预测值
  42. def le_net(x, y):
  43.     # 1、输入层
  44.     with tf.variable_scope('input1'):
  45.         # [None, input_dim] --> [None, height, width, channels]
  46.         net = tf.reshape(x, shape=[-1, 28, 28, 1])
  47.     # 2、conv+relu
  48.     with tf.variable_scope('conv2'):
  49.         w = get_variable(name='w', shape=[5, 5, 1, 20])
  50.         # data_format NHWC NCHW
  51.         # conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC", name=None):
  52.         net = tf.nn.conv2d(input=net, filter=w, strides=[1, 1, 1, 1], padding='SAME', data_format='NHWC')
  53.         net = tf.nn.bias_add(net, get_variable('b', shape=[20]))
  54.         print('conv2之后的shape:{}'.format(net.shape))
  55.         net = tf.nn.relu(net)
  56.     # 3、pool
  57.     with tf.variable_scope('pool3'):
  58.         net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', data_format='NHWC')
  59.         print('pool3之后的shape:{}'.format(net.shape))
  60.     # 4、conv
  61.     with tf.variable_scope('conv4'):
  62.         net = tf.nn.conv2d(input=net, filter=get_variable(name='w', shape=[5, 5, 20, 50]), strides=[1, 1, 1, 1], padding='SAME', data_format='NHWC')
  63.         net = tf.nn.bias_add(net, get_variable('b', shape=[50]))
  64.         print('conv4之后的shape:{}'.format(net.shape))
  65.         net = tf.nn.relu(net)
  66.     # 5、pool
  67.     with tf.variable_scope('pool5'):
  68.         net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME', data_format='NHWC')
  69.         print('pool5之后的shape:{}'.format(net.shape))
  70.     # 6、fc
  71.     with tf.variable_scope('fc6'):
  72.         # 28 -> 14 --> 7
  73.         size = 7*7*50
  74.         net = tf.reshape(net, shape=[-1, size])
  75.         net = tf.add(tf.matmul(net, get_variable('w', shape=[size, 500])), get_variable('b', shape=[500]))
  76.         print('fc6之后的shape:{}'.format(net.shape))
  77.         net = tf.nn.relu(net)
  78.     # 7 fc
  79.     with tf.variable_scope('fc7'):
  80.         net = tf.add(tf.matmul(net, get_variable('w', shape=[500, n_classes])), get_variable('b', shape=[n_classes]))
  81.         print('fc7之后的shape:{}'.format(net.shape))

  82.     return net


  83. act = le_net(x, y)

  84. # 模型的损失函数
  85. cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=act, labels=y))

  86. # train = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)
  87. train = tf.train.AdadeltaOptimizer(learning_rate=learn_rate).minimize(cost)

  88. pred = tf.equal(tf.argmax(act, axis=1), tf.argmax(y, axis=1))
  89. acc = tf.reduce_mean(tf.cast(pred, dtype=tf.float32))

  90. init_op = tf.global_variables_initializer()

  91. with tf.Session() as sess:
  92.     sess.run(init_op)

  93.     saver = tf.train.Saver()
  94.     epoch = 0
  95.     while True:
  96.         avg_cost = 0
  97.         total_batch = int(train_sample_number / batch_size)
  98.         for i in range(total_batch):
  99.             batch_xs, batch_ys = mnist.train.next_batch(batch_size)
  100.             feeds = {x: batch_xs, y: batch_ys, learn_rate: learn_rate_func(epoch)}
  101.             sess.run(train, feed_dict=feeds)
  102.             avg_cost += sess.run(cost, feed_dict=feeds)

  103.         avg_cost = avg_cost / total_batch

  104.         if (epoch + 1) % display_step == 0:
  105.             print('批次: %03d 损失函数值:%.9f' % (epoch, avg_cost))
  106.             train_acc = sess.run(acc, feed_dict={x: mnist.train.images[:1000], y: mnist.train.labels[:1000], learn_rate: learn_rate_func(epoch)})
  107.             print('训练集的准确率:%0.3f' % train_acc)
  108.             test_acc = sess.run(acc, feed_dict={x: mnist.test.images[:1000], y: mnist.test.labels[:1000], learn_rate: learn_rate_func(epoch)})
  109.             print('测试集的准确率:%0.3f' % test_acc)

  110.             if train_acc > 0.99 and test_acc > 0.98:
  111.                 saver.save(sess, './data/lenet/model_{}_{}'.format(train_acc, test_acc), global_step=epoch)
  112.                 break
  113.         epoch += 1
  114.     writer = tf.summary.FileWriter('./data/lenet/graph', tf.get_default_graph())
  115.     writer.close()

  116. print('end....')
复制代码
  1. # -*- coding: utf-8 -*-
  2. __author__ = 'dongfangyao'
  3. __date__ = '2019/1/9 下午9:05'
  4. __product__ = 'PyCharm'
  5. __filename__ = 'tf27_注释完整版'
  6. """
  7. 手写数字识别的CNN网络 LeNet
  8. 注意:一般情况下,我们都是直接将网络结构翻译成为这个代码,最多稍微的修改一下网络中的参数(超参数、窗口大小、步长等信息)
  9. https://js.tensorflow.org/
  10. https://js.tensorflow.org/#getting-started

  11. """

  12. import tensorflow as tf
  13. from tensorflow.examples.tutorials.mnist import input_data

  14. # 设置一个随机数种子
  15. tf.set_random_seed(28)

  16. # 数据加载
  17. mnist = input_data.read_data_sets('data/lenet', one_hot=True)
  18. # 样本数 55000
  19. print(mnist.train.num_examples)
  20. # images 特征矩阵 784个特征属性
  21. print(mnist.train.images.shape)
  22. # labels 目标属性10个 刚好是10个数字 进行了哑编码
  23. print(mnist.train.labels.shape)

  24. print('测试集shape:{}'.format(mnist.test.images.shape))
  25. print('验证集shape:{}'.format(mnist.validation.images.shape))

  26. # 手写数字识别的数据集主要包含三个部分:训练集(5.5w, mnist.train)、测试集(1w, mnist.test)、验证集(0.5w, mnist.validation)
  27. # 手写数字图片大小是28*28*1像素的图片(黑白),也就是每个图片由784维的特征描述
  28. train_img = mnist.train.images
  29. train_label = mnist.train.labels
  30. test_img = mnist.test.images
  31. test_label = mnist.test.labels

  32. train_sample_number = mnist.train.num_examples

  33. # 相关的参数、超参数的设置
  34. # 学习率,一般学习率设置的比较小
  35. learn_rate_base = 0.1
  36. # 每次迭代的训练样本数量
  37. batch_size = 64
  38. # 展示信息的间隔大小
  39. display_step = 1

  40. # 输入的样本维度大小信息
  41. input_dim = train_img.shape[1]
  42. # 输出的维度大小信息
  43. n_classes = train_label.shape[1]

  44. # 模型构建
  45. # 1. 设置数据输入的占位符
  46. x = tf.placeholder(tf.float32, shape=[None, input_dim], name='x')
  47. y = tf.placeholder(tf.float32, shape=[None, n_classes], name='y')
  48. learn_rate = tf.placeholder(tf.float32, name='learn_rate')


  49. def learn_rate_func(epoch):
  50.     """
  51.     根据给定的迭代批次,更新产生一个学习率的值 均匀分布策略
  52.     :param epoch:
  53.     :return:
  54.     """
  55.     return max(0.001, learn_rate_base * (0.9 ** int(epoch / 10)))

  56. # learn_rate = tf.train.exponential_decay() tf自带的学习率的


  57. def get_variable(name, shape=None, dtype=tf.float32, initializer=tf.random_normal_initializer(mean=0, stddev=0.1)):
  58.     """
  59.     返回一个对应的变量
  60.     :param name:
  61.     :param shape:
  62.     :param dtype:
  63.     :param initializer:
  64.     :return:
  65.     """
  66.     return tf.get_variable(name, shape, dtype, initializer)


  67. # 2. 构建网络
  68. def le_net(x, y):
  69.     # 1. 输入层
  70.     with tf.variable_scope('input1'):
  71.         # 将输入的x的格式转换为规定的格式
  72.         # [None, input_dim] -> [None, height, width, channels]
  73.         net = tf.reshape(x, shape=[-1, 28, 28, 1])
  74.     # 2. 卷积层
  75.     with tf.variable_scope('conv2'):
  76.         # 卷积
  77.         # conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC", name=None) => 卷积的API
  78.         # data_format: 表示的是输入的数据格式,两种:NHWC和NCHW,N=>样本数目,H=>Height, W=>Weight, C=>Channels
  79.         # use_cudnn_on_gpu:设置GPU加速
  80.         # name:设置操作的名字 与tf一样
  81.         # input:输入数据,必须是一个4维格式的图像数据,具体格式和data_format有关,如果data_format是NHWC的时候,input的格式为: [batch_size, height, width, channels] => [批次中的图片数目,图片的高度,图片的宽度,图片的通道数];如果data_format是NCHW的时候,input的格式为: [batch_size, channels, height, width] => [批次中的图片数目,图片的通道数,图片的高度,图片的宽度]
  82.         # filter: 卷积核或过滤器,是一个4维格式的数据,shape: [height, width, in_channels, out_channels] => [窗口的高度,窗口的宽度,输入的channel通道数(上一层图片的深度),输出的通道数(卷积核数目或深度,到底是几组w和b)]
  83.         # strides:步长,是一个4维的数据,每一维数据必须和data_format格式匹配,表示的是在data_format每一维上的移动步长,当格式为NHWC的时候,strides的格式为: [batch, in_height, in_width, in_channels] => [样本上的移动大小,高度的移动大小,宽度的移动大小,深度的移动大小],API要求在样本上和在深度通道上的移动必须是1;当格式为NCHW的时候,strides的格式为: [batch,in_channels, in_height, in_width]
  84.         # padding: 只支持两个参数"SAME", "VALID",当取值为SAME的时候,表示进行填充,"有个特例(特别强调):在TensorFlow中,如果步长为1,并且padding为SAME的时候,经过卷积之后的图像大小是不变的";当VALID的时候,表示多余的特征会丢弃;
  85.         w = get_variable('w', [5, 5, 1, 20])
  86.         net = tf.nn.conv2d(input=net, filter=w, strides=[1, 1, 1, 1], padding='SAME')
  87.         net = tf.nn.bias_add(net, get_variable('b', [20]))
  88.         print('conv2之后的shape:{}'.format(net.shape))
  89.         # 激励 ReLu
  90.         # tf.nn.relu => max(fetures, 0)
  91.         # tf.nn.relu6 => min(max(fetures,0), 6)
  92.         net = tf.nn.relu(net)
  93.     # 3. 池化
  94.     with tf.variable_scope('pool3'):
  95.         # 和conv2一样,需要给定窗口大小和步长
  96.         # max_pool(value, ksize, strides, padding, data_format="NHWC", name=None)
  97.         # avg_pool(value, ksize, strides, padding, data_format="NHWC", name=None)
  98.         # 默认格式下:NHWC,value:输入的数据,必须是[batch_size, height, width, channels]格式
  99.         # 默认格式下:NHWC,ksize:指定窗口大小,必须是[batch, in_height, in_width, in_channels], 其中batch和in_channels必须为1
  100.         # 默认格式下:NHWC,strides:指定步长大小,必须是[batch, in_height, in_weight, in_channels],其中batch和in_channels必须为1
  101.         # padding: 只支持两个参数"SAME", "VALID",当取值为SAME的时候,表示进行填充,;当VALID的时候,表示多余的特征会丢弃;
  102.         net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
  103.         print('pool3之后的shape:{}'.format(net.shape))
  104.     # 4. 卷积
  105.     with tf.variable_scope('conv4'):
  106.         net = tf.nn.conv2d(input=net, filter=get_variable('w', [5, 5, 20, 50]), strides=[1, 1, 1, 1], padding='SAME')
  107.         net = tf.nn.bias_add(net, get_variable('b', [50]))
  108.         print('conv4之后的shape:{}'.format(net.shape))
  109.         net = tf.nn.relu(net)
  110.     # 5. 池化
  111.     with tf.variable_scope('pool5'):
  112.         net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
  113.         print('pool5之后的shape:{}'.format(net.shape))
  114.     # 6. 全连接
  115.     with tf.variable_scope('fc6'):
  116.         # 28 -> 14 -> 7(因为此时的卷积不改变图片的大小,只有池化会改变)
  117.         size = 7 * 7 * 50
  118.         net = tf.reshape(net, shape=[-1, size])
  119.         net = tf.add(tf.matmul(net, get_variable('w', [size, 500])), get_variable('b', [500]))
  120.         print('fc6之后的shape:{}'.format(net.shape))
  121.         net = tf.nn.relu(net)
  122.     # 7. 全连接
  123.     with tf.variable_scope('fc7'):
  124.         net = tf.add(tf.matmul(net, get_variable('w', [500, n_classes])), get_variable('b', [n_classes]))
  125.         print('fc7之后的shape:{}'.format(net.shape))

  126.     return net


  127. # 构建网络
  128. act = le_net(x, y)

  129. # 构建模型的损失函数
  130. # softmax_cross_entropy_with_logits: 计算softmax中的每个样本的交叉熵,logits指定预测值,labels指定实际值
  131. cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=act, labels=y))

  132. # 使用Adam优化方式比较多 动量GD
  133. # learning_rate: 要注意,不要过大,过大可能不收敛,也不要过小,过小收敛速度比较慢
  134. train = tf.train.AdadeltaOptimizer(learning_rate=learn_rate).minimize(cost)
  135. # train = tf.train.AdamOptimizer(learning_rate=learn_rate).minimize(cost)


  136. # 得到预测的类别是那一个
  137. # tf.argmax:对矩阵按行或列计算最大值对应的下标,和numpy中的一样
  138. # tf.equal:是对比这两个矩阵或者向量的相等的元素,如果是相等的那就返回True,反正返回False,返回的值的矩阵维度和A是一样的
  139. pred = tf.equal(tf.argmax(act, axis=1), tf.argmax(y, axis=1))
  140. # 正确率(True转换为1,False转换为0)
  141. acc = tf.reduce_mean(tf.cast(pred, tf.float32))

  142. # 初始化
  143. init = tf.global_variables_initializer()

  144. with tf.Session() as sess:
  145.     # 进行数据初始化
  146.     sess.run(init)

  147.     # 模型保存、持久化
  148.     saver = tf.train.Saver()
  149.     epoch = 0
  150.     while True:
  151.         avg_cost = 0
  152.         # 计算出总的批次
  153.         total_batch = int(train_sample_number / batch_size)
  154.         # 迭代更新
  155.         for i in range(total_batch):
  156.             # 获取x和y
  157.             batch_xs, batch_ys = mnist.train.next_batch(batch_size)
  158.             feeds = {x: batch_xs, y: batch_ys, learn_rate: learn_rate_func(epoch)}
  159.             # 模型训练
  160.             sess.run(train, feed_dict=feeds)
  161.             # 获取损失函数值
  162.             avg_cost += sess.run(cost, feed_dict=feeds)

  163.         # 重新计算平均损失(相当于计算每个样本的损失值)
  164.         avg_cost = avg_cost / total_batch

  165.         # DISPLAY  显示误差率和训练集的正确率以此测试集的正确率
  166.         if (epoch + 1) % display_step == 0:
  167.             print("批次: %03d 损失函数值: %.9f" % (epoch, avg_cost))
  168.             # 这里之所以使用train_img[:1000]和train_label[:1000],是因为我使用train_img会出现内存不够的情况,直接就会退出
  169.             feeds = {x: train_img[:1000], y: train_label[:1000], learn_rate: learn_rate_func(epoch)}
  170.             train_acc = sess.run(acc, feed_dict=feeds)
  171.             print("训练集准确率: %.3f" % train_acc)
  172.             feeds = {x: test_img[:1000], y: test_label[:1000], learn_rate: learn_rate_func(epoch)}
  173.             test_acc = sess.run(acc, feed_dict=feeds)
  174.             print("测试准确率: %.3f" % test_acc)

  175.             if train_acc >= 0.99 and test_acc >= 0.98:
  176.                 saver.save(sess, './data/lenet/model_{}_{}'.format(train_acc, test_acc), global_step=epoch)
  177.                 break
  178.         epoch += 1

  179.     # 模型可视化输出
  180.     writer = tf.summary.FileWriter('./data/lenet/graph', tf.get_default_graph())
  181.     writer.close()

  182. print("end....")
复制代码




LeNet实战1.png (429.99 KB, 下载次数: 221)

LeNet实战1.png

LeNet实战2.png (184.94 KB, 下载次数: 228)

LeNet实战2.png

画板 1.png (957.58 KB, 下载次数: 224)

画板 1.png

画板 2.png (1.32 MB, 下载次数: 219)

画板 2.png
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

0

主题

87

帖子

230

积分

人工智能VIP

Rank: 9Rank: 9Rank: 9

积分
230
沙发
发表于 2019-1-10 09:59:02 | 只看该作者
挺厉害的蛤
回复

使用道具 举报

0

主题

87

帖子

230

积分

人工智能VIP

Rank: 9Rank: 9Rank: 9

积分
230
板凳
发表于 2019-1-10 09:59:29 | 只看该作者
挺厉害的蛤
回复

使用道具 举报

0

主题

12

帖子

46

积分

新手上路

Rank: 1

积分
46
地板
发表于 2020-3-17 10:20:30 | 只看该作者

好样的66666666666
回复

使用道具 举报

0

主题

18

帖子

56

积分

注册会员

Rank: 2

积分
56
5#
发表于 2020-6-1 21:54:34 | 只看该作者
学习一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|人工智能工程师的摇篮 ( 湘ICP备2020019608号-1 )

GMT+8, 2024-4-26 10:59 , Processed in 0.192912 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表