一、序言

本项目环境 python 3.8,keras 2.6.0,opencv 4.5.4.58,tensorflow 2.6.0,使用pycharm编译器。
意在使用现有主流框架实现AlexNet经典网络并对猫狗数据集进行训练,实现猫狗的图像分类功能。

目录结构:

  • data中存有三个文件,image文件夹中猫狗图片各存放三张;model文件夹中有txt文件,存放猫0狗1用于分类;dataset.txt文件中为所有训练照片的索引文字
  • logs文件夹中存放大量训练集训练好的图片,以h5文件格式存储
  • model文件夹中存放AlexNet网络的具体实现
  • train文件夹中为猫狗数据集
  • Test图片文件用于最后训练完毕后的测试功能

二、AlexNet的设计

此文件存放在model文件夹下,使用karas框架构建神经网络

AlexNet网络用于训练数据集,karas框架中的核心数据结构是模型(model),Keras里有两种搭建模型的方式,一种是序贯模型(Sequential),一种是函数式模型(Model)。本项目使用序贯模型构建神经网络,每增加网络,可以使用karas中add方法,顺序添加想要添加的神经网络层。

序贯模型是多个网络层的线性堆叠,也就是“一条路走到黑”。使用序列模型,首先我们要实例化Sequential类,之后就是使用该类的add函数加入我们想要的每一层,从而实现我们的模型。或者通过向Sequential模型传递一个layer的list来构造该模型。

from keras.models import Sequential
from keras.layers import Dense, Activation, Conv2D, MaxPooling2D, Flatten, Dropout, BatchNormalization#编写AlexNet模型用于训练数据集
#karas中的主要数据结构时模型model,提供完整计算图的方法def AlexNet(input_shape=(224, 224, 3), output_shape=2): #输入为224*224的像素大小,3通道输入# AlexNetmodel = Sequential() #使用karas中的sequential构建模型,序贯模型# 使用步长为4*4,大小为11的卷积核对图像进行卷积,输出的特征层为96层,输出的shape为(55,55,96);#(224-11)/4 = 53余1,余出来的再卷积一次,之前减去的第一次也算一次,故输出shape为55*55# 所建模型后输出为48特征层,AlexNet两个gpu各运算48#向模型中添加一个48个大小为11*11的卷积核,使用relu激活函数model.add(Conv2D( #c1层卷积操作filters=48, #卷积核个数kernel_size=(11, 11), #卷积形状strides=(4, 4), #卷积步长padding='valid', #padding设为valid,不进行扩充边缘input_shape=input_shape, #指定输入形状activation='relu' #激活函数))#单个gpu运算结束后得到55*55*48model.add(BatchNormalization()) #进行c1层的归一化,归一化也可以在池化之后做#归一化优化神经网络,加快训练速度甚至在提高准确度、降低损失度# 使用步长为2的最大池化层进行池化,此时输出的shape为(27,27,96)model.add(MaxPooling2D( #c1层的池化操作pool_size=(3, 3), #池化尺寸strides=(2, 2), #步长padding='valid' #不进行填充))#至此最终获得第一层卷积的feature map# 使用步长为1x1,大小为5的卷积核对图像进行卷积,输出的特征层为256层,输出的shape为(27,27,256);# 所建模型后输出为128特征层model.add( #c2层卷积核padding为2,步长为1Conv2D( #c2层卷积操作filters=128,kernel_size=(5, 5),strides=(1, 1),padding='same', #padding为same,卷积核中心与像素点相交时开始运算,运算后得到的像素与之前相同activation='relu'))model.add(BatchNormalization())# 使用步长为2的最大池化层进行池化,此时输出的shape为(13,13,256);  (27-3)/2 = 12model.add( #c2层的池化操作MaxPooling2D(pool_size=(3, 3),strides=(2, 2),padding='valid'))# 使用步长为1x1,大小为3的卷积核对图像进行卷积,输出的特征层为384层,输出的shape为(13,13,384);# 所建模型后输出为192特征层model.add(Conv2D( #c3层卷积操作,没有做池化和归一化的操作filters=192,kernel_size=(3, 3),strides=(1, 1),padding='same',activation='relu'))# 使用步长为1x1,大小为3的卷积核对图像进行卷积,输出的特征层为384层,输出的shape为(13,13,384);# 所建模型后输出为192特征层model.add(Conv2D( #c4层卷积操作,没有做池化和归一化的操作filters=192,kernel_size=(3, 3),strides=(1, 1),padding='same',activation='relu'))# 使用步长为1x1,大小为3的卷积核对图像进行卷积,输出的特征层为256层,输出的shape为(13,13,256);# 所建模型后输出为128特征层model.add(Conv2D( #c5层卷积和操作filters=128,kernel_size=(3, 3),strides=(1, 1),padding='same',activation='relu'))# 使用步长为2的最大池化层进行池化,此时输出的shape为(6,6,256); (13-3)/2 = 5model.add(MaxPooling2D( #c5层池化操作pool_size=(3, 3),strides=(2, 2),padding='valid'))# 三个全连接层,最后输出为1000类,这里改为2类# 缩减为1024model.add(Flatten()) #把多维的输入一维化,用在从卷积层到全连接层的过渡#将一个维度大于或等于3的高维矩阵,“压扁”为一个二维矩阵。即保留第一个维度(如:batch的个数),然后将剩下维度的值相乘作为“压扁”矩阵的第二个维度。model.add(Dense(1024, activation='relu')) #Dense为全连接层,全连接输出的维度为1024,激活函数为relumodel.add(Dropout(0.25)) #缓解过拟合,实现正则化,0.25为失活比例,随机四分之一的数据失活model.add(Dense(1024, activation='relu')) #再加一层全连接层model.add(Dropout(0.25)) #再加一层Dropoutmodel.add(Dense(output_shape, activation='softmax')) #输出为2类,激活函数为softmax#sofemax经常用于分类,返回的值时该类别的指数概率,在0-1之间return model

