pytorch实现vgg-16


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

%matplotlib inline

data_dir = "E:/01-论文指导/04-代码/莫烦/PyTorch-Tutorial-master/kaggle_DogsVSCats"
# 定义要对数据进行的处理
data_transform = {x: transforms.Compose([transforms.Resize([224, 224]),
                                         transforms.ToTensor(),
                                         transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])
                  for x in ["train"]}
# 数据载入
image_datasets = {x: datasets.ImageFolder(root=os.path.join(data_dir, x),
                                          transform=data_transform[x])
                  for x in ["train"]}
# 数据装载
dataloader = {x: torch.utils.data.DataLoader(dataset=image_datasets[x],
                                             batch_size=16,
                                             shuffle=True)
              for x in ["train"]}

X_example, y_example = next(iter(dataloader["train"]))
print(u'X_example个数{}'.format(len(X_example)))
print(u'y_example个数{}'.format(len(y_example)))
print(X_example.shape)
print(y_example.shape)
#torch.Size([16, 3, 224, 224])第一位表示batchsize,第二维表示输入的channels,第三位表示图片height,第四位表示图片的width
# 验证独热编码的对应关系
index_classes = image_datasets["train"].class_to_idx
# print(index_classes)
# 使用example_classes存放原始标签的结果
example_classes = image_datasets["train"].classes
# print(example_classes)

# 图片预览
img = torchvision.utils.make_grid(X_example)
# print(img.shape)
img = img.numpy().transpose([1, 2, 0])

for i in range(len(y_example)):
    index = y_example[i]
    print(example_classes[index], end='   ')
    if (i + 1) % 8 == 0:
        print()

# print(img.max())
# print(img.min())
# print(img.shape)

std = [0.5, 0.5, 0.5]
mean = [0.5, 0.5, 0.5]
img = img * std + mean

# print(img.max())
# print(img.min())
# print(img.shape)

plt.imshow(img)
plt.show()

# 下载已经具备最优参数的VGG16模型
model = models.vgg16(pretrained=True)
# 查看迁移模型细节
# print("迁移VGG16:\n", model)

# 对迁移模型进行调整
for parma in model.parameters():
    parma.requires_grad = False

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("调整后VGG16:\n", model)
# 判断计算机的GPUs是否可用
Use_gpu = torch.cuda.is_available()
if Use_gpu:
    model = model.cuda()

# 定义代价函数和优化函数
loss_f = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.classifier.parameters(), lr=0.00001)

# 模型训练和参数优化
epoch_n = 5
time_open = time.time()

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

    for phase in ["train"]:
        if phase == "train":
            print("Training...")
            # 设置为True,会进行Dropout并使用batch mean和batch var
            model.train(True)
        else:
            print("Validing...")
            # 设置为False,不会进行Dropout并使用running mean和running var
            model.train(False)

        running_loss = 0.0
        running_corrects = 0

        # enuerate(),返回的是索引和元素值,数字1表明设置start=1,即索引值从1开始
        for batch, data in enumerate(dataloader[phase], 1):
            # X: 图片,16*3*224*224; y: 标签,16
            X, y = data

            # 修改处
            if Use_gpu:
                X, y = Variable(X.cuda()), Variable(y.cuda())
            else:
                X, y = Variable(X), Variable(y)

            # y_pred: 预测概率矩阵,16*2
            y_pred = model(X)

            # pred,概率较大值对应的索引值,可看做预测结果
            _, 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 += float(loss)

            # 统计预测正确的图片数
            running_corrects += torch.sum(pred == y.data)

            # 共20000张测试图片,1250个batch,在使用500个及1000个batch对模型进行训练之后,输出训练结果
            if batch % 500 == 0 and phase == "train":
                print("Batch {}, Train Loss:{:.4f}, Train ACC:{:.4F}%".format(batch, running_loss / batch,
                                                                              100 * running_corrects / (16 * batch)))

        epoch_loss = running_loss * 16 / len(image_datasets[phase])
        epoch_acc = 100 * running_corrects / len(image_datasets[phase])

        # 输出最终的结果
        print("{} Loss:{:.4f} Acc:{:.4f}%".format(phase, epoch_loss, epoch_acc))

# 输出模型训练、参数优化用时
time_end = time.time() - time_open
print(time_end)

结果:

 

 

遇到的问题很多。。。

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

%matplotlib inline

1、导包

报错:ModuleNotFoundError: No module named 'matplotlib'

之前还可以运行,后来就报错这句,解决办法是cmd到当前环境下,然后运行pip install matplotlib安装后重启不管是jupyter notebook还是pycharm都可以了

另外%matplotlib inline前面%后不要空格

# 数据载入
image_datasets = {x: datasets.ImageFolder(root=os.path.join(data_dir, x),
                                          transform=data_transform[x])
                  for x in ["train"]}

2、数据载入

报错:Found 0 files in subfolders....

开始还以为是读不到文件。后来才知道这句代码和数据集不匹配有问题:

ImageFolder假设所有的文件按文件夹保存好,每个文件夹下面存贮同一类别的图片,文件夹的名字为分类的名字

数据集中是猫和狗的图片,没有分文件夹,不能从train中文件夹获得标签,手动建了文件夹就可以了。

3、数据装载

dataloader = {x: torch.utils.data.DataLoader(dataset=image_datasets[x],
                                             batch_size=16,
                                             shuffle=True)
              for x in ["train"]}

PyTorch中数据读取的一个重要接口是torch.utils.data.DataLoader。

只要是用PyTorch来训练模型基本都会用到该接口,该接口主要用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensor,后续只需要再包装成Variable即可作为模型的输入

(1)dataset,这个就是PyTorch已有的数据读取接口(比如torchvision.datasets.ImageFolder)或者自定义的数据接口的输出,该输出要么是torch.utils.data.Dataset类的对象,要么是继承自torch.utils.data.Dataset类的自定义类的对象。
(2)batch_size,根据具体情况设置即可。
(3)shuffle,一般在训练数据中会采用。
(4)collate_fn,是用来处理不同情况下的输入dataset的封装,一般采用默认即可,除非你自定义的数据读取输出非常少见。
(5)batch_sampler,从注释可以看出,其和batch_size、shuffle等参数是互斥的,一般采用默认。
(6)sampler,从代码可以看出,其和shuffle是互斥的,一般默认即可。
(7)num_workers,从注释可以看出这个参数必须大于等于0,0的话表示数据导入在主进程中进行,其他大于0的数表示通过多个进程来导入数据,可以加快数据导入速度。
(8)pin_memory,注释写得很清楚了: pin_memory (bool, optional): If True, the data loader will copy tensors into CUDA pinned memory before returning them. 也就是一个数据拷贝的问题。
(9)timeout,是用来设置数据读取的超时时间的,但超过这个时间还没读取到数据的话就会报错。

4、遍历图片?

打印#torch.Size([16, 3, 224, 224])第一位表示batchsize,第二维表示输入的channels,第三位表示图片height,第四位表示图片的width
X_example, y_example = next(iter(dataloader["train"]))
print(u'X_example个数{}'.format(len(X_example)))
print(u'y_example个数{}'.format(len(y_example)))
print(X_example.shape)
print(y_example.shape)  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM