第3次作业-卷积神经网络
第三次作業(yè):卷積神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
文章目錄
- 第三次作業(yè):卷積神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
- 一、要求:
- 二、`Part1` 視頻學(xué)習(xí)
- 以下是在視頻學(xué)習(xí)后,根據(jù)所學(xué)繪制的思維導(dǎo)圖,其大致涵蓋了本次學(xué)習(xí)卷積神經(jīng)網(wǎng)絡(luò)的所得。
- 三、`Part2` 代碼練習(xí)
- 1.MNIST 數(shù)據(jù)集分類:構(gòu)建簡單的CNN對 mnist 數(shù)據(jù)集進行分類。同時,還會在實驗中學(xué)習(xí)池化與卷積操作的基本作用。
- (1)加載數(shù)據(jù) (MNIST)
- (2)創(chuàng)建網(wǎng)絡(luò)
- (3)在小型全連接網(wǎng)絡(luò)上訓(xùn)練(Fully-connected network)
- (4)在卷積神經(jīng)網(wǎng)絡(luò)上訓(xùn)練
- (5)打亂像素順序再次在兩個網(wǎng)絡(luò)上訓(xùn)練與測試
- 2.CIFAR10 數(shù)據(jù)集分類:使用 CNN 對 CIFAR10 數(shù)據(jù)集進行分類
- (1)加載并歸一化 CIFAR10 使用 torchvision
- (2)展示 CIFAR10 里面的一些圖片
- (3)定義網(wǎng)絡(luò),損失函數(shù)和優(yōu)化器
- (4)從測試集中取出8張圖片,檢測CNN識圖的能力
- (5)測試驗證準確率
- 3.使用 VGG16 對 CIFAR10 分類
- (1)定義 dataloader
- (2)VGG 網(wǎng)絡(luò)定義
- (3)網(wǎng)絡(luò)訓(xùn)練
- (4)測試驗證準確率
- (5)運行結(jié)果:
- ①找到`cfg`所在的位置:
- ②報錯信息變?yōu)?/li>
- ③出現(xiàn)新的錯誤
- 四、思考的問題:
- 1、dataloader 里面 shuffle 取不同值有什么區(qū)別?
- 2、transform 里,取了不同值,這個有什么區(qū)別?
- 3、epoch 和 batch 的區(qū)別?
- 4、1x1的卷積和 FC 有什么區(qū)別?主要起什么作用?
- 5、residual leanring 為什么能夠提升準確率?
- 6、代碼練習(xí)二里,網(wǎng)絡(luò)和1989年 Lecun 提出的 LeNet 有什么區(qū)別?
- 7、代碼練習(xí)二里,卷積以后feature map 尺寸會變小,如何應(yīng)用 Residual Learning?
- 8、有什么方法可以進一步提升準確率?
一、要求:
Part1 視頻學(xué)習(xí):學(xué)習(xí)專知課程《卷積神經(jīng)網(wǎng)絡(luò)》,主要內(nèi)容包括:
- CNN的基本結(jié)構(gòu):卷積、池化、全連接
- 典型的網(wǎng)絡(luò)結(jié)構(gòu):AlexNet、VGG、GoogleNet、ResNet
Part2 代碼練習(xí):需要使用谷歌的 Colab ,大家有任何問題可以隨時在群里 AT 我。有部分同學(xué)已經(jīng)做過這部分代碼練習(xí),可以略過。
- MNIST 數(shù)據(jù)集分類:構(gòu)建簡單的CNN對 mnist 數(shù)據(jù)集進行分類。同時,還會在實驗中學(xué)習(xí)池化與卷積操作的基本作用。鏈接:https://github.com/OUCTheoryGroup/colab_demo/blob/master/05_01_ConvNet.ipynb
- CIFAR10 數(shù)據(jù)集分類:使用 CNN 對 CIFAR10 數(shù)據(jù)集進行分類,鏈接:https://github.com/OUCTheoryGroup/colab_demo/blob/master/05_02_CNN_CIFAR10.ipynb
- 使用 VGG16對 CIFAR10分類,鏈接:https://github.com/OUCTheoryGroup/colab_demo/blob/master/05_03_VGG_CIFAR10.ipynb
本周需要各個小組寫一個學(xué)習(xí)博客,并回答下面的問題,博客鏈接在下面提交任務(wù)即可,時間截止為本周六(10月15日22:00)
本周寫博客需要思考的問題:
1、dataloader 里面 shuffle 取不同值有什么區(qū)別?
2、transform 里,取了不同值,這個有什么區(qū)別?
3、epoch 和 batch 的區(qū)別?
4、1x1的卷積和 FC 有什么區(qū)別?主要起什么作用?
5、residual leanring 為什么能夠提升準確率?
6、代碼練習(xí)二里,網(wǎng)絡(luò)和1989年 Lecun 提出的 LeNet 有什么區(qū)別?
7、代碼練習(xí)二里,卷積以后feature map 尺寸會變小,如何應(yīng)用 Residual Learning?
8、有什么方法可以進一步提升準確率?
二、Part1 視頻學(xué)習(xí)
以下是在視頻學(xué)習(xí)后,根據(jù)所學(xué)繪制的思維導(dǎo)圖,其大致涵蓋了本次學(xué)習(xí)卷積神經(jīng)網(wǎng)絡(luò)的所得。
三、Part2 代碼練習(xí)
1.MNIST 數(shù)據(jù)集分類:構(gòu)建簡單的CNN對 mnist 數(shù)據(jù)集進行分類。同時,還會在實驗中學(xué)習(xí)池化與卷積操作的基本作用。
學(xué)習(xí)資料:https://github.com/OUCTheoryGroup/colab_demo/blob/master/05_01_ConvNet.ipynb
深度卷積神經(jīng)網(wǎng)絡(luò)中,有如下特性
- 很多層: compositionality
- 卷積: locality + stationarity of images
- 池化: Invariance of object class to translations
(1)加載數(shù)據(jù) (MNIST)
PyTorch里包含了 MNIST, CIFAR10 等常用數(shù)據(jù)集,調(diào)用 torchvision.datasets 即可把這些數(shù)據(jù)由遠程下載到本地,下面給出MNIST的使用方法:
torchvision.datasets.MNIST(root, train=True, transform=None, target_transform=None, download=False)
- root 為數(shù)據(jù)集下載到本地后的根目錄,包括 training.pt 和 test.pt 文件
- train,如果設(shè)置為True,從training.pt創(chuàng)建數(shù)據(jù)集,否則從test.pt創(chuàng)建。
- download,如果設(shè)置為True, 從互聯(lián)網(wǎng)下載數(shù)據(jù)并放到root文件夾下
- transform, 一種函數(shù)或變換,輸入PIL圖片,返回變換之后的數(shù)據(jù)。
- target_transform 一種函數(shù)或變換,輸入目標,進行變換。
另外值得注意的是,DataLoader是一個比較重要的類,提供的常用操作有:batch_size(每個batch的大小), shuffle(是否進行隨機打亂順序的操作), num_workers(加載數(shù)據(jù)的時候使用幾個子進程)
input_size = 28*28 # MNIST上的圖像尺寸是 28x28 output_size = 10 # 類別為 0 到 9 的數(shù)字,因此為十類train_loader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=True, download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])),batch_size=64, shuffle=True)test_loader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=False, transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])),batch_size=1000, shuffle=True)顯示數(shù)據(jù)集中的部分圖像
plt.figure(figsize=(8, 5)) for i in range(20):plt.subplot(4, 5, i + 1)image, _ = train_loader.dataset.__getitem__(i)plt.imshow(image.squeeze().numpy(),'gray')plt.axis('off');(2)創(chuàng)建網(wǎng)絡(luò)
定義網(wǎng)絡(luò)時,需要繼承nn.Module,并實現(xiàn)它的forward方法,把網(wǎng)絡(luò)中具有可學(xué)習(xí)參數(shù)的層放在構(gòu)造函數(shù)init中。
只要在nn.Module的子類中定義了forward函數(shù),backward函數(shù)就會自動被實現(xiàn)(利用autograd)。
class FC2Layer(nn.Module):def __init__(self, input_size, n_hidden, output_size):# nn.Module子類的函數(shù)必須在構(gòu)造函數(shù)中執(zhí)行父類的構(gòu)造函數(shù)# 下式等價于nn.Module.__init__(self) super(FC2Layer, self).__init__()self.input_size = input_size# 這里直接用 Sequential 就定義了網(wǎng)絡(luò),注意要和下面 CNN 的代碼區(qū)分開self.network = nn.Sequential(nn.Linear(input_size, n_hidden), nn.ReLU(), nn.Linear(n_hidden, n_hidden), nn.ReLU(), nn.Linear(n_hidden, output_size), nn.LogSoftmax(dim=1))def forward(self, x):# view一般出現(xiàn)在model類的forward函數(shù)中,用于改變輸入或輸出的形狀# x.view(-1, self.input_size) 的意思是多維的數(shù)據(jù)展成二維# 代碼指定二維數(shù)據(jù)的列數(shù)為 input_size=784,行數(shù) -1 表示我們不想算,電腦會自己計算對應(yīng)的數(shù)字# 在 DataLoader 部分,我們可以看到 batch_size 是64,所以得到 x 的行數(shù)是64# 大家可以加一行代碼:print(x.cpu().numpy().shape)# 訓(xùn)練過程中,就會看到 (64, 784) 的輸出,和我們的預(yù)期是一致的# forward 函數(shù)的作用是,指定網(wǎng)絡(luò)的運行過程,這個全連接網(wǎng)絡(luò)可能看不啥意義,# 下面的CNN網(wǎng)絡(luò)可以看出 forward 的作用。x = x.view(-1, self.input_size)return self.network(x)class CNN(nn.Module):def __init__(self, input_size, n_feature, output_size):# 執(zhí)行父類的構(gòu)造函數(shù),所有的網(wǎng)絡(luò)都要這么寫super(CNN, self).__init__()# 下面是網(wǎng)絡(luò)里典型結(jié)構(gòu)的一些定義,一般就是卷積和全連接# 池化、ReLU一類的不用在這里定義self.n_feature = n_featureself.conv1 = nn.Conv2d(in_channels=1, out_channels=n_feature, kernel_size=5)self.conv2 = nn.Conv2d(n_feature, n_feature, kernel_size=5)self.fc1 = nn.Linear(n_feature*4*4, 50)self.fc2 = nn.Linear(50, 10) # 下面的 forward 函數(shù),定義了網(wǎng)絡(luò)的結(jié)構(gòu),按照一定順序,把上面構(gòu)建的一些結(jié)構(gòu)組織起來# 意思就是,conv1, conv2 等等的,可以多次重用def forward(self, x, verbose=False):x = self.conv1(x)x = F.relu(x)x = F.max_pool2d(x, kernel_size=2)x = self.conv2(x)x = F.relu(x)x = F.max_pool2d(x, kernel_size=2)x = x.view(-1, self.n_feature*4*4)x = self.fc1(x)x = F.relu(x)x = self.fc2(x)x = F.log_softmax(x, dim=1)return x定義訓(xùn)練和測試函數(shù)
# 訓(xùn)練函數(shù) def train(model):model.train()# 主里從train_loader里,64個樣本一個batch為單位提取樣本進行訓(xùn)練for batch_idx, (data, target) in enumerate(train_loader):# 把數(shù)據(jù)送到GPU中data, target = data.to(device), target.to(device)optimizer.zero_grad()output = model(data)loss = F.nll_loss(output, target)loss.backward()optimizer.step()if batch_idx % 100 == 0:print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(batch_idx * len(data), len(train_loader.dataset),100. * batch_idx / len(train_loader), loss.item()))def test(model):model.eval()test_loss = 0correct = 0for data, target in test_loader:# 把數(shù)據(jù)送到GPU中data, target = data.to(device), target.to(device)# 把數(shù)據(jù)送入模型,得到預(yù)測結(jié)果output = model(data)# 計算本次batch的損失,并加到 test_loss 中test_loss += F.nll_loss(output, target, reduction='sum').item()# get the index of the max log-probability,最后一層輸出10個數(shù),# 值最大的那個即對應(yīng)著分類結(jié)果,然后把分類結(jié)果保存在 pred 里pred = output.data.max(1, keepdim=True)[1]# 將 pred 與 target 相比,得到正確預(yù)測結(jié)果的數(shù)量,并加到 correct 中# 這里需要注意一下 view_as ,意思是把 target 變成維度和 pred 一樣的意思 correct += pred.eq(target.data.view_as(pred)).cpu().sum().item()test_loss /= len(test_loader.dataset)accuracy = 100. * correct / len(test_loader.dataset)print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(test_loss, correct, len(test_loader.dataset),accuracy))(3)在小型全連接網(wǎng)絡(luò)上訓(xùn)練(Fully-connected network)
n_hidden = 8 # number of hidden unitsmodel_fnn = FC2Layer(input_size, n_hidden, output_size) model_fnn.to(device) optimizer = optim.SGD(model_fnn.parameters(), lr=0.01, momentum=0.5) print('Number of parameters: {}'.format(get_n_params(model_fnn)))train(model_fnn) test(model_fnn)(4)在卷積神經(jīng)網(wǎng)絡(luò)上訓(xùn)練
需要注意的是,上在定義的CNN和全連接網(wǎng)絡(luò),擁有相同數(shù)量的模型參數(shù)
# Training settings n_features = 6 # number of feature mapsmodel_cnn = CNN(input_size, n_features, output_size) model_cnn.to(device) optimizer = optim.SGD(model_cnn.parameters(), lr=0.01, momentum=0.5) print('Number of parameters: {}'.format(get_n_params(model_cnn)))train(model_cnn) test(model_cnn)通過上面的測試結(jié)果,可以發(fā)現(xiàn),含有相同參數(shù)的 CNN 效果要明顯優(yōu)于 簡單的全連接網(wǎng)絡(luò),是因為 CNN 能夠更好的挖掘圖像中的信息,主要通過兩個手段:
- 卷積:Locality and stationarity in images
- 池化:Builds in some translation invariance
(5)打亂像素順序再次在兩個網(wǎng)絡(luò)上訓(xùn)練與測試
考慮到CNN在卷積與池化上的優(yōu)良特性,如果我們把圖像中的像素打亂順序,這樣 卷積 和 池化 就難以發(fā)揮作用了,為了驗證這個想法,我們把圖像中的像素打亂順序再試試。
首先下面代碼展示隨機打亂像素順序后,圖像的形態(tài):
# 這里解釋一下 torch.randperm 函數(shù),給定參數(shù)n,返回一個從0到n-1的隨機整數(shù)排列 perm = torch.randperm(784) plt.figure(figsize=(8, 4)) for i in range(10):image, _ = train_loader.dataset.__getitem__(i)# permute pixelsimage_perm = image.view(-1, 28*28).clone()image_perm = image_perm[:, perm]image_perm = image_perm.view(-1, 1, 28, 28)plt.subplot(4, 5, i + 1)plt.imshow(image.squeeze().numpy(), 'gray')plt.axis('off')plt.subplot(4, 5, i + 11)plt.imshow(image_perm.squeeze().numpy(), 'gray')plt.axis('off')重新定義訓(xùn)練與測試函數(shù),我們寫了兩個函數(shù) train_perm 和 test_perm,分別對應(yīng)著加入像素打亂順序的訓(xùn)練函數(shù)與測試函數(shù)。
與之前的訓(xùn)練與測試函數(shù)基本上完全相同,只是對 data 加入了打亂順序操作。
# 對每個 batch 里的數(shù)據(jù),打亂像素順序的函數(shù) def perm_pixel(data, perm):# 轉(zhuǎn)化為二維矩陣data_new = data.view(-1, 28*28)# 打亂像素順序data_new = data_new[:, perm]# 恢復(fù)為原來4維的 tensordata_new = data_new.view(-1, 1, 28, 28)return data_new# 訓(xùn)練函數(shù) def train_perm(model, perm):model.train()for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device)# 像素打亂順序data = perm_pixel(data, perm)optimizer.zero_grad()output = model(data)loss = F.nll_loss(output, target)loss.backward()optimizer.step()if batch_idx % 100 == 0:print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(batch_idx * len(data), len(train_loader.dataset),100. * batch_idx / len(train_loader), loss.item()))# 測試函數(shù) def test_perm(model, perm):model.eval()test_loss = 0correct = 0for data, target in test_loader:data, target = data.to(device), target.to(device)# 像素打亂順序data = perm_pixel(data, perm)output = model(data)test_loss += F.nll_loss(output, target, reduction='sum').item()pred = output.data.max(1, keepdim=True)[1] correct += pred.eq(target.data.view_as(pred)).cpu().sum().item()test_loss /= len(test_loader.dataset)accuracy = 100. * correct / len(test_loader.dataset)print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(test_loss, correct, len(test_loader.dataset),accuracy))在全連接網(wǎng)絡(luò)上訓(xùn)練與測試:
在卷積神經(jīng)網(wǎng)絡(luò)上訓(xùn)練與測試:
從打亂像素順序的實驗結(jié)果來看,全連接網(wǎng)絡(luò)的性能基本上沒有發(fā)生變化,但是 卷積神經(jīng)網(wǎng)絡(luò)的性能明顯下降。
這是因為對于卷積神經(jīng)網(wǎng)絡(luò),會利用像素的局部關(guān)系,但是打亂順序以后,這些像素間的關(guān)系將無法得到利用。
2.CIFAR10 數(shù)據(jù)集分類:使用 CNN 對 CIFAR10 數(shù)據(jù)集進行分類
學(xué)習(xí)資料:colab_demo/05_02_CNN_CIFAR10.ipynb at master · OUCTheoryGroup/colab_demo (github.com)
對于視覺數(shù)據(jù),PyTorch 創(chuàng)建了一個叫做 totchvision 的包,該包含有支持加載類似Imagenet,CIFAR10,MNIST 等公共數(shù)據(jù)集的數(shù)據(jù)加載模塊 torchvision.datasets 和支持加載圖像數(shù)據(jù)數(shù)據(jù)轉(zhuǎn)換模塊 torch.utils.data.DataLoader。
下面將使用CIFAR10數(shù)據(jù)集,它包含十個類別:‘a(chǎn)irplane’, ‘a(chǎn)utomobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。CIFAR-10 中的圖像尺寸為3x32x32,也就是RGB的3層顏色通道,每層通道內(nèi)的尺寸為32*32。
(1)加載并歸一化 CIFAR10 使用 torchvision
torchvision 數(shù)據(jù)集的輸出是范圍在[0,1]之間的 PILImage,我們將他們轉(zhuǎn)換成歸一化范圍為[-1,1]之間的張量 Tensors。
大家肯定好奇,下面代碼中說的是 0.5,怎么就變化到[-1,1]之間了?PyTorch源碼中是這么寫的:
input[channel] = (input[channel] - mean[channel]) / std[channel]這樣就是:((0,1)-0.5)/0.5=(-1,1)。
import torch import torchvision import torchvision.transforms as transforms import matplotlib.pyplot as plt import numpy as np import torch.nn as nn import torch.nn.functional as F import torch.optim as optim# 使用GPU訓(xùn)練,可以在菜單 "代碼執(zhí)行工具" -> "更改運行時類型" 里進行設(shè)置 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# 注意下面代碼中:訓(xùn)練的 shuffle 是 True,測試的 shuffle 是 false # 訓(xùn)練時可以打亂順序增加多樣性,測試是沒有必要 trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,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, num_workers=2)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')(2)展示 CIFAR10 里面的一些圖片
def imshow(img):plt.figure(figsize=(8,8))img = img / 2 + 0.5 # 轉(zhuǎn)換到 [0,1] 之間npimg = img.numpy()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()# 得到一組圖像 images, labels = iter(trainloader).next() # 展示圖像 imshow(torchvision.utils.make_grid(images)) # 展示第一行圖像的標簽 for j in range(8):print(classes[labels[j]])運行報錯:
解決方法:搜索BrokenPipeError: [Errno 32] Broken pipe
在CSDN中找到問題的原因和解決方法:
原因:線程數(shù)為2
解決方法:設(shè)為0
成功!
(3)定義網(wǎng)絡(luò),損失函數(shù)和優(yōu)化器
class 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 x# 網(wǎng)絡(luò)放到GPU上 net = Net().to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(net.parameters(), lr=0.001)#訓(xùn)練網(wǎng)絡(luò) for epoch in range(10): # 重復(fù)多輪訓(xùn)練for i, (inputs, labels) in enumerate(trainloader):inputs = inputs.to(device)labels = labels.to(device)# 優(yōu)化器梯度歸零optimizer.zero_grad()# 正向傳播 + 反向傳播 + 優(yōu)化 outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 輸出統(tǒng)計信息if i % 100 == 0: print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch + 1, i + 1, loss.item())) print('Finished Training')結(jié)果:
(4)從測試集中取出8張圖片,檢測CNN識圖的能力
# 得到一組圖像 images, labels = iter(testloader).next() # 展示圖像 imshow(torchvision.utils.make_grid(images)) # 展示圖像的標簽 for j in range(8):print(classes[labels[j]]) outputs = net(images.to(device)) _, predicted = torch.max(outputs, 1)# 展示預(yù)測的結(jié)果 for j in range(8):print(classes[predicted[j]])
識別效果還是很不錯的。
(5)測試驗證準確率
準確率達到了63%,還可以,通過改進網(wǎng)絡(luò)結(jié)構(gòu),性能還可以進一步提升。在 Kaggle 的LeaderBoard上,準確率高的達到95%以上。
3.使用 VGG16 對 CIFAR10 分類
學(xué)習(xí)資料:colab_demo/05_03_VGG_CIFAR10.ipynb at master · OUCTheoryGroup/colab_demo (github.com)
VGG是由Simonyan 和Zisserman在文獻《Very Deep Convolutional Networks for Large Scale Image Recognition》中提出卷積神經(jīng)網(wǎng)絡(luò)模型,其名稱來源于作者所在的牛津大學(xué)視覺幾何組(Visual Geometry Group)的縮寫。
該模型參加2014年的 ImageNet圖像分類與定位挑戰(zhàn)賽,取得了優(yōu)異成績:在分類任務(wù)上排名第二,在定位任務(wù)上排名第一。
VGG16的網(wǎng)絡(luò)結(jié)構(gòu)如下圖所示:
16層網(wǎng)絡(luò)的結(jié)節(jié)信息如下:
(1)定義 dataloader
這里的 transform,dataloader 和之前定義的有所不同
import torch import torchvision import torchvision.transforms as transforms import matplotlib.pyplot as plt import numpy as np import torch.nn as nn import torch.nn.functional as F import torch.optim as optim# 使用GPU訓(xùn)練,可以在菜單 "代碼執(zhí)行工具" -> "更改運行時類型" 里進行設(shè)置 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")transform_train = transforms.Compose([transforms.RandomCrop(32, padding=4),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])transform_test = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train) testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2) testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False, num_workers=2)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')本地CUDA運行,num_workers=2報錯,要修改為num_workers=0
(2)VGG 網(wǎng)絡(luò)定義
參數(shù)有很多,可手動修改別的。現(xiàn)在的結(jié)構(gòu)基本上是:
(這樣設(shè)置沒有什么特殊用意,作者說:“就是覺得對稱,我自己隨便改的。。。”)
模型的實現(xiàn)代碼如下:
class VGG(nn.Module):def __init__(self):super(VGG, self).__init__()self.cfg = [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M']self.features = self._make_layers(cfg)self.classifier = nn.Linear(2048, 10)def forward(self, x):out = self.features(x)out = out.view(out.size(0), -1)out = self.classifier(out)return outdef _make_layers(self, cfg):layers = []in_channels = 3for x in cfg:if x == 'M':layers += [nn.MaxPool2d(kernel_size=2, stride=2)]else:layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),nn.BatchNorm2d(x),nn.ReLU(inplace=True)]in_channels = xlayers += [nn.AvgPool2d(kernel_size=1, stride=1)]return nn.Sequential(*layers)初始化網(wǎng)絡(luò),根據(jù)實際需要,修改分類層。因為 tiny-imagenet 是對200類圖像分類,這里把輸出修改為200。
# 網(wǎng)絡(luò)放到GPU上 net = VGG().to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(net.parameters(), lr=0.001)(3)網(wǎng)絡(luò)訓(xùn)練
訓(xùn)練代碼同之前一模一樣。
(4)測試驗證準確率
測試代碼也同之前一模一樣。
(5)運行結(jié)果:
解決過程:方法就1個字:搜!
①找到cfg所在的位置:
將其修改為:
②報錯信息變?yōu)?/h5>
找到out:
將其修改為
out = self.classifier(self.out)③出現(xiàn)新的錯誤
一番查找之下,猜測可能的原因有以下幾種:
- 環(huán)境配置有問題,torch或其他包版本過低,項目中中當真沒有’out’
- 在本地運行代碼,由多線程&&CPU運行改為單線程&&CUDA,代碼不支持
- ……
實在無從下手,只得作罷…
四、思考的問題:
參考研究生新生培訓(xùn)第二周:卷積神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
1、dataloader 里面 shuffle 取不同值有什么區(qū)別?
shuffle的取值為 “True” 或 “False”,不同取值標志著是否要對數(shù)據(jù)進行打亂洗牌。
“True” ->每次加載的數(shù)據(jù)都是隨機的,將輸入數(shù)據(jù)進行打亂洗牌;“False”->輸入數(shù)據(jù)順序固定。
通常需要對訓(xùn)練集打亂洗牌,測試集可以不打亂。
2、transform 里,取了不同值,這個有什么區(qū)別?
在進行CIFAR10 數(shù)據(jù)集分類部分時,transform取不同值的代碼為:
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])所以transform取不同值就是調(diào)用了不同的函數(shù)。
在配置conda和環(huán)境時,安裝了torch和torchvision。其中的torchvision是計算機視覺工具。torchvision.transforms提供了大量的圖像數(shù)據(jù)預(yù)處理的方法,如數(shù)據(jù)中心化、數(shù)據(jù)標準化、縮放、裁剪、旋轉(zhuǎn)、翻轉(zhuǎn)、填充、噪聲增加、灰度變化、線性變換、仿射變換、亮度等。
-
transforms.Compose()是將一系列的transforms有序組合,實現(xiàn)時按照這些方法依次對圖像操作。
-
transforms.ToTensor() 作用是轉(zhuǎn)換為tensor格式,這個格式可以直接輸入進神經(jīng)網(wǎng)絡(luò);
-
transforms.Normalize()是對像素值進行歸一化處理,使得數(shù)據(jù)服從均值為0,標準差為1的分布;
3、epoch 和 batch 的區(qū)別?
epoch和batch都是神經(jīng)網(wǎng)絡(luò)訓(xùn)練中的超參數(shù),epoch表示神經(jīng)網(wǎng)絡(luò)訓(xùn)練的輪數(shù),batch用于定義在更新內(nèi)部模型參數(shù)之前要處理的樣本數(shù),一次epoch至少要訓(xùn)練完成一個batch.
4、1x1的卷積和 FC 有什么區(qū)別?主要起什么作用?
FC可以看作全局卷積,1*1卷積可以替代FC,FC主要起到線性變化和分類的作用,1*1通常用于實現(xiàn)降維,用作非線性變化。
5、residual leanring 為什么能夠提升準確率?
解決了梯度消失問題 。
6、代碼練習(xí)二里,網(wǎng)絡(luò)和1989年 Lecun 提出的 LeNet 有什么區(qū)別?
代碼練習(xí)二中激活函數(shù)為ReLU,而LeNet激活函數(shù)是Sigmoid。代碼二中的網(wǎng)絡(luò)結(jié)構(gòu)通常較=叫LeNet-5。
7、代碼練習(xí)二里,卷積以后feature map 尺寸會變小,如何應(yīng)用 Residual Learning?
通過線性變換將原圖像縮小為和feature map大小相同的圖像。當輸入輸出維度上升時有兩種處理方式:第一種是仍使用恒等映射,多出來的通道使用零矩陣填充,這樣做的好處是不會帶來額外的參數(shù);第二種是添加變換方程,通常來說會使用 1*1 卷積來完成升維。
8、有什么方法可以進一步提升準確率?
- 改進網(wǎng)絡(luò)結(jié)構(gòu)
- 選擇合適優(yōu)化器
- 選擇合適損失函數(shù)
- 選擇合適激活函數(shù)
- 增加網(wǎng)絡(luò)深度
- 增加訓(xùn)練輪數(shù)
- 采用更大的數(shù)據(jù)集
總結(jié)
以上是生活随笔為你收集整理的第3次作业-卷积神经网络的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安装cnpm后运行报cnpm :无法加载
- 下一篇: 【深度学习】5:CNN卷积神经网络原理