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