【CV】Pytorch一小时教程添加损失函数图像可视化训练过程
生活随笔
收集整理的這篇文章主要介紹了
【CV】Pytorch一小时教程添加损失函数图像可视化训练过程
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Pytorch一小時教程中的圖像分類器(GPU版本)的原代碼為:
import torch.optim as optim
import torch
import torchvision
import torchvision.transforms as transformstransform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,shuffle=False, num_workers=2)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')import matplotlib.pyplot as plt
import numpy as np# functions to show an imagedef imshow(img):img = img / 2 + 0.5 # unnormalizenpimg = img.cpu().numpy()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))import torch.nn as nn
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = x.view(-1, 16 * 5 * 5)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xnet = Net()device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# Assuming that we are on a CUDA machine, this should print a CUDA device:print(device)net.to(device)for epoch in range(2): # loop over the dataset multiple timesrunning_loss = 0.0for i, data in enumerate(trainloader, 0):# get the inputsinputs, labels = datainputs, labels = inputs.to(device), labels.to(device)# zero the parameter gradientscriterion = nn.CrossEntropyLoss()optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)optimizer.zero_grad()# forward + backward + optimizeoutputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# print statisticsrunning_loss += loss.item()if i % 2000 == 1999: # print every 2000 mini-batchesprint('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))running_loss = 0.0print('Finished Training')dataiter = iter(testloader)
images, labels = dataiter.next()
images, labels = inputs.to(device), labels.to(device)# print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))outputs = net(images)_, predicted = torch.max(outputs, 1)print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]for j in range(4)))correct = 0
total = 0
with torch.no_grad():for data in testloader:images, labels = dataimages, labels = inputs.to(device), labels.to(device)outputs = net(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))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 testloader:images, labels = dataimages, labels = inputs.to(device), labels.to(device)outputs = net(images)_, predicted = torch.max(outputs, 1)c = (predicted == labels).squeeze()for i in range(4):label = labels[i]class_correct[label] += c[i].item()class_total[label] += 1for i in range(10):print('Accuracy of %5s : %2d %%' % (classes[i], 100 * class_correct[i] / class_total[i]))
增加可視化訓練過程后的代碼:
import torch
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import torch.utils.data
import torch.nn as nn
import torch.nn.functional as F# 數據處理
transform = transforms.Compose([transforms.ToTensor(), # 轉換為tensor格式# 對圖像進行標準化,即讓數據集的圖像的均值變為0,標準差變為1,把圖片3個通道中的數據整理到[-1,1]的區間中# 輸入的參數第一個括號內是3個通道的均值,第二個是3個通道的標準差,這些數據需要自己算好再放進這個函數里,不然每次運行normalize函數都要遍歷一遍數據集transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])# 定義訓練集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
# 如果沒有import torch.utils.data,這里會出現Warning:Cannot find reference ‘data‘ in ‘__init__.py‘
# torch.utils.data.DataLoader用于將已有的數據讀取接口的輸入按照batch size封裝成Tensor
# shuffle參數表示是否在每個epoch后打亂數據;num_workers表示用多少個子進程加載數據,0表示數據將在主進程中加載,默認為0,這里不知道為啥設置多線程會報錯
trainloader = torch.utils.data.DataLoader(trainset, batch_size=8, shuffle=True)
# trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=8, shuffle=False)
# testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')# 顯示圖片函數
def imshow(img):img = img / 2 + 0.5 # 逆歸一化,公式似乎是img/(均值*batchsize)+方差# numpy不能讀取CUDA tensor 需要將它轉化為 CPU tensornpimg = img.cpu().numpy()# plt.imshow()中應有的參數為(imagesize1,imagesize2,channels),在RGB圖像中,channels=3,imagesize1為行數,imagesize2為列數,即分別為圖片的高和寬# npimg中的參數順序為(channels,imagesize1,imagesize2)# np.transpose(0,2,1)表示將數據的第二維和第三維交換# 則np.transpose(npimg, (1, 2, 0))就能將npimg變成(imagesize1,imagesize2,channels)的參數順序,然后輸入plt.imshow()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()plt.pause(0.5)plt.close()# get some random training images得到隨機的batchsize張圖片(隨機是因為之前定義trainloader的時候設置開啟了隨機)
# dataloader本質上是一個可迭代對象,可以使用iter()進行訪問,采用iter(dataloader)返回的是一個迭代器,然后可以使用next()或者enumerate訪問
dataiter = iter(trainloader)
# 訪問iter(dataloader)時,imgs在前,labels在后,分別表示:圖像轉換0~1之間的值,labels為標簽值(在這里labels就是圖像所屬的分類的標號)。并且imgs和labels是按批次進行輸入的。
# 因為之前設置了batch_size=4,所以這里的images中會有4張圖片
images, labels = dataiter.next()# show images
# torchvision.utils.make_grid()將多張圖片組合成一張圖片,padding為多張圖片之間的間隙
imshow(torchvision.utils.make_grid(images, padding=2))
# 按順序輸出四張圖片的標簽(所屬分類的名字)
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))# 定義網絡
class Net(nn.Module):def __init__(self):super(Net, self).__init__()# 第一個卷積,輸入1通道,用6個5×5的卷積核self.conv1 = nn.Conv2d(3, 6, (5, 5))# 2×2maxpool池化self.pool = nn.MaxPool2d(2, 2)# 第二個卷積,輸入6個通道(因為上一層卷積中用了6個卷積核),用16個5×5的卷積核self.conv2 = nn.Conv2d(6, 16, (5, 5))# 第一個全連接層,輸入16個5×5的圖像(5×5是因為最開始輸入的是32×32的圖像,然后經過2個卷積2個池化變成了5×5),用全連接將其變為120個節點(一維化)self.fc1 = nn.Linear(16 * 5 * 5, 120)# 將120個節點變為84個self.fc2 = nn.Linear(120, 84)# 將84個節點變為10個self.fc3 = nn.Linear(84, 10)def forward(self, x):# conv1的結果先用ReLU激活,再以2×2的池化核做max pool池化x = self.pool(F.relu(self.conv1(x)))# conv2的結果先用ReLU激活,再以2×2的池化核做max pool池化x = self.pool(F.relu(self.conv2(x)))# 將高維向量轉為一維x = x.view(-1, 16 * 5 * 5)# 用ReLU激活fc1的結果x = F.relu(self.fc1(x))# 用ReLU激活fc2的結果x = F.relu(self.fc2(x))# 計算出fc3的結果x = self.fc3(x)return xnet = Net()# 如果GPU(CUDA)可用,則用GPU,否則用CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 打印使用的是GPU/CPU
print(device)
# 將網絡放置到GPU
net.to(device)plt.ion()
loss_data = [0]
times = [0]
for epoch in range(3): # 多次循環訪問整個數據集(這里用了兩個epoch,即循環訪問2遍整個數據集)running_loss = 0.0for i, data in enumerate(trainloader, 0):# get the inputs 得到輸入的batchsize張圖片,放在inputs中,labels存儲該圖片所屬分類的名字inputs, labels = data# 將數據放置到GPU上inputs, labels = inputs.to(device), labels.to(device)# 計算交叉熵https://zhuanlan.zhihu.com/p/98785902criterion = nn.CrossEntropyLoss()# optim.SGD表示使用隨機梯度下降算法# lr是學習率;momentum是動量(在梯度下降算法中添加動量法)https://blog.csdn.net/weixin_40793406/article/details/84666803optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)# 歸零參數梯度optimizer.zero_grad()# forward + backward + optimize# 向神經網絡輸入數據,然后得到輸出outputsoutputs = net(inputs)# 輸入神經網絡輸出的預測和實際的數據的labels,計算交叉熵(偏差)loss = criterion(outputs, labels)# 將誤差反向傳播loss.backward()# 更新所有參數(權重)optimizer.step()# 累加經過這一個batchsize張圖片學習后的誤差# 《pytorch學習:loss為什么要加item()》https://blog.csdn.net/github_38148039/article/details/107144632running_loss += loss.item()if i % 2000 == 1999: # 每2000個mini-batches(即2000個batchsize次)打印一次,然后歸零running_lossprint('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))running_loss = 0.0# 可視化訓練過程with torch.no_grad():if i % 100 == 0:# loss_data.append(loss.cpu()) # 縱軸的list(loss)# 可以# times.append(i + 1 + epoch * 12000) # 橫軸的list # 可以loss_data.append(loss.cpu().tolist())times.append(times[len(times) - 1] + 1) # 行了!# print(times)# print(loss_data)plt.cla()# plt.plot(loss_data, 'r-', lw=1) # 直接輸入y軸坐標,不輸入x軸坐標是可以的plt.plot(times, loss_data, 'r-', lw=1)plt.ylabel('Loss')plt.title('loss=%.4f step=%d' % (loss.cpu(), i))plt.pause(0.1)print('Finished Training')# 創建測試集的迭代器
dataiter = iter(testloader)
# 讀取測試集中的前四張圖片
images, labels = dataiter.next()
# 將數據放置到GPU上
images, labels = images.to(device), labels.to(device)# 顯示前面讀取出來的四張圖片和其所屬的分類的名字(label)
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))# 傳入神經網絡得到預測結果
outputs = net(images)# 輸入的第一個參數是softmax輸出的一個tensor,這里就是outputs所存儲的內容;第二個參數是max函數索引的維度,0是取每列的最大值,1是每行的最大值
# 返回的第一個參數是預測出的實際概率,由于我們不需要得知實際的概率,所以在返回的第一個參數填入_不讀取,第二個返回是概率的最大值的索引,存在predicted中
# 《torch.max()使用詳解》https://www.jianshu.com/p/3ed11362b54f
_, predicted = torch.max(outputs, 1)# 打印四張圖片預測的分類
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]for j in range(4)))# 計數器初始化置零
correct = 0
total = 0
# 計算總準確率
# 被該語句包裹起來的代碼將不會被跟蹤梯度,如果測試集進行的運算被跟蹤進度可能會導致顯存爆炸
with torch.no_grad():for data in testloader:# 讀取數據(batchsize個數據,這里為4張圖片)images, labels = data# 將數據放置到GPU上images, labels = images.to(device), labels.to(device)# 得到神經網絡的輸出outputs = net(images)# 返回每行概率最大值的索引_, predicted = torch.max(outputs.data, 1)# labels.size(0)指batchsize的值,這里batchsize=4total += labels.size(0)# predicted == labels對predicted和labels中的每一項判斷是否相等# (predicted == labels).sum()返回一個tensor,tensor中是判斷為真的數量,比如有一項是相同的,則返回tensor(1)# 如果有一項是相同的,(predicted == labels).sum().item()返回1# correct在這里即為4張圖片中預測正確的數量(這里計算的是總概率)correct += (predicted == labels).sum().item()# 輸出神經網絡在測試集上的準確率
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))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 testloader:# 讀取數據(batchsize個數據,這里為4張圖片)images, labels = data# 將數據放置到GPU上images, labels = images.to(device), labels.to(device)# 得到神經網絡的輸出outputs = net(images)# 返回每行概率最大值的索引_, predicted = torch.max(outputs, 1)# squeeze()用于去除維數為1的維度,比如1行3列矩陣就會去掉行這個維度,變成第一維含有3個元素c = (predicted == labels).squeeze()for i in range(4):# label存儲當前圖像所屬分類的索引號label = labels[i]class_correct[label] += c[i].item()class_total[label] += 1
# 輸出神經網絡在測試集上的每個分類準確率
for i in range(10):print('Accuracy of %5s : %2d %%' % (classes[i], 100 * class_correct[i] / class_total[i]))
改動的部分:
在開始訓練之前,創建plt窗口,定義一個用來存儲損失函數值的list,和一個用來存儲訓練次數的list,兩者一一對應
plt.ion()
loss_data = [0]
times = [0]
在訓練的代碼中
# 可視化訓練過程with torch.no_grad(): # 關閉梯度跟蹤,防止顯存爆炸if i % 100 == 0: # 每一百次訓練添加一個點,這樣橫坐標的數值乘上100才是實際的訓練次數,當然也可以每次訓練都添加點loss_data.append(loss.cpu().tolist()) # loss是返回的交叉熵,是一個長度為1的tensor,用cpu()放到cpu上,用tolist()轉為一個list元素times.append(times[len(times) - 1] + 1) # 自動遞增次數plt.cla() # 清空上一次畫的圖# plt.plot(loss_data, 'r-', lw=1) # 直接輸入y軸坐標,不輸入x軸坐標是可以的,這樣的話x軸坐標會自動生成plt.plot(times, loss_data, 'r-', lw=1) # x軸的list和y軸的list需要原始的數據總量是一樣的,比如x中有2個元素,y中有1個元素,這樣是不行的plt.ylabel('Loss')plt.title('loss=%.4f step=%d' % (loss.cpu(), i))plt.pause(0.1)
總結
以上是生活随笔為你收集整理的【CV】Pytorch一小时教程添加损失函数图像可视化训练过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【CV】Pytorch一小时入门教程-代
- 下一篇: 代理记账一个月多少钱啊?