VGG13卷积神经网络识别难度较大的Cifar10彩色图片数据集,Cifar10数据集一共包含60000张32*32像素的三通道彩色图片,其中已经划分好训练集50000张,测试集10000张,并给出了10种分类标签。数据集较大,在第一次运行程序时请注意流量使用。
我们这次还使用了tensorboard对网络结构进行了可视化。
环境 pycharm2019 + tensorflow2.0 avx2_for_cpu
还是先放完整源码
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.keras import layers, optimizers, datasets
import datetime
import time
import os
def data_sets():
(train_images, train_labels), (val_images, val_labels) = datasets.cifar10.load_data()
return train_images, train_labels, val_images, val_labels
def function(x):
x = x/255
return x
def model_build():
network = tf.keras.Sequential(
[
layers.Conv2D(64, kernel_size=3, padding='same', activation='relu'),
layers.Conv2D(64, kernel_size=3, padding='same', activation='relu'),
layers.BatchNormalization(),
layers.MaxPool2D(pool_size=2, strides=2),
layers.Conv2D(128, kernel_size=3, padding='same', activation='relu'),
layers.Conv2D(128, kernel_size=3, padding='same', activation='relu'),
layers.BatchNormalization(),
layers.MaxPool2D(pool_size=2, strides=2),
layers.Conv2D(256, kernel_size=3, padding='same', activation='relu'),
layers.Conv2D(256, kernel_size=3, padding='same', activation='relu'),
layers.BatchNormalization(),
layers.MaxPool2D(pool_size=2, strides=2),
layers.Conv2D(512, kernel_size=3, padding='same', activation='relu'),
layers.Conv2D(512, kernel_size=3, padding='same', activation='relu'),
layers.BatchNormalization(),
layers.MaxPool2D(pool_size=2, strides=2),
layers.Conv2D(512, kernel_size=3, padding='same', activation='relu'),
layers.Conv2D(512, kernel_size=3, padding='same', activation='relu'),
layers.BatchNormalization(),
layers.MaxPool2D(pool_size=2, strides=2),
layers.Flatten(),
layers.Dense(256, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(10),
layers.Softmax()
]
)
network.build(input_shape=(4, 32, 32, 3))
network.summary()
return network
train_images, train_labels, val_images, val_labels = data_sets()
print(train_images.shape, train_labels.shape)
train_images = tf.cast(train_images, tf.float32)/255
val_images = tf.cast(val_images, tf.float32)/255
train_labels = tf.squeeze(train_labels, axis=1)
val_labels = tf.squeeze(val_labels, axis=1)
train_labels = tf.one_hot(train_labels, depth=10)
val_labels = tf.one_hot(val_labels, depth=10)
print(train_images.shape, train_labels.shape, val_images.shape, val_labels.shape)
log_dir = 'D:requestslogs'
if not os.path.exists(log_dir):
os.mkdir(log_dir)
log_dir = os.path.join(log_dir, datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
summary_writer = tf.summary.create_file_writer(log_dir, )
tf.summary.trace_on(graph=True, profiler=True)
model = model_build()
optimizers = tf.keras.optimizers.Adam(0.001)
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
model.compile(optimizer=optimizers, loss=tf.keras.losses.CategoricalCrossentropy(), metrics=["acc"])
hist = model.fit(train_images, train_labels, batch_size=256, epochs=2, validation_data=[val_images, val_labels],
callbacks=[tensorboard_callback])
with summary_writer.as_default():
tf.summary.trace_export(name="model_trace", step=0, profiler_outdir=log_dir)
def data_sets():
(train_images, train_labels), (val_images, val_labels) = datasets.cifar10.load_data()
return train_images, train_labels, val_images, val_labels
定义数据集获取函数,在第一次运行时会先下载cifar10数据集,默认的下载路径在C:User用户.kerasdatasets路径下,可以查看到的。
同样的我们还是使用了Sequential对网络进行了封装
layers.Conv2D(64, kernel_size=3, padding='same', activation='relu'),
layers.Conv2D(64, kernel_size=3, padding='same', activation='relu'),
layers.BatchNormalization(),
layers.MaxPool2D(pool_size=2, strides=2),
在卷积层设置的时候一般卷积核个数逐渐增多。
添加了BatchNormalization层,对参数进行标准化
并使用最大池化层进行降维,经过这样一层后,数据集可以在宽高上都缩小为原来的1/2。
![8b88bb102c043fe1ec0176d3f3ad2cf5.png](https://i-blog.csdnimg.cn/blog_migrate/5cd9f3b959b5aa49c716aee80309ca07.jpeg)
train_images, train_labels, val_images, val_labels = data_sets()
print(train_images.shape, train_labels.shape)
train_images = tf.cast(train_images, tf.float32)/255
val_images = tf.cast(val_images, tf.float32)/255
train_labels = tf.squeeze(train_labels, axis=1)
val_labels = tf.squeeze(val_labels, axis=1)
train_labels = tf.one_hot(train_labels, depth=10)
val_labels = tf.one_hot(val_labels, depth=10)
print(train_images.shape, train_labels.shape, val_images.shape, val_labels.shape)
在获取数据后,我们要检查数据输入进网络的type和shape
发现train_labels的shape为(50000, 1)不符合转化为独热编码的要求,对labels数据进行降维处理变为了(50000, )
log_dir = 'D:requestslogs'
if not os.path.exists(log_dir):
os.mkdir(log_dir)
log_dir = os.path.join(log_dir, datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
summary_writer = tf.summary.create_file_writer(log_dir, )
tf.summary.trace_on(graph=True, profiler=True)
设置记录训练日志的路径为D:requestslogs 如果路径不存在,就调用os库的mkdir创建这个路径。
为了更方便地对每次训练日志的分类,使用path.join 在我们原有的路径下生成一个文件夹,并以现在的时间命名。
将日志写入语句实例化,得到summary_writer
tf.summary.trace_on(graph=True, profiler=True)
开启踪迹追踪,之后tensorboard的callback会自动地把网络的信息记录在日志里。
model = model_build()
optimizers = tf.keras.optimizers.Adam(0.001)
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
model.compile(optimizer=optimizers, loss=tf.keras.losses.CategoricalCrossentropy(), metrics=["acc"])
hist = model.fit(train_images, train_labels, batch_size=256, epochs=2, validation_data=[val_images, val_labels],
callbacks=[tensorboard_callback])
建立网络模型
设置优化器为Adam,学习率0.001
设置tensorboardcallback 这个设置的好处是在进行mode-fit的时候,fit中会自动把callback反馈给tensorboard,而不用停止fit。
对比我在第一篇全连接层文章中写的,我使用了一个 for i in range 语句循环执行 fit 在每一次执行完一个fit的epoch后,才反馈信息绘制图表,训练速度会被一次次中断。但是那个网络比较简单,运算很快,并没有受到什么影响。
在model fit中加入了callback 输入的参数为我们在上面定义的tensorboard callback
![4d98fe247755b47e31fe0afc1d0376af.png](https://i-blog.csdnimg.cn/blog_migrate/abfb0c4926c39e69ab553dbb18eca250.jpeg)
在训练过程比较慢,一个epoch大概要20分钟,cpu也直接满了。
我设置了一个比较大的batch,因为我发现在设置为32的小batch的时候准确率反馈的不太准确。
在这个256batch下准确率还是在逐步提高的,经过实验,在一个epoch训练结束后准确率能到50%左右,最终的准确率在70%以上。经过一些超参数调优可能能达到更高的准确率。
至于训练速度,我也在程序层面想办法。
用的华为 matebook x pro 神机目前就只能跑cpu版的了,有条件使用gpu 运算比较大的数据量应该会比cpu快不少,x pro 100%色域超 高清屏,代码看的非常舒服。
- 关于tensorboard的可视化
- 在pycharm 的terminal 或cmd中输入tensorboard --logdir +日志路径 根据上面的logdir设置,路径的最后一个文件夹应该是以时间命名的
![1e4c108d7f92c52c7e73f3a38b98fb8c.png](https://i-blog.csdnimg.cn/blog_migrate/e3b757e9d77c34f6184ab78209471000.png)
![3426c49e7d9e5e173e5c34d6b4e2b268.png](https://i-blog.csdnimg.cn/blog_migrate/17d67881c7c519cc66c9cf85ea9d4d81.jpeg)
![5fc597bcca04abfdc034418dfd141aac.png](https://i-blog.csdnimg.cn/blog_migrate/3cc73e3eba3d2285c82e199997917dd8.jpeg)
得到上面的网络结构,或者是这样的。。
![fe931e9267d767e25b9f2429c144bbe7.png](https://i-blog.csdnimg.cn/blog_migrate/b6e113106faaa828150f5c5e65c3ea6b.jpeg)
这样的
![66ccd17b537cc1482824cdcdf67e57b8.png](https://i-blog.csdnimg.cn/blog_migrate/393ac070cae5e79e675c5825a74fc133.jpeg)
网络结构
最后,至于pycharm的背景,可以双击shift,输入set background image 然后直接输入路径进行设置,或者去修改里面的程序就可以了。
![70c3760f827284cabd42799cd4509279.png](https://i-blog.csdnimg.cn/blog_migrate/2a9f5ce81ae9f2baaafda845baef7232.jpeg)
写程序,看accuracy也挺无趣的,给pycharm换个主题就有趣了很多。
下一篇可能会更的更慢些吧,下一篇预计介绍著名的ResNet 深度残差网络 还是训练CIFAR10,性能与这次的VGG13做个对比。