zoukankan      html  css  js  c++  java
  • 猫狗识别——PyTorch

    猫狗识别


    数据集下载:

      网盘链接:https://pan.baidu.com/s/1SlNAPf3NbgPyf93XluM7Fg

      提取密码:hpn4


    1. 要导入的包

    import os
    import time
    import numpy as np
    
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    from torch.utils.data import DataLoader
    from torch.utils import data
    from torchvision import transforms as T
    from PIL import Image
    import

    2. 模型配置

    ###################################
    # SETTINGS
    ###################################
    
    class Config(object):
        
        batch_size = 32
        max_epoch = 30
        num_workers = 2
        lr = 0.001
        lr_decay = 0.95
        weight_decay = 0.0001
        
        train_data_root = '/home/dong/Documents/DATASET/train'
        test_data_root = '/home/dong/Documents/DATASET/test'
        
        load_dict_path = None
    
    opt = Config()
    SETTINGS

    3. 选择DEVICE

    device = 'cuda:0' if torch.cuda.is_available() else 'cpu'

     4. 数据集

    ###################################
    # DATASETS
    ###################################
    
    
    class DogCatDataset(data.Dataset):
        
        def __init__(self, root, transforms=None, train=True, test=False):
            
            super(DogCatDataset, self).__init__()
            
            imgs = [os.path.join(root, img) for img in os.listdir(root)]
            
            
            np.random.seed(10000)
            np.random.permutation(imgs)
            
            len_imgs = len(imgs)
            
            self.test = test
            
            # -----------------------------------------------------------------------------------------
            # 因为在猫狗数据集中,只有训练集和测试集,但是我们还需要验证集,因此从原始训练集中分离出30%的数据
            # 用作验证集。
            # ------------------------------------------------------------------------------------------
            if self.test:
                self.imgs = imgs
            elif train:
                self.imgs = imgs[: int(0.7*len_imgs)]
            else:
                self.imgs = imgs[int(0.7*len_imgs): ]
                
            
            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.Scale(224),
                        T.CenterCrop(224),
                        T.ToTensor(),
                        normalize
                    ])
                else:
                    self.transforms = T.Compose([
                        T.Scale(246),
                        T.RandomCrop(224),
                        T.RandomHorizontalFlip(),
                        T.ToTensor(),
                        normalize
                    ])
                
            
        def __getitem__(self, index):
            
            # 当前要获取图像的路径
            img_path = self.imgs[index]
            
            if self.test:
                img_label = int(img_path.split('.')[-2].split('/')[-1])
            else:
                img_label = 1 if 'dog' in img_path.split('/')[-1] else 0
                
            img_data = Image.open(img_path)
            img_data = self.transforms(img_data)
            
            return img_data, img_label
        
        def __len__(self):
            return len(self.imgs)
    
    
    train_dataset = DogCatDataset(root=opt.train_data_root, train=True)   # train=True, test=False -> 训练集
    val_dataset = DogCatDataset(root=opt.train_data_root, train=False)    # train=False, test=False -> 验证集
    test_dataset = DogCatDataset(root=opt.test_data_root, test=True)      # test=True -> 测试集
    
    train_dataloader = DataLoader(dataset=train_dataset,
                                  shuffle=True,
                                  batch_size=opt.batch_size,
                                  num_workers = opt.num_workers)
    val_dataloader = DataLoader(dataset=val_dataset,
                                shuffle=False,
                                batch_size=opt.batch_size,
                                num_workers = opt.num_workers)
    test_dataloader = DataLoader(dataset=test_dataset,
                                 shuffle=False,
                                 batch_size=opt.batch_size,
                                 num_workers = opt.num_workers)
    DATASETS

    5. 检查数据集的 shape

    # ------------------------------------------------
    #  CHECKING THE DATASETS
    # ------------------------------------------------
    print("Training set:")
    for  images, labels in train_dataloader:
        print('Image Batch Dimensions:', images.size())
        print('Label Batch Dimensions:', labels.size())
        break
    
    print("Validation set:")
    for  images, labels in val_dataloader:
        print('Image Batch Dimensions:', images.size())
        print('Label Batch Dimensions:', labels.size())
        break
        
    print("Testing set:")
    for  images, labels in test_dataloader:
        print('Image Batch Dimensions:', images.size())
        print('Label Batch Dimensions:', labels.size())
        break
    View Code

    eg:

    Training set:
    Image Batch Dimensions: torch.Size([32, 3, 224, 224])
    Label Batch Dimensions: torch.Size([32])
    Validation set:
    Image Batch Dimensions: torch.Size([32, 3, 224, 224])
    Label Batch Dimensions: torch.Size([32])
    Testing set:
    Image Batch Dimensions: torch.Size([32, 3, 224, 224])
    Label Batch Dimensions: torch.Size([32])

    6. 模型定义

    ###################################################
    # MODEL
    ###################################################
    
    class AlexNet(nn.Module):
        
        def __init__(self, num_classes=2):       # num_classes代表数据集的类别数
            
            super(AlexNet, self).__init__()
            
            self.features = nn.Sequential(
                nn.Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=2),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=(3, 3), stride=2),
    
                nn.Conv2d(64, 192, kernel_size=5, padding=2),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2),
    
                nn.Conv2d(192, 384, kernel_size=3, padding=1),
                nn.ReLU(inplace=True),
    
                nn.Conv2d(384, 256, kernel_size=3, padding=1),
                nn.ReLU(inplace=True),
    
                nn.Conv2d(256, 256, kernel_size=3, padding=1),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2)
            )
            
            self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
            
            self.classifers = nn.Sequential(
                nn.Dropout(),
                nn.Linear(256 * 6 * 6, 4096),
                nn.ReLU(inplace=True),
    
                nn.Dropout(),
                nn.Linear(4096, 4096),
                nn.ReLU(inplace=True),
                nn.Linear(4096, num_classes),
            )
        
        def forward(self, x):
            x = self.features(x)
            x = self.avgpool(x)
            x = x.view(x.size(0), 256*6*6)
            logits = self.classifers(x)
            probas = F.softmax(logits, dim=1)
            return logits, probas  
        
        # 记载模型
        def load(self, model_path):
            self.load_state_dict(torch.load(model_path))
        
        # 保存模型
        def save(self, model_name):
            # 状态字典的保存格式:文件名 + 日期时间 .pth
            prefix = 'checkpoints/' + model_name + '_'
            name = time.strftime(prefix + '%m%d_%H:%M:%S.pth')
            torch.save(self.state_dict, name)
    
    model = AlexNet()
    model = model.to(device)
    Model

    7. 定义优化器

    ##############################################
    # Optimizer
    ##############################################
    
    # optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=opt.weight_decay)
    
    optimizer = torch.optim.SGD(model.parameters(), lr=opt.lr, momentum=0.8)
    Optimizer

    8. 计算准确率

    # -------------------------------------------
    # 计算准确率
    # -------------------------------------------
    def compute_acc(model, dataloader, device):
        
        correct_pred, num_examples = 0, 0            # correct_pred 统计正确预测的样本数,num_examples 统计样本总数
        for i, (features, targets) in enumerate(dataloader):
            
            features = features.to(device)
            targets = targets.to(device)
            
            logits, probas = model(features)
            _, predicted_labels = torch.max(probas, 1)
            
            num_examples += targets.size(0)
            assert predicted_labels.size() == targets.size()
            correct_pred += (predicted_labels == targets).sum()
        
        return correct_pred.float() / num_examples * 100     
    compute_acc

    9. 训练 and 验证

    ##############################################
    # TRAINING and VALIDATION
    ##############################################
    
    cost_list = []
    train_acc_list, val_acc_list = [], []
    
    start_time = time.time()
    
    for epoch in range(opt.max_epoch):
        
        model.train()
        for batch_idx, (features, targets) in enumerate(train_dataloader):
            
            features = features.to(device)
            targets = targets.to(device)
            
            optimizer.zero_grad()
            
            logits, probas = model(features)
            # print(targets.size(), logits.size(), probas.size())
            cost = F.cross_entropy(logits, targets)
            # cost = torch.nn.CrossEntropyLoss(logits, targets)
            
            cost.backward()
            
            optimizer.step()
            
            cost_list.append(cost.item())
            
            if not batch_idx % 50:
                print('Epoch: %03d/%03d | Batch %03d/%03d | Cost: %.4f'
                     %(epoch+1, opt.max_epoch, batch_idx, len(train_dataloader), cost))
        
        model.eval()
        with torch.set_grad_enabled(False):     # save memory during inference
            
            train_acc = compute_acc(model, train_dataloader, device=device)
            val_acc = compute_acc(model, val_dataloader, device=device)
            
            print('Epoch: %03d/%03d | Training ACC: %.4f%% | Validation ACC: %.4f%%'
                 %(epoch+1, opt.max_epoch, train_acc, val_acc))
            
            train_acc_list.append(train_acc)
            val_acc_list.append(val_acc)
        
        print('Time Elapsed: %.2f min' % ((time.time() - start_time)/60))
    
    print('Total Time Elapsed: %.2f min' % ((time.time() - start_time)/60))
    Training and Validation

    eg:

    Epoch: 001/030 | Batch 000/547 | Cost: 0.6945
    Epoch: 001/030 | Batch 050/547 | Cost: 0.6920
    Epoch: 001/030 | Batch 100/547 | Cost: 0.6942
    Epoch: 001/030 | Batch 150/547 | Cost: 0.6926
    Epoch: 001/030 | Batch 200/547 | Cost: 0.6926
    Epoch: 001/030 | Batch 250/547 | Cost: 0.6946
    Epoch: 001/030 | Batch 300/547 | Cost: 0.6920
    Epoch: 001/030 | Batch 350/547 | Cost: 0.6951
    Epoch: 001/030 | Batch 400/547 | Cost: 0.6943
    Epoch: 001/030 | Batch 450/547 | Cost: 0.6946
    Epoch: 001/030 | Batch 500/547 | Cost: 0.6932
    Epoch: 001/030 | Training ACC: 51.7657% | Validation ACC: 50.8933%
    Time Elapsed: 2.98 min
    Epoch: 002/030 | Batch 000/547 | Cost: 0.6926
    Epoch: 002/030 | Batch 050/547 | Cost: 0.6931
    Epoch: 002/030 | Batch 100/547 | Cost: 0.6915
    Epoch: 002/030 | Batch 150/547 | Cost: 0.6913
    Epoch: 002/030 | Batch 200/547 | Cost: 0.6908
    Epoch: 002/030 | Batch 250/547 | Cost: 0.6964
    Epoch: 002/030 | Batch 300/547 | Cost: 0.6939
    Epoch: 002/030 | Batch 350/547 | Cost: 0.6914
    Epoch: 002/030 | Batch 400/547 | Cost: 0.6941
    Epoch: 002/030 | Batch 450/547 | Cost: 0.6937
    Epoch: 002/030 | Batch 500/547 | Cost: 0.6948
    Epoch: 002/030 | Training ACC: 53.0400% | Validation ACC: 52.2933%
    Time Elapsed: 6.00 min
    ...
    Epoch: 030/030 | Batch 000/547 | Cost: 0.1297
    Epoch: 030/030 | Batch 050/547 | Cost: 0.2972
    Epoch: 030/030 | Batch 100/547 | Cost: 0.2468
    Epoch: 030/030 | Batch 150/547 | Cost: 0.1685
    Epoch: 030/030 | Batch 200/547 | Cost: 0.3452
    Epoch: 030/030 | Batch 250/547 | Cost: 0.3029
    Epoch: 030/030 | Batch 300/547 | Cost: 0.2975
    Epoch: 030/030 | Batch 350/547 | Cost: 0.2125
    Epoch: 030/030 | Batch 400/547 | Cost: 0.2317
    Epoch: 030/030 | Batch 450/547 | Cost: 0.2464
    Epoch: 030/030 | Batch 500/547 | Cost: 0.2487
    Epoch: 030/030 | Training ACC: 89.5314% | Validation ACC: 88.6400%
    Time Elapsed: 92.85 min
    Total Time Elapsed: 92.85 min
    View Code

    10. 可视化 Loss

    plt.plot(cost_list, label='Minibatch cost')
    plt.plot(np.convolve(cost_list, 
                         np.ones(200,)/200, mode='valid'), 
             label='Running average')
    plt.ylabel('Cross Entropy')
    plt.xlabel('Iteration')
    plt.legend()
    plt.show()
    visualize loss

    eg:

    11. 可视化 准确率

    plt.plot(np.arange(1, opt.max_epoch+1), train_acc_list, label='Training')
    plt.plot(np.arange(1, opt.max_epoch+1), val_acc_list, label='Validation')
    
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend()
    plt.show()
    View Code

    eg:

     
  • 相关阅读:
    HTTP Status 401
    Spring Data Elasticsearch 应用
    Elasticsearch基础概念
    Windows上使用Linux命令
    在服务器搭建git仓库
    SSH
    Linux/Windows 配置config 使用ssh连接
    在阿里云CentOS服务器上安装Python3.7并设置为默认Python
    Linux下Python3源码安装
    Vue
  • 原文地址:https://www.cnblogs.com/xxxxxxxxx/p/11525583.html
Copyright © 2011-2022 走看看