|
51、经典CNN网络VGGNet比赛:17种花的图片识别_笔记
如果报错:OOM when allocating tensor with shape
If you want to see a list of allocated tensors when OOM happens
tensorflow.python.framework.errors_impl.ResourceExhaustedError: OOM when allocating tensor with shape
errors_impl.ResourceExhaustedError: OOM when allocating tensor with shape是因为:OOM内存溢出 修改代码中 卷积层的深度(核数目调小) 计算指标时传入的训练集数据与测试集数据都需要调小
- # -*- coding: utf-8 -*-
- __author__ = 'dongfangyao'
- __date__ = '2019/1/12 下午5:34'
- __product__ = 'PyCharm'
- __filename__ = 'tf28'
- """
- 17种花数据分类,是VGG网络初赛时候的数据集,现在网上没有下载;现在唯一一份数据集在tflearn这个框架中默认自带
- tflearn这个框架起始是在tensorflow基础上的一个封装,API比较简单(如果代码功底比较好,建议用tensorflow)
- tensorflow的执行速度比tflearn要快
- 基于tensorflow的框架有很多:tflearn Keras 速度上有区别
- Keras是一个高层神经网络API,Keras由纯Python编写而成并基Tensorflow、Theano以及CNTK后端。
- Keras 为支持快速实验而生,能够把你的idea迅速转换为结果
- tflearn安装:pip install tflearn
- """
- from tflearn.datasets import oxflower17
- from tflearn.datasets import mnist
- from tflearn.datasets import cifar10
- import tensorflow as tf
- from sklearn.model_selection import train_test_split
- # import tflearn as tfl
- # incoming, nb_filter, filter_size, strides=1, padding='same'
- # tfl.conv_2d()
- # 第一步:导入数据
- X, Y = oxflower17.load_data(dirname="17flowers", one_hot=True)
- print(X.shape) # sample_number,224,224,3
- print(Y.shape) # sample_number,17
- ## 数据分割
- train_img, test_img, train_label, test_label = train_test_split(X, Y, test_size=0.2, random_state=0)
- print("训练数据-图片shape:{};目标属性shape:{}" .format(train_img.shape, train_label.shape))
- print("测试数据-图片shape:{};目标属性shape:{}" .format(test_img.shape, test_label.shape))
- train_sample_number = train_img.shape[0]
- print('训练数据样本总数:{}'.format(train_sample_number))
- # 第二步:设置超参并定义学习率调整策略
- # 学习率,一般学习率设置的比较小
- learn_rate_base = 0.1
- # 每次迭代的训练样本数量
- batch_size = 32
- # 展示信息的间隔大小
- display_step = 1
- def learn_rate_func(epoch):
- """
- 根据给定的迭代批次,更新产生一个学习率的值 均匀分布策略
- :param epoch:
- :return:
- """
- return max(0.001, learn_rate_base * (0.9 ** int(epoch / 10)))
- # 第三步:开始构建模型 设置输入数据的占位符
- # 输出的维度大小信息
- n_classes = train_label.shape[1]
- x = tf.placeholder(tf.float32, shape=[None, 224, 224, 3], name='x')
- y = tf.placeholder(tf.float32, shape=[None, n_classes], name='y')
- learn_rate = tf.placeholder(tf.float32, name='learn_rate')
- # 第四步:构建VGG Net网络(直接将网络结构翻译成为这个代码)
- def get_variable(name, shape=None, dtype=tf.float32, initializer=tf.random_normal_initializer(mean=0, stddev=0.1)):
- """
- 返回一个对应的变量
- :param name:
- :param shape:
- :param dtype:
- :param initializer:
- :return:
- """
- return tf.get_variable(name, shape, dtype, initializer)
- def vgg_network(x, y):
- layer1_kernel_size = 8
- layer3_kernel_size = 16
- layer5_kernal_size_1 = 32
- layer5_kernal_size_2 = 32
- layer7_kernal_size_1 = 64
- layer7_kernal_size_2 = 64
- layer9_kernal_size_1 = 64
- layer9_kernal_size_2 = 64
- layer11_unit_size = 120
- layer12_unit_size = 120
- layer13_unit_size = 17
- # cov3-64 LRN局部响应归一化
- with tf.variable_scope('layer1'):
- net = tf.nn.conv2d(x, filter=get_variable('w', [3, 3, 3, layer1_kernel_size]), strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b', [layer1_kernel_size]))
- net = tf.nn.relu(net)
- # lrn(input, depth_radius=5, bias=1, alpha=1, beta=0.5, name=None)
- # LRN, 局部响应归一化),主要是对ReLU激活函数的输出进行局部归一化操作 而NB层是对样本进行归一化
- # depth_radius ==> 对应公式上的n,bias => 对应公式上的k, alpha => 对应公式上的α, beta=>对应公式上的β
- net = tf.nn.lrn(net)
- print('layer1之后的shape:{}'.format(net.shape))
- # maxpool
- with tf.variable_scope('layer2'):
- net = tf.nn.max_pool(net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
- print('layer2之后的shape:{}'.format(net.shape))
- # conv3-128
- with tf.variable_scope('layer3'):
- net = tf.nn.conv2d(net, filter=get_variable('w', [3, 3, layer1_kernel_size, layer3_kernel_size]),
- strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b', [layer3_kernel_size]))
- net = tf.nn.relu(net)
- print('layer3之后的shape:{}'.format(net.shape))
- # maxpool
- with tf.variable_scope('layer4'):
- net = tf.nn.max_pool(net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
- print('layer4之后的shape:{}'.format(net.shape))
- # conv3-256 conv3-256
- with tf.variable_scope('layer5'):
- net = tf.nn.conv2d(net, filter=get_variable('w1', [3, 3, layer3_kernel_size, layer5_kernal_size_1]),
- strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b1', [layer5_kernal_size_1]))
- net = tf.nn.relu(net)
- net = tf.nn.conv2d(net, filter=get_variable('w2', [3, 3, layer5_kernal_size_1, layer5_kernal_size_2]),
- strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b2', [layer5_kernal_size_2]))
- net = tf.nn.relu(net)
- print('layer5之后的shape:{}'.format(net.shape))
- # maxpool
- with tf.variable_scope('layer6'):
- net = tf.nn.max_pool(net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
- print('layer6之后的shape:{}'.format(net.shape))
- # conv3-512 conv3-512
- with tf.variable_scope('layer7'):
- net = tf.nn.conv2d(net, filter=get_variable('w1', [3, 3, layer5_kernal_size_2, layer7_kernal_size_1]),
- strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b1', [layer7_kernal_size_1]))
- net = tf.nn.relu(net)
- net = tf.nn.conv2d(net, filter=get_variable('w2', [3, 3, layer7_kernal_size_1, layer7_kernal_size_2]),
- strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b2', [layer7_kernal_size_2]))
- net = tf.nn.relu(net)
- print('layer7之后的shape:{}'.format(net.shape))
- # maxpool
- with tf.variable_scope('layer8'):
- net = tf.nn.max_pool(net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
- print('layer8之后的shape:{}'.format(net.shape))
- # conv3-512 conv3-512
- with tf.variable_scope('layer9'):
- net = tf.nn.conv2d(net, filter=get_variable('w1', [3, 3, layer7_kernal_size_2, layer9_kernal_size_1]),
- strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b1', [layer9_kernal_size_1]))
- net = tf.nn.relu(net)
- net = tf.nn.conv2d(net, filter=get_variable('w2', [3, 3, layer9_kernal_size_1, layer9_kernal_size_2]),
- strides=[1, 1, 1, 1],
- padding='SAME')
- net = tf.nn.bias_add(net, get_variable('b2', [layer9_kernal_size_2]))
- net = tf.nn.relu(net)
- print('layer9之后的shape:{}'.format(net.shape))
- # maxpool
- with tf.variable_scope('layer10'):
- net = tf.nn.max_pool(net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
- print('layer10之后的shape:{}'.format(net.shape))
- # fc-4096
- with tf.variable_scope('layer11'):
- # 将四维的数据转换为两维的数据
- shape = net.get_shape()
- feature_number = shape[1] * shape[2] * shape[3]
- net = tf.reshape(net, shape=[-1, feature_number])
- # 全连接
- net = tf.add(tf.matmul(net, get_variable('w', [feature_number, layer11_unit_size])),
- get_variable('b', [layer11_unit_size]))
- net = tf.nn.relu(net)
- print('layer11之后的shape:{}'.format(net.shape))
- # fc - 4096
- with tf.variable_scope('layer12'):
- # 全连接
- net = tf.add(tf.matmul(net, get_variable('w', [layer11_unit_size, layer12_unit_size])),
- get_variable('b', [layer12_unit_size]))
- net = tf.nn.relu(net)
- print('layer12之后的shape:{}'.format(net.shape))
- # fc - 1000
- with tf.variable_scope('layer13'):
- # 全连接
- net = tf.add(tf.matmul(net, get_variable('w', [layer12_unit_size, layer13_unit_size])),
- get_variable('b', [layer13_unit_size]))
- print('layer13之后的shape:{}'.format(net.shape))
- return net
- act = vgg_network(x, y)
- # 第五步:构建模型的损失函数
- # softmax_cross_entropy_with_logits: 计算softmax中的每个样本的交叉熵,logits指定预测值,labels指定实际值
- cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=act, labels=y))
- # 第六步:构建梯度下降的优化方法(一般用Adam 动量GD)
- # 使用Adam优化方式比较多 动量GD
- # learning_rate: 要注意,不要过大,过大可能不收敛,也不要过小,过小收敛速度比较慢
- train = tf.train.AdadeltaOptimizer(learning_rate=learn_rate).minimize(cost)
- # 第七步:计算模型正确率
- # tf.argmax:对矩阵按行或列计算最大值对应的下标,和numpy中的一样
- # tf.equal:是对比这两个矩阵或者向量的相等的元素,如果是相等的那就返回True,反正返回False,返回的值的矩阵维度和A是一样的
- pred = tf.equal(tf.argmax(act, axis=1), tf.argmax(y, axis=1))
- # 正确率(True转换为1,False转换为0)
- acc = tf.reduce_mean(tf.cast(pred, tf.float32))
- # 第八步:会话中执行阶段(模型的训练与迭代)
- # 初始化
- init = tf.global_variables_initializer()
- with tf.Session() as sess:
- # 进行数据初始化
- sess.run(init)
- # 模型保存、持久化
- saver = tf.train.Saver()
- epoch = 0
- while True:
- avg_cost = 0
- # 计算出总的批次
- total_batch = int(train_sample_number / batch_size)
- # 迭代更新
- for i in range(total_batch):
- # 获取x和y
- batch_xs = train_img[i * batch_size:(i+1) * batch_size]
- batch_ys = train_label[i * batch_size:(i+1) * batch_size]
- feeds = {x: batch_xs, y: batch_ys, learn_rate: learn_rate_func(epoch)}
- # 模型训练
- sess.run(train, feed_dict=feeds)
- # 获取损失函数值
- avg_cost += sess.run(cost, feed_dict=feeds)
- # 重新计算平均损失(相当于计算每个样本的损失值)
- avg_cost = avg_cost / total_batch
- # DISPLAY 显示误差率和训练集的正确率以此测试集的正确率
- if (epoch + 1) % display_step == 0:
- print("批次: %03d 损失函数值: %.9f" % (epoch, avg_cost))
- # 这里之所以使用train_img[:30]和train_label[:30],是因为我使用train_img会出现内存不够的情况,直接就会退出
- feeds = {x: train_img[:30], y: train_label[:30], learn_rate: learn_rate_func(epoch)}
- train_acc = sess.run(acc, feed_dict=feeds)
- print("训练集准确率: %.3f" % train_acc)
- feeds = {x: test_img[:30], y: test_label[:30], learn_rate: learn_rate_func(epoch)}
- test_acc = sess.run(acc, feed_dict=feeds)
- print("测试准确率: %.3f" % test_acc)
- if train_acc >= 0.99 and test_acc >= 0.98:
- saver.save(sess, './data/vggnet/model_{}_{}'.format(train_acc, test_acc), global_step=epoch)
- break
- epoch += 1
- # 模型可视化输出
- writer = tf.summary.FileWriter('./data/vggnet/graph', tf.get_default_graph())
- writer.close()
- print("end....")
复制代码
|
|