【貓狗數據集】定義模型並進行訓練模型


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))
 
下一節:存儲模型並進行測試。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM