AlexNet 实现猫狗分类

前言

在训练网络过程中遇到了很多问题,先在这里抱怨一下,没有硬件条件去使用庞大的ImageNet2012 数据集 。所以在选择合适的数据集上走了些弯路,最后选择有kaggle提供的猫狗数据集,因为二分类问题可能训练起来比较容易一些。实验结果和代码我放在kaggle上了,有时会加载不出来。ipynb文件百度云里面也有 下载完成后用jupyter打开。下面附上链接

内容 地址
数据集 链接
kaggle实验过程 链接
百度云ipynb文件 链接 提取码:di7c

好,我们开始介绍吧!

AlexNet简介

首先呢,AlexNet是2012年,由Alex Krizhevsky、 llya Sutskever 和 Geoffrey E. Hinton 提出来的一种卷积神经网络模型,并获得了2012年ILSVRC图像分类大赛的冠军,自此呢也掀起了深度学习的热潮。神经网络通常都是直接上图比较直观。


看上去好像 很复杂的样子,其实由于当时硬件条件限制,所以将图片分成了两个部分,分别用两块GPU进行训练,分别放置了一半的卷积核。相比上一篇提到的LeNet, 它有很多优点。如下表所示:

技巧 AlexNet LeNet
Relu,多GPU 训练速度块 训练速度慢
局部响应归一化 提高了精度,缓解过拟合
数据扩充,丢失输出 减少过拟合

这里有争议的就是局部响应归一化(Local Response Normalization,简称LRN),在它之后有论文证明局部响应归一化并没有太大作用,我第一次实验也用的局部响应归一化但效果并不好,后面采用的是批标准化(BatchNormalization, 简称BN)。

网络结构

网络节后从图中可以详细看出,这里就不再进行赘述,我们可以看看keras搭建好的AlexNet网络结构:

Model: "AlexNet"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_3 (InputLayer)         [(None, 224, 224, 3)]     0
_________________________________________________________________
zero_padding2d_2 (ZeroPaddin (None, 227, 227, 3)       0
_________________________________________________________________
conv_block_1 (Conv2D)        (None, 55, 55, 96)        34944
_________________________________________________________________
max_pooling_1 (MaxPooling2D) (None, 27, 27, 96)        0
_________________________________________________________________
batch_normalization_12 (Batc (None, 27, 27, 96)        384
_________________________________________________________________
conv_block_2 (Conv2D)        (None, 27, 27, 256)       614656
_________________________________________________________________
max_pooling_2 (MaxPooling2D) (None, 13, 13, 256)       0
_________________________________________________________________
batch_normalization_13 (Batc (None, 13, 13, 256)       1024
_________________________________________________________________
conv_block_3 (Conv2D)        (None, 13, 13, 384)       885120
_________________________________________________________________
max_pooling_3 (MaxPooling2D) (None, 6, 6, 384)         0
_________________________________________________________________
batch_normalization_14 (Batc (None, 6, 6, 384)         1536
_________________________________________________________________
conv_block_4 (Conv2D)        (None, 6, 6, 384)         1327488
_________________________________________________________________
conv_block_5 (Conv2D)        (None, 6, 6, 256)         884992
_________________________________________________________________
max_pooling_5 (MaxPooling2D) (None, 2, 2, 256)         0
_________________________________________________________________
batch_normalization_15 (Batc (None, 2, 2, 256)         1024
_________________________________________________________________
flatten (Flatten)            (None, 1024)              0
_________________________________________________________________
fc_1 (Dense)                 (None, 4096)              4198400
_________________________________________________________________
dropout_1 (Dropout)          (None, 4096)              0
_________________________________________________________________
batch_normalization_16 (Batc (None, 4096)              16384
_________________________________________________________________
fc_2 (Dense)                 (None, 4096)              16781312
_________________________________________________________________
dropout_2 (Dropout)          (None, 4096)              0
_________________________________________________________________
batch_normalization_17 (Batc (None, 4096)              16384
_________________________________________________________________
dense_2 (Dense)              (None, 1000)              4097000
=================================================================
Total params: 28,860,648
Trainable params: 28,842,280
Non-trainable params: 18,368

可以清楚的看到每一层网络的输入输出及节点数。我们不用ImageNet2012作为训练数据,这里直接用一块GPU训练就好。

注意事项

由于输入是224x224x3(HWC)大小的图片,但实际运算时使用的是227x227x3(HWC)大小的图片。所以又要进行填0操作:

 x = ZeroPadding2D(((3, 0), (3, 0)))(img_input)

下面请看详细代码:

  1. 构建网络模型:
#定义网络结构
import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Flatten, Lambda, MaxPooling2D, Dropout, Input, Dense,ZeroPadding2D,BatchNormalization
from tensorflow.python.keras import backend
from tensorflow.python.keras.engine import training
from tensorflow.python.keras.utils import layer_utils
from tensorflow.keras import optimizers, losses, initializers
def alexnet(input_shape=(224, 224, 3), input_tensor=None,classes=1000):if input_tensor is None:img_input = Input(shape=input_shape)else:if not backend.is_keras_tensor(input_tensor):img_input = Input(tensor=input_tensor, shape=input_shape)else:img_input = input_tensorx = ZeroPadding2D(((3, 0), (3, 0)))(img_input)# 第一个块x = Conv2D(filters=96, kernel_size=(11, 11), kernel_initializer=initializers.RandomNormal(stddev=0.01),strides=4, padding='valid', name='conv_block_1', activation='relu')(x)x = MaxPooling2D(pool_size=(3, 3), strides=2, name='max_pooling_1')(x)
#     x = Lambda(tf.nn.local_response_normalization, name='lrn_1')(x)x=BatchNormalization()(x)# 第二个块x = Conv2D(filters=256, kernel_size=(5, 5),kernel_initializer=initializers.RandomNormal(stddev=0.01),strides=1, padding='same', activation='relu', name='conv_block_2')(x)x = MaxPooling2D(pool_size=(3, 3), strides=2, name='max_pooling_2')(x)
#     x = Lambda(tf.nn.local_response_normalization, name='lrn_2')(x)x=BatchNormalization()(x)# 第三个块x = Conv2D(filters=384, kernel_size=(3, 3),kernel_initializer=initializers.RandomNormal(stddev=0.01),strides=1, padding='same', activation='relu', name='conv_block_3')(x)x = MaxPooling2D(pool_size=(3, 3), strides=2, name='max_pooling_3')(x)x=BatchNormalization()(x)# 第四到第五块x = Conv2D(filters=384, kernel_size=(3, 3),kernel_initializer=initializers.RandomNormal(stddev=0.01),strides=1, padding='same', activation='relu', name='conv_block_4')(x)x = Conv2D(filters=256, kernel_size=(3, 3),kernel_initializer=initializers.RandomNormal(stddev=0.01),strides=1, padding='same', activation='relu', name='conv_block_5')(x)x = MaxPooling2D(pool_size=(3, 3), strides=2, name='max_pooling_5')(x)x=BatchNormalization()(x)# 这个是将卷积接口一维化 用于链接全连接x = Flatten(name='flatten')(x)# 全连接层x = Dense(4096, name='fc_1', activation='relu')(x)x=Dropout(0.4,name='dropout_1')(x)x=BatchNormalization()(x)x = Dense(4096, name='fc_2', activation='relu')(x)x = Dropout(0.4, name='dropout_2')(x)x=BatchNormalization()(x)x=Dense(classes,activation='softmax')(x)if input_tensor is not None:inputs = layer_utils.get_source_inputs(input_tensor)else:inputs = img_inputmodel = training.Model(inputs, x, name='AlexNet')return model
model =alexnet(classes=2)
model.summary()

代码里注解得有LRN的使用方法,感兴趣的话可以自己去调试。

  1. 数据集加载:
    这里借助的是kaggle得在线平台,直接在kaggle上使用在线数据集。自己使用时记得改路径。
import os
train_data_dir =r'../input/cat-and-dog/training_set/training_set'
test_data_dir =r'../input/cat-and-dog/test_set/test_set'
IMG_WEIGHT=224
IMG_HEIGHT=224
IMG_CHANEL=3
floders = os.listdir(train_data_dir)
NUM_Categories=len(os.listdir(train_data_dir))
print(NUM_Categories) #这里总共会有2个分类
for floder in floders:path = train_data_dir+'/'+floderprint(floder.split('-')[-1]) #查看标签读取是否正确import cv2
from PIL import Image
import numpy as np
floders = os.listdir(train_data_dir)
image_data=[] #用于保存分类
image_labels=[] #用于保存标签
type_dict={}  #下表和所属类别对应
index =-1 #用于字典下表和标签
for floder in floders:index+=1#从0开始编号path = train_data_dir+'/'+floderprint('loading '+path)type_dict[index]=floder.split('-')[-1]images = os.listdir(path)for img in images:try:  #加入异常判断 防止读取的时候 出错image = cv2.imread(path+'/'+img)img_fromarray =Image.fromarray(image,'RGB')img_resize = img_fromarray.resize((IMG_WEIGHT,IMG_HEIGHT))image_data.append(np.array(img_resize))image_labels.append(index)except Exception as err: #防止出错print(err)print('Error in '+img)
  1. 数据转换及验证集划分:
image_data=np.array(image_data,np.float32)
image_labels=np.array(image_labels,np.int)
print(image_data.shape,image_labels.shape)rom tensorflow import keras
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(image_data, image_labels, train_size=0.7,random_state=42,shuffle=True)
del image_data  #删除不适用得变量,防止内存溢出
del image_labels #删除不适用得变量,防止内存溢出
X_train = X_train / 255.0 #归一化
X_val = X_val / 255.0 #归一化
y_train = keras.utils.to_categorical(y_train,NUM_Categories)
y_val = keras.utils.to_categorical(y_val,NUM_Categories)
print("X_train.shape", X_train.shape)
print("X_valid.shape", X_val.shape)
print("y_train.shape", y_train.shape)
print("y_valid.shape", y_val.shape)
  1. 数据数量可视化: 这里主要是为了 看样本之前得数量占比,防止某一样本数量过少,导致模型收敛过慢,个别类别学习特征较少,导致模型泛化能力
    较差。
import matplotlib.pyplot as plt
def visual_train_data(train_path,classes):"""
​:param train_path: 训练数据路径:param classes: 标签字典 如classes = { 0:'Speed limit (20km/h)',1:'Speed limit (30km/h)',2:'Speed limit (50km/h)',3:'Speed limit (60km/h)',4:'Speed limit (70km/h)'}:return:"""folders = os.listdir(train_path)train_num = []class_num = []index=0for folder in folders:train_files = os.listdir(train_path + '/' + folder)train_num.append(len(train_files))class_num.append(classes[index])index+=1zipped_lists = zip(train_num, class_num)sorted_pair = sorted(zipped_lists)tuples = zip(*sorted_pair)  # 这里是解压# 这个人一定是脑子有问题才压缩之后还要解压,还要用 tuples来遍历train_num, class_num = [list(tuple) for tuple in tuples]plt.figure(figsize=(21, 10))plt.bar(class_num, train_num)plt.xticks(class_num, rotation='vertical')plt.show()visual_train_data(train_data_dir,type_dict)
  1. 模型训练配置:
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import Adam,SGD
lr=0.0001
epochs=20
opt=Adam(lr=lr,decay=lr/(epochs/0.5))
model = alexnet(classes=2)
model.compile(loss='categorical_crossentropy',optimizer=opt,metrics=['acc'])
aug = ImageDataGenerator( #这里设置数据增强,提高模型得泛化能力rotation_range=10,zoom_range=0.15,width_shift_range=0.1,height_shift_range=0.1,shear_range=0.15,horizontal_flip=False,vertical_flip=False,fill_mode='nearest'
)
history = model.fit(X_train, y_train, batch_size=50,epochs=epochs, validation_data=(X_val, y_val))
  1. 测试集加载与测试:
del X_train #同样是为了防止内存溢出
del y_train
del X_val
del y_val
import cv2
from PIL import Image
import numpy as np
floders = os.listdir(test_data_dir)
test_data=[] #用于保存分类
test_labels=[] #用于保存标签
test_dict={}  #下表和所属类别对应
index =-1 #用于字典下表和标签
for floder in floders:index+=1#从0开始编号path = test_data_dir+'/'+floderprint('loading '+path)test_dict[index]=floder.split('-')[-1]images = os.listdir(path)for img in images:try:  #加入异常判断 防止读取的时候 出错image = cv2.imread(path+'/'+img)img_fromarray =Image.fromarray(image,'RGB')img_resize = img_fromarray.resize((IMG_WEIGHT,IMG_HEIGHT))test_data.append(np.array(img_resize))test_labels.append(index)except Exception as err:print(err)print('Error in '+img)test_data=np.array(test_data,np.float32)
test_labels=np.array(test_labels,np.int)
print(test_labels.shape,test_labels.shape)
test_data = test_data / 255.0 #归一化
test_labels = keras.utils.to_categorical(test_labels,NUM_Categories)
model.evaluate(test_data,test_labels
  1. 这里是最后的准确率:
64/64 [==============================] - 12s 171ms/step - loss: 0.6805 - acc: 0.8052
[0.680515706539154, 0.805239737033844]
  1. 训练过程可视化:
import pandas as pd
pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid(True)
plt.gca().set_ylim(0, 3)
plt.show()
model.save('my_model.h5')

pytorch复现

pytoch的复现主要是实现网络结构,数据读取可以参考其他教程。
下面我们看详细代码:

from numpy import zeros
from torch import nn
from torch.nn.modules import activation, module
import torch
from torchsummary import summary
class AlexNet(nn.Module):def __init__(self,classes=7):super(AlexNet,self).__init__()#第一个块,这里的padding=3 是由于 数据集使用的是224*224的图像,padding=3 self.zeropadding2d=nn.ZeroPad2d(padding=(3,0,3,0))self.conv1=nn.Conv2d(in_channels=3,out_channels=96,kernel_size=(11,11),stride=4) self.relu1 = nn.ReLU()self.maxpool1=nn.MaxPool2d(kernel_size=(3,3),stride=2)#第二个块self.conv2=nn.Conv2d(in_channels=96,out_channels=256,kernel_size=(5,5),padding='same',stride=1)self.relu2 = nn.ReLU()self.maxpool2=nn.MaxPool2d(kernel_size=(3,3),stride=2)#第三个快self.conv3=nn.Conv2d(in_channels=256,out_channels=384,kernel_size=(5,5),padding='same',stride=1)self.relu3 = nn.ReLU()self.maxpool3=nn.MaxPool2d(kernel_size=(3,3),stride=2)#第四~五块self.conv4=nn.Conv2d(in_channels=384,out_channels=384,kernel_size=(3,3),padding='same',stride=1)self.conv5=nn.Conv2d(in_channels=384,out_channels=256,kernel_size=(3,3),padding='same',stride=1)self.relu4 = nn.ReLU()self.maxpool4=nn.MaxPool2d(kernel_size=(3,3),stride=2)#self.globalmax=nn.AdaptiveAvgPool2d()self.flatten=nn.Flatten()self.linear1=nn.Linear(in_features=1024,out_features=4096)self.linear_relu1 = nn.ReLU()self.linear2=nn.Linear(in_features=4096,out_features=4096)self.linear_relu2 = nn.ReLU()self.linear3=nn.Linear(in_features=4096,out_features=classes)self.softmax=nn.Softmax()#定义计算过程def forward(self,x):x=self.zeropadding2d(x)x=self.conv1(x)x=self.relu1(x)x=self.maxpool1(x)x=self.conv2(x)x=self.relu2(x)x=self.maxpool2(x)x=self.conv3(x)x=self.relu3(x)x=self.maxpool3(x)x=self.conv4(x)x=self.conv5(x)x=self.relu4(x)x=self.maxpool4(x)x=self.flatten(x)#linear connectx=self.linear1(x)x=self.linear_relu1(x)x=self.linear2(x)x=self.linear_relu2(x)x=self.linear3(x)self.softmax(x)return xdevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
x=torch.randn((1,3,224,224))
model=AlexNet().to(device)
summary(model,input_size=(3,224,224))

pytorch复现以类的形式复现,在_init_ 函数中定义网络的主要结构,包括,卷积,池化,激活函数,归一化等,这样更有注意了解网络结构。在forward 中定义前向传播过程,对网络的计算过程有更深刻的理解。
需要大家去定义网络的数据加载和训练过程,可以参考前一篇 LetNet中的train_one_epoch和 evaluate 函数。

总结:

从头开始训练一个模型太难了,所以还是了解一下迁移学习吧。我个人感觉目前的数据集和硬件条件,是深度学习面临的最大挑战。从AlexNet中学到的东西就是怎样减少过拟合。但我的理论推导有些欠缺。以后会尝试添加一点理论推导。下一篇可能做ZFNet,但它仅仅在AlexNet上有一点点创新。如把11x11的卷积核改为7x7,只用一个GPU训练等。

参考:

书籍:
深度学习:卷积神经网络从入门到精通作者:李玉鑑 张婷 单传辉 刘兆英ISBN:9787111602798版次:1-1字数:258出版社:机械工业出版社
链接:
[1]https://blog.csdn.net/qq_35912099/article/details/107237182
[2]https://zhuanlan.zhihu.com/p/141530560
[3]https://blog.csdn.net/DeepLearningJay/article/details/107971526

AlexNet 实现猫狗分类(keras and pytorch)相关推荐

  1. DL之AlexNet:利用卷积神经网络类AlexNet实现猫狗分类识别(图片数据增强→保存h5模型)

    DL之AlexNet:利用卷积神经网络类AlexNet实现猫狗分类识别(图片数据增强→保存h5模型) 目录 利用卷积神经网络类AlexNet实现猫狗分类识别(图片数据增强→保存h5模型) 设计思路 处 ...

  2. Pytorch采用AlexNet实现猫狗数据集分类(训练与预测)

    Pytorch采用AlexNet实现猫狗数据集分类(训练与预测) 介绍 AlexNet网络模型 猫狗数据集 AlexNet网络训练 训练全代码 预测 预测图片 介绍 AlexNet模型是CNN网络中经 ...

  3. 【CNN】搭建AlexNet网络——并处理自定义的数据集(猫狗分类)

    前言 2012年,AlexNet横空出世.它首次证明了学习到的特征可以超越手工设计的特征.它一举打破了计算机视觉研究的现状. AlexNet使用了8层卷积神经网络,并以很大的优势赢得了2012年Ima ...

  4. Pytorch+CNN+猫狗分类实战

    文章目录 0.前言 1.猫狗分类数据集 1.1数据集下载(可选部分) 1.2数据集分析 2.猫狗分类数据集预处理 2.1训练集和测试集划分 2.2训练集和测试集读取 3.剩余代码 4.总结 0.前言 ...

  5. 【深度学习】ResNet残差网络 ResidualBlock残差块实现(pytorch) | 跟着李沐学AI笔记 | ResNet18进行猫狗分类

    文章目录 前言 一.卷积的相关计算公式(复习) 二.残差块ResidualBlock复现(pytorch) 三.残差网络ResNet18复现(pytorch) 四.直接调用方法 五.具体实践(ResN ...

  6. 基于Pytorch的猫狗分类

    无偿分享~ 猫狗二分类文件下载地址 在下一章说        猫狗分类这个真是困扰我好几天,找了好多资料都是以TensorFlow的猫狗分类,但我们要求的是以pytorch的猫狗分类.刚开始我找到了也 ...

  7. 基于Pytorch实现猫狗分类

    基于Pytorch实现猫狗分类 一.环境配置 二.数据集准备 三.猫狗分类的实例 四.实现分类预测测试 五.参考资料 一.环境配置 1.环境使用 Anaconda 2.配置Pytorch pip in ...

  8. PyTorch深度学习实战 | 猫狗分类

    本文内容使用TensorFlow和Keras建立一个猫狗图片分类器. 图1 猫狗图片 01.安装TensorFlow和Keras库 TensorFlow是一个采用数据流图(data flow grap ...

  9. 基于MATLAB的Alexnet迁移学习进行猫狗分类(数据集:Kaggle)

    基本介绍 软件:Matlab R2018b 数据集:Kaggle猫狗数据集 网络:AlexNet 前期准备 数据集 Kaggle猫狗数据集猫与狗用于训练的图片(train)分别12500张,每张图片的 ...

最新文章

  1. 系统技术方案 系统构架_构架系统时应注意的事项
  2. 你是如何自学 Python 的?
  3. Git 工作流的正确打开方式
  4. .Net高并发解决思路(转)
  5. SIFT四部曲之——高斯滤波
  6. 百度api:根据经纬度获取地理位置信息
  7. 如何启用SAP CRM text的html编辑器
  8. 微软为.NET程序员带来了最优的跨平台开发体验-WSL
  9. Unable to resolve dependency问题解决
  10. IT男1-10分打分标准,请对号入座!
  11. discuz集思街淘宝客模板
  12. Python借助百度搜索引擎爬取Python小屋密切相关文章
  13. 嵌入式大杂烩周记 | 第 7 期:zlog
  14. Weblogic安装部署步骤
  15. cisco下模拟Linux防火墙,linux下配置cisco防火墙日志服务器
  16. cle IMP-00015: 由于对象已存在, 下列语句失败
  17. CentOS 7 开机自启汇总
  18. 【看好了】如何使用fiddler实现手机抓包,Filters过滤器!
  19. 苹果6电池价格_格派 | 11月6日电池金属价格指数
  20. 功能监控器MAX706SESA中文资料

热门文章

  1. 前端学习笔记之流式布局(百分比布局) 3.24
  2. ad7606与stm32连接电路介绍
  3. 新生儿婴幼儿宝宝护理知识学习
  4. wifidog 源码初分析
  5. jetty 去掉项目名称访问
  6. C# 几种选择文件Filter文件后缀很全
  7. 在proteus中的排阻的查找_PROTEUS中这个排阻怎么找到?
  8. mongodb java api chm_MongoDB中文手册chm版
  9. HTML 随机点名 --个人写法
  10. Scrapy 爬取今日头条街拍图片