天天看點

【pytorch】實作VGG網絡的建構1. 建構vgg_block函數2. 定義VGG網絡3. 擷取資料集4. 其他步驟5.完整代碼6.實作效果參考内容

【pytorch實作VGG網絡的建構】

  • 1. 建構vgg_block函數
  • 2. 定義VGG網絡
    • 2.1 初始化VGG網絡中特征提取的參數
  • 3. 擷取資料集
  • 4. 其他步驟
  • 5.完整代碼
  • 6.實作效果
  • 參考内容

1. 建構vgg_block函數

定義vgg_block函數,在這裡是定義了VGG網絡的基礎子產品.

def vgg_block(num_convs,in_channels,out_channels):
    blk = []
    for i in range(num_convs):
        if i == 0:
            blk.append(nn.Conv2d(in_channels,out_channels,kernel_size=3,padding=1))
        else:
            blk.append(nn.Conv2d(out_channels,out_channels,kernel_size=3,padding=1))
        blk.append(nn.ReLU())
    blk.append(nn.MaxPool2d(kernel_size=2,stride=2))   #最大池化操作,将高寬減半
    return nn.Sequential(*blk)
           

提示:以下是本篇文章正文内容,下面案例可供參考

2. 定義VGG網絡

在第一步中我們建構了vgg_block函數,這個函數是實作了VGG網絡中,卷積層的堆疊,便于網絡看上去更加清晰。堆疊的卷積層,我們一眼就能看明白。

def VGG(conv_arch,fc_features,fc_hidden_neurons=4096):
    net = nn.Sequential()
    #卷積層
    for i,(num_convs,in_channels,out_channels) in enumerate(conv_arch):
        net.add_module("vgg_block" + str(i+1),vgg_block(num_convs,in_channels,out_channels))
    #全連接配接層
    net.add_module(
        "fc",nn.Sequential(nn.Flatten(),
                           nn.Linear(fc_features,fc_hidden_neurons),
                           nn.ReLU(),
                           nn.Dropout(0.5),
                           nn.Linear(fc_hidden_neurons,fc_hidden_neurons),
                           nn.ReLU(),
                           nn.Dropout(0.5),
                           nn.Linear(fc_hidden_neurons,10)
        )
    )
    return net
           

2.1 初始化VGG網絡中特征提取的參數

在《動手學深度學習》這本書中,conv_arch = ((1, 1, 64), (1, 64, 128), (2, 128, 256), (2, 256, 512), (2, 512, 512)) 最開始是這樣的定義的,但是由于計算過于複雜,是以就變成了下面代碼中的small_conv_arch.

fc_features = 512 * 7 * 7 # c * w * h
fc_hidden_neurons = 4096 # 任意
#因為VGG-11計算上比AlexNet更加複雜,出于測試的目的我們構造一個通道數更小,或者說更窄的網絡在Fashion-MNIST資料集上進行訓練
ratio = 8
small_conv_arch = [(1, 1, 64//ratio), (1, 64//ratio, 128//ratio), (2, 128//ratio, 256//ratio),
                   (2, 256//ratio, 512//ratio), (2, 512//ratio, 512//ratio)]
net = VGG(small_conv_arch, fc_features // ratio, fc_hidden_neurons // ratio)
           

3. 擷取資料集

不同于之前部落格中寫的擷取資料集函數,VGG網絡中擷取資料集後,對資料集進行了水準旋轉和裁剪高斯歸一化處理,提高網絡的訓練中的精确率。

def gain_datasets(batch_size):
    data_path = '../../../Datasets'
    data_tf = transforms.Compose([
        transforms.Resize(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(0, 0.01)
    ])
    mnist_train = mnist.FashionMNIST(data_path,train=True,transform=data_tf,download=True)
    mnist_test = mnist.FashionMNIST(data_path,train=False,transform=data_tf,download=True)

    train_iter = data.DataLoader(mnist_train,batch_size=batch_size,shuffle=True,num_workers=4)
    test_iter = data.DataLoader(mnist_test,batch_size=128,shuffle=True,num_workers=4)
    return train_iter,test_iter
           

4. 其他步驟

建構網絡的其他步驟和我的之前的兩個部落格類似,我就不再詳細介紹了,代碼沒有太多的改動,大家可以自行參考:

  • 【PyTorch】實作LeNet網絡的建構
  • 【PyTorch】實作多層感覺機的建構

5.完整代碼

VGG網絡整體代碼如下:

import torch
from torch import nn
import torch.utils.data as data
from torchvision.datasets import mnist
from torchvision.transforms import transforms
import matplotlib.pyplot as plt

import time
import sys
sys.path.append('../..')
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

#使用函數vgg_block來實作VGG的基礎子產品
def vgg_block(num_convs,in_channels,out_channels):
    blk = []
    for i in range(num_convs):
        if i == 0:
            blk.append(nn.Conv2d(in_channels,out_channels,kernel_size=3,padding=1))
        else:
            blk.append(nn.Conv2d(out_channels,out_channels,kernel_size=3,padding=1))
        blk.append(nn.ReLU())
    blk.append(nn.MaxPool2d(kernel_size=2,stride=2))   #最大池化操作,将高寬減半
    return nn.Sequential(*blk)

#定義網絡VGG
def VGG(conv_arch,fc_features,fc_hidden_neurons=4096):
    net = nn.Sequential()
    #卷積層
    for i,(num_convs,in_channels,out_channels) in enumerate(conv_arch):
        net.add_module("vgg_block" + str(i+1),vgg_block(num_convs,in_channels,out_channels))
    #全連接配接層
    net.add_module(
        "fc",nn.Sequential(nn.Flatten(),
                           nn.Linear(fc_features,fc_hidden_neurons),
                           nn.ReLU(),
                           nn.Dropout(0.5),
                           nn.Linear(fc_hidden_neurons,fc_hidden_neurons),
                           nn.ReLU(),
                           nn.Dropout(0.5),
                           nn.Linear(fc_hidden_neurons,10)
        )
    )
    return net

fc_features = 512 * 7 * 7 # c * w * h
fc_hidden_neurons = 4096 # 任意
#因為VGG-11計算上比AlexNet更加複雜,出于測試的目的我們構造一個通道數更小,或者說更窄的網絡在Fashion-MNIST資料集上進行訓練
ratio = 8
small_conv_arch = [(1, 1, 64//ratio), (1, 64//ratio, 128//ratio), (2, 128//ratio, 256//ratio),
                   (2, 256//ratio, 512//ratio), (2, 512//ratio, 512//ratio)]
net = VGG(small_conv_arch, fc_features // ratio, fc_hidden_neurons // ratio)

#擷取資料集
def gain_datasets(batch_size):
    data_path = '../../../Datasets'
    data_tf = transforms.Compose([
        transforms.Resize(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(0, 0.01)
    ])
    mnist_train = mnist.FashionMNIST(data_path,train=True,transform=data_tf,download=True)
    mnist_test = mnist.FashionMNIST(data_path,train=False,transform=data_tf,download=True)

    train_iter = data.DataLoader(mnist_train,batch_size=batch_size,shuffle=True,num_workers=4)
    test_iter = data.DataLoader(mnist_test,batch_size=128,shuffle=True,num_workers=4)
    return train_iter,test_iter

batch_size = 256
train_iter,test_iter = gain_datasets(batch_size)


def evaluate_accuracy(data_iter,net,device=None):
    if device is None and isinstance(net,nn.Module):
        #如果沒有指定device就用net的device
        device = list(net.parameters())[0].device
    acc_sum,n = 0.0,0
    with torch.no_grad():
        for X,y in data_iter:
            if isinstance(net,nn.Module):
                net.eval()   #進行模式評估,關閉dropout
                acc_sum += (net(X.to(device)).argmax(dim=1) == y.to(device)).float().sum().cpu().item()
                net.train()   #改回訓練模式
            else:
                if('is_training' in net.__code__.co_varnames):  #is_training 是一個參數
                    acc_sum += (net(X,is_training=False).argmax(dim=1) == y).float().sum().item()
                else:
                    acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
            n += y.shape[0]
    return acc_sum/n


#畫圖函數
def draw_function(x_vals, y_vals, x_label, y_label, y2_vals=None, y3_vals=None,legend=None):

    fig, ax1 = plt.subplots()
    plt.title('VGG')
    ax1.plot(x_vals, y_vals, marker='o')
    ax1.plot(x_vals,y2_vals,color='r',marker='o')
    ax1.set_xlabel(x_label)
    ax1.set_ylabel(y_label)
    plt.legend(legend)

    ax2 = ax1.twinx()
    ax2.plot(x_vals, y3_vals, linestyle='--',color='g')
    ax2.set_ylabel('Loss')
    plt.show()


lr,num_epoches = 0.001,20
optimizer = torch.optim.Adam(net.parameters(),lr)
# scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer)


#訓練
def train_VGG(net,train_iter,test_iter,batch_size,optimizer,device,num_epochs):
    net = net.to(device)
    print("training on ",device)
    loss = nn.CrossEntropyLoss()
    loss_list,train_list,test_list = [],[],[]

    for epoch in range(num_epochs):
        train_loss_sum,train_acc_sum,n,batch_count,startTime = 0.0,0.0,0,0,time.time()
        for X,y in train_iter:
            X = X.to(device)
            y = y.to(device)
            y_hat = net(X)
            l = loss(y_hat,y)
            optimizer.zero_grad()
            l.backward()
            optimizer.step()
            train_loss_sum += l.cpu().item()
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
            n += y.shape[0]
            batch_count += 1
        test_acc_sum = evaluate_accuracy(test_iter,net)

        loss_list.append(train_loss_sum/n)
        train_list.append(train_acc_sum/n)
        test_list.append(test_acc_sum)

        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'
              % (epoch + 1, train_loss_sum / n, train_acc_sum / n, test_acc_sum, time.time() - startTime))
    draw_function(range(1,num_epochs+1),train_list,'epochs','Accuracy',
                  test_list,loss_list,['train','test','loss'],)


train_VGG(net,train_iter,test_iter,batch_size,optimizer,device,num_epoches)

           

6.實作效果

6.1 畫圖效果

【pytorch】實作VGG網絡的建構1. 建構vgg_block函數2. 定義VGG網絡3. 擷取資料集4. 其他步驟5.完整代碼6.實作效果參考内容

6.2 疊代效果

【pytorch】實作VGG網絡的建構1. 建構vgg_block函數2. 定義VGG網絡3. 擷取資料集4. 其他步驟5.完整代碼6.實作效果參考内容

參考内容

https://tangshusen.me/Dive-into-DL-PyTorch/#/chapter05_CNN/5.7_vgg

繼續閱讀