【Pytorch神经网络实战案例】08 识别黑白图中的服装图案(Fashion-MNIST)
1 Fashion-MNIST簡介
FashionMNIST 是一個替代 MNIST 手寫數字集 的圖像數據集。 它是由 Zalando(一家德國的時尚科技公司)旗下的研究部門提供。其涵蓋了來自 10 種類別的共 7 萬個不同商品的正面圖片。
FashionMNIST 的大小、格式和訓練集/測試集劃分與原始的 MNIST 完全一致。60000/10000 的訓練測試數據劃分,28x28 的灰度圖片。你可以直接用它來測試你的機器學習和深度學習算法性能,且不需要改動任何的代碼。說白了就是手寫數字沒有衣服鞋子之類的更復雜。
1.1?Fashion-MNIST數據集標簽類件組成
Fashion-MNIST數據集包含了10個類別的圖像,分別是:t-shirt(T恤),trouser(牛仔褲),pullover(套衫),dress(裙子),coat(外套),sandal(涼鞋),shirt(襯衫),sneaker(運動鞋),bag(包),ankle boot(短靴)。
1.2?Fashion-MNIST數據集文件組成
共包含四個文件,分別為:
- 訓練數據圖片train-images-idx3-ubyte
- 訓練數據標簽train-labels-idx1-ubyte
- 測試數據圖片t10k-images-idx3-ubyte
- 測試數據標簽t10k-labels-idx1-ubyte
1.3?Fashion-MNIST數據集序列號
標注編號描述
0:T-shirt/top(T恤)
1:Trouser(褲子)
2:Pullover(套衫)
3:Dress(裙子)
4:Coat(外套)
5:Sandal(涼鞋)
6:Shirt(汗衫)
7:Sneaker(運動鞋)
8:Bag(包)
9:Ankle boot(踝靴)
2 識別黑白圖中的服裝圖案實戰代碼分解
2.1 自動下載Fashion-MNIST數據集
2.1.1 自動下載代碼---Fashion-MNISt-CNN.py(第1部分)
import torchvision import torchvision.transforms as transforms import pylab import torch from matplotlib import pyplot as plt import torch.utils.data import torch.nn.functional as F import numpy as np import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"# 定義顯示圖像的函數 def imshow(img):print("圖片形狀",np.shape(img))img = img/2 +0.5npimg = img.numpy()plt.axis('off')plt.imshow(np.transpose(npimg,(1,2,0)))### 1.1 自動下載FashionMNIST數據集 data_dir = './fashion_mnist' # 設置存放位置 transform = transforms.Compose([transforms.ToTensor()]) # 可以自動將圖片轉化為Pytorch支持的形狀[通道,高,寬],同時也將圖片的數值歸一化 train_dataset = torchvision.datasets.FashionMNIST(data_dir,train=True,transform=transform,download=True) print("訓練集的條數",len(train_dataset))2.2 讀取及其顯示Fashion-MNIST中的數據
2.2.1?讀取及其顯示Fashion-MNIST中的數據代碼實現 ---Fashion-MNISt-CNN.py(第2部分)
### 1.2 讀取及顯示FashionMNIST數據集中的數據 val_dataset = torchvision.datasets.FashionMNIST(root=data_dir,train=False,transform=transform) print("測試集的條數",len(val_dataset))2.2.2 FAshion-MNIST數據集補充知識
Fashion-MNST數據集中的圖片大小是28像素×28像素。每-幅圖就是1行784(28×28)列的數據括二中的每個值優麥一個像素。
關于像素:如果是黑白的圖片,那么圖案中黑色的地方數值為Q;在有圖案的地方,數據為0~255的數字,代表其顏色的深度。如果是彩色的圖片,那么一個像素會有3個值來表示其RGB(紅、綠、藍)值。
2.3 制造批次數據集
2.3.1 數據集封裝類 DataLoader
torch.utils.data.DataLoader(dataset, batch_size=1,shuffle=False,sampler=None,batch_sampler=None, num_workers=0, collate_fn=None,pin_memory=False, drop_last=False, timeout=0,worker_init_fn=None) Arguments:dataset (Dataset): 是一個DataSet對象,表示需要加載的數據集.batch_size (int, optional): 每一個batch加載多少組樣本,即指定batch_size,默認是 1 shuffle (bool, optional): 布爾值True或者是False ,表示每一個epoch之后是否對樣本進行隨機打亂,默認是False ------------------------------------------------------------------------------------sampler (Sampler, optional): 接受一個采集器對象,并且使用該策略進行提取樣本,如果指定這個參數,那么shuffle必須為Falsebatch_sampler (Sampler, optional): 與sampler類似,但是一次只返回一個batch的indices(索引),需要注意的是,一旦指定了這個參數,那么batch_size,shuffle,sampler,drop_last就不能再制定了(互斥)。 ------------------------------------------------------------------------------------num_workers (int, optional): 設置加載數據的額外進程數量。0意味著所有的數據都會被load進主進程。(默認為0)collate_fn (callable, optional): 接收一個自定義函數。當該參數不為None時,系統會在從數據集中取出數據之后,將數據傳入collate_fn中,由collate_fn參數所指向的函數對數據進行二次加工。該參數常用于在不同場景(測試和訓練場景)下對同一數據集的數據提取。pin_memory (bool, optional): 如果設置為True,那么data loader將會在返回它們之前,將tensors拷貝到CUDA中的固定內存(CUDA pinned memory)中. ------------------------------------------------------------------------------------drop_last (bool, optional): 如果設置為True:這個是對最后的未完成的batch來說的,比如你的batch_size設置為64,而一個epoch只有100個樣本,那么訓練的時候后面的36個就被扔掉了,如果為False(默認),那么會繼續正常執行,只是最后的batch_size會小一點。 ------------------------------------------------------------------------------------timeout (numeric, optional): 如果是正數,表明等待從worker進程中收集一個batch等待的時間,若超出設定的時間還沒有收集到,停止收集。這個numeric應總是大于等于0。默認為0. worker_init_fn (callable, optional): 每個子進程的初始化函數,加載數據之前運行。2.3.3?DataLoader中的Sampler類
- SequentialSampler:按照原有的樣本順序進行采樣。
- RandomSampler:按照隨機u順序進行采樣,可以設置是否重復采樣。
- SubsetRandomSampler:按照指定的集合或索引列表進行隨機順序采樣。
- WeightedRandomSampler:按照指定的概率進行隨機,順序采樣。
- BatchSampler:按照指定的批次索引進行采樣。
2.3.4 按照批次封裝Fashion-MNIST數據集 ---Fashion-MNISt-CNN.py(第3部分)
### 1.3 按批次封裝FashionMNIST數據集 batch_size = 10 #設置批次大小 train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_loader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=False)2.3.5 讀取批次數據集實戰代碼 ---Fashion-MNISt-CNN.py(第4部分)
### 1.4 讀取批次數據集 ## 定義類別名稱 classes = ('T-shirt', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle_Boot') sample = iter(train_loader) # 將數據集轉化成迭代器 images,labels = sample.next() # 從迭代器中取得一批數據 print("樣本形狀",np.shape(images)) # 打印樣本形狀 # 輸出 樣本形狀 torch.Size([10, 1, 28, 28]) print("樣本標簽",labels) # 輸出 圖片形狀 torch.Size([3, 32, 302]) imshow(torchvision.utils.make_grid(images,nrow = batch_size)) # 數據可視化:make_grid()將該批次的圖片內容組合為一個圖片,用于顯示,nrow用于設置生成圖片中每行的樣本數量 print(','.join('%5s' % classes[labels[j]] for j in range(len(images)))) # 輸出 Trouser,Trouser,Dress, Bag,Shirt,Sandal,Shirt,Dress, Bag, Bag2.4 構建并訓練模型
2.4.1 定義模型類MyConNet---Fashion-MNISt-CNN.py(第5部分)
總體結構為兩個卷積層結合3個全連接層,如下圖:
### 1.5 定義模型類 class myConNet(torch.nn.Module):def __init__(self):super(myConNet, self).__init__()# 定義卷積層self.conv1 = torch.nn.Conv2d(in_channels = 1 ,out_channels = 6,kernel_size = 5)self.conv2 = torch.nn.Conv2d(in_channels = 6,out_channels = 12,kernel_size = 5)# 定義全連接層self.fc1 = torch.nn.Linear(in_features = 12*4*4,out_features = 120)self.fc2 = torch.nn.Linear(in_features = 120,out_features = 60)self.out = torch.nn.Linear(in_features = 60,out_features = 10) # 10是固定的,因為必須要和模型所需要的分類個數一致def forward(self,t):# 第一層卷積和池化處理t = self.conv1(t)t = F.relu(t)t = F.max_pool2d(t, kernel_size=2, stride=2)# 第二層卷積和池化處理t = self.conv2(t)t = F.relu(t)t = F.max_pool2d(t, kernel_size=2, stride=2)# 搭建全連接網絡,第一層全連接t = t.reshape(-1, 12 * 4 * 4) # 將卷積結果由4維變為2維t = self.fc1(t)t = F.relu(t)# 第二層全連接t = self.fc2(t)t = F.relu(t)# 第三層全連接t = self.out(t)return t if __name__ == '__main__':network = myConNet() # 生成自定義模塊的實例化對象#指定設備device = torch.device("cuda:0"if torch.cuda.is_available() else "cpu")print(device)network.to(device)print(network) # 打印myConNet網絡輸出:
cuda:0
myConNet(
? (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
? (conv2): Conv2d(6, 12, kernel_size=(5, 5), stride=(1, 1))
? (fc1): Linear(in_features=192, out_features=120, bias=True)
? (fc2): Linear(in_features=120, out_features=60, bias=True)
? (out): Linear(in_features=60, out_features=10, bias=True)
)
2.4.2 定義損失的計算方法與優化---Fashion-MNISt-CNN.py(第6部分)
### 1.6 損失函數與優化器criterion = torch.nn.CrossEntropyLoss() #實例化損失函數類optimizer = torch.optim.Adam(network.parameters(), lr=.01)2.4.3 訓練模型---Fashion-MNISt-CNN.py(第7部分)
### 1.7 訓練模型for epoch in range(2): # 數據集迭代2次running_loss = 0.0for i, data in enumerate(train_loader, 0): # 循環取出批次數據 使用enumerate()函數對循環計數,第二個參數為0,表示從0開始inputs, labels = datainputs, labels = inputs.to(device), labels.to(device) #optimizer.zero_grad() # 清空之前的梯度outputs = network(inputs)loss = criterion(outputs, labels) # 計算損失loss.backward() # 反向傳播optimizer.step() # 更新參數running_loss += loss.item()### 訓練過程的顯示if i % 1000 == 999:print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))running_loss = 0.0print('Finished Training')輸出:
[1, ?1000] loss: 0.465
[1, ?2000] loss: 0.346
[1, ?3000] loss: 0.320
[1, ?4000] loss: 0.301
[1, ?5000] loss: 0.293
[1, ?6000] loss: 0.293
[2, ?1000] loss: 0.290
[2, ?2000] loss: 0.280
[2, ?3000] loss: 0.280
[2, ?4000] loss: 0.288
[2, ?5000] loss: 0.285
[2, ?6000] loss: 0.288
Finished Training
2.4.4 保存模型---Fashion-MNISt-CNN.py(第8部分)
### 1.8 保存模型torch.save(network.state_dict(),'./models/CNNFashionMNist.PTH')2.5 加載模型,并進行預測
2.5.1 加載模型并預測代碼實現?---Fashion-MNISt-CNN.py(第9部分)
### 1.9 加載模型,并且使用該模型進行預測network.load_state_dict(torch.load('./models/CNNFashionMNist.PTH')) # 加載模型# 使用模型dataiter = iter(test_loader) # 獲取測試數據images, labels = dataiter.next()inputs, labels = images.to(device), labels.to(device)imshow(torchvision.utils.make_grid(images, nrow=batch_size)) # 取出一批數據進行展示print('真實標簽: ', ' '.join('%5s' % classes[labels[j]] for j in range(len(images))))# 輸出:真實標簽: Ankle_Boot Pullover Trouser Trouser Shirt Trouser Coat Shirt Sandal Sneakeroutputs = network(inputs) # 調用network對輸入樣本進行預測,得到測試結果outputs_, predicted = torch.max(outputs, 1) # 對于預測結果outputs沿著第1維度找出最大值及其索引值,該索引值即為預測的分類結果print('預測結果: ', ' '.join('%5s' % classes[predicted[j]] for j in range(len(images))))# 輸出:預測結果: Ankle_Boot Pullover Trouser Trouser Pullover Trouser Shirt Shirt Sandal Sneaker輸出:
圖片形狀 torch.Size([3, 32, 302])
真實標簽: Ankle_Boot Pullover Trouser Trouser Shirt Trouser ?Coat Shirt Sandal Sneaker
預測結果: Ankle_Boot Pullover Trouser Trouser Shirt Trouser Pullover Shirt Sandal Sneaker
2.6 評估模型
2.6.1 評估模型的作用
對于模型的能力進行一個精確的評估,需要對每一個分類的精度進行量化計算
2.6.2?評估模型代碼實現
### 1.10 評估模型# 測試模型class_correct = list(0. for i in range(10)) # 定義列表,收集每個類的正確個數class_total = list(0. for i in range(10)) # 定義列表,收集每個類的總個數with torch.no_grad():for data in test_loader: # 遍歷測試數據集images, labels = datainputs, labels = images.to(device), labels.to(device)outputs = network(inputs) # 將每個批次的數據輸入模型_, predicted = torch.max(outputs, 1) # 計算預測結果predicted = predicted.to(device)c = (predicted == labels).squeeze() # 統計正確的個數for i in range(10): # 遍歷所有類別label = labels[i]class_correct[label] = class_correct[label] + c[i].item() # 若該類別正確則+1class_total[label] = class_total[label] + 1 # 根據標簽中的類別,計算類的總數sumacc = 0for i in range(10): # 輸出每個類的預測結果Accuracy = 100 * class_correct[i] / class_total[i]print('Accuracy of %5s : %2d %%' % (classes[i], Accuracy))sumacc = sumacc + Accuracyprint('Accuracy of all : %2d %%' % (sumacc / 10.)) # 輸出最終的準確率輸出:
Accuracy of T-shirt : 70 %
Accuracy of Trouser : 91 %
Accuracy of Pullover : 77 %
Accuracy of Dress : 81 %
Accuracy of ?Coat : 64 %
Accuracy of Sandal : 89 %
Accuracy of Shirt : 50 %
Accuracy of Sneaker : 90 %
Accuracy of ? Bag : 94 %
Accuracy of Ankle_Boot : 95 %
Accuracy of all : 80 %
2.6.3 Tip
- 模型的測試結果只是一個模型能力的參考值,它并不能完全反映模型的真實情況。這取決于訓練樣本和測試樣本的分布情況,也取決于摸型本身的擬合質量。
- 在計算機上運行代碼時,得到的值可能的值不一樣,甚至每次運行時,得到的值也不一樣,這是因為每次初始的權重w是隨機的。由于初始權重不同,而且每次訓練的批次數據也不同,因此最終生成的模型也不會完全相同。但如果核心算法一致,那么會保證最終的結果不會有太大的偏差。
3 識別黑白圖中的服裝圖案總覽
import torchvision import torchvision.transforms as transforms import pylab import torch from matplotlib import pyplot as plt import torch.utils.data import torch.nn.functional as F import numpy as np import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"# 定義顯示圖像的函數 def imshow(img):print("圖片形狀",np.shape(img))img = img/2 +0.5npimg = img.numpy()plt.axis('off')plt.imshow(np.transpose(npimg,(1,2,0)))### 1.1 自動下載FashionMNIST數據集 data_dir = './fashion_mnist' # 設置存放位置 transform = transforms.Compose([transforms.ToTensor()]) # 可以自動將圖片轉化為Pytorch支持的形狀[通道,高,寬],同時也將圖片的數值歸一化 train_dataset = torchvision.datasets.FashionMNIST(data_dir,train=True,transform=transform,download=True) print("訓練集的條數",len(train_dataset))### 1.2 讀取及顯示FashionMNIST數據集中的數據 val_dataset = torchvision.datasets.FashionMNIST(root=data_dir,train=False,transform=transform) print("測試集的條數",len(val_dataset)) ##1.2.1 顯示數據集中的數據 im = train_dataset[0][0].numpy() im = im.reshape(-1,28) pylab.imshow(im) pylab.show() print("當前圖片的標簽為",train_dataset[0][1])### 1.3 按批次封裝FashionMNIST數據集 batch_size = 10 #設置批次大小 train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_loader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=False)### 1.4 讀取批次數據集 ## 定義類別名稱 classes = ('T-shirt', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle_Boot') sample = iter(train_loader) # 將數據集轉化成迭代器 images,labels = sample.next() # 從迭代器中取得一批數據 print("樣本形狀",np.shape(images)) # 打印樣本形狀 # 輸出 樣本形狀 torch.Size([10, 1, 28, 28]) print("樣本標簽",labels) # 輸出 圖片形狀 torch.Size([3, 32, 302]) imshow(torchvision.utils.make_grid(images,nrow = batch_size)) # 數據可視化:make_grid()將該批次的圖片內容組合為一個圖片,用于顯示,nrow用于設置生成圖片中每行的樣本數量 print(','.join('%5s' % classes[labels[j]] for j in range(len(images)))) # 輸出 Trouser,Trouser,Dress, Bag,Shirt,Sandal,Shirt,Dress, Bag, Bag### 1.5 定義模型類 class myConNet(torch.nn.Module):def __init__(self):super(myConNet, self).__init__()# 定義卷積層self.conv1 = torch.nn.Conv2d(in_channels = 1 ,out_channels = 6,kernel_size = 5)self.conv2 = torch.nn.Conv2d(in_channels = 6,out_channels = 12,kernel_size = 5)# 定義全連接層self.fc1 = torch.nn.Linear(in_features = 12*4*4,out_features = 120)self.fc2 = torch.nn.Linear(in_features = 120,out_features = 60)self.out = torch.nn.Linear(in_features = 60,out_features = 10) # 10是固定的,因為必須要和模型所需要的分類個數一致def forward(self,t):# 第一層卷積和池化處理t = self.conv1(t)t = F.relu(t)t = F.max_pool2d(t, kernel_size=2, stride=2)# 第二層卷積和池化處理t = self.conv2(t)t = F.relu(t)t = F.max_pool2d(t, kernel_size=2, stride=2)# 搭建全連接網絡,第一層全連接t = t.reshape(-1, 12 * 4 * 4) # 將卷積結果由4維變為2維t = self.fc1(t)t = F.relu(t)# 第二層全連接t = self.fc2(t)t = F.relu(t)# 第三層全連接t = self.out(t)return t if __name__ == '__main__':network = myConNet() # 生成自定義模塊的實例化對象#指定設備device = torch.device("cuda:0"if torch.cuda.is_available() else "cpu")print(device)network.to(device)print(network) # 打印myConNet網絡 ### 1.6 損失函數與優化器criterion = torch.nn.CrossEntropyLoss() #實例化損失函數類optimizer = torch.optim.Adam(network.parameters(), lr=.01) ### 1.7 訓練模型for epoch in range(2): # 數據集迭代2次running_loss = 0.0for i, data in enumerate(train_loader, 0): # 循環取出批次數據 使用enumerate()函數對循環計數,第二個參數為0,表示從0開始inputs, labels = datainputs, labels = inputs.to(device), labels.to(device) #optimizer.zero_grad() # 清空之前的梯度outputs = network(inputs)loss = criterion(outputs, labels) # 計算損失loss.backward() # 反向傳播optimizer.step() # 更新參數running_loss += loss.item()### 訓練過程的顯示if i % 1000 == 999:print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))running_loss = 0.0print('Finished Training') ### 1.8 保存模型torch.save(network.state_dict(),'./models/CNNFashionMNist.PTH')### 1.9 加載模型,并且使用該模型進行預測network.load_state_dict(torch.load('./models/CNNFashionMNist.PTH')) # 加載模型# 使用模型dataiter = iter(test_loader) # 獲取測試數據images, labels = dataiter.next()inputs, labels = images.to(device), labels.to(device)imshow(torchvision.utils.make_grid(images, nrow=batch_size)) # 取出一批數據進行展示print('真實標簽: ', ' '.join('%5s' % classes[labels[j]] for j in range(len(images))))# 輸出:真實標簽: Ankle_Boot Pullover Trouser Trouser Shirt Trouser Coat Shirt Sandal Sneakeroutputs = network(inputs) # 調用network對輸入樣本進行預測,得到測試結果outputs_, predicted = torch.max(outputs, 1) # 對于預測結果outputs沿著第1維度找出最大值及其索引值,該索引值即為預測的分類結果print('預測結果: ', ' '.join('%5s' % classes[predicted[j]] for j in range(len(images))))# 輸出:預測結果: Ankle_Boot Pullover Trouser Trouser Pullover Trouser Shirt Shirt Sandal Sneaker### 1.10 評估模型# 測試模型class_correct = list(0. for i in range(10)) # 定義列表,收集每個類的正確個數class_total = list(0. for i in range(10)) # 定義列表,收集每個類的總個數with torch.no_grad():for data in test_loader: # 遍歷測試數據集images, labels = datainputs, labels = images.to(device), labels.to(device)outputs = network(inputs) # 將每個批次的數據輸入模型_, predicted = torch.max(outputs, 1) # 計算預測結果predicted = predicted.to(device)c = (predicted == labels).squeeze() # 統計正確的個數for i in range(10): # 遍歷所有類別label = labels[i]class_correct[label] = class_correct[label] + c[i].item() # 若該類別正確則+1class_total[label] = class_total[label] + 1 # 根據標簽中的類別,計算類的總數sumacc = 0for i in range(10): # 輸出每個類的預測結果Accuracy = 100 * class_correct[i] / class_total[i]print('Accuracy of %5s : %2d %%' % (classes[i], Accuracy))sumacc = sumacc + Accuracyprint('Accuracy of all : %2d %%' % (sumacc / 10.)) # 輸出最終的準確率總結
以上是生活随笔為你收集整理的【Pytorch神经网络实战案例】08 识别黑白图中的服装图案(Fashion-MNIST)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有点看不懂了,回填知识中~~~~~
- 下一篇: 爬虫实战学习笔记_1 爬虫基础+HTTP