zoukankan      html  css  js  c++  java
  • pytorch练习

    自动求导

    计算图

    关于计算图的内容,可以参考[1]

    变量加入与去除计算图

    pytorch中的tensor会有一个requires_grad属性,当设定为True时则标记为追踪计算并计算梯度,可以通过tensor.requires_grad_(False)来改变标记,默认为False。也可以使用tensor.detach_()从计算图中去除,detach()方法不会改变自身属性。也可以使用with torch.no_grad():这样的上下文管理器,对当期计算图不进行求导计算,这个方法可以使用在模型评估上。

    求导

    tensor中有一个.grad属性,当计算完成,对计算结果使用.backward()方法时,requires_gradTrue的变量当前的梯度信息都会累加到.grad属性。

    如果计算结果为向量,那么backward方法还需要传入求导的方向参数。

    Custom Network

    构造custom网络

    自定义网络需要继承自nn.Module模块,并实现forward函数。网络搭建完成后,可以训练的参数都存放在parameters属性中,parameters是一个生成器,按照网络结构顺序排列。

    参数更新

    在确定optimizer和criterion的时候,可以用backward()optimizer.step()来更新一步参数。

    需要注意的是,nn.Module模块仅支持batch的输入形式。

    Custom Auto Grad Function

    custom atuo grad函数需要继承torch.autograd.Function,并实现forwardbackward两个方法。

    Custom Dataloader

    custom dataset需要实现__len____getitem__两个方法,custom dataloader需要实现__len____iter__两个方法。

    实例一(FCN)

    这里复现了一个用以图像分割的FCN(忘记从哪里找的了,找到了会加入参考资料里)。

    # Custom dataset
    from PIL import Image
    from torchvision import transforms as T
    from torch.utils.data import Dataset
    from glob import glob
    import os
    import numpy as np
    import matplotlib.pyplot as plt
    
    
    class CustomDataset(Dataset):
        def __init__(self, image_path = "data/BagImages", mode = "train"):
            assert mode in ("train", "val", "test")
            self.image_path = image_path
            self.image_list = glob(os.path.join(self.image_path, "*.jpg"))
            self.mode = mode
    
            if mode in ("train", "val"):
                self.mask_path = self.image_path + "Masks"
    
            self.transform_x = T.Compose([T.Resize((256, 256)), T.ToTensor(), T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])  # transform
            self.transform_mask = T.Compose([ T.ToTensor()])
    
        def __getitem__(self, index):
            if self.mode in ("train", "val"):
                image_name = self.image_list[index].split("/")[-1].split(".")[0]
                X = Image.open(self.image_list[index])
                
                mask = np.array(Image.open(os.path.join(self.mask_path, image_name+".jpg")).convert('1').resize((256, 256)))
                masks = np.zeros((mask.shape[0], mask.shape[1], 2), dtype=np.uint8)
                masks[:, :, 0] = mask
                masks[:, :, 1] = ~mask
    
                X = self.transform_x(X)
                masks = self.transform_mask(masks) * 255
                return X, masks
            
            else:
                X = Image.open(self.image_list[index])
                X = self.transform_x(X)
                path = self.image_list[index]
                return X, path
    
        def __len__(self):
            return len(self.image_list)
    
    # Network
    
    import torch.nn as nn
    from model.vgg import VGG
    import torch
    
    
    class FCN32s(nn.Module):
        def __init__(self, num_classes, backbone="vgg"):
            super(FCN32s, self).__init__()
            self.num_classes = num_classes
            if backbone == "vgg":
                self.features = VGG()
    
            # deconv1 1/16
            self.deconv1 = nn.ConvTranspose2d(512, 512, kernel_size=3, stride=2, padding=1, output_padding=1)
            self.bn1 = nn.BatchNorm2d(512)
            self.relu1 = nn.ReLU()
    
            # deconv1 1/8
            self.deconv2 = nn.ConvTranspose2d(512, 256, kernel_size=3, stride=2, padding=1, output_padding=1)
            self.bn2 = nn.BatchNorm2d(256)
            self.relu2 = nn.ReLU()
    
            # deconv1 1/4
            self.deconv3 = nn.ConvTranspose2d(256, 128, kernel_size=3, stride=2, padding=1, output_padding=1)
            self.bn3 = nn.BatchNorm2d(128)
            self.relu3 = nn.ReLU()
    
            # deconv1 1/2
            self.deconv4 = nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=1, output_padding=1)
            self.bn4 = nn.BatchNorm2d(64)
            self.relu4 = nn.ReLU()
    
            # deconv1 1/1
            self.deconv5 = nn.ConvTranspose2d(64, 32, kernel_size=3, stride=2, padding=1, output_padding=1)
            self.bn5 = nn.BatchNorm2d(32)
            self.relu5 = nn.ReLU()
    
            self.classifier = nn.Conv2d(32, num_classes, kernel_size=1)
    
        def forward(self, x):
            features = self.features(x)
    
            y = self.bn1(self.relu1(self.deconv1(features[4])))
    
            y = self.bn2(self.relu2(self.deconv2(y)))
    
            y = self.bn3(self.relu3(self.deconv3(y)))
    
            y = self.bn4(self.relu4(self.deconv4(y)))
    
            y = self.bn5(self.relu5(self.deconv5(y)))
    
            y = self.classifier(y)
    
            return y
    
    # train
    
    CUDA = torch.cuda.is_available()
    
    def train(**kwargs):
        mymodel = kwargs["mymodel"]
        criterion = kwargs["criterion"]
        data_loader = kwargs["data_loader"]
        optimizer = kwargs["optimizer"]
        epoch = kwargs["epoch"]
        save_freq = kwargs["save_freq"]
        save_dir = kwargs["save_dir"]
        verbose = kwargs["verbose"]
    
        start_time = time.time()
        logging.info("Epoch %03d, Learning Rate %g" % (epoch + 1, optimizer.param_groups[0]["lr"]))
        mymodel.train()
    
        epoch_loss = 0.0
        batches = 0
        for i, sample in enumerate(data_loader):
            image, target = sample
            if CUDA:
                image = image.cuda()
                target = target.cuda()
    
            optimizer.zero_grad()
            output = mymodel(image)
            loss = criterion(output, target)
            
            loss.backward()
            optimizer.step()
    
            epoch_loss += loss.item()		
            batches += 1
            
            if (i + 1) % verbose == 0:
                logging.info('Training Loss: %.6f' % epoch_loss / batches)
                logging.info('')
    
        # save checkpoint model
        if epoch % save_freq == 0:
            state_dict = mymodel.module.state_dict()
            for key in state_dict.keys():
                state_dict[key] = state_dict[key].cpu()
    
            torch.save({
                'epoch': epoch,
                'save_dir': save_dir,
                'state_dict': state_dict,},
                os.path.join(save_dir, '%03d.ckpt' % (epoch + 1)))
    
        end_time = time.time()
        logging.info('Batch Loss: %.6f Time: %d s' % (epoch_loss / batches, end_time - start_time))
    
    # main
    
    def main(hyper_parameter=hyper_parameter):
        # training
        start_epoch = 0
        mymodel = FCNs(hyper_parameter["num_classes"], hyper_parameter["back_bone"])
    
        if hyper_parameter["ckpt"]:
            ckpt = hyper_parameter["ckpt"]
    
            if hyper_parameter["initial_training"] == 0:
                epoch_name = (ckpt.split('/')[-1]).split('.')[0]
                start_epoch = int(epoch_name)
    
            checkpoint = torch.load(ckpt)
            state_dict = checkpoint["state_dict"]
    
            mymodel.load_state_dict(state_dict)
            logging.info(f'Model loaded from {hyper_parameter["ckpt"]}')
    
        save_dir = hyper_parameter["save_dir"]
        if not os.path.exists(save_dir):
            os.mkdir(save_dir)
    
        # CUDA
        if CUDA:
            mymodel.to(torch.device("cuda"))
            mymodel = nn.DataParallel(mymodel)
    
        custom_dataset = CustomDataset()
        test_set = CustomDataset("data/testImages", mode="test")
    
        train_size = int(0.9 * len(custom_dataset))
        val_size = len(custom_dataset) - train_size
        train_set, val_set = random_split(custom_dataset, [train_size, val_size])
    
        train_loader = DataLoader(train_set, batch_size=hyper_parameter["batch_size"], shuffle=True)
        val_loader = DataLoader(val_set, batch_size=hyper_parameter["batch_size"], shuffle=False)
        test_loader = DataLoader(test_set, batch_size=hyper_parameter["batch_size"], shuffle=False)
    
        if hyper_parameter["mode"] == "test":
            test(mymodel=mymodel,
                    data_loader=test_loader)
            return
    
        optimizer = torch.optim.Adam(mymodel.parameters(), lr=hyper_parameter["lr"])
        criterion = nn.BCEWithLogitsLoss()
    
        logging.info('Start training: Total epochs: {}, Batch size: {}, Training size: {}, Validation size: {}'.
                        format(hyper_parameter["epochs"], hyper_parameter["batch_size"], len(train_set), len(val_set)))
    
        for epoch in tqdm(range(start_epoch, hyper_parameter["epochs"])):
            train(  epoch=epoch,
                    data_loader=train_loader, 
                    mymodel=mymodel,
                    criterion=criterion,
                    optimizer=optimizer,
                    save_freq=hyper_parameter["save_freq"],
                    save_dir=hyper_parameter["save_dir"],
                    verbose=hyper_parameter["verbose"])
    
            validate(data_loader=val_loader,
                    mymodel=mymodel,
                    criterion=criterion,
                    verbose=hyper_parameter["verbose"])
            # scheduler.step()
    

    实例二(LSTM)

    使用LSTM做的分类(关于LSTM可阅读[4]),一些需要注意的地方:

    1. CrossEntropyLoss对预测仅支持Long int类型
    2. T.Tensor()要求维度是2/3
    3. DataLoader会莫名多出来一个维度
    4. CrossEntropyLoss要求真实标签的维度为1
    5. 多分类的精准率,召回率与二分类有所不同,详细请参考[3]
    import scipy.io as scio
    import time
    import logging
    import numpy as np
    
    # hyper parameters
    OPTIONS = {'batch_size':64, 'lr':0.01}
    logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    # prepare dataset wrapped in pytorch
    from torchvision import transforms as T
    from torch.utils.data import Dataset
    import torch
    
    class CustomDataset(Dataset):
        def __init__(self, mode = "train"):
            assert mode in ("train", "test")
            self.mode = mode
            self.dataset = eval("".join([self.mode, "_dataset"]))
            
            self.transform = T.Compose([T.ToTensor()]) 
    
        def __getitem__(self, index):
            if self.mode == "train":            
                X = self.dataset['X'][index]
                Y = self.dataset['Y'][index]
    
                X = self.transform(X)
                Y = torch.from_numpy(Y).long()  # crossentropy only support long int type
                return X, Y
            
            else:
                X = self.dataset['X'][index]
                Y = self.dataset['Y'][index]
    
                X = self.transform(X)
                Y = torch.from_numpy(Y).long()
                return X, Y
    
        def __len__(self):
            return len(self.dataset['Y'])
    
    from torch.utils.data import DataLoader
    
    torch.manual_seed(seed=1)
    train_set = CustomDataset()
    test_set = CustomDataset(mode="test")
    train_loader = DataLoader(train_set, batch_size=OPTIONS["batch_size"], shuffle=True)
    test_loader = DataLoader(test_set, batch_size=OPTIONS["batch_size"], shuffle=True)
    
    # LSTM for classification
    # Model
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    import torch.optim as optim
    import torchvision
    class CustomModel(nn.Module):
        
        def __init__(self, input_size, hidden_size, output_size, num_layer=1):
            super(CustomModel, self).__init__()
            self.lstm = nn.LSTM(input_size=input_size,
                                hidden_size=hidden_size,
                                num_layers=num_layer, batch_first=True)  # if batch_first is True, input shape should be (batch, seq_length, feature)
            self.out = nn.Linear(hidden_size, output_size)
        
        def forward(self, x):
            output, (h_n, c_m) = self.lstm(x)
            predict_y = self.out(output[:, -1, :])
            return predict_y  # don't need softmax function if using crossentropy loss
    
    # Training
    def train(model, loss_fn, epochs, train_loader, optimizer):
        for epoch in range(epochs):
            epoch_loss = 0.0
            batches = 0
            start_time = time.time()
            
            for i, data in enumerate(train_loader):
                x , y = data
                x = torch.squeeze(x)  
                y = torch.squeeze(y)  # shape should be 1
                
                optimizer.zero_grad()
                output = model(x)
                loss = loss_fn(output, y)
                loss.backward()
                optimizer.step()
                
                epoch_loss += loss.item()
                batches += 1
                
            logging.info('In epoch %d, training Loss: %.6f' % (epoch, epoch_loss / batches))
    

    参考资料

    1. 吴立德, 数值优化, 2015
    1. pytorch教程
    1. hfutdog, sklearn计算准确率、精确率、召回率、F1 score
    1. ymmy, LSTM细节分析理解(pytorch版)
  • 相关阅读:
    ORACLE复制数据库【weber出品】
    AJAX和jquery简单试用
    git 基本命令大全
    git使用技巧
    listagg( ) within group ( order by ) 与 wm_concat
    oracle 数据库查询多条数据的一列值
    Fstdfs +nginx 安装详细步骤
    解决Oracle用户被锁定的方法
    解决tomcat内存溢出
    PowerDesigner将PDM导出生成WORD文档
  • 原文地址:https://www.cnblogs.com/DemonHunter/p/12815556.html
Copyright © 2011-2022 走看看