pytorch fourteen: pytorch combat (cats and dogs binary)

Binary cats and dogs is a classic game on kaggle data set available for download at the official website kaggle, its training set contains 25 000.

In doing deep learning projects often require the following sections:

  • Model definition
  • Data processing and loading
  • Configuration parameters
  • Training model (train & validate)
  • test

About __init__.py 

It can be seen almost every folder has __init__.py, if a directory contains a file __init__.py, then it becomes a package (package). __init__.py can be empty or can define the properties and methods of the package, but it must be present, other program modules, or to import the corresponding function from this directory. And dataset.py example __init__.py two files in the data / folder, in order to be introduced dataset.py function or class in other functions (such as defined herein dataset.py DogCat class file), in other function you can import DogCat introduced DogCat classes from data.dataset.

Model definition

Folder under models have defined the AlexNet and ResNet34 peer networks, used here AlexNet network model.

from torch import nn
class AlexNet(nn.Module):
    def __init__(self,num_class=2):
        nn.Module.__init__(self)
        
        self.features = nn.Sequential(
            #conv1
            nn.Conv2d(3,96,kernel_size=11,stride=4),
            nn.ReLU(inplace=True),#对原变量进行覆盖
            nn.MaxPool2d(kernel_size=3,stride=2),
            nn.ReLU(inplace=True),

            #conv2
            nn.Conv2d(96,256,kernel_size=5,padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3,stride=2),
            nn.ReLU(inplace=True),

            #conv3
            nn.Conv2d(256,384,kernel_size=3,padding=1),
            nn.ReLU(inplace=True),

            #conv4
            nn.Conv2d(384,384,kernel_size=3,padding=1),
            nn.ReLU(inplace=True),

            #conv5
            nn.Conv2d(384,256,kernel_size=3,padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3,stride=2)   
        )
        self.classifier = nn.Sequential(
            #fc6
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),

            #fc7
            nn.Linear(4096,4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),

            #fc8
            nn.Linear(4096,num_class)
        )
    def forward(self,x):
        x = self.features(x)
        x = x.view(x.size(0),256 * 6 * 6)
        x = self.classifier(x)
        return x  

Loading

import os
import numpy as np
import torch as t
from torchvision import transforms as T
from torch.utils import data
from PIL import Image

class DogCat(data.Dataset):
    def __init__(self,root,transforms=None,train=True,test=False):
        self.test = test
        #获取所有图片地址
        imgs = [os.path.join(root,img) for img in os.listdir(root)]
        imgs = sorted(imgs,key = lambda x: int(x.split('.')[-2]))
        imgs_num = len(imgs)
        
        #划分训练集、验证集,验证:训练=3:7
        if self.test:
            self.imgs = imgs
        elif train:
            self.imgs = imgs[:int(0.7*imgs_num)]
        else:
            self.imgs = imgs[int(0.7*imgs_num):]
        
        #如果用户没有自定义数据转换工作,用默认的
        if transforms is None:
            #测试验证和训练的数据转换有所区别
            #测试集和验证集
            normalize = T.Normalize(mean = [0.485,0.456,0.406],std=[0.229,0.224,0.225])
            if self.test or not train:
                self.transforms = T.Compose([
                    T.Resize(224), #长宽比不变,保持最短边为224
                    T.CenterCrop(224),#中心裁切
                    T.ToTensor(),
                    normalize
                ])
            else:
                self.transforms = T.Compose([
                    T.Resize(256),
                    T.RandomResizedCrop(224),
                    T.RandomHorizontalFlip(),
                    T.ToTensor(),
                    normalize
                ])
    def __getitem__(self,index):
        img_path = self.imgs[index]
        label = 1 if 'dog' in img_path.split('.')[-3] else 0
        data = Image.open(img_path)
        data = self.transforms(data)
        return data,label
    
    def __len__(self):
        #返回数据集中所有图片的个数
        return len(self.imgs)

Configuration parameters

class DefaultConfig(object):
    #使用的模型
    model = 'AlexNet'
    #训练集路径
    train_data_root = './samples/sub_training_set/'
    #测试集路径
    test_data_root = './samples/sub_test_set/'
    #加载预训练模型的路径,为None代表不加载
    load_model_path = None
    #批处理大小
    batch_size = 2
    #进程个数
    num_workers = 0
    #学习率
    lr = 0.1
    lr_decay = 0.95#when val_loss increase,lr=lr*0.95
    weight_decay = 1e-4 #损失函数
    max_epoch = 10

    #根据字典kwargs更新config参数
    def parse(self,kwargs):
        #更新配置参数
        for k,v,in kwargs.items():
            if not hasattr(self,k):
                print('has not attribut %s'%k)
            setattr(self,k,v)
    
    #hasattr(self,k):判断sekf里是否有k属性
    #setattr(self,k,v):给self里的k属性赋值为v
    #getattr(self,k):获得self的k属性

 

 

Trainer

import fire
from models.AlexNet import AlexNet
from data.dataset import DogCat
from torch.utils import data
import torch as t
from torch.autograd import Variable as V
from torchnet import meter
from config import DefaultConfig
import numpy as np

opt = DefaultConfig()

def train(**kwargs):
    #根据命令行参数更新配置
    opt.parse(kwargs)
    
    #step1:模型
    model = AlexNet()
    if opt.load_model_path:
        model.load_state_dict(t.load(opt.load_model_path))
    
    #step2:数据
    #训练数据
    train_data = DogCat(opt.train_data_root,train=True)
    #验证数据
    val_data = DogCat(opt.train_data_root,train=False)
    #由训练数据构成批量的数据,神经网络有效的输入格式,即增加了一个batch_size维度
    train_dataloader = data.DataLoader(train_data,batch_size=opt.batch_size,shuffle=True)
    #批量的验证数据,神经网络有效的输入格式
    val_dataloader = data.DataLoader(val_data,batch_size=opt.batch_size,shuffle=False)
    
    #step3:目标函数和优化器,交叉熵损失函数(内部其实就是softmax机制)
    criterion = t.nn.CrossEntropyLoss()
    lr = opt.lr
    #随机梯度下降优化模型
    optimizer = t.optim.SGD(model.parameters(),lr = lr,weight_decay=opt.weight_decay)
    
    #step4:统计指标:平滑处理之后的损失,还有混淆矩阵
    loss_meter = meter.AverageValueMeter()
    previous_loss = 1e10
    
    #训练
    for epoch in range(opt.max_epoch):
        loss_meter.reset()
        for i,(datas,labels) in enumerate(train_dataloader):
            #训练模型参数
            input = V(datas)
            target = V(labels)
            optimizer.zero_grad()#梯度清零
            score = model(input)
            loss = criterion(score,target)
            loss.backward()
            #所有optimizer都实现了step()方法,调用这个方法可以更新参数
            #每次用backward()这类方法计算出了梯度后,就可以调用一次这个方法来更新参数。
            optimizer.step()
            
            #更新统计指标
            loss_meter.add(loss.data)
            
        t.save(model.state_dict(),'AlexNet.pth')
        
        #计算验证集上的指标及可视化
        val_accuracy = val(model,val_dataloader)
        print(val_accuracy)
        #如果损失不再下降,则降低学习率
        if loss_meter.value()[0] > previous_loss:
            lr = lr * opt.lr_decay
            for param_group in optimizer.param_groups:
                param_group['lr'] = lr 
        previous_loss = loss_meter.value()[0]      
          
#验证
def val(model,dataloader):
    #计算模型在验证集上的准确率等信息
    #把模型设为验证模式,验证模式和训练模式dropout层工作不一样
    model.eval()
    a = 0.0
    num = 0
    for i,(datas,labels) in enumerate(dataloader):
        with t.no_grad():   
            val_input = V(datas)
            val_label = V(labels.long())
        score = model(val_input)
        soft_score = t.nn.functional.softmax(score)
        a = a+ sum((np.argmax(np.array(soft_score.data),axis=1) == np.array(val_label)))
        num = num + len(labels)               
    #把模式恢复为训练模式
    model.train()
    accuracy = a/num
    return accuracy   

if __name__ == '__main__':
    fire.Fire()

test

from models.AlexNet import AlexNet
model = AlexNet()
model.load_state_dict(t.load('AlexNet.pth'))

train_data = DogCat(opt.train_data_root,train=True)
train_dataloader = data.DataLoader(train_data,batch_size=10,shuffle=True)

a = 0
for datas,labels in train_dataloader:
    with t.no_grad():
        input = V(datas)
    score = model(input)
    probability = t.nn.functional.softmax(score)
    a = a + sum(np.argmax(np.array(probability.data),axis=1) == np.array(labels))

a
>>43

I am here to test directly on the test set, I am here for the training data 100, divided into 70 training, 30 authentication, so the test 70 43 accurate, the accuracy rate of 61.43%.

Here are few training sample data, and the number of iterations is small, increasing the number of samples and the number of iterations, the accuracy rate will be significantly improved.

 

Extended Content

fire

A command-line tool fire is Google's open source, you can install by pip install fire. The following describes the basic usage of fire.

Create a new file example.py:

import fire

def add(x,y):
    return x + y

def mul(**kwargs):
    a = kwargs['a']
    b = kwargs['b']
    return a * b

if __name__=='__main__':
    fire.Fire()

We can perform example.py in function at the command line:

python example.py add --x=1 --y=2 #执行add(x=1,y=2)
>>3

python example.py mul --a=1 --b=2 #执行mul(a=1,b=2),kwargs={'a':1,'b':2}
>>2

 

Cross-entropy (essentially a mechanism softmax)

import torch as t

#交叉熵对象里输入向量要求是神经网络接受的格式,即有batch_size维
score = V(t.Tensor([1,2,3]).unsqueeze(0)) 
label = V(t.Tensor([2]).long())

from math import exp,log
criterion = t.nn.CrossEntropyLoss()
criterion(score,label),-log(exp(-1)/(exp(-1)+exp(-2)+exp(-3)))

>>(tensor(0.4076), 0.4076059644443803)

 

Guess you like

Origin blog.csdn.net/qq_24946843/article/details/89509694