【猫狗数据集】定义模型并进行训练模型

时间:2022-07-23
本文章向大家介绍【猫狗数据集】定义模型并进行训练模型,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

2020.3.10

发现数据集没有完整的上传到谷歌的colab上去,我说怎么计算出来的step不对劲。

测试集是完整的。

训练集中cat的确是有10125张图片,而dog只有1973张,所以完成一个epoch需要迭代的次数为:

(10125+1973)/128=94.515625,约等于95。

顺便提一下,有两种方式可以计算出数据集的量:

第一种:print(len(train_dataset))

第二种:在../dog目录下,输入ls | wc -c

今天重新上传dog数据集。

分割线-----------------------------------------------------------------

数据集下载地址:

链接:https://pan.baidu.com/s/1l1AnBgkAAEhh0vI5_loWKw 提取码:2xq4

之前准备好了数据集:

创建数据集:https://www.cnblogs.com/xiximayou/p/12398285.html

读取数据集:https://www.cnblogs.com/xiximayou/p/12422827.html

这节我们要定义模型然后开始进行训练啦。

首先还是在谷歌colab中的目录如下:

其中rdata是我们读取数据的文件,将其进行改造一下:

from torch.utils.data import DataLoader
import torchvision
import torchvision.transforms as transforms
import torch

def load_dataset(batch_size):
  #预处理
  transform = transforms.Compose([transforms.RandomResizedCrop(224),transforms.ToTensor()])
  path = "/content/drive/My Drive/colab notebooks/data/dogcat"
  train_path=path+"/train"
  test_path=path+"/test"
  #使用torchvision.datasets.ImageFolder读取数据集指定train和test文件夹
  train_data = torchvision.datasets.ImageFolder(train_path, transform=transform)
  train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=1)
  
  test_data = torchvision.datasets.ImageFolder(test_path, transform=transform)
  test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=True, num_workers=1)
  """
  print(train_data.classes)  #根据分的文件夹的名字来确定的类别
  print(train_data.class_to_idx) #按顺序为这些类别定义索引为0,1...
  print(train_data.imgs) #返回从所有文件夹中得到的图片的路径以及其类别

  print(test_data.classes)  #根据分的文件夹的名字来确定的类别
  print(test_data.class_to_idx) #按顺序为这些类别定义索引为0,1...
  print(test_data.imgs) #返回从所有文件夹中得到的图片的路径以及其类别
  """
  return train_loader,test_loader,train_data,test_data

进行数据增强时,我们暂时只选择两种,一是将图片随机切割成224×224大小,因为大多数网络的输入大小是这个,同时将其转换成tensor。这里需要注意的是:ToTensor()要在所有的数据增强之后,除了标准化。因为ToTensor()会将图像转换为pytorch的tensor类型,同时还会将每个像素转换为0-1之间的数值。

最终我们要返回的是train_loader,test_loader,train_data,test_data。

train_loader,test_loader:就不必多说了,用于加载数据集的

train_data,test_data:传过去这个是为了获取数据集的长度。

然后在train.py中就可以定义模型并进行训练了。

resnet.py中是存储的resnet的模型,这里是从pytorch中的torchvision中的resnet拷贝过来的,当然我们也可以直接使用torchvision中的模型,里面封装了很多模型。

模型结构:

ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace=True)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=2, bias=False)
)

在train.py中,我们一步步来解析:

import sys
#为了避免找不到相应目录下的文件,将该目录加入到path中
sys.path.append("/content/drive/My Drive/colab notebooks")
from utils import rdata
from model import resnet
import torch.nn as nn
import torch
import numpy as np
import torchvision

#设置随机种子
np.random.seed(0)
torch.manual_seed(0)
torch.cuda.manual_seed_all(0)

#torch.backends.cudnn.deterministic一般设置成True即可
#如果网络的结构不是经常变换的,也就是固定的,将
#torch.backends.cudnn.benchmark设置True
torch.backends.cudnn.deterministic = True
#torch.backends.cudnn.benchmark = False
torch.backends.cudnn.benchmark = True

#将模型和数据放入到gpu中有两种方式,一种是model.to(device),另一种是model.cuda()
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

#就是每次输入到网络中图像的个数
batch_size=128
#读取数据
train_loader,test_loader,train_data,test_data=rdata.load_dataset(batch_size)
#为了方便起见,我们直接从torchvision中获得模型,但是该模型默认是imagenet数据集,类别有1000类,我们通过以下方式获取非预训练的模型,并修改最后全连接层为2类
model =torchvision.models.resnet18(pretrained=False)
model.fc = nn.Linear(model.fc.in_features,2,bias=False)
model.cuda()
#print(model) 

#定义训练的epochs
num_epochs=50
#定义学习率
learning_rate=0.01
#定义损失函数
criterion=nn.CrossEntropyLoss()
#optimizer #=torch.optim.Adam(model.parameters(),lr=learning_rate)
#定义优化方法,简单起见,就是用带动量的随机梯度下降
optimizer = torch.optim.SGD(params=model.parameters(), lr=0.1, momentum=0.9,
                          weight_decay=1*1e-4)
# 计算step
total_step = len(train_loader)
#定义模型训练函数
def train():
  #打印每一个epoch的输出
  for epoch in range(num_epochs):
      #为了计算每个epoch的损失
      tot_loss = 0.0
      #计算每个epoch的正确的个数
      correct = 0
      #i是step,images是图片张量,lables是标签
      for i ,(images, labels) in enumerate(train_loader):
          #将数据放入到GPU中
          images = images.cuda()
          labels = labels.cuda()

          # Forward pass
          #图片张量送入网络计算输出
          outputs = model(images)
          #取得概率大的那个结果
          _, preds = torch.max(outputs.data,1)
          loss = criterion(outputs, labels)

          # Backward and optimizer
          #反向传播优化网络参数
          optimizer.zero_grad()
          loss.backward()
          optimizer.step()
          #累加每个step的损失
          tot_loss += loss.data
          #每隔2个step就打印当前损失
          if (i+1) % 2 == 0:
              print('Epoch: [{}/{}], Step: [{}/{}], Loss: {:.4f}'
                    .format(epoch+1, num_epochs, i+1, total_step, loss.item()))
          #统计正确的个数
          correct += torch.sum(preds == labels.data).to(torch.float32)
      ### Epoch info ####
      #epoch损失
      epoch_loss = tot_loss/len(train_data)
      print('train loss: ', epoch_loss)
      #epoch准确率
      epoch_acc = correct/len(train_data)
      print('train' + ' acc: ', epoch_acc)
train()


    

关于step、epoch、batch_size之间的关系可以看:

https://www.cnblogs.com/xiximayou/p/12405485.html

最后,我们在test.ipynb中输入命令进行训练,不过先要进入到train目录下:

cd /content/drive/My Drive/colab notebooks/train

然后输入:

!python train.py

看下部分结果:

然后到第一个epoch完成:

再到最后一个epoch完成:

有93%的准确率了。这还仅仅是简单的训练。

发现train loss和train acc中输出不太好,这样处理一下:

epoch_loss = tot_loss/len(train_data)

print('train loss: {:.4f}'.format(epoch_loss))

epoch_acc = correct/len(train_data)

print('train acc: {:.4f}',.format(epoch_acc))

下一节:存储模型并进行测试。