三、准备数据

将准备好的猫与狗的数据集分别写入0和1为标签的dataset中,可以用这个模块随时添加数据

import os #opreating system包photos = os.listdir("./data/image/train/") #返回指定目录下的所有文件和目录名,文件夹里有猫狗各三张照片# 该部分用于将cat和dog的图片进行分类,0为猫,1为狗,并写入大数据集dataset.txt
with open("data/dataset.txt","w") as f:for photo in photos:name = photo.split(".")[0] #name为cat/dog,通过name判断if name=="cat":f.write(photo + ";0\n") #写入dataset.txt中cat.0.jpg;0elif name=="dog":f.write(photo + ";1\n")
f.close()

util文件中编写三个函数用于在训练时处理数据,使用tensorflow与opencv框架

import matplotlib.image as mpimg
import numpy as np
import cv2
import tensorflow as tfdef resize_image(image, size): #将图片的大小重塑with tf.name_scope('resize_image'): #name_scope函数用与规定范围与标签,增加区域名‘resize_image’images = []for i in image:i = cv2.resize(i, size) #将image中的每个图片重塑为size大小images.append(i) #加入修改后的iimages = np.array(images) #返回数组return imagesdef print_answer(argmax): #输入的是输出数组中的索引with open("./data/model/index_word.txt", "r", encoding='utf-8') as f: #文件中设置猫0狗1synset = [l.split(";")[1][:-1] for l in f.readlines()]return synset[argmax] #返回猫/狗

四、训练数据

训练数据使用之前设定好的AlexNet神经网络,使用karas,opencv包

from keras.callbacks import  ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from keras.utils import np_utils
from model.AlexNet import AlexNet #model包,AlexNet.py中的AlexNet函数
import numpy as np
import utils
import cv2
from keras import backend as K #backend为karas中后端包,可用于处理卷积,可以使用三个后端引擎(TensorFlow、Theano、CNTK)K.set_image_data_format('channels_last') #返回默认图像的维度顺序,将图像的通道数放在返回参数中的最后def generate_arrays_from_file(lines, batch_size): #参数为batch,batch的数目# 获取总长度n = len(lines)i = 0while 1:X_train = []Y_train = []# 获取一个batch_size大小的数据for b in range(batch_size): #batch中的每一个数据处理后加入XY两个数组中if i == 0:np.random.shuffle(lines) #当i = 0时,为每个batch的第一个数据,此时打乱lines中的数据name = lines[i].split(';')[0] #提取出txt文件中的;之前的名字,即为猫或狗的图片名称# 从文件中读取图像img = cv2.imread(r"E:\\Pycharm\\workspace\\OpenCV\\cifer\\train" + '\\' + name) #opencv读入为BGR,值为0-255img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #将图像转为RGB图像img = img / 255 #全部变为0-1之间的值X_train.append(img) #X_train中加入img的所有像素值,数量和Y_train相等Y_train.append(lines[i].split(';')[1]) #Y_train中为原数据中的;后的值(0或1)i = (i + 1) % n # 读完一个batch周期后重新开始# 处理图像X_train = utils.resize_image(X_train, (224, 224)) #将X_trian中每个图像重定义为224*224大小,用于使用AlexNet模型进行训练X_train = X_train.reshape(-1, 224, 224, 3) #-1为通配符,python自动识别224*224*3的数据个数Y_train = np_utils.to_categorical(np.array(Y_train), num_classes=2) #karas中函数,用于设值2个类别(0,1)和(1,0)作为猫狗分类yield (X_train, Y_train) #返回值为yield,作为生成器,带有 yield 的函数不再是一个普通函数#返回的是输入数据集图像重塑后,标签设置后的X与Y数据集if __name__ == "__main__": #只有在本脚本可以直接运行# 模型保存的位置log_dir = "./logs/"# 打开数据集的txt,读文件操作readwith open('E:\\Pycharm\\workspace\\OpenCV\\cifer\\data\\dataset.txt', 'r', encoding='UTF-8') as f:lines = f.readlines() #readLine读取所有文件# 打乱行,这个txt主要用于帮助读取数据来训练# 打乱的数据更有利于训练np.random.seed(10101) #随机数种子,用于保证后面随机数生成的结果一样,每次随机生成前定义种子才能得到相同随机值#算法会根据种子值计算出随机值,故确定seed值后生成随机数不会变np.random.shuffle(lines) #改变序列的内容来修改序列的位置,修改lines中的各个元素顺序np.random.seed(None)# 90%用于训练,10%用于估计。num_val = int(len(lines) * 0.1) #百分之十的长度num_train = len(lines) - num_val #百分之九十的长度# 建立AlexNet模型,model中返回由keras框架构建的AlexNet模型model = AlexNet() #karas的数据结构model赋值为AlexNet函数的返回值# 保存的方式,3世代保存一次,即epoch三次保存一次,一次epoch为训练所有数据集checkpoint_period1 = ModelCheckpoint( #karas框架中的方法,回调函数,将每3个epoch的结果保存到路径下log_dir + 'last1.h5', #将epoch的模型保存到此路径monitor='acc', #需要监视的值,准确率save_weights_only=False, #保存整个模型,若TRUE则只保留权重save_best_only=True, #只保存在验证集上性能最好的模型period=3 #间隔的epoch数)#在运行过程中可能效率不会提升,这时可能会用到下降学习率的方式# 学习率下降的方式,acc三次不下降就下降学习率继续训练reduce_lr = ReduceLROnPlateau(monitor='acc',factor=0.5, #缩放学习率的值,每次*1/2patience=3, #当3个epoch过后性能不再提升,则下降学习率verbose=1)# 是否需要早停,当val_loss一直不下降的时候意味着模型基本训练完毕,可以停止early_stopping = EarlyStopping(monitor='val_loss', #检测值为验证集的损失函数min_delta=0, #对于小于0的变化不关心,即为所有变化都会影响是否提前停止patience=10, #10个epoch都没有效率提升则结束verbose=1)#交叉熵,编译创建好的模型,网络模型搭建完后,需要对网络的学习过程进行配置#用于在配置训练方法时,告知训练时用的优化器、损失函数和准确率评测标准,均为karas自带model.compile(loss='categorical_crossentropy',optimizer='sgd',metrics=['accuracy'])# 一次的训练集大小batch_size = 128#输出为训练集个数,验证集个数,一次的训练集大小print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))# 开始训练,利用Python的生成器,逐个生成数据的batch并进行训练# karas中sequence生成器(generator)model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size), #lines为百分之九十数据集(训练集)steps_per_epoch=max(1, num_train // batch_size), #每个epoch中需要执行多少次generator,最少1次,//为整除算法validation_data=generate_arrays_from_file(lines[num_train:], batch_size), #用于验证,不参与计算,百分之十(验证集)validation_steps=max(1, num_val // batch_size), #每个epoch中执行多少次generatorepochs=50, #迭代次数(世代)initial_epoch=0,callbacks=[checkpoint_period1, reduce_lr]) #训练时用之前设定好的的回调函数model.save_weights(log_dir + 'last1.h5') #只保留其训练出的的模型参数

五、预测图像

predict文件用来测试训练好的网络能否使用测试数据分类猫狗

import numpy as np
import utils
import cv2from keras import backend as K
from model.AlexNet import AlexNetK.set_image_data_format('channels_last') #返回的值中最后的值为通道数if __name__ == "__main__":model = AlexNet() #返回AlexNet的模型model.load_weights("./logs/last1.h5") #加载已训练好的h5文件img = cv2.imread("D:\\Image\\gou.jpg") #img为需要验证的猫或狗的图片img_RGB = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #将img转为RGB模式img_nor = img_RGB/255 #此时为(488,500,3)的数据,将像素值降到0-1之见img_nor = np.expand_dims(img_nor,axis = 0) #用于扩展数组形状,在0的维数处增加一个维度,变为(1,488,500,3)的数据img_resize = utils.resize_image(img_nor,(224,224)) #改变数组大小为(224,224)arr = model.predict(img_resize) #返回的值为得出的每一种类别的概率,predict函数为karas中自带print(arr) #输出为以一维数组,有两个值,分别为是猫的概率和是狗的概率if(arr[0][0]>0.9):print(utils.print_answer(np.argmax(arr)))#argmax返回数组中最大值的索引elif(arr[0][1]>0.9):print(utils.print_answer(np.argmax(arr)))cv2.imshow("test_img",img)cv2.waitKey(0)

六、结果测试

根据训练好的h5文件用karas预测

karas + opencv 实现AlexNet神经网络应用于图像分类相关推荐

  1. cnn卷积神经网络应用_卷积神经网络(CNN):应用的核心概念

    cnn卷积神经网络应用 In this tutorial, we'll work through the core concepts of convolutional neural networks ...

  2. 一个关于卷积神经网络应用于图像语义分割的PPT

    转自:https://yhlleo.github.io/2016/10/19/CNN-SemanticSeg/ 把前段时间自己整理的一个关于卷积神经网络应用于图像语义分割的PPT整理发布在本篇博客内, ...

  3. bp神经网络应用实例_自监督图神经网络

    近年来,深度学习在视觉以及自然语言处理等领域取得了革命性的进步,但是诸如图像与自然语言之类的数据往往是高度结构与顺序化的.然而实际中大多数数据并无此特性,例如人际关系.社交网络.蛋白质分子结构等等,这 ...

  4. 时雨月五| AI机器学习实战の电磁导航智能车中神经网络应用的问题与思考

    "不愤不启,不悱不发.举一隅不以三隅反,则不复也". – <论语·述而> 再次将论语中的这句"不愤不启,不悱不发"引用在这里,说明学生的学习的活动部 ...

  5. 【深度学习】CNN神经网络应用(用于亚洲大黄蜂分类)

    [深度学习]CNN神经网络应用(用于亚洲大黄蜂分类) 文章目录 1 概述 2 假设条件 3 网络结构 4 数据集和参数 5 Asian hornet classification experiment ...

  6. DeepLearning tutorial(5)CNN卷积神经网络应用于人脸识别(详细流程+代码实现)

    DeepLearning tutorial(5)CNN卷积神经网络应用于人脸识别(详细流程+代码实现) @author:wepon @blog:http://blog.csdn.net/u012162 ...

  7. 论文解读丨图神经网络应用于半结构化文档的命名实体识别和关系提取

    摘要: 随着用于传递和记录业务信息的管理文档的广泛使用,能够鲁棒且高效地从这些文档中自动提取和理解内容的方法成为一个迫切的需求.本次解读的文章提出利用图神经网络来解决半结构化文档中的实体识别(NER) ...

  8. 人工智能 人工神经网络,人工神经网络应用实例

    人工智能应用在哪些方面呢?能举几个典型的例子吗? 人工智能应用的领域非常广泛,随着人工智能的不断发展,这些都会一一实现.1.智能制造领域. 标准化工业制造中信息感知,自主控制,系统协调,个性化定制,检 ...

  9. 神经网络应用较多的算法,图卷积神经网络应用

    神经网络原理及应用 神经网络原理及应用1.什么是神经网络?神经网络是一种模拟动物神经网络行为特征,进行分布式并行信息处理的算法. 这种网络依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从 ...

最新文章

  1. centos 更换java版本_centos7 更换jdk版本
  2. D3DPOOL(资源池)
  3. C++ stringstream的用法
  4. java backlog满_java socket参数详解:BackLog
  5. 区块链中的数学 - EdDSA签名机制
  6. 漫画让你秒懂5G黑科技....
  7. flutter打包出的问题
  8. OpenCV读取多幅图片,读取系列图片,读取文件夹中指定图像类型的系列图片
  9. oracle备份文件命令,oracle备份命令使用实例
  10. 【2017-04-16】抽象类、接口、构造函数、重载和重写的区别、静态成员和方法
  11. java jax ws_Java 7是否包含JAX-WS实现或API?
  12. 北航计算机录取最低分,2019年北京航空航天大学考研复试最低分数要求_北航各科目分数线-聚英北航考研网...
  13. Excel学习笔记一关于色彩
  14. 数据库并发问题 封锁协议 隔离级别
  15. OfficePlus 微软官方大量 模板与图片素材 可供个人免费下载试用
  16. Bootstrap4从入门到精通视频教程
  17. 深度长文:Power Automation 帮助企业实现数字化转型
  18. 转载:domain adaption
  19. 记安装win10和deepin双系统的经过(附一些常见问题和解决方案)
  20. 基于WIN10的ElasticSearch部署实践

热门文章

  1. Angular 组件类测试
  2. linux运行lnk,LNK 文件扩展名: 它是什么以及如何打开它?
  3. JavaScript选项卡/页签/Tab的实现
  4. java中的JDBC是什么
  5. 形式化语言——时序逻辑
  6. 安装2008 R2 SQL,在安装程序支持文件时页面闪退
  7. CTF-SMB信息泄露【简单易懂】
  8. matlab六轴直线插补代码
  9. Js实现获取当前时间并显示
  10. 用css写一个向下的箭头