各位同学好,今天和大家分享一下TensorFlow2.0中的VGG16卷积神经网络模型,案例:现在有四种鸟类的图片各200张,构建卷积神经网络,预测图片属于哪个分类。

1. 数据加载

将鸟类图片按类分开存放,使用tf.keras.preprocessing.image_dataset_from_directory()函数分批次读取图片数据,统一指定图片加载进来的大小224*224,指定参数label_model'int'代表目标值y是数值类型,即0, 1, 2, 3等;'categorical'代表onehot类型,对应索引的值为1,如图像属于第二类则表示为0,1,0,0,0;'binary'代表二分类

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import Sequential, optimizers, layers, Model#(1)数据加载
def get_data(height, width, batchsz):# 获取训练集数据filepath1 = 'C:/Users/admin/.spyder-py3/test/数据集/4种鸟分类/new_data/train'train_ds = tf.keras.preprocessing.image_dataset_from_directory(filepath1, # 指定训练集数据路径label_mode = 'categorical',  # 进行onehot编码image_size = (height, width), # 对图像risizebatch_size = batchsz, # 每次迭代取32个数据 )# 获取验证集数据filepath2 = 'C:/Users/admin/.spyder-py3/test/数据集/4种鸟分类/new_data/val'val_ds = tf.keras.preprocessing.image_dataset_from_directory(filepath1, # 指定训练集数据路径label_mode = 'categorical',  image_size = (height, width), # 对图像risizebatch_size = batchsz, # 每次迭代取32个数据 )    # 获取测试集数据filepath2 = 'C:/Users/admin/.spyder-py3/test/数据集/4种鸟分类/new_data/test'test_ds = tf.keras.preprocessing.image_dataset_from_directory(filepath1, # 指定训练集数据路径label_mode = 'categorical',  image_size = (height, width), # 对图像risizebatch_size = batchsz, # 每次迭代取32个数据 )      # 返回数据集return train_ds, val_ds, test_ds# 数据读取函数,返回训练集、验证集、测试集
train_ds, val_ds, test_ds = get_data(height=224, width=224, batchsz=32)
# 查看有哪些分类
class_names = train_ds.class_names
print('类别有:', class_names)
# 类别有: ['Bananaquit', 'Black Skimmer', 'Black Throated Bushtiti', 'Cockatoo']# 查看数据集信息
sample = next(iter(train_ds)) #每次取出一个batch的训练数据
print('x_batch.shape:', sample[0].shape, 'y_batch.shape:',sample[1].shape)
# x_batch.shape: (128, 224, 224, 3) y_batch.shape: (128, 4)
print('y[:5]:', sample[1][:5]) # 查看前五个目标值

2. 数据预处理

使用.map()函数转换数据集中所有x和y的类型,并将每张图象的像素值映射到[-1,1]之间,打乱训练集数据的顺序.shuffle(),但不改变特征值x和标签值y之间的对应关系。iter()生成迭代器,配合next()每次运行取出训练集中的一个batch数据

#(2)显示图像
import matplotlib.pyplot as plt
for i in range(15):plt.subplot(3,5,i+1)plt.imshow(sample[0][i]/255.0) # sample[0]代表取出的一个batch的所有图像信息,映射到[0,1]之间显示图像plt.xticks([]) # 不显示xy轴坐标刻度plt.yticks([])
plt.show()#(3)数据预处理
# 定义预处理函数
def processing(x, y):x = 2 * tf.cast(x, dtype=tf.float32)/255.0 - 1  #映射到[-1,1]之间y = tf.cast(y, dtype=tf.int32) # 转换数据类型return x,y# 对所有数据集预处理
train_ds = train_ds.map(processing).shuffle(10000)
val_ds = val_ds.map(processing)
test_ds = test_ds.map(processing)# 再次查看数据信息
sample = next(iter(train_ds)) #每次取出一个batch的训练数据
print('x_batch.shape:', sample[0].shape, 'y_batch.shape:',sample[1].shape)
# x_batch.shape: (128, 224, 224, 3) y_batch.shape: (128, 4)
print('y[:5]:', sample[1][:5]) # 查看前五个目标值
# [[0 0 1 0], [1 0 0 0], [0 1 0 0], [0 1 0 0], [1 0 0 0]]

