深度学习(7)--卷积神经网络项目详解

一.项目介绍:

用Keras工具包搭建训练自己的一个卷积神经网络(Simple_VGGNet,简单版VGGNet),用来识别猫/狗/羊三种图片。

数据集:

二.卷积神经网络构造

查看API文档

Convolution layers (keras.io)icon-default.png?t=N7T8https://keras.io/api/layers/convolution_layers/

# 导入所需模块
from keras.models import Sequential
from keras.layers import BatchNormalization
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.initializers import TruncatedNormal
from keras.layers import Activation
from keras.layers import Flatten
from keras.layers import Dropout
from keras.layers import Dense
from keras import backend as Kclass SimpleVGGNet:@staticmethoddef build(width, height, depth, classes):   # 长 宽 深度(特征图的个数)model = Sequential()inputShape = (height, width, depth)chanDim = -1if K.image_data_format() == "channels_first":inputShape = (depth, height, width)chanDim = 1# CONV => RELU => POOLmodel.add(Conv2D(32, (3, 3), padding="same",input_shape=inputShape, kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("relu"))#  model.add(BatchNormalization(axis=chanDim))model.add(MaxPooling2D(pool_size=(2, 2)))#  model.add(Dropout(0.25))# (CONV => RELU) * 2 => POOLmodel.add(Conv2D(64, (3, 3), padding="same", kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("relu"))#  model.add(BatchNormalization(axis=chanDim))model.add(Conv2D(64, (3, 3), padding="same", kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("relu"))#  model.add(BatchNormalization(axis=chanDim))model.add(MaxPooling2D(pool_size=(2, 2)))#  model.add(Dropout(0.25))# (CONV => RELU) * 3 => POOLmodel.add(Conv2D(128, (3, 3), padding="same", kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("relu"))#  model.add(BatchNormalization(axis=chanDim))model.add(Conv2D(128, (3, 3), padding="same", kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("relu"))#  model.add(BatchNormalization(axis=chanDim))model.add(Conv2D(128, (3, 3), padding="same", kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("relu"))#  model.add(BatchNormalization(axis=chanDim))model.add(MaxPooling2D(pool_size=(2, 2)))#  model.add(Dropout(0.25))# FC层model.add(Flatten())model.add(Dense(256, kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("relu"))#  model.add(BatchNormalization())#  model.add(Dropout(0.6))# softmax 分类model.add(Dense(classes, kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Activation("softmax"))return model


2.1.判断是否是channels first的back end

不同backend的颜色通道设置的位置可能不同,tensorflow的颜色通道在最后一个参数,有些backend的颜色通道则在第一个参数,所以需要进行一次判断。

if K.image_data_format() == "channels_first":inputShape = (depth, height, width)chanDim = 1

如果判断为真,则重新设置参数的顺序。

2.2.卷积层构造

model.add(Conv2D(32, (3, 3), padding="same",input_shape=inputShape,kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Conv2D(64, (3, 3), padding="same",kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))
model.add(Conv2D(64, (3, 3), padding="same",kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))model.add(Conv2D(128, (3, 3), padding="same",kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))
model.add(Conv2D(128, (3, 3), padding="same",kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))
model.add(Conv2D(128, (3, 3), padding="same",kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))

拿第一层卷积层的构造为例:32是输出层的维度(即特征图个数,每个特征图大小为最开始设置height x weight)。(3,3)是卷积核的大小,即一次性读取3x3大小的特征值。padding是边界填充,padding=same表示有padding,且padding大小与步长相同,padding=valid则表示没有padding。最后再设置权重初始化方式为截断初始化。

对于卷积神经网络,需要经过池化层对数据进行压缩,而在每次经过池化层压缩后,我们希望数据的特征图个数可以翻倍。(与传统神经网络的减少不同)

如上图所示:数据的特征图个数由32→64→128.(每个特征图都是height x weight x 1的大小)

2.3.添加激活函数

model.add(Activation("relu"))

除去池化层因为只是对参数进行压缩而不进行计算,不需要添加激活函数,其他对参数进行计算了的层,例如卷积层和全连接层都需要添加一个激活函数。

2.4.池化层构造

model.add(MaxPooling2D(pool_size=(2, 2)))

此处调用的池化层是MaxPooling,表示对每个2x2大小的区域进行池化,只取出其中最大的那个权重值。

2.5.全连接FC层构造 

# FC层
model.add(Flatten())
model.add(Dense(512,kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))
model.add(Activation("relu"))
#  model.add(BatchNormalization())
#  model.add(Dropout(0.6))# softmax 分类
model.add(Dense(classes,kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.01)))
model.add(Activation("softmax"))

经过卷积后,要通过矩阵相乘得到相应类别的概率值,所以需要将三维的图片数据拉长成一维的特征值矩阵。同时增加一层全连接层,特征值矩阵经过该全连接层剩下512个特征值。

最后再添加一层全连接层,得到的类别数量与最开始设置的classes相同,并通过softmax激活函数来分类。

三.完整代码

# 导入所需工具包
from CNN_net import Simple_VGGNet
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from keras.optimizers import SGD
from keras.preprocessing.image import ImageDataGenerator
from my_utlis import utlis_paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os
import kerasos.environ["CUDA_VISIBLE_DEVICES"] = "0"# 读取数据和标签
print("------开始读取数据------")
data = []
labels = []# 拿到图像数据路径,方便后续读取
imagePaths = sorted(list(utlis_paths.list_images('./dataset')))
random.seed(42)
random.shuffle(imagePaths)# 遍历读取数据
for imagePath in imagePaths:# 读取图像数据image = cv2.imread(imagePath)image = cv2.resize(image, (64, 64))  # 将图片resize为相同尺寸data.append(image)# 读取标签label = imagePath.split(os.path.sep)[-2]  # 根据文件夹获取标签labels.append(label)# 对图像数据做scale操作
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)# 数据集切分
(trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.25, random_state=42)# 转换标签为one-hot encoding格式(三分类及以上需要,二分类不需要)
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)# 数据增强处理
"""
aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,horizontal_flip=True, fill_mode="nearest")
"""# 建立卷积神经网络
model = Simple_VGGNet.SimpleVGGNet.build(width=64, height=64, depth=3, classes=len(lb.classes_))# 设置初始化超参数
INIT_LR = 0.01
EPOCHS = 30
BS = 32# 损失函数,编译模型
print("------准备训练网络------")
lr_schedule = keras.optimizers.schedules.ExponentialDecay(initial_learning_rate=INIT_LR,decay_steps=10,decay_rate=0.98)
opt = SGD(lr=lr_schedule)  # 一开始的权重参数较好,可以把学习参数设置的较大,后续权重参数变差,学习参数也设置较低
# one-hot编码用loss="CategoricalCrossentropy" 数组编码用loss="SparseCategoricalCrossentropy"
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])# 训练网络模型
"""
H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,epochs=EPOCHS)
"""H = model.fit(trainX, trainY, validation_data=(testX, testY),epochs=EPOCHS, batch_size=32)# 测试
print("------测试网络------")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),predictions.argmax(axis=1), target_names=lb.classes_))# 绘制结果曲线
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["accuracy"], label="train_acc")
plt.plot(N, H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig('./output_cnn/cnn_plot.png')# 保存模型
print("------正在保存模型------")
model.save('./output_cnn/cnn.model')
f = open('./output_cnn/cnn_lb.pickle', "wb")
f.write(pickle.dumps(lb))
f.close()

3.1.学习率衰减设置

lr_schedule = keras.optimizers.schedules.ExponentialDecay(initial_learning_rate=INIT_LR,decay_steps=5,decay_rate=0.9)
opt = SGD(lr=lr_schedule)  # 一开始的权重参数较好,可以把学习参数设置的较大,后续权重参数变差,学习参数也设置较低

decay_steps表示的是每几次迭代进行一次衰减,dacay_rate表示的是衰减的程度,上述代码中即为每五次迭代进行一次学习率的衰减,即 lr*0.9。

一开始的权重参数较好,可以把学习参数设置的较大,后续权重参数变差,学习参数也相应设置的较低。

四.首次运行结果

第一次运行结果如下:

发现数据异常,有两种类没有结果值,编译器warning:UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.

出现上述warning的原因是有些样本是正确的,但是没有预测到。

博主认为出现这种warning的解决方法是修改数据集或者调整你的网络结构。

卷积神经网络的数据参数较少,所以当时有截断初始化、Dropout等操作时可能会导致结果出现异常。

此处博主删去了网络中卷积层和全连接层中的截断初始化,得到的结果:

五.数据增强对结果的影响

Data Augmentation ,基于有限的数据生成更多等价(同样有效)的数据,丰富训练数据的分布,使通过训练集得到的模型泛化能力更强。

# 数据增强处理
aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,horizontal_flip=True, fill_mode="nearest")# 训练网络模型
H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,epochs=EPOCHS)

 加上数据增强的训练结果:

六.BatchNormalization对结果的影响

每次卷积层、全连接层后可以加上一个BatchNormalization层进行修正,使标准化。

BatchNormalization layer (keras.io)icon-default.png?t=N7T8https://keras.io/api/layers/normalization_layers/batch_normalization/

model.add(Conv2D(32, (3, 3), padding="same",input_shape=inputShape, ))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))

加上数据增强,BatchNormalization层的训练结果: 

七.加载模型进行测试

编写一个predict.py程序来加载模型进行测试:

# 导入所需工具包
from keras.models import load_model
import argparse
import pickle
import cv2# 加载测试数据并进行相同预处理操作
image = cv2.imread('./cs_image/dog.jpeg')
output = image.copy()
image = cv2.resize(image, (64, 64))# scale图像数据
image = image.astype("float") / 255.0# 对图像进行拉平操作
image = image.reshape((1, image.shape[0], image.shape[1],image.shape[2]))# 读取模型和标签
print("------读取模型和标签------")
model = load_model('./output_cnn/cnn.model')
lb = pickle.loads(open('./output_cnn/cnn_lb.pickle', "rb").read())# 预测
preds = model.predict(image)# 得到预测结果以及其对应的标签
i = preds.argmax(axis=1)[0]
label = lb.classes_[i]# 在图像中把结果画出来
text = "{}: {:.2f}%".format(label, preds[0][i] * 100)
cv2.putText(output, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(0, 0, 255), 2)# 绘图
cv2.imshow("Image", output)
cv2.waitKey(0)

增加数据增强,BatchNormalization层并训练100EPOCH得到的训练结果:

使用上述得到的网络模型进行测试:

首次运行predict程序出现如下问题:

cv2.error: OpenCV(4.6.0) C:\b\abs_f8n1j3l9l0\croot\opencv-suite_1691622637237\work\modules\highgui\src\window.cpp:1267: error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Cocoa support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'

解决方法:在对应环境中依次输入以下代码

安装opencv-python

pip install opencv-python

安装opencv-contrib-python 

pip install opencv-contrib-python 

安装过慢可以使用国内的镜像源:

清华:https://pypi.tuna.tsinghua.edu.cn/simple

阿里云:http://mirrors.aliyun.com/pypi/simple/

中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/

华中理工大学:http://pypi.hustunique.com/

山东理工大学:http://pypi.sdutlinux.org/ 

豆瓣:http://pypi.douban.com/simple/

pip install opencv-python  -i https://pypi.tuna.tsinghua.edu.cn/simple

测试结果: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/248352.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Tomcat与网络1】史前时代—没有Spring该如何写Web服务

在前面我们介绍了网络与Java相关的问题, 最近在调研的时候发现这块内容其实非常复杂,涉及的内容多而且零碎,想短时间梳理出整个体系是不太可能的,所以我们还是继续看Tomcat的问题,后面有网络的内容继续补充吧。 目录 …

酒店|酒店管理小程序|基于微信小程序的酒店管理系统设计与实现(源码+数据库+文档)

酒店管理小程序目录 目录 基于微信小程序的酒店管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员模块的实现 (1) 用户信息管理 (2) 酒店管理员管理 (3) 房间信息管理 2、小程序序会员模块的实现 (1)系统首页 &#xff0…

Visual Studio 2022 打开“程序包管理器控制台”失败

Visual Studio 2022 打开“程序包管理器控制台”失败 昨天下午,正在用Visual studio 2022写代码,当使用EF core 做数据迁移时,需要用到“程序包管理器控制台”,打开失败,前一秒还好好的,怎么突然就用不了了…

excel给数据库初始化/旧数据处理(自动sql拼装)

思路: 首先导出数据到excel编写单条数据操作的sql利用excel CONCATENATE 函数自动生成,每一行数据的操作sql 小技巧:对于需要套娃的字段值,可以加一个临时列同样使用CONCATENATE函数进行sql拼装 案例: 1.临时列:CONCATENATE(C2, …

【计算机网络】网络的网络

网络的网络 客户 customer 接入ISP提供商 provider 全球承载ISP多个ISP的层级结构 第一层ISP (tier-1 ISP ) 位于顶部 区域ISP (reginal ISP)Level 3通信 ,AT&T,Sprint ,NTT存在点&#x…

嘿嘿,vue之输出土味情话

有点好玩&#xff0c;记录一下。通过按钮调用网站接口&#xff0c;然后解构数据输出土味情话。 lovetalk.vue: <!--vue简单框架--> <template> <!-- 这是一个div容器&#xff0c;用于显示土味情话 --> <div class"talk"> <!-- 当点…

记录springboot bug

mybatis bug mapper 自动生成xml 产生错误 首先我这个bug十分奇怪,不管是报错,还是解决方法 首先,我还原我bug的过程 我首先要在 ordersMapper生成一个方法 本来是这样的方法 Mapper public interface OrdersMapper extends BaseMapper<Orders> {List<GoodsSales…

故障诊断 | 一文解决,LSTM长短期记忆神经网络故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍模型描述源码设计参考资料效果一览 文章概述 故障诊断模型 | Maltab实现LSTM长短期记忆神经网络故障诊断 专栏介绍 订阅【故障诊断】专栏,不定期更新机器学习和深度学习在故障诊断中的应用;订阅

扫地机器人(二分算法+贪心算法)

1. if(robot[i]-len<sweep)这个代码的意思是——如果机器人向左移动len个长度后&#xff0c;比现在sweep的位置&#xff08;现在已经覆盖的范围&#xff09;还要靠左&#xff0c;就是覆盖连续不起来&#xff0c;呢么这个len就是有问题的&#xff0c;退出函数&#xff0c;再…

React Native学习记录

一、创建RN项目的时候是空文件夹的问题 1.使用npx react-native init RNDemos初始化项目的时候&#xff0c;会报错&#xff0c;模版错误&#xff0c;然后创建出来一个空的文件夹 2.如果出现这种情况&#xff0c;需要设置npm install -g react-native-cli 3.安装完成以后再次初…

iOS开发Xcode中的ld64和-ld_classic是什么意思

在iOS应用程序开发中&#xff0c;Xcode是一款广泛使用的集成开发环境&#xff08;IDE&#xff09;&#xff0c;而链接器是构建应用程序的关键组成部分之一。在Xcode中&#xff0c;我们常常会遇到两个重要的概念&#xff1a;ld64和-ld_classic。它们分别代表了默认链接器和经典链…

【大厂AI课学习笔记】1.3 人工智能产业发展(1)

我国人工智能政策&#xff0c;分为5个阶段。从探索期&#xff0c;到后面的4个阶段。 MORE:&#xff08;以下为文心一言4.0的参考内容&#xff0c;和腾讯课程资料的分阶段&#xff0c;略有不同&#xff09; 我国的人工智能政策发展可以大致分为以下几个阶段&#xff0c;每个阶段…

深度学习快速入门--7天做项目

深度学习快速入门--7天做项目 0. 引言1. 本文内容2. 深度学习是什么3. 项目是一个很好的切入点4. 7天做项目4.1 第一天&#xff1a;数据整理4.2 第二天&#xff1a;数据处理4.3 第三天&#xff1a;简单神经网络设计4.4 第四天&#xff1a;分析效果与原因4.5 第五天&#xff1a;…

Linux网络编程——网络套接字初识

文章目录 1. IP地址2. 端口号3. 初识TCP协议 && UDP协议4. 网络字节序5. socket创建API 1. IP地址 举个例子&#xff1a; 《西游记》中&#xff0c;唐僧要去取件&#xff0c;总是说从“东土大唐”来&#xff0c;前往“西天”拜佛求经&#xff0c;从哪里来&#xff0c;…

Linux安装Jdk8

本文以centos7为例&#xff0c;一步一步进行jdk1.8的安装。 1. 下载安装 笑小枫网站下载&#xff1a;https://xiaoxiaofeng.com/resource/16 官网下载链接&#xff1a; https://www.oracle.com/cn/java/technologies/downloads/#java8 上传jdk的压缩包到服务器的/usr/local目…

基于Matlab无刷直流电机系统仿真建模的新方法

摘 要&#xff1a;在分析无刷直流电机&#xff08;BLDC&#xff09;数学模型的基础上&#xff0c;提出了无刷直流电机系统仿真建模的 新方法。在Matlab/Simulink 中&#xff0c;建立独立的功能模块&#xff0c;如BLDC 本体模块、电流滞环控制模块、 速度控制模块等&#xff0c;…

compose部署tomcat

1.部署tomcat 1.1.下载相关镜像tomcat8.5.20 $ docker pull tomcat:8.5.20 1.2 在/data目录下创建tomcat/webapps目录 mkdir -p /data/tomcat/webapps 注意&#xff1a;这里是准备将宿主机的/data/tomcat/webapps映射到容器的 /usr/…

如何在有或没有备份的 iPhone 上检索已删除的短信

iPhone 清理垃圾短信时不小心删除了一些重要短信&#xff1f;想知道如何找回 iPhone 上已删除的短信吗&#xff1f;如果您已将设备备份到 iCloud 或 iTunes&#xff0c;则可以从备份恢复 iPhone 上的短信。如果没有备份&#xff0c;您可以尝试第三方iPhone短信恢复程序来恢复它…

qt5-入门

参考&#xff1a; qt学习指南 Qt5和Qt6的区别-CSDN博客 Qt 学习之路_w3cschool Qt教程&#xff0c;Qt5编程入门教程&#xff08;非常详细&#xff09; 本地环境&#xff1a; win10专业版&#xff0c;64位 技术选择 Qt5力推QML界面编程。QML类似HTML&#xff0c;可以借助CSS进…

消息中间件RabbitMQ介绍

一、基础知识 1. 什么是RabbitMQ RabbitMQ是2007年发布&#xff0c;是一个在AMQP(高级消息队列协议)基础上完成的&#xff0c;简称MQ全称为Message Queue, 消息队列&#xff08;MQ&#xff09;是一种应用程序对应用程序的通信方法&#xff0c;由Erlang&#xff08;专门针对于大…