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目錄下:
然后到第一個epoch完成:

再到最后一個epoch完成:

有93%的准確率了。這還僅僅是簡單的訓練。
發現train loss和train acc中輸出不太好,這樣處理一下:
