1.  Resnet 50
# -*- coding: utf-8 -*-

import torch.nn as nn
import math
import torch.utils.model_zoo as model_zoo


class residual_block(nn.Module):
    expansion = 4
    def __init__(self, inplanes, planes, stride=1, downsample = None):
        super(residual_block, self).__init__()
        self.conv1 = nn.Conv2d(inplanes, planes,  bias=False, kernel_size=1)
        self.bn1 = nn.BatchNorm2d(planes)
        self.conv2 = nn.Conv2d(planes, planes, stride = stride, kernel_size=3 , padding=1, bias = False)
        self.bn2 = nn.BatchNorm2d(planes)
        self.conv3 = nn.Conv2d(planes, planes*4,  kernel_size=1,bias=False)
        self.bn3 = nn.BatchNorm2d(planes * 4)
        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample
        self.stride = stride


    def forward(self, x):
        residual = x

        conv1 = self.conv1(x)
        bn1 = self.bn1(conv1)
        relu1 = self.relu(bn1)

        conv2 = self.conv2(relu1)
        bn2 = self.bn2(conv2)
        relu2 = self.relu(bn2)

        conv3 = self.conv3(relu2)
        bn3 = self.bn3(conv3)
        if self.downsample is not None:
            residual = self.downsample(x)
        bn3 += residual
        out = self.relu(bn3)

        return out





class Resnet(nn.Module):
    def __init__(self,   s, numclass):
        self.inplanes = 64
        super(Resnet, self).__init__() ## super函数是用于调用父类(超类)的一个方法
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=7, stride=2,
                               padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(num_features=64)
        self.relu = nn.ReLU(inplace=True)   ##inplace为True,将会改变输入的数据 ,否则不会改变原输入,只会产生新的输出
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        self. 1 = self._make_ (residual_block, 64, blocks =  s[0], stride=1)
        self. 2 = self._make_ (residual_block, 128, blocks =  s[1], stride=2)
        self. 3 = self._make_ (residual_block, 256, blocks =  s[2], stride=2)
        self. 4 = self._make_ (residual_block, 512, blocks =  s[3], stride=2)
        self.avgpool = nn.AvgPool2d(kernel_size=7, stride=1)
        self.fc = nn.Linear(512* residual_block.expansion, numclass)
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()


    def _make_ (self, block, planes, blocks, stride=1):
        downsample = None
        if stride !=1 or self.inplanes != block.expansion * planes :
            print (planes, blocks)
            ## torch.nn.Sequential是一个Sequential容器,模块将按照构造函数中传递的顺序添加到模块中。
            downsample = nn.Sequential(
                nn.Conv2d(self.inplanes, planes*block.expansion, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(planes*block.expansion)
            )

         s = []
         s.append(block(self.inplanes, planes, stride, downsample)) ###该部分是将每个blocks的第一个residual结构保存在 s列表中,这个地方是用来进行下采样的
        self.inplanes = planes * block.expansion

        for i in range(1, blocks):
             s.append(block(self.inplanes, planes))##该部分是将每个blocks的剩下residual 结构保存在 s列表中,这样就完成了一个blocks的构造。

        return nn.Sequential(* s)

    def forward(self, x):
        x = self.conv1(x)
        bn1 = self.bn1(x)
        relu = self.relu(bn1)
        maxpool = self.maxpool(relu)
         1 = self. 1(maxpool)
         2 = self. 2( 1)
         3 = self. 3( 2)
         4 = self. 4( 3)

        avgpool = self.avgpool( 4)
        x = avgpool.view(avgpool.size(0),-1)
        x = self.fc(x)

        return x



def resnet50(pretrained=False, **kwargs):
    \"\"\"Constructs a ResNet-50 model.

    Args:
        pretrained (bool): If True, returns a model pre-trained on ImageNet
    \"\"\"
    model = Resnet([3, 4, 6, 3], **kwargs)
    if pretrained:
        model.load_state_dict(model_zoo.load_url(model_urls[\'resnet50\']))
    return model
  1. 利用Resnet50, 在场景数据集MIT67上进行Finetune,并进行训练
  2. 
    # -*- coding: utf-8 -*-
    \"\"\"
    Auther : Haitao Zeng
    date : 2018.12.18
    Function: finetune the pre-trained model on MIT67 $sun397
    \"\"\"
    from __future__ import print_function, division, absolute_import
    from PIL import Image
    import torch
    import torchvision
    import torch.nn as nn
    from torch.autograd import Variable
    import torch.optim as optim
    from torch.optim import lr_scheduler
    import numpy as np
    from torchvision import datasets, models, transforms
    import os
    import time
    import copy
    import torch.utils.data as data
    from Rsenet50 import Resnet
    import torch.utils.model_zoo as model_zoo
    
    
    def pil_loader(path):
        with open(path, \'rb\') as f:
            with Image.open(f) as img:
                return img.convert(\'RGB\')
    
    def accimage_loader(path):
        import accimage
        try:
            return accimage.Image(path)
        except IOError:
            # Potentially a decoding problem, fall back to PIL.Image
            return pil_loader(path)
    
    def default_loader(path):
        from torchvision import get_image_backend
    
        if get_image_backend() == \'accimage\':
            return accimage_loader(path)
        else:
            return pil_loader(path)
    
    
    class CustomImageLoader(data.Dataset):
        ##自定义类型数据输入
        def __init__(self, img_path, txt_path, dataset = \'\', data_transforms=None, loader = default_loader):
            im_list = []
            im_labels = []
            with open(txt_path, \'r\') as files:
                for line in files:
                    items = line.split()
    
                    if items[0][0] == \'/\':
                        # fnewname = \'_\'.join(items[0][1:-4].split(\'/\'))
                        imname = line.split()[0][1:]
    
                    else:
                        # fnewname = \'_\'.join(items[0][:-4].split(\'/\'))
                        imname = line.split()[0]
                    im_list.append(os.path.join(img_path, imname))
                    im_labels.append(int(items[1]))
            self.imgs = im_list
            self.labels = im_labels
            self.data_tranforms = data_transforms
            self.loader = loader
            self.dataset = dataset
    
        def __len__(self):
    
            return len(self.imgs)
    
        def __getitem__(self, item):
            img_name = self.imgs[item]
            label = self.labels[item]
            img = self.loader(img_name)
    
            if self.data_tranforms is not None:
                try:
                    img = self.data_tranforms[self.dataset](img)
                except:
                    print(\"Cannot transform image: {}\".format(img_name))
            return img, label
    
    
    NUM_EPOCH=20
    batch_size = 32
    device = torch.device(\'cuda:0\')
    ##对数据进行预处理,训练部分包括随机裁剪和水平变换
    ##测试部分包括中心裁剪, 两个部分都包含了数据的正则化的过程
    data_tranforms={
        \'Train\':transforms.Compose([
            transforms.RandomResizedCrop(224),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
        ]),
        \'Test\':transforms.Compose([
            transforms.Resize(256),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
        ])
    }
    
    
    image_dir = \'/media/haitaizeng/00038FCE000387A5/cgw/Datasets/MIT67/Images\'
    
    image_datasets = {x : CustomImageLoader(image_dir, txt_path=(\'/home/haitaizeng/stanforf/alex_mit/data_image/\'+x+\'Images.label\'),
                                            data_transforms=data_tranforms,
                                            dataset=x) for x in [\'Train\', \'Test\']
                      }
    
    dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],
                                                     batch_size=batch_size,
                                                     shuffle=True) for x in [\'Train\', \'Test\']}
    
    
    dataset_sizes = {x: len(image_datasets[x]) for x in [\'Train\', \'Test\']}
    Train_nums= 5360
    Test_nums = 1340
    
    def train_model(model, crtiation, optimizer,schedular, num_epochs=NUM_EPOCH):
        begin_time = time.time()
        best_weights = copy.deepcopy(model.state_dict())#copy the weights from the model
        best_acc = 0.0
    
        for epoch in range(num_epochs):
            print(\"-*-\" * 20)
            for phase in [\'Train\', \'Test\']:
                if phase==\'Train\':
                    schedular.step()
                    model.train()
                else:
                    model.eval()
                running_loss = 0.0
                running_acc = 0.0
    
                for images, labels in dataloders[phase]:
                    images.to(device)
                    labels.to(device)
                    optimizer.zero_grad()
    
                    with torch.set_grad_enabled(phase==\'Train\'):
                        opt = model(images.cuda())
                        # opt = model(images)
                        _,pred = torch.max(opt,1)
                        labels = labels.cuda()
                        loss = crtiation(opt, labels)
                        if phase==\'Train\':
                            loss.backward()
                            optimizer.step()
    
                    running_loss += loss.item()*images.size(0)
                    running_acc += torch.sum(pred==labels)
                if phase == \'Train\':
                    nums = Train_nums
                elif phase==\'Test\':
                    nums == Test_nums
                epoch_loss = running_loss/dataset_sizes[phase]
                epoch_acc = running_acc.double()/dataset_sizes[phase]
                print(\'epoch={}, Phase={}, Loss={:.4f}, ACC:{:.4f}\'.format(epoch, phase, epoch_loss, epoch_acc))
    
    
                if phase == \'Test\' and epoch_acc>best_acc:
                    # Upgrade the weights
                    best_acc=epoch_acc
                    best_weights = copy.deepcopy(model.state_dict())
    
        time_elapes = time.time() - begin_time
        print(\'Training Complete in{:.0f}m {:0f}s\'.format(
            time_elapes // 60, time_elapes % 60
        ))
        print(\'Best Val ACC: {:}\'.format(best_acc))
    
        model.load_state_dict(best_weights)
    
        return models
    
    
    
    
    if __name__ == \'__main__\':
        NUMCLASS = 67
      
        pthpath = \'/home/haitaizeng/cgw/for_zht/CVPR19/resnet50_places365.pth.tar\'
        
        
        # model_ft = models.__ dict__[\'resnet50\'](num_classes=365)  ## 加载的是pytorch库中预先写好的Resnet50的网络结构
        
        model_ft = Resnet([3, 4, 6, 3], 365)##这是自行编写的Resnet50,用于后面的特征提取的操作
        ##load pre-trained model for funetuning
        ckpt = torch.load(pthpath, map_location=lambda storage, loc: storage)
        state_dict = {str.replace(k, \'module.\', \'\'): v for k, v in ckpt[\'state_dict\'].items()}
        model_ft.load_state_dict(state_dict)
    
        ## change the last fully connedected  
        num_fits = model_ft.fc.in_features
        model_ft.fc = nn.Linear(num_fits, NUMCLASS)
        ## run the model on the cuda---Nvidia -1080ti
        model_ft = model_ft.to(device)
        model_ft.cuda()
        ## cacluate the cross entropu loss
        criterion = nn.CrossEntropyLoss()
        ## using SGD to optimize 
        optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
        ## learning rate decay ,when epoch ==10
        exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=10, gamma=0.1)
        model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=25)
    
    
    

     

收藏 打印