一步步带你敲卷积网络识别猫狗图片算法,步骤详细思路清晰。本文章利用 模块化模型解决猫狗图片识别问题。
构建一个网络模型基本由这四个步骤逐步搭建:
- 构建网络模型
- 准备及处理数据集
- 定义损失函数和优化器
- 训练和测试
文章还会对训练好的模型进行测试使用,延伸利用图像的函数做训练过程数据的可视化,分享数据训练的情况。
1、构建网络模型
首先先构建Alex Net网络模型,我把网络模型写在一个独立的文件上,模块化,我后期可以替换模型来训练数据集。
Alex Net :
这是Alex Net模型的结构图,没有复杂的结构,就是CONV卷积层和Max pool最大池化的堆叠,最后连到全连接层并做Softmax的分类,网络输出的是1000,但是我们做的是猫狗的分类只需要2个答案,所以1000的输出在做一层线性转换为2输出即可。
tips:每次卷积后要做Rule激活
网络模型结构细分步骤(依次往下走): |
---|
Conv(输入:3,输出:96,卷积核:11*11,步数:4) |
Max pool(卷积核:3*3,步数:2) |
Relu |
Conv(输入:96,输出:256,卷积核:5*5,padding:2) |
Max pool(卷积核:3*3,步数:2) |
Relu |
Conv(输入:256,输出:384,卷积核:3*3,padding:1) |
Relu |
Conv(输入:384,输出:384,卷积核:3*3,padding:1) |
Relu |
Conv(输入:384,输出:256,卷积核:3*3,padding:1) |
Max pool(卷积核:3*3,步数:2) |
Relu |
Linear(输入:4096,输出:4096) |
Linear(输入:4096,输出:2048) |
Linear(输入:2048,输出:1000) |
Linear(输入:1000,输出:2) |
第一层Linear的输入是通过卷积后的数据变形成一维的数据得到的,可以先不填让系统报错得到:
这里把网络模型另外写出了一个文件net.py:
import torch
import torch.nn.functional as f
'''Alex net '''
class MyAlexNet(torch.nn.Module):
def __init__(self):
'''定义子类和参数'''
super(MyAlexNet, self).__init__()
self.conv1 = torch.nn.Conv2d(3,96,kernel_size=11,stride=4)
self.mp = torch.nn.MaxPool2d(kernel_size=3,stride=2)
self.conv2 = torch.nn.Conv2d(96,256,kernel_size=5,padding=2)
self.conv3 = torch.nn.Conv2d(256,384,kernel_size=3,padding=1)
self.conv4 = torch.nn.Conv2d(384,384,kernel_size=3,padding=1)
self.conv5 = torch.nn.Conv2d(384,256,kernel_size=3)
self.Linear1 = torch.nn.Linear(1,4096)
self.Linear2 = torch.nn.Linear(4096,2048)
self.Linear3 = torch.nn.Linear(2048,1000)
self.Linear4 = torch.nn.Linear(1000,2)
def forward(self,x):
'''网络构建'''
batch_size =x.size(0)#x.Size([1, 3, 224, 224])
x = f.relu(self.mp(self.conv1(x)))
x = f.relu(self.mp(self.conv2(x)))
x = f.relu(self.conv3(x))
x = f.relu(self.conv4(x))
x = f.relu(self.conv5(x))
x = self.mp(x)
x = x.view(batch_size,-1)#(数据维度,数据长度)-1是指让电脑自动运算数据得到
x = self.Linear1(x)
x = f.dropout(x, p=0.5) # 防止过拟合,有50%的数据随机失效
x = self.Linear2(x)
x = f.dropout(x,p=0.5)
x = self.Linear3(x)
x = f.dropout(x, p=0.5)
x = self.Linear4(x)
return x
model = MyAlexNet()
2、准备及处理数据集
数据集链接: https://pan.baidu.com/s/1CTPq-ttZXX_MJsXaRz3vDg
提取码: cofr
拿到的数据集是只有两个Cat和Dog文件,文件需要做些预处理:
1.建立train训练的数据集和val验证的数据集并存入数据
2.载入数据,并利用transform图像预处理包,对图像进行预处理:大小统一设置为224*224、数据类型转换为Pytorch可处理的tensor形式。读取图像数据,将可视化的图像处理为数字信息用于计算。
建立train和val数据文件,train存入80%数据val存入20%,我们直接用python的os模块来分块,代码主要功能分为三步,第一步检测是否,没有就生成,第二步创建train和val文件夹,第三步把区分好的数据传入train和val文件中。
流程图:
建立和划分数据的代码split_data.py:
import os
from shutil import copy
import random
def mkfile(file):
if not os.path.exists(file):
os.makedirs(file)#如果没有file文件就创建一个
# 获取data文件夹下所有文件夹名(即需要分类的类名)
file_path = '/Users/aixuexi_pro/PycharmProjects/pytorch/torch/Alex net 猫狗识别/data_name'
flower_class = [cla for cla in os.listdir(file_path)]
# 创建 训练集train 文件夹,并由类名在其目录下创建5个子目录
mkfile('data/train')
for cla in flower_class:
mkfile('data/train/' + cla)
# 创建 验证集val 文件夹,并由类名在其目录下创建子目录
mkfile('data/val')
for cla in flower_class:
mkfile('data/val/' + cla)
# 划分比例,训练集 : 验证集 = 8 : 2
split_rate = 0.2
# 遍历所有类别的全部图像并按比例分成训练集和验证集
for cla in flower_class:
cla_path = file_path + '/' + cla + '/' # 某一类别的子目录
images = os.listdir(cla_path) # iamges 列表存储了该目录下所有图像的名称
num = len(images)
eval_index = random.sample(images, k=int(num * split_rate)) # 从images列表中随机抽取 k 个图像名称
for index, image in enumerate(images):
'''保存图像进文件中'''
# eval_index 中保存验证集val的图像名称
if image in eval_index:
image_path = cla_path + image
new_path = 'data/val/' + cla
copy(image_path, new_path) # 将选中的图像复制到新路径
# 其余的图像保存在训练集train中
else:
image_path = cla_path + image
new_path = 'data/train/' + cla
copy(image_path