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)