鸟类图像如下:


3. VGG16网络构造

VGG16的模型框架如下图所示,原理见下文:深度学习-VGG16原理详解 。

1)输入图像尺寸为224x224x3,经64个通道为3的3x3的卷积核,步长为1,padding=same填充,卷积两次,再经ReLU激活,输出的尺寸大小为224x224x64

2)经max pooling(最大化池化),滤波器为2x2,步长为2,图像尺寸减半,池化后的尺寸变为112x112x64

3)经128个3x3的卷积核,两次卷积,ReLU激活,尺寸变为112x112x128

4)max pooling池化,尺寸变为56x56x128

5)经256个3x3的卷积核,三次卷积,ReLU激活,尺寸变为56x56x256

6)max pooling池化,尺寸变为28x28x256

7)经512个3x3的卷积核,三次卷积,ReLU激活,尺寸变为28x28x512

8)max pooling池化,尺寸变为14x14x512

9)经512个3x3的卷积核,三次卷积,ReLU,尺寸变为14x14x512

10)max pooling池化,尺寸变为7x7x512

11)然后Flatten(),将数据拉平成向量,变成一维51277=25088。

11)再经过两层1x1x4096,一层1x1x1000的全连接层(共三层),经ReLU激活

12)最后通过softmax输出1000个预测结果

下面通过代码来实现,这里我们需要的是4分类,因此把最后的1000个预测结果改为4既可。

#(4)构建CNN-VGG16
def VGG16(input_shape=(224,224,3), output_shape=4):# 输入层input_tensor = keras.Input(shape=input_shape)# unit1# 卷积层x = layers.Conv2D(64, (3,3), activation='relu', strides=1, padding='same')(input_tensor) # [224,224,64]# 卷积层x = layers.Conv2D(64, (3,3), activation='relu' , strides=1, padding='same')(x) #[224,224,64]# 池化层,size变成1/2x = layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(x) #[112,112,64]# unit2# 卷积层x = layers.Conv2D(128, (3,3), activation='relu', strides=1, padding='same')(x) #[112,112,128]# 卷积层x = layers.Conv2D(128, (3,3), activation='relu', strides=1, padding='same')(x) #[112,112,128]# 池化层x = layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(x) #[56,56,128]# unit3# 卷积层x = layers.Conv2D(256, (3,3), activation='relu', strides=1, padding='same')(x) #[56,56,256]# 卷积层x = layers.Conv2D(256, (3,3), activation='relu', strides=1, padding='same')(x) #[56,56,256]# 卷积层x = layers.Conv2D(256, (3,3), activation='relu', strides=1, padding='same')(x) #[56,56,256]# 池化层x = layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(x) #[28,28,256]# unit4# 卷积层x = layers.Conv2D(512, (3,3), activation='relu', strides=1, padding='same')(x) #[28,28,512]# 卷积层x = layers.Conv2D(512, (3,3), activation='relu', strides=1, padding='same')(x) #[28,28,512]    # 卷积层x = layers.Conv2D(512, (3,3), activation='relu', strides=1, padding='same')(x) #[28,28,512]# 池化层x = layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(x) #[14,14,512]# unit5# 卷积层x = layers.Conv2D(512, (3,3), activation='relu', strides=1, padding='same')(x) #[14,14,512]# 卷积层x = layers.Conv2D(512, (3,3), activation='relu', strides=1, padding='same')(x) #[14,14,512]# 卷积层x = layers.Conv2D(512, (3,3), activation='relu', strides=1, padding='same')(x) #[14,14,512]# 池化层x = layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(x) #[7,7,512]# uint6# Flatten层x = layers.Flatten()(x) #压平[None,4096]# 全连接层x = layers.Dense(4096, activation='relu')(x) #[None,4096]# 全连接层x = layers.Dense(4096, activation='relu')(x) #[None,4096]# 输出层,输出结果不做softmaxoutput_tensor = layers.Dense(output_shape)(x) #[None,4]# 构建模型model = Model(inputs=input_tensor, outputs=output_tensor)# 返回模型return model# 构建VGG16模型
model = VGG16()
# 查看模型结构
model.summary()

该网络构架如下

Model: "model"
_________________________________________________________________Layer (type)                Output Shape              Param #
=================================================================input_1 (InputLayer)        [(None, 224, 224, 3)]     0         conv2d (Conv2D)             (None, 224, 224, 64)      1792      conv2d_1 (Conv2D)           (None, 224, 224, 64)      36928     max_pooling2d (MaxPooling2D  (None, 112, 112, 64)     0         )                                                               conv2d_2 (Conv2D)           (None, 112, 112, 128)     73856     conv2d_3 (Conv2D)           (None, 112, 112, 128)     147584    max_pooling2d_1 (MaxPooling  (None, 56, 56, 128)      0         2D)                                                             conv2d_4 (Conv2D)           (None, 56, 56, 256)       295168    conv2d_5 (Conv2D)           (None, 56, 56, 256)       590080    conv2d_6 (Conv2D)           (None, 56, 56, 256)       590080    max_pooling2d_2 (MaxPooling  (None, 28, 28, 256)      0         2D)                                                             conv2d_7 (Conv2D)           (None, 28, 28, 512)       1180160   conv2d_8 (Conv2D)           (None, 28, 28, 512)       2359808   conv2d_9 (Conv2D)           (None, 28, 28, 512)       2359808   max_pooling2d_3 (MaxPooling  (None, 14, 14, 512)      0         2D)                                                             conv2d_10 (Conv2D)          (None, 14, 14, 512)       2359808   conv2d_11 (Conv2D)          (None, 14, 14, 512)       2359808   conv2d_12 (Conv2D)          (None, 14, 14, 512)       2359808   max_pooling2d_4 (MaxPooling  (None, 7, 7, 512)        0         2D)                                                             flatten (Flatten)           (None, 25088)             0         dense (Dense)               (None, 4096)              102764544 dense_1 (Dense)             (None, 4096)              16781312  dense_2 (Dense)             (None, 4)                 16388     =================================================================
Total params: 134,276,932
Trainable params: 134,276,932
Non-trainable params: 0
_________________________________________________________________

4. 网络编译

在网络编译时.compile(),指定损失loss采用交叉熵损失,设置参数from_logits=True,由于网络的输出层没有使用softmax函数将输出的实数转为概率,参数设置为True时,会自动将logits的实数转为概率值,再和真实值计算损失,这里的真实值y是经过onehot编码之后的结果。

#(5)模型配置
# 设置优化器
opt = optimizers.Adam(learning_rate=1e-4)  # 学习率model.compile(optimizer=opt, #学习率loss=keras.losses.CategoricalCrossentropy(from_logits=True), #损失metrics=['accuracy']) #评价指标# 训练,给定训练集、验证集
history = model.fit(train_ds, validation_data=val_ds, epochs=30) #迭代30次#(6)循环结束后绘制损失和准确率的曲线
# ==1== 准确率
train_acc = history.history['accuracy']  #训练集准确率
val_acc = history.history['val_accuracy']  #验证集准确率
# ==2== 损失
train_loss = history.history['loss'] #训练集损失
val_loss = history.history['val_loss'] #验证集损失
# ==3== 绘图
epochs_range = range(len(train_acc))
plt.figure(figsize=(10,5))
# 准确率
plt.subplot(1,2,1)
plt.plot(epochs_range, train_acc, label='train_acc')
plt.plot(epochs_range, val_acc, label='val_acc')
plt.legend()
# 损失曲线
plt.subplot(1,2,2)
plt.plot(epochs_range, train_loss, label='train_loss')
plt.plot(epochs_range, val_loss, label='val_loss')
plt.legend()

5. 结果展示

如图可见网络效果预测较好,在迭代至25次左右时网络准确率达到99%左右,如果迭代次数较多的话,可考虑在编译时使用early stopping保存最优权重,若后续网络效果都没有提升就可以提早停止网络,节约训练时间。

训练过程中的损失和准确率如下

Epoch 1/30
13/13 [==============================] - 7s 293ms/step - loss: 1.3627 - accuracy: 0.3116 - val_loss: 1.3483 - val_accuracy: 0.5075
Epoch 2/30
13/13 [==============================] - 3s 173ms/step - loss: 1.1267 - accuracy: 0.5251 - val_loss: 1.0235 - val_accuracy: 0.5226
------------------------------------------------------------------------------------------
省略N行
------------------------------------------------------------------------------------------
Epoch 26/30
13/13 [==============================] - 2s 174ms/step - loss: 0.1184 - accuracy: 0.9874 - val_loss: 0.1093 - val_accuracy: 0.9774
Epoch 27/30
13/13 [==============================] - 2s 174ms/step - loss: 0.3208 - accuracy: 0.9196 - val_loss: 0.2678 - val_accuracy: 0.9347
Epoch 28/30
13/13 [==============================] - 2s 172ms/step - loss: 0.2366 - accuracy: 0.9322 - val_loss: 0.1247 - val_accuracy: 0.9648
Epoch 29/30
13/13 [==============================] - 3s 173ms/step - loss: 0.1027 - accuracy: 0.9648 - val_loss: 0.0453 - val_accuracy: 0.9849
Epoch 30/30
13/13 [==============================] - 3s 171ms/step - loss: 0.0491 - accuracy: 0.9849 - val_loss: 0.0250 - val_accuracy: 0.9925

6. 其他方法

如果想更灵活的计算损失和准确率,可以不使用.compile(),.fit()函数。在模型构建完之后,自己敲一下代码实现前向传播,同样能实现模型训练效果。下面的代码可以代替第4小节中的第(5)步

# 指定优化器
optimizer = optimizers.Adam(learning_rate=1e-5)
# 记录训练和测试过程中的每个batch的准确率和损失
train_acc = []
train_loss = []
val_acc = []
val_loss = []# 大循环
for epochs in range(30): #循环30次train_total_sum=0train_total_loss=0train_total_correct=0val_total_sum=0val_total_loss=0val_total_correct=0    #(5)网络训练for step, (x,y) in enumerate(train_ds): #每次从训练集中取出一个batch# 梯度跟踪with tf.GradientTape() as tape:# 前向传播logits = model(x)  # 输出属于每个分类的实数值# 计算准确率prob = tf.nn.softmax(logits, axis=1) # 计算概率predict = tf.argmax(prob, axis=1, output_type=tf.int32) # 概率最大值的下标correct = tf.cast(tf.equal(predict, y), dtype=tf.int32) # 对比预测值和真实值,将结果从布尔类型转变为1和0correct = tf.reduce_sum(correct) # 计算一共预测对了几个total = x.shape[0] # 每次迭代有多少参与进来train_total_sum += total #记录一共有多少个样本参与了循环train_total_correct += correct #记录一整次循环下来预测对了几个acc = correct/total # 每一个batch的准确率train_acc.append(acc) # 将每一个batch的准确率保存下来# 计算损失y = tf.one_hot(y, depth=4) # 对真实值进行onehot编码,分为4类loss = tf.losses.categorical_crossentropy(y, logits, from_logits=True) # 将预测值放入softmax种再计算损失# 求每个batch的损失均值loss_avg = tf.reduce_mean(loss, axis=1)# 记录总损失train_total_loss += tf.reduce_sum(loss)  #记录每个batch的损失          # 梯度计算,因变量为loss损失,自变量为模型中所有的权重和偏置grads = tape.gradient(loss_avg, model.trainable_variables)# 梯度更新,对所有的权重和偏置更新梯度optimizer.apply_gradients(zip(grads, model.trainable_variables))# 每20个batch打印一次损失和准确率if step%20 == 0:print('train', 'step:', step, 'loss:', loss_avg, 'acc:', acc)# 记录每次循环的损失和准确率train_acc.append(train_total_correct/train_total_sum) # 总预测对的个数除以总个数,平均准确率train_loss.append(train_total_loss/train_total_sum) # 总损失处于总个数,得平均损失#(6)网络测试for step, (x, y) in enumerate(val_ds):  #每次取出一个batch的验证数据# 前向传播logits = model(x)# 计算准确率prob = tf.nn.softmax(logits, axis=1) # 计算概率predict = tf.argmax(prob, axis=1, output_type=tf.int32) # 概率最大值的下标correct = tf.cast(tf.equal(predict, y), dtype=tf.int32) # 对比预测值和真实值,将结果从布尔类型转变为1和0correct = tf.reduce_sum(correct) # 计算一共预测对了几个val_total_correct += correct # 计算整个循环预测对了几个total = x.shape[0] # 每次迭代有多少参与进来val_total_sum += total # 整个循环有多少参与进来acc = correct/total # 每一个batch的准确率val_acc.append(acc) # 将每一个batch的准确率保存下来# 计算损失y = tf.one_hot(y, depth=4) # 对真实值进行onehot编码,分为4类loss = tf.losses.categorical_crossentropy(y, logits, from_logits=True) # 将预测值放入softmax种再计算损失# 求每个batch的损失均值loss_avg = tf.reduce_mean(loss, axis=1)# 记录总损失val_total_loss += tf.reduce_sum(loss) # 每10个btch打印一次准确率和损失if step%10 == 0:print('val', 'step:', step, 'loss:', loss_avg, 'acc:', acc)# 记录每次循环的损失和准确率val_acc.append(val_total_correct/val_total_sum) # 总预测对的个数除以总个数,平均准确率val_loss.append(val_total_loss/val_total_sum) # 总损失处于总个数,得平均损失

【神经网络】(6) 卷积神经网络(VGG16),案例:鸟类图片4分类相关推荐

  1. 卷积神经网络 图像识别,卷积神经网络图像处理

    街道垃圾识别系统的原理是什么? 不久前上海关于垃圾分类的出台政策大家应该还记得,做好垃圾分类成为了许多人的难题.其实,随着人工智能技术的突飞猛进,自动分类垃圾桶已经出现了. 目前有许多关于人工智能自动 ...

  2. 【数据挖掘】卷积神经网络 ( 视觉原理 | CNN 模仿视觉 | 卷积神经网络简介 | 卷积神经网络组成 | 整体工作流程 | 卷积计算图示 | 卷积计算简介 | 卷积计算示例 | 卷积计算参数 )

    文章目录 I . 人类的视觉原理 II . 卷积神经网络 模仿 视觉原理 III . 卷积神经网络简介 IV . 卷积神经网络 组成 V . 卷积神经网络 工作流程 VI . 降低样本参数数量级 VI ...

  3. 04.卷积神经网络 W1.卷积神经网络(作业:手动/TensorFlow 实现卷积神经网络)

    文章目录 作业1:实现卷积神经网络 1. 导入一些包 2. 模型框架 3. 卷积神经网络 3.1 Zero-Padding 3.2 单步卷积 3.3 卷积神经网络 - 前向传播 4. 池化层 5. 卷 ...

  4. 【卷积神经网络】卷积神经网络(Convolutional Neural Networks, CNN)基础

    卷积神经网络(Convolutional Neural Networks, CNN),是一种 针对图像 的特殊的 神经网络. 卷积神经网络概述 Why not DNN? 图像数据的维数很高,比如 1, ...

  5. 卷积神经网络 图像识别,卷积神经网络 图像处理

    基于深度卷积神经网络进行人脸识别的原理是什么? 本质上是模式识别,把现实的东西抽象成计算机能够理解的数字.如果一个图片是256色的,那么图像的每一个像素点,都是0到255中间的一个值,这样你可以把一个 ...

  6. 全连接神经网络、卷积神经网络

    全连接神经网络.卷积神经网络 前言 全连接神经网络 介绍 结构 损失函数 梯度下降 链式法则 反向传播 总结 卷积神经网络 背景 结构 卷积(Convolution) 池化(Max Pooling) ...

  7. 卷积神经网络 图像处理,卷积神经网络基本原理

    基于深度卷积神经网络进行人脸识别的原理是什么? 本质上是模式识别,把现实的东西抽象成计算机能够理解的数字.如果一个图片是256色的,那么图像的每一个像素点,都是0到255中间的一个值,这样你可以把一个 ...

  8. 什么是卷积神经网络算法,卷积神经网络运算公式

    卷积公式指的是什么? 卷积公式是指两个函数f和g生成第三个函数的一种数学算子.表征函数f与经过翻转和平移的g的重叠部分的累积,如果将参加卷积的一个函数看作区间的指示函数,卷积还可以被看作是滑动平均的推 ...

  9. 神经网络与卷积神经网络_神经网络与人的思想

    神经网络与卷积神经网络 If you are familiar with the terms Artificial Intelligence, Machine Learning , Deep Lear ...

  10. BP神经网络与卷积神经网络(CNN)

    BP神经网络与卷积神经网络(CNN) 1.BP神经网络  1.1 神经网络基础  神经网络的基本组成单元是神经元.神经元的通用模型如图 1所示,其中常用的激活函数有阈值函数.sigmoid函数和双曲正 ...

最新文章

  1. directly to phd is good for laying a solid foundation for future career
  2. 每日程序C语言34-利用指针将输入的三个数排序
  3. matlab imhist灰度直方图
  4. paip.提升效率---提升绑定层次--form绑定取代field绑定
  5. mysql 5.5 替换字符_MySQL replace函数替换字符串语句的用法
  6. 在线文本去重统计工具
  7. 如何抓取http请求/拦截器用法
  8. Django日志模块logging的配置详解
  9. [转载] Python学习系列之下划线与变量命名规则
  10. @ OutputCache 指令的 VaryByCustom 属性来缓存不同版本的页面
  11. 免费代理ip网站总结
  12. 2022-华为-大数据研发工程师-秋招面经
  13. 基于java点播影院运营系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  14. Android 解决TextView排版参差不齐的问题
  15. C语言学习(三)内存初识、数据在内存中的保存形式、程序载入内存
  16. 陀螺仪程序---可直接用
  17. 11.Django基础九之中间件
  18. STM32 Keil快速新建工程
  19. 施工测量中Cad一些非常有用的插件
  20. [组会论文]CAIL 2018

热门文章

  1. Android 如何防止用户同时点击多个控件问题
  2. AndroidManifest 配置Activity 一直提示找不到,
  3. Buttomsheetdialog的简单实用
  4. haystack全文检索框架
  5. 深入理解Java的接口和抽象类
  6. 分享一个小工具:Excel表高速转换成JSON字符串
  7. java script DOM操作
  8. android之AlertDialog 点击其它区域自己主动消失
  9. 网游生命周期在百度指数曲线上呈“M”形分布,各阶段搜索行为呈一定特征
  10. HDU 1429 胜利大逃亡(续) (BFS+位压缩)