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)