pytorch实现kaggle猫狗识别
参考:https://blog.csdn.net/weixin_37813036/article/details/90718310
深度学习的基础就是数据,咱们先从数据谈起。此次使用的猫狗分类图像一共25000张,猫狗分别有12500张。下载地址:https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data我们先来简单的看看都是一些什么图片。我们从下载文件里可以看到有两个文件夹:train和test1,分别用于训练和测试。打开train文件夹可以看到有25000 张小猫小狗的图片,图片名字为cat.0.jpg,cat.1.jpg,dog.0.jpg,dog.1.jpg。
data_transform = transforms.Compose([
transforms.Resize(),
transforms.CenterCrop(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
]) train_dataset = datasets.ImageFolder(root='./data2/train/',
transform=data_transform)
train_loader = torch.utils.data.DataLoader(train_dataset,
batch_size=batch_size,
shuffle=True,
num_workers=num_workers)
为方便训练过程,需要把训练集进行处理:把猫狗的图片分别放在cat,dog文件夹中,并划分出一部分图片作为测试集(与下载的测试集不同)。代码如下:
#接下来的数据是把原训练集90%的数据做训练,%做测试集,其中把分为训练集的数据内的猫和狗分开,分为测试集的数据的猫和狗进行分开保存在新的各自的目录下
# kaggle原始数据集地址
original_dataset_dir = 'D:\\Code\\Python\\Kaggle-Dogs_vs_Cats_PyTorch-master\\data\\train' #训练集地址
total_num = int(len(os.listdir(original_dataset_dir)) ) #训练集数据总数,包含猫和狗
random_idx = np.array(range(total_num))
np.random.shuffle(random_idx)#打乱图片顺序 # 待处理的数据集地址
base_dir = 'D:\\Code\\dogvscat\\data2' #把原训练集数据分类后的数据存储在该目录下
if not os.path.exists(base_dir):
os.mkdir(base_dir) # 训练集、测试集的划分
sub_dirs = ['train', 'test']
animals = ['cats', 'dogs']
train_idx = random_idx[:int(total_num * 0.9)] #打乱后的数据的90%是训练集,10是测试集
test_idx = random_idx[int(total_num * 0.9):int(total_num * )]
numbers = [train_idx, test_idx]
for idx, sub_dir in enumerate(sub_dirs):
dir = os.path.join(base_dir, sub_dir)#'D:\\Code\\dogvscat\\data2\\train'或'D:\\Code\\dogvscat\\data2\\test'
if not os.path.exists(dir):
os.mkdir(dir) animal_dir = "" #fnames = ['.{}.jpg'.format(i) for i in numbers[idx]]
fnames = ""
if sub_dir == 'train':
idx =
else:
idx =
for i in numbers[idx]:
#print(i)
if i>=:#把数据保存在dogs目录下
fnames = str('dog'+'.{}.jpg'.format(i))
animal_dir = os.path.join(dir,'dogs') if not os.path.exists(animal_dir):
os.mkdir(animal_dir)
if i<:#图片是猫,数据保存在cats目录下
fnames = str('cat'+'.{}.jpg'.format(i))
animal_dir = os.path.join(dir, 'cats')
if not os.path.exists(animal_dir):
os.mkdir(animal_dir)
src = os.path.join(original_dataset_dir, str(fnames)) #原数据地址
#print(src)
dst = os.path.join(animal_dir, str(fnames))#新地址
#print(dst)
shutil.copyfile(src, dst)#复制 # 验证训练集、测试集的划分的照片数目
print(dir + ' total images : %d' % (len(os.listdir(dir+'\\dogs'))+len(os.listdir(dir+'\\cats'))))
# coding=utf-
# 创建模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.maxpool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 53 * 53, 1024)
self.fc2 = nn.Linear(1024, 512)
self.fc3 = nn.Linear(512, 2) def forward(self, x):
x = self.maxpool(F.relu(self.conv1(x)))
x = self.maxpool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 53 * 53)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x) return x
class Net2(nn.Module):
def __init__(self):
super(Net2, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.maxpool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 53 * 53, 1024)
torch.nn.Dropout(0.5)
self.fc2 = nn.Linear(1024, 512)
torch.nn.Dropout(0.5)
self.fc3 = nn.Linear(512, 2) def forward(self, x):
x = self.maxpool(F.relu(self.conv1(x)))
x = self.maxpool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 53 * 53)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x) return x
我们从conv1说起。conv1实际上就是定义一个卷积层,3,6,5分别是什么意思?3代表的是输入图像的像素数组的层数,一般来说就是你输入的图像的通道数,比如这里使用的小猫图像都是彩色图像,由R、G、B三个通道组成,所以数值为3;6代表的是我们希望进行6次卷积,每一次卷积都能生成不同的特征映射数组,用于提取小猫和小狗的6种特征。每一个特征映射结果最终都会被堆叠在一起形成一个图像输出,再作为下一步的输入;5就是过滤框架的尺寸,表示我们希望用一个5 * 5的矩阵去和图像中相同尺寸的矩阵进行点乘再相加,形成一个值。定义好了卷基层,我们接着定义池化层。池化层所做的事说来简单,其实就是因为大图片生成的像素矩阵实在太大了,我们需要用一个合理的方法在降维的同时又不失去物体特征,所以深度学习学者们想出了一个称为池化的技术,说白了就是从左上角开始,每四个元素(2 * 2)合并成一个元素,用这一个元素去代表四个元素的值,所以图像体积一下子降为原来的四分之一。再往下一行,我们又一次碰见了一个卷积层:conv2,和conv1一样,它的输入也是一个多层像素数组,输出也是一个多层像素数组,不同的是这一次完成的计算量更大了,我们看这里面的参数分别是6,16,5。之所以为6是因为conv1的输出层数为6,所以这里输入的层数就是6;16代表conv2的输出层数,和conv1一样,16代表着这一次卷积操作将会学习小猫小狗的16种映射特征,特征越多理论上能学习的效果就越好,大家可以尝试一下别的值,看看效果是否真的编变好。conv2使用的过滤框尺寸和conv1一样,所以不再重复。
关于53这个数字可以根据((n+2p-f)/ s)+1计算出来。而三个全连接层所做的事很类似,就是不断训练,最后输出一个二分类数值。net类的forward函数表示前向计算的整个过程。forward接受一个input,返回一个网络输出值,中间的过程就是一个调用init函数中定义的层的过程。F.relu是一个激活函数,把所有的非零值转化成零值。此次图像识别的最后关键一步就是真正的循环训练操作。
进行训练的代码:
def train(): for epoch in range(epochs):
running_loss = 0.0
train_correct =
train_total =
for step, data in enumerate(train_loader, ):#第二个参数表示指定索引从0开始
inputs, train_labels = data
if use_gpu:
inputs, labels = Variable(inputs.cuda()), Variable(train_labels.cuda())
else:
inputs, labels = Variable(inputs), Variable(train_labels)
optimizer.zero_grad()
outputs = net(inputs)
_, train_predicted = torch.max(outputs.data, ) #返回每一行最大值的数值和索引,索引对应分类
train_correct += (train_predicted == labels.data).sum()
loss = cirterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
train_total += train_labels.size() print('train %d epoch loss: %.3f acc: %.3f ' % (
epoch + , running_loss / train_total, * train_correct / train_total))
# 模型测试
correct =
test_loss = 0.0
test_total =
test_total =
net.eval() #测试的时候整个模型的参数不再变化
for data in test_loader:
images, labels = data
if use_gpu:
images, labels = Variable(images.cuda()), Variable(labels.cuda())
else:
images, labels = Variable(images), Variable(labels)
outputs = net(images)
_, predicted = torch.max(outputs.data, )
loss = cirterion(outputs, labels)
test_loss += loss.item()
test_total += labels.size()
correct += (predicted == labels.data).sum()
完整的代码如下
# coding=utf-
import os
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data import Dataset
from torchvision import transforms, datasets, models
import shutil
from matplotlib import pyplot as plt
# 随机种子设置
random_state =
np.random.seed(random_state)
#接下来的数据是把原训练集90%的数据做训练,%做测试集,其中把分为训练集的数据内的猫和狗分开,分为测试集的数据的猫和狗进行分开保存在新的各自的目录下
# kaggle原始数据集地址
original_dataset_dir = 'D:\\Code\\Python\\Kaggle-Dogs_vs_Cats_PyTorch-master\\data\\train' #训练集地址
total_num = int(len(os.listdir(original_dataset_dir)) ) #训练集数据总数,包含猫和狗
random_idx = np.array(range(total_num))
np.random.shuffle(random_idx)#打乱图片顺序 # 待处理的数据集地址
base_dir = 'D:\\Code\\dogvscat\\data2' #把原训练集数据分类后的数据存储在该目录下
if not os.path.exists(base_dir):
os.mkdir(base_dir) # 训练集、测试集的划分
sub_dirs = ['train', 'test']
animals = ['cats', 'dogs']
train_idx = random_idx[:int(total_num * 0.9)] #打乱后的数据的90%是训练集,10是测试集
test_idx = random_idx[int(total_num * 0.9):int(total_num * )]
numbers = [train_idx, test_idx]
for idx, sub_dir in enumerate(sub_dirs):
dir = os.path.join(base_dir, sub_dir)#'D:\\Code\\dogvscat\\data2\\train'或'D:\\Code\\dogvscat\\data2\\test'
if not os.path.exists(dir):
os.mkdir(dir) animal_dir = "" #fnames = ['.{}.jpg'.format(i) for i in numbers[idx]]
fnames = ""
if sub_dir == 'train':
idx =
else:
idx =
for i in numbers[idx]:
#print(i)
if i>=:#把数据保存在dogs目录下
fnames = str('dog'+'.{}.jpg'.format(i))
animal_dir = os.path.join(dir,'dogs') if not os.path.exists(animal_dir):
os.mkdir(animal_dir)
if i<:#图片是猫,数据保存在cats目录下
fnames = str('cat'+'.{}.jpg'.format(i))
animal_dir = os.path.join(dir, 'cats')
if not os.path.exists(animal_dir):
os.mkdir(animal_dir)
src = os.path.join(original_dataset_dir, str(fnames)) #原数据地址
#print(src)
dst = os.path.join(animal_dir, str(fnames))#新地址
#print(dst)
shutil.copyfile(src, dst)#复制 # 验证训练集、测试集的划分的照片数目
print(dir + ' total images : %d' % (len(os.listdir(dir+'\\dogs'))+len(os.listdir(dir+'\\cats'))))
# coding=utf- # 配置参数
random_state =
torch.manual_seed(random_state) # 设置随机数种子,确保结果可重复
torch.cuda.manual_seed(random_state)# #为GPU设置种子用于生成随机数,以使得结果是确定的
torch.cuda.manual_seed_all(random_state) #为所有GPU设置种子用于生成随机数,以使得结果是确定的
np.random.seed(random_state)
# random.seed(random_state) epochs = # 训练次数
batch_size = # 批处理大小
num_workers = # 多线程的数目
use_gpu = torch.cuda.is_available()
PATH='D:\\Code\\dogvscat\\model.pt'
# 对加载的图像作归一化处理, 并裁剪为[224x224x3]大小的图像
data_transform = transforms.Compose([
transforms.Resize(),#重置图像分辨率
transforms.CenterCrop(), #中心裁剪
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) #归一化
]) train_dataset = datasets.ImageFolder(root='D:\\Code\\dogvscat\\data2\\train',
transform=data_transform)
print(train_dataset)
train_loader = torch.utils.data.DataLoader(train_dataset,
batch_size=batch_size,
shuffle=True,
num_workers=num_workers) test_dataset = datasets.ImageFolder(root='D:\\Code\\dogvscat\\data2\\test', transform=data_transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers) # 创建模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(, , )
self.maxpool = nn.MaxPool2d(, )
self.conv2 = nn.Conv2d(, , )
self.fc1 = nn.Linear( * * , )
self.fc2 = nn.Linear(, )
self.fc3 = nn.Linear(, ) def forward(self, x):
x = self.maxpool(F.relu(self.conv1(x)))
x = self.maxpool(F.relu(self.conv2(x)))
x = x.view(-, * * )
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x) return x
class Net2(nn.Module):
def __init__(self):
super(Net2, self).__init__()
self.conv1 = nn.Conv2d(, , )
self.maxpool = nn.MaxPool2d(, )
self.conv2 = nn.Conv2d(, , )
self.fc1 = nn.Linear( * * , )
torch.nn.Dropout(0.5)
self.fc2 = nn.Linear(, )
torch.nn.Dropout(0.5)
self.fc3 = nn.Linear(, ) def forward(self, x):
x = self.maxpool(F.relu(self.conv1(x)))
x = self.maxpool(F.relu(self.conv2(x)))
x = x.view(-, * * )
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x) return x net = Net2()
if(os.path.exists('D:\\Code\\dogvscat\\model.pt')):
net=torch.load('D:\\Code\\dogvscat\\model.pt') if use_gpu:
print('gpu is available')
net = net.cuda()
else:
print('gpu is unavailable') print(net)
trainLoss = []
trainacc = []
testLoss = []
testacc = []
x = np.arange(,)
# 定义loss和optimizer
cirterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9) def train(): for epoch in range(epochs):
running_loss = 0.0
train_correct =
train_total =
for step, data in enumerate(train_loader, ):#第二个参数表示指定索引从0开始
inputs, train_labels = data
if use_gpu:
inputs, labels = Variable(inputs.cuda()), Variable(train_labels.cuda())
else:
inputs, labels = Variable(inputs), Variable(train_labels)
optimizer.zero_grad()
outputs = net(inputs)
_, train_predicted = torch.max(outputs.data, ) #返回每一行最大值的数值和索引,索引对应分类
train_correct += (train_predicted == labels.data).sum()
loss = cirterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
train_total += train_labels.size() print('train %d epoch loss: %.3f acc: %.3f ' % (
epoch + , running_loss / train_total, * train_correct / train_total))
# 模型测试
correct =
test_loss = 0.0
test_total =
test_total =
net.eval() #测试的时候整个模型的参数不再变化
for data in test_loader:
images, labels = data
if use_gpu:
images, labels = Variable(images.cuda()), Variable(labels.cuda())
else:
images, labels = Variable(images), Variable(labels)
outputs = net(images)
_, predicted = torch.max(outputs.data, )
loss = cirterion(outputs, labels)
test_loss += loss.item()
test_total += labels.size()
correct += (predicted == labels.data).sum() print('test %d epoch loss: %.3f acc: %.3f ' % (epoch + , test_loss / test_total, * correct / test_total))
trainLoss.append(running_loss / train_total)
trainacc.append( * train_correct / train_total)
testLoss.append(test_loss / test_total)
testacc.append( * correct / test_total)
plt.figure()
plt.title('train')
plt.plot(x,trainacc,'r')
plt.plot(x,trainLoss,'b')
plt.show()
plt.figure()
plt.title('test')
plt.plot(x,testacc,'r')
plt.plot(x,testLoss,'b')
plt.show() torch.save(net, 'D:\\Code\\dogvscat\\model.pt') train()
看一下某次的运行结果
D:\anaconda\anaconda\pythonw.exe D:/Code/Python/pytorch入门与实践/第六章_pytorch实战指南/猫和狗二分类.py
D:\Code\dogvscat\data2\train\cats total images :
D:\Code\dogvscat\data2\test\dogs total images :
Net(
(conv1): Conv2d(, , kernel_size=(, ), stride=(, ))
(maxpool): MaxPool2d(kernel_size=, stride=, padding=, dilation=, ceil_mode=False)
(conv2): Conv2d(, , kernel_size=(, ), stride=(, ))
(fc1): Linear(in_features=, out_features=, bias=True)
(fc2): Linear(in_features=, out_features=, bias=True)
(fc3): Linear(in_features=, out_features=, bias=True)
)
train epoch loss: 0.162 acc: 61.000
test epoch loss: 0.153 acc: 66.000
train epoch loss: 0.148 acc: 68.000
test epoch loss: 0.143 acc: 71.000
train epoch loss: 0.138 acc: 71.000
test epoch loss: 0.138 acc: 72.000
train epoch loss: 0.130 acc: 74.000
test epoch loss: 0.137 acc: 72.000
train epoch loss: 0.119 acc: 77.000
test epoch loss: 0.132 acc: 74.000
train epoch loss: 0.104 acc: 81.000
test epoch loss: 0.129 acc: 75.000
train epoch loss: 0.085 acc: 85.000
test epoch loss: 0.132 acc: 75.000
train epoch loss: 0.060 acc: 90.000
test epoch loss: 0.146 acc: 75.000
train epoch loss: 0.036 acc: 94.000
test epoch loss: 0.200 acc: 74.000
train epoch loss: 0.022 acc: 97.000
test epoch loss: 0.207 acc: 75.000 Process finished with exit code
发现这个程序运行结果训练集准确率很高,测试集准确率为75%左右,因此Net类有点过拟合,Net2加入了Dropout降低网络复杂度处理过拟合。这个程序属于最基础的分类算法,因此准确率并不是很高,但是我认为初学者可以先会这个程序,再继续提高网络的准确率。
pytorch实现kaggle猫狗识别的更多相关文章
- 使用pytorch完成kaggle猫狗图像识别
kaggle是一个为开发商和数据科学家提供举办机器学习竞赛.托管数据库.编写和分享代码的平台,在这上面有非常多的好项目.好资源可供机器学习.深度学习爱好者学习之用.碰巧最近入门了一门非常的深度学习框架 ...
- 猫狗识别——PyTorch
猫狗识别 数据集下载: 网盘链接:https://pan.baidu.com/s/1SlNAPf3NbgPyf93XluM7Fg 提取密码:hpn4 1. 要导入的包 import os import ...
- 猫狗识别-CNN与VGG实现
本次项目首先使用CNN卷积神经网络模型进行训练,最终训练效果不太理想,出现了过拟合的情况.准确率达到0.72,loss达到0.54.使用预训练的VGG模型后,在测试集上准确率达到0.91,取得了不错的 ...
- keras猫狗图像识别
这里,我们介绍的是一个猫狗图像识别的一个任务.数据可以从kaggle网站上下载.其中包含了25000张毛和狗的图像(每个类别各12500张).在小样本中进行尝试 我们下面先尝试在一个小数据上进行训练, ...
- 深度学习原理与框架-猫狗图像识别-卷积神经网络(代码) 1.cv2.resize(图片压缩) 2..get_shape()[1:4].num_elements(获得最后三维度之和) 3.saver.save(训练参数的保存) 4.tf.train.import_meta_graph(加载模型结构) 5.saver.restore(训练参数载入)
1.cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR) 参数说明:image表示输入图片,image_size表示变 ...
- Kaggle系列1:手把手教你用tensorflow建立卷积神经网络实现猫狗图像分类
去年研一的时候想做kaggle上的一道题目:猫狗分类,但是苦于对卷积神经网络一直没有很好的认识,现在把这篇文章的内容补上去.(部分代码参考网上的,我改变了卷积神经网络的网络结构,其实主要部分我加了一层 ...
- 【猫狗数据集】pytorch训练猫狗数据集之创建数据集
猫狗数据集的分为训练集25000张,在训练集中猫和狗的图像是混在一起的,pytorch读取数据集有两种方式,第一种方式是将不同类别的图片放于其对应的类文件夹中,另一种是实现读取数据集类,该类继承tor ...
- paddlepaddle实现猫狗分类
目录 1.预备工作 1.1 数据集准备 1.2 数据预处理 2.训练 2.1 模型 2.2 定义训练 2.3 训练 3.预测 4.参考文献 声明:这是我的个人学习笔记,大佬可以点评,指导,不喜勿喷.实 ...
- Java中如何分析一个案列---猫狗案例为例
猫狗案例: 具体事务: 猫.狗 共性: 姓名.年龄.吃饭 分析:从具体到抽象 猫: 姓名.年龄--->成员变量 吃饭 ---> 成员方法 构造方法:无参.有参 狗: 姓名.年龄 ...
随机推荐
- Hive速览
一.概述 Hive由Facebook开源,是一个构建在Hadoop之上的数据仓库工具 将结构化的数据映射成表 支持类SQL查询,Hive中称为HQL 1.读模式 2.Hive架构 3.使用Hive的原 ...
- 【dart学习】-- Dart之函数
1. 指定返回值得函数 /** * 无返回值的函数 * params: 可以是任意类型(var和Object类型也可以任意类型). 当然这里的参数类型你可以随意指定我这里已dynamic为例 * 参数 ...
- MySql中创建存储过程
MySQL 存储过程是从 MySQL 5.0 开始增加的新功能.存储过程的优点有一箩筐.不过最主要的还是执行效率和SQL 代码封装.特别是 SQL 代码封装功能,如果没有存储过程,在外部程序访问数据库 ...
- elementUi-复选框,使用v-for循环出来的复选框,默认多个值为勾选状态
1. 使用 v-model="BottomSelectFor[index].tick" 绑定要默认勾选的状态 2.在数组中定义 tick:true,没有的字段默认为false 3. ...
- HBase与Hive交互操作案例
HBase与Hive交互操作 1.环境准备 因为我们后续可能会在操作Hive的同时对HBase也会产生影响,所以Hive需要持有操作HBase的Jar,那么接下来拷贝Hive所依赖的Jar包(或者使用 ...
- MySql命令行无法显示中文
好烦遇到了,遇到MySql命令行无法显示中文问题????? show variables like 'char%';//显示字符集 set names utf8;//设置字符集 describer t ...
- CSS:CSS Positioning(定位)
ylbtech-CSS:CSS Positioning(定位) 1.返回顶部 1. CSS Positioning(定位) position 属性指定了元素的定位类型. position 属性的四个值 ...
- svn启动服务
bin目录添加到环境变量classpathsvn --version 查看版本svnadmin create D:\\xx 创建本地中央仓库启动svn服务 cmd命令 svnserve -d -r D ...
- Vim用法AAAAA
.linux系统中如何进入退出vim编辑器,方法及区别 我们当然要保存并退出了,然后下一步了.这时,我们要按键盘左上角的"ESC",留意到了没有?左下角的插入状态不见了,如图. 然 ...
- vbs 之 解决打开Excel文件格式与扩展名指定格式不一致的问题
' Q:解决打开Excel文件格式与扩展名指定格式不一致的问题' A: 使用工作簿saveAs时,往往忽略掉它的第二个参数FileFormat,添加即可. 比如: set bookDiff = oEx ...