《深度学习之PyTorch实战计算机视觉》学习笔记(6)

这部分是利用pytorch进行迁移学习,迁移的是VGG16

代码基于python3.7, pytorch 1.0,cuda 10.0 .

import torch
import torchvision
from torch.autograd import Variable
from torchvision import datasets, transforms, models
import os            # os包集成了一些对文件路径和目录进行操作的类
import matplotlib.pyplot as plt
import time
# 读取数据
data_dir = 'DogsVSCats'
data_transform = {x:transforms.Compose([transforms.Scale([224, 224]),
                                       transforms.ToTensor(),
                                        transforms.Normalize(mean=[0.5,0.5,0.5],std=[0.5,0.5,0.5])
                                        ]) for x in ['train', 'valid']}   # 这一步类似预处理,相比于手动搭建模型的方法,这里增加了预处理,图像大小为vgg的标准输入
image_datasets = {x:datasets.ImageFolder(root = os.path.join(data_dir,x),
                                        transform = data_transform[x]) for x in ['train', 'valid']}  # 这一步相当于读取数据
dataloader = {x:torch.utils.data.DataLoader(dataset = image_datasets[x],
                                           batch_size = 16,
                                           shuffle = True) for x in ['train', 'valid']}   # 读取完数据后,对数据进行装载
e:\project3.7\lib\site-packages\torchvision\transforms\transforms.py:207: UserWarning: The use of the transforms.Scale transform is deprecated, please use transforms.Resize instead.
  warnings.warn("The use of the transforms.Scale transform is deprecated, " +
model = models.vgg16(pretrained=True)   # 调用Vgg16的预训练模型参数
print(model)
for parma in model.parameters():
    parma.requires_grad = False     # 冻结全部的梯度,使之梯度不进行更新

# 重新定义全连接层为我们想要的输出维度,进行二分类, 这里第一个全连接层的输入不应该对应是25088么?25088会报错??修改后2048可以运行
# 这是因为开始的时候把图像裁剪到64*64导致的,标准vgg的输入是224*224的
model.classifier = torch.nn.Sequential(torch.nn.Linear(25088, 4096),
                                       torch.nn.ReLU(),
                                       torch.nn.Dropout(p = 0.5),
                                       torch.nn.Linear(4096, 4096),
                                       torch.nn.ReLU(),
                                       torch.nn.Dropout(p = 0.5),
                                       torch.nn.Linear(4096, 2))

print(model)  # 打印改变后的模型进行对比
VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (25): ReLU(inplace)
    (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (27): ReLU(inplace)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace)
    (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  (classifier): Sequential(
    (0): Linear(in_features=25088, out_features=4096, bias=True)
    (1): ReLU(inplace)
    (2): Dropout(p=0.5)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU(inplace)
    (5): Dropout(p=0.5)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)
VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (25): ReLU(inplace)
    (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (27): ReLU(inplace)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace)
    (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  (classifier): Sequential(
    (0): Linear(in_features=25088, out_features=4096, bias=True)
    (1): ReLU()
    (2): Dropout(p=0.5)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU()
    (5): Dropout(p=0.5)
    (6): Linear(in_features=4096, out_features=2, bias=True)
  )
)
#  定义好模型的损失函数和对参数进行优化的优化函数
loss_f = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.classifier.parameters(), lr=0.00001)
# 用cpu计算太慢了,改用GPU计算,model = model.cuda()和X, y = Variable(X.cuda()),
# Variable(y.cuda())就是参与迁移至GPUs的具体代码


print(torch.cuda.is_available())
Use_gpu = torch.cuda.is_available()

if Use_gpu:
    model = model.cuda()
True
# 开始训练
epoch_n = 5
time_open = time.time()

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

    for phase in ['train', 'valid']:
        if phase == 'train':
            print('Training...')
            model.train(True)
        else:
            print('Validing...')
            model.train(False)

        running_loss = 0.0
        running_correct = 0.0

        for batch, data in enumerate(dataloader[phase], 1):
            X, Y = data
            if Use_gpu:
                X, Y = Variable(X.cuda()), Variable(Y.cuda())
            else:
                X, Y = Variable(X), Variable(Y)

            y_pred = model(X)

            _, pred = torch.max(y_pred.data , 1)  # 找出每一行中的最大的值对应的索引

            optimizer.zero_grad()

            loss = loss_f(y_pred, Y)

            if phase == 'train':
                loss.backward()
                optimizer.step()

            running_loss += loss.data.item()
            running_correct += torch.sum(pred == Y.data)

            if batch % 500 == 0 and phase == 'train':
                print('Batch {}, Train Loss:{:.4f},Train ACC: {:.4f}'.format(batch,
                                                                             running_loss / batch,
                                                                             100 * running_correct / (16 * batch)))
        epoch_loss = running_loss * 16 / len(image_datasets[phase])
        epoch_acc = 100 * running_correct / len(image_datasets[phase])
        print('{} Loss:{:.4f} ACC:{:.4f}%'.format(phase, epoch_loss, epoch_acc))
    time_end = time.time() - time_open
    print(time_end)

True
Epoch 0/4

Training…
Batch 500, Train Loss:0.1004,Train ACC: 96.0000
Batch 1000, Train Loss:0.0789,Train ACC: 97.0000
train Loss:0.0710 ACC:97.0000%
Validing…
valid Loss:0.0557 ACC:98.0000%
189.56190013885498
Epoch 1/4

Training…
Batch 500, Train Loss:0.0278,Train ACC: 99.0000
Batch 1000, Train Loss:0.0250,Train ACC: 99.0000
train Loss:0.0242 ACC:99.0000%
Validing…
valid Loss:0.0793 ACC:97.0000%
379.47217535972595
Epoch 2/4

Training…
Batch 500, Train Loss:0.0091,Train ACC: 99.0000
Batch 1000, Train Loss:0.0090,Train ACC: 99.0000
train Loss:0.0101 ACC:99.0000%
Validing…
valid Loss:0.0549 ACC:98.0000%
570.3123188018799
Epoch 3/4

Training…
Batch 500, Train Loss:0.0055,Train ACC: 99.0000
Batch 1000, Train Loss:0.0058,Train ACC: 99.0000
train Loss:0.0057 ACC:99.0000%
Validing…
valid Loss:0.0700 ACC:98.0000%
760.5475089550018
Epoch 4/4

Training…
Batch 500, Train Loss:0.0022,Train ACC: 99.0000
Batch 1000, Train Loss:0.0019,Train ACC: 99.0000
train Loss:0.0023 ACC:99.0000%
Validing…
valid Loss:0.0854 ACC:98.0000%
949.4390785694122

猜你喜欢

转载自blog.csdn.net/weixin_40017911/article/details/89017471