文章目錄
- 前言
- 影像分類篇
- Lenet
- model.py
- train.py
- 匯入訓練資料
- 匯入測驗資料
- 關于損失的計算
- predict.py
前言
之前苦于CV不知道具體怎么入手,在看完cs231n的課程之后,算是對整體的套路和方法有了大概的認識,但是牽扯但具體的代碼,感徑訓是處于一個非常懵的狀態,好在突然發現了一個大佬github倉庫,講的正好是CV很經典的論文和具體的代碼實作,因此我決定寫一個筆記追蹤我的學習程序,
下面給上大佬的倉庫鏈接: https://github.com/WZMIAOMIAO/deep-learning-for-image-processing
再貼上另一位大佬的csdn博客,他也跟蹤學習了這個倉庫:https://blog.csdn.net/m0_37867091
影像分類篇
Lenet
這個網路的代碼放在
deep-learning-for-image-processing-master\pytorch_classification\Test1_official_demo檔案目錄下
model .py
predict.py
train.py
model.py
先貼上代碼和模型
模型結構:

代碼:
import torch.nn as nn
import torch.nn.functional as F
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__() #為了多繼承時子類正確呼叫父類方法
self.conv1 = nn.Conv2d(3, 16, 5) #卷積操作
self.pool1 = nn.MaxPool2d(2,2) #池化操作
self.conv2 = nn.Conv2d(16,32,5)
self.pool2 = nn.MaxPool2d(2,2)
self.fc1 = nn.Linear(32*5*5, 120) #把32*5*5,全連接到120個輸出
self.fc2 = nn.Linear(120,84)
self.fc3 = nn.Linear(84,10) #全連接84個出入連接到最后的 10個輸出(根據資料集決定)
def forward(self, x):
x = F.relu(self.conv1(x)) # input(3, 32, 32) output(16,28,28)
x = self.pool1(x) # output(16,14,14)
x = F.relu(self.conv2(x)) # output(32,10,10)
x = self.pool2(x) # output(32,5,5)
x = x.view(-1,32*5*5) # output(32*5*5)
x = F.relu(self.fc1(x)) # input(32*5*5) output(120)
x = F.relu(self.fc2(x)) # output(84)
x = self.fc3(x) # output(10)
return x
tensor.view() 則是調整tensor的形狀,為全連接做準備,此處就是做了展平,當某個維度是-1,就是自動計算大小
此處則是會自動計算batch的大小,因為圖片都是一批一批計算的,我們的tensor其實有四個維度[batch,channel,height,width]
可以看他的解釋代碼:
import torch as t
a=t.arange(0,6).view(2,3)
print(a)
b=a.view(-1,2) #當某一維是-1時,會自動計算它的大小
print(b)
#輸出
tensor([[0, 1, 2],
[3, 4, 5]])
tensor([[0, 1],
[2, 3],
[4, 5]])
下面貼上 nn.Conv2d()的建構式
def __init__(
self,
in_channels: int, #輸入維度指定為int型
out_channels: int, #輸出維度指定為int型
kernel_size: _size_2_t, #卷積核大小,可以為int或者tuple型
stride: _size_2_t = 1, #可選引數,卷積步長可以為int或者tuple默認為1
padding: Union[str, _size_2_t] = 0, #可選引數,padding大小,可以為int,string或者tuple,默認為0
dilation: _size_2_t = 1,
groups: int = 1,
bias: bool = True, #是否有偏置項,默認為True
padding_mode: str = 'zeros', # TODO: refine this type
device=None,
dtype=None
) -> None:
'''Args:
in_channels (int): Number of channels in the input image
out_channels (int): Number of channels produced by the convolution
kernel_size (int or tuple): Size of the convolving kernel
stride (int or tuple, optional): Stride of the convolution. Default: 1
padding (int, tuple or str, optional): Padding added to all four sides of
the input. Default: 0
padding_mode (string, optional): ``'zeros'``, ``'reflect'``,
``'replicate'`` or ``'circular'``. Default: ``'zeros'``
dilation (int or tuple, optional): Spacing between kernel elements. Default: 1
groups (int, optional): Number of blocked connections from input
channels to output channels. Default: 1
bias (bool, optional): If ``True``, adds a learnable bias to the
output. Default: ``True`` '''
關于padding: Union[str, _size_2_t] = 0的解釋,聯合體union在記憶體中只占有一塊記憶體空間,空間大小由union中占位最多的資料型別決定,union在初始化的時候,union的值,由最后一個有效引數決定,因此在此處即指str型別引數或_size_2_t 僅有一個有效值,默認值為0.
x = x.view(-1,32*5*5) 則是把tensor展平,并自動計算batch的大小
train.py
同樣先給上代碼:
import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms
def main():
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
# 50000張訓練圖片
# 第一次使用時要將download設定為True才會自動去下載資料集
train_set = torchvision.datasets.CIFAR10(root='./data', train=True,
download=False, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=36,
shuffle=True, num_workers=0)
# 10000張驗證圖片
# 第一次使用時要將download設定為True才會自動去下載資料集
val_set = torchvision.datasets.CIFAR10(root='./data', train=False,
download=False, transform=transform)
val_loader = torch.utils.data.DataLoader(val_set, batch_size=5000,
shuffle=False, num_workers=0)
val_data_iter = iter(val_loader)
val_image, val_label = val_data_iter.next()
# classes = ('plane', 'car', 'bird', 'cat',
# 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
net = LeNet()
loss_function = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)
for epoch in range(5): # loop over the dataset multiple times
running_loss = 0.0
for step, data in enumerate(train_loader, start=0):
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad() #將累計的梯度清零,如果不清零會累加batch,能夠實作一個大的batch
# forward + backward + optimize
outputs = net(inputs)
loss = loss_function(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if step % 500 == 499: # print every 500 mini-batches
with torch.no_grad():
outputs = net(val_image) # [batch, 10]
predict_y = torch.max(outputs, dim=1)[1]
accuracy = torch.eq(predict_y, val_label).sum().item() / val_label.size(0)
print('[%d, %5d] train_loss: %.3f test_accuracy: %.3f' %
(epoch + 1, step + 1, running_loss / 500, accuracy))
running_loss = 0.0
print('Finished Training')
save_path = './Lenet.pth'
torch.save(net.state_dict(), save_path)
if __name__ == '__main__':
main()
with torch.no_grad():被這個陳述句包裹的部分不會自動計算每個結點的損失和梯度并進行保存,在預測和驗證的時候要進來,不然容易發生記憶體問題,詳細的可以看 這篇博客
transforms.Compose() 是pytorch給出的組合函式,他能把多個transform組合到一起,他的實作是靠遍歷list,因此中括號一定要加,
下面貼上transform.Compose()函式的內部實作函式方便理解,
example:
transforms.Compose([
transforms.CenterCrop(10),
transforms.ToTensor(),
])
內部實作:
def __init__(self, transforms):
self.transforms = transforms
def __call__(self, img):
for t in self.transforms: #在此處的for回圈中呼叫多個transform函式操作img圖片
img = t(img)
return img #最后把處理好的圖片回傳
transforms.ToTensor()函式先把PIL.Image或者numpy.ndarray轉換成tensor型別,內部主要做了兩個操作:1.把[0,255]的資料轉換到[0.0, 1.0]之間,2.交換了資料的維度PIL.Image和numpy.ndarray是(H, W, C),H:height,W:width,C:channel,而tensor是(C, H, W),
匯入訓練資料
# 匯入50000張訓練圖片
train_set = torchvision.datasets.CIFAR10(root='./data', # 資料集存放目錄
train=True, # 表示是資料集中的訓練集
download=True, # 第一次運行時為True,下載資料集,下載完成后改為False
transform=transform) # 預處理程序
# 加載訓練集,實際程序需要分批次(batch)訓練
train_loader = torch.utils.data.DataLoader(train_set, # 匯入的訓練集
batch_size=50, # 每批訓練的樣本數
shuffle=False, # 是否打亂訓練集
num_workers=0) # 使用執行緒數,在windows下設定為0
匯入測驗資料
# 匯入10000張測驗圖片
test_set = torchvision.datasets.CIFAR10(root='./data',
train=False, # 表示是資料集中的測驗集
download=False,transform=transform)
# 加載測驗集
test_loader = torch.utils.data.DataLoader(test_set,
batch_size=10000, # 每批用于驗證的樣本數
shuffle=False, num_workers=0)
# 獲取測驗集中的影像和標簽,用于accuracy計算
test_data_iter = iter(test_loader)
test_image, test_label = test_data_iter.next()
關于損失的計算
optimizer.zero_grad()
loss.backward()
optimizer.step()
這三個函式請參考這篇博文:損失計算
predict.py
代碼:
import torch
import torchvision.transforms as transforms
from PIL import Image
from model import LeNet
def main():
transform = transforms.Compose(
[transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
net = LeNet() #實體化網路模型
net.load_state_dict(torch.load('Lenet.pth')) #傳入權重檔案Lenet.pth
im = Image.open('1.jpg') #PIL包讀入圖片
im = transform(im) # [C, H, W]
im = torch.unsqueeze(im, dim=0) # [N, C, H, W] 對資料維度進行擴充,因為現在的圖片是3維度,
#但是我們網路的輸入是四維的,最前面還有batch維度
with torch.no_grad(): #torch.no_grad() 是一個背景關系管理器,被該陳述句 wrap 起來的部分將不會track 梯度,
outputs = net(im)
predict = torch.max(outputs, dim=1)[1].data.numpy() #獲取最大的輸出的index并從tensor轉換成numpy
print(classes[int(predict)]) #把numpy型別陣列轉換成int型別,只能是一個元素的numpy
if __name__ == '__main__':
main()
預測代碼中transforms.Compose()函式中比train檔案中多了個resize函式,transforms.Resize((32, 32)是為了把圖片重新定義為32*32的大小,因為我們下載的圖片大小不一樣的,無法傳入網路訓練,
torch.unsqueeze(im, dim=0)對im的維度進行擴充,dim=0在最前面增加一列,
im[C, H, W],擴充后[B, C, H, W]
Lenet.ph檔案是在我們運行完train.py之后生成的權重檔案,會生成在和train.py相同的檔案目錄下,用于預測,
剛剛入門,如有錯誤,謝謝指出,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/385480.html
標籤:AI
上一篇:回圈計數器行為例外
