pytorch知识一tensor数据声明、类型转换。微调rensnet34的注意点。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yangdashi888/article/details/84024939

1、tensor类型的数据声明:

A、

import torch
import numpy as np
from torch.autograd import Variable
running_corrects = 0.0
# 声明一个单一变量3,Tensor默认的tensor类型是(torch.FloaTensor)的简称
a=torch.Tensor([3])
aa=torch.Tensor(0)
# 其中tensor默认生成的数据类型是int64位的
aaa=torch.tensor([3])
aaaa=torch.tensor(0)
print(a.dtype)
print(aa.dtype)
print(aaa.dtype)
print(aaaa.dtype)
print(aaa)
print(aaaa)
b=torch.Tensor([3])
# 声明一个2*3的矩阵数据
numpy_tensor=np.random.randn(2,3)
c=torch.Tensor(numpy_tensor)
print(c)
# 进行数据的第二维度求和,此时sum返回的是跟数据一样的浮点型数据
testarray=torch.sum(c,1)
print(testarray)
# 此时sum返回的数据是int64为的,此时要使用强制转换进行float类型
running_corrects += torch.sum(a == b).float()
hh = running_corrects / 4.0
print(hh)

其输出结果是:

torch.float32
torch.float32
torch.int64
torch.int64
tensor([3])
tensor(0)
tensor([[-0.2286,  0.7078, -0.9872],
        [-0.3574, -0.6509, -0.3000]])
tensor([-0.5080, -1.3083])
tensor(0.2500)

   注意:从上面可以看出torch声明变量的时候使用:Tensor()跟tensor()两个函数声明的得出的数据类型是不一样的,不过其作用倒是一样的,这两者声明的都是CPU的数据类型,所以使用到GPU的使用需要使用(.cuda())来把数据加载到gpu,或者在声明数据的时候就使用gpu tensor类型来声明,其是torch.cuda.FloatTensor()等,具体类型可以看下面解释。

  B、Torch定义的其中CPU tensor类型和八种GPU tensor类型:

参考网站: PyTorch中文文档  

torch.Tensor

torch.Tensor是一种包含单一数据类型元素的多维矩阵。

Torch定义了七种CPU tensor类型和八种GPU tensor类型:

Data tyoe CPU tensor GPU tensor
32-bit floating point torch.FloatTensor torch.cuda.FloatTensor
64-bit floating point torch.DoubleTensor torch.cuda.DoubleTensor
16-bit floating point N/A torch.cuda.HalfTensor
8-bit integer (unsigned) torch.ByteTensor torch.cuda.ByteTensor
8-bit integer (signed) torch.CharTensor torch.cuda.CharTensor
16-bit integer (signed) torch.ShortTensor torch.cuda.ShortTensor
32-bit integer (signed) torch.IntTensor torch.cuda.IntTensor
64-bit integer (signed) torch.LongTensor torch.cuda.LongTensor

torch.Tensor是默认的tensor类型(torch.FlaotTensor)的简称。

一个张量tensor可以从Python的list或序列构建:

>>> torch.FloatTensor([[1, 2, 3], [4, 5, 6]])
1 2 3
4 5 6
[torch.FloatTensor of size 2x3]

一个空张量tensor可以通过规定其大小来构建:

>>> torch.IntTensor(2, 4).zero_()
0 0 0 0
0 0 0 0
[torch.IntTensor of size 2x4]

可以用python的索引和切片来获取和修改一个张量tensor中的内容:

>>> x = torch.FloatTensor([[1, 2, 3], [4, 5, 6]])
>>> print(x[1][2])
6.0
>>> x[0][1] = 8
>>> print(x)
 1 8 3
 4 5 6
[torch.FloatTensor of size 2x3]

每一个张量tensor都有一个相应的torch.Storage用来保存其数据。类tensor提供了一个存储的多维的、横向视图,并且定义了在数值运算。

!注意: 会改变tensor的函数操作会用一个下划线后缀来标示。比如,torch.FloatTensor.abs_()会在原地计算绝对值,并返回改变后的tensor,而tensor.FloatTensor.abs()将会在一个新的tensor中计算结果。

class torch.Tensor
class torch.Tensor(*sizes)
class torch.Tensor(size)
class torch.Tensor(sequence)
class torch.Tensor(ndarray)
class torch.Tensor(tensor)
class torch.Tensor(storage)

根据可选择的大小和数据新建一个tensor。 如果没有提供参数,将会返回一个空的零维张量。如果提供了numpy.ndarray,torch.Tensortorch.Storage,将会返回一个有同样参数的tensor.如果提供了python序列,将会从序列的副本创建一个tensor。

2、下面是微调resnet34的注意点:

其下面是微调训练代码:

from __future__ import print_function, division

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.autograd import Variable
import torchvision
from torchvision import datasets, models, transforms
import time
import os
import matplotlib as mpl
import matplotlib.pyplot as plt

model_path='model/madel_state_dict.pt'
def train_model(model, criterion, optimizer, scheduler, num_epochs=1):
    since = time.time()

    best_model_wts = model.state_dict()
    best_acc = 0.0

    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch, num_epochs - 1))
        print('-' * 10)

        # Each epoch has a training and validation phase
        for phase in ['train', 'val']:
            if phase == 'train':
                scheduler.step()
                model.train(True)  # Set model to training mode
            else:
                # 设置这个eval()可以让dropout、bn等进入预估状态,而不启用否则启用另一种计算方法。
                model.eval()  # Set model to evaluate mode

            running_loss = 0.0
            running_corrects = 0.0
            # Iterate over data.
            for data in dataloders[phase]:
                # get the inputs
                inputs, labels = data

                # wrap them in Variable
                if use_gpu:
                    inputs = Variable(inputs.cuda())
                    labels = Variable(labels.cuda())
                else:
                    inputs, labels = Variable(inputs), Variable(labels)

                # zero the parameter gradients,这个不会影响网络的验证的
                optimizer.zero_grad()

                # forward
                outputs = model(inputs)
                _, preds = torch.max(outputs.data, 1)
                # 这个也是不会影响到网络的验证的
                loss = criterion(outputs, labels)
                # backward + optimize only if in training phase
                if phase == 'train':
                    loss.backward()
                    optimizer.step()

                # statistics这里有个问题的:由于loss单个数值来的,而后面使用running_loss进行求平均值,
#导致损失值很低。所以这里正确的代码是要乘多一个inputs.size(0)
                running_loss += loss.data[0]
                # 其中这里最坑,其中如果sum里面的是bool类型数据,则其返回的是int64为数据类型
                # 这就会导致epoch_acc的准确度一直是0
                running_corrects += torch.sum(preds == labels.data).float()
                if phase == 'train':
                    train_loss.append(loss.data[0] / 15)
                    train_acc.append(torch.sum(preds == labels.data) / 15)
                else:
                    test_loss.append(loss.data[0] / 15)
                    test_acc.append(torch.sum(preds == labels.data) / 15)

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects / dataset_sizes[phase]

            print('{} Loss {:.4f} Acc: {:.4f}'.format(
                phase, epoch_loss, epoch_acc))

            # deep copy the model
            if phase == 'val' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = model.state_dict()
                torch.save(best_model_wts, model_path)

    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val Acc: {:4f}'.format(best_acc))

    # load best model weights更新网络的权重,使用最高准确度的那个

    # model.load_state_dict(best_model_wts)
    model.load_state_dict(torch.load(model_path))
    return model


if __name__ == '__main__':

    # data_transform, pay attention that the input of Normalize() is Tensor and the input of RandomResizedCrop() or RandomHorizontalFlip() is PIL Image
    data_transforms = {
        'train': transforms.Compose([
            transforms.RandomResizedCrop(224),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
        'val': transforms.Compose([
            transforms.Resize(256),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
    }

    # your image data file,这个数据很量很重要,每类数据多的话收敛的快
    data_dir = 'foodsmall'
    image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
                                              data_transforms[x]) for x in ['train', 'val']}
    # wrap your data and label into Tensor 这里的shuffle一定要开启,否者训练出来的准确度很低
    dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],
                                                 batch_size=5,
                                                 shuffle=True,
                                                 num_workers=10) for x in ['train', 'val']}

    dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}

    # use gpu or not
    use_gpu = torch.cuda.is_available()

    # get model and replace the original fc layer with your fc layer
    model_ft = models.resnet34(pretrained=True)
    num_ftrs = model_ft.fc.in_features
    model_ft.fc = nn.Linear(num_ftrs, 7)
    # model_ft = torch.load('/home/syj/Documents/model/resnet18_0.003.pkl')

    ##paint
    train_loss = []
    train_acc = []
    test_loss = []
    test_acc = []

    if use_gpu:
        model_ft = model_ft.cuda()

    # define loss function
    criterion = nn.CrossEntropyLoss()

    # Observe that all parameters are being optimized,微调全部参数,其开始准确度很低,训练速度很慢
    # optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.03, momentum=0.9)
    # 微调全连层的参数,其准确度上升的很快,收敛速度很快
    optimizer_ft = optim.SGD(model_ft.fc.parameters(), lr=0.03, momentum=0.9)
    # 使用Adam训练,准确度上升的更快,收敛速度很快
    # optimizer_ft=optim.Adam(model_ft.parameters(),lr=0.03)

    # Decay LR by a factor of 0.1 every 7 epochs
    exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)

    model_ft = train_model(model=model_ft,
                           criterion=criterion,
                           optimizer=optimizer_ft,
                           scheduler=exp_lr_scheduler,
                           num_epochs=20)

    torch.save(model_ft, '/home/syj/Documents/model/resnet18_0.003.pkl')

其要注意点是:

A、微调的话使用要注意定义optim的时候其参数要使用全连层的参数。如果使用全局的参数的话也可以,不过刚开始准确度会很低,然后慢慢收敛。

B、使用DataLoader()进行加载数据的时候其中shuffle参数一定要设置为True。否则收敛不了或者上升很慢慢。、

C、其中在验证的时候网络一定要设置为:model.eval().使网络进入验证模式,其才会禁用dropout()等功能。

下面是一些使用总结:

  进行全局参数的调整,其需要的epoch比较多。这里的把训练的梯度清零函数跟计算损失的函数都放到test里面,其对预测没有影响。所以一切ok:

使用Fenet进行微调10类每类只有7张人脸的数据。微调最后一层参数,其识别率从很低往上升,收敛的速度也挺快的:

使用Fenet进行微调10类每类只有7张人脸的数据。训练全部参数,其识别率特别低,如果epoch最够大的话其或许是可以上升的,因为其准确度有上升趋势:

使用foodsmall数据集其共有7类,每类数据是7张,其训练全部参数,开始准确度很低,然后就很慢有上升趋势,跟fenet数据集一样。所以其数据集是多通道灰度图使用三通道的网络进行训练是不会影响到网络训练的:

使用foodsmall数据集其共有7类,每类数据是7张,其训练全部参数,开始准确度很低,然后就很慢有上升趋势,跟fenet数据集一样。所以其数据集是多通道灰度图使用三通道的网络进行训练是不会影响到网络训练的使用Adam进行梯度计算:

猜你喜欢

转载自blog.csdn.net/yangdashi888/article/details/84024939
今日推荐