1. 程式人生 > >【pytorch速成】Pytorch影象分類從模型自定義到測試

【pytorch速成】Pytorch影象分類從模型自定義到測試

文章首發於微信公眾號《與有三學AI》

前面已跟大家介紹了Caffe和TensorFlow,連結如下。

今天說說Pytorch。

01 什麼是 Pytorch

一句話總結 Pytorch = Python + Torch。

Torch 是紐約大學的一個機器學習開源框架,幾年前在學術界非常流行,包括 Lecun等大佬都在使用。但是由於使用的是一種絕大部分人絕對沒有聽過的 Lua 語言,導致很多人都被嚇退。後來隨著 Python 的生態越來越完善,Facebook 人工智慧研究院推出了Pytorch並開源。Pytorch不是簡單的封裝 Torch並提供Python介面,而是對Tensor以上的所有程式碼進行了重構,同TensorFlow一樣,增加了自動求導。

後來Caffe2全部併入Pytorch,如今已經成為了非常流行的框架。很多最新的研究如風格化、GAN 等大多數採用Pytorch原始碼,這也是我們必須要講解它的原因。

1.1 特點

(1)動態圖計算。TensorFlow從靜態圖發展到了動態圖機制Eager Execution,pytorch則一開始就是動態圖機制。動態圖機制的好處就是隨時隨地修改,隨處debug,沒有類似編譯的過程。

(2)簡單。相比TensorFlow中Tensor、Variable、Session等概念充斥,資料讀取介面頻繁更新,tf.nn、tf.layers、tf.contrib各自重複,Pytorch則是從Tensor到Variable再到nn.Module,最新的Pytorch已經將Tensor和Variable合併,這分別就是從資料張量到網路的抽象層次的遞進。有人調侃TensorFlow的設計是“make it complicated”,那麼 Pytorch的設計就是“keep it simple”。

1.2 重要概念

(1)Tensor/Variable

每一個框架都有基本的資料結構,Caffe是blob,TensorFlow和Pytorch都是Tensor,都是高維陣列。Pytorch中的Tensor使用與Numpy的陣列非常相似,兩者可以互轉且共享記憶體。

tensor包括cpu和gpu兩種型別,如torch.FloatTensortorch.cuda.FloatTensorvirable,就分別表示cpu和gpu下的32位浮點數。

tensor包含一些屬性。data,即Tensor內容;Grad,是與data對應的梯度;requires_grad,是否容許進行反向傳播的學習,更多的可以去檢視API。

(2)nn.module

抽象好的網路資料結構,可以表示為網路的一層,也可以表示為一個網路結構,這是一個基類。在實際使用過程中,經常會定義自己的網路,並繼承nn.Module。具體的使用,我們看下面的網路定義吧。

(3)torchvision包,包含了目前流行的資料集,模型結構和常用的圖片轉換工具

02 Pytorch 訓練

安裝咱們就不說了,接下來的任務就是開始訓練模型。訓練模型包括資料準備、模型定義、結果儲存與分析。

2.1 資料讀取

前面已經介紹了Caffe和TensorFlow的資料讀取,兩者的輸入都是圖片list,但是讀取操作過程差異非常大,Pytorch與這兩個又有很大的差異。這一次,直接利用資料夾作為輸入,這是 Pytorch更加方便的做法。資料讀取的完整程式碼如下:

data_dir = '../../../../datas/head/'    
   data_transforms = {
       'train': transforms.Compose([
           transforms.RandomSizedCrop(48),
           transforms.RandomHorizontalFlip(),
           transforms.ToTensor(),
           transforms.Normalize([0.5,0.5,0.5], [0.5,0.5,0.5])
       ]),
       'val': transforms.Compose([
           transforms.Scale(64),
           transforms.CenterCrop(48),
           transforms.ToTensor(),
           transforms.Normalize([0.5,0.5,0.5], [0.5,0.5,0.5])
       ]),
   }
   image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
                                             data_transforms[x]) for x in ['train', 'val']}
   dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],
                                                batch_size=16,
                                                shuffle=True,
                                                num_workers=4) for x in ['train', 'val']}

下面一個一個解釋,完整程式碼請移步 Git 工程。

(1)datasets.ImageFolder

Pytorch的torchvision模組中提供了一個dataset 包,它包含了一些基本的資料集如mnist、coco、imagenet和一個通用的資料載入器ImageFolder。

它會以這樣的形式組織資料,具體的請到Git工程中檢視。

root/left/1.png
root/left/2.png
root/left/3.png

root/right/1.png
root/right/2.png
root/right/3.png

imagefolder有3個成員變數。

self.classes:用一個list儲存類名,就是資料夾的名字。

self.class_to_idx:類名對應的索引,可以理解為 0、1、2、3 等。

self.imgs:儲存(imgpath,class),是圖片和類別的陣列。

不同資料夾下的圖,會被當作不同的類,天生就用於影象分類任務。

(2)Transforms

這一點跟Caffe非常類似,就是定義了一系列資料集的預處理和增強操作。到此,資料介面就定義完畢了,接下來在訓練程式碼中看如何使用迭代器進行資料讀取就可以了,包括 scale、減均值等。

(3)torch.utils.data.DataLoader

這就是建立了一個 batch,生成真正網路的輸入。關於更多 Pytorch 的資料讀取方法,請自行學習。

2.2 模型定義

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
class simpleconv3(nn.Module):`
def __init__(self):
       super(simpleconv3,self).__init__()
       self.conv1 = nn.Conv2d(3, 12, 3, 2)
       self.bn1 = nn.BatchNorm2d(12)
       self.conv2 = nn.Conv2d(12, 24, 3, 2)
       self.bn2 = nn.BatchNorm2d(24)
       self.conv3 = nn.Conv2d(24, 48, 3, 2)
       self.bn3 = nn.BatchNorm2d(48)
       self.fc1 = nn.Linear(48 * 5 * 5 , 1200)
       self.fc2 = nn.Linear(1200 , 128)
       self.fc3 = nn.Linear(128 , 2)
def forward(self , x):
       x = F.relu(self.bn1(self.conv1(x)))
       x = F.relu(self.bn3(self.conv3(x)))
       x = x.view(-1 , 48 * 5 * 5) 
       x = F.relu(self.fc1(x))
       x = F.relu(self.fc2(x))
       x = self.fc3(x)
       return x

我們的例子都是採用一個簡單的3層卷積 + 2層全連線層的網路結構。根據上面的網路結構的定義,需要做以下事情。

(1)simpleconv3(nn.Module)

繼承nn.Module,前面已經說過,Pytorch的網路層是包含在nn.Module 裡,所以所有的網路定義,都需要繼承該網路層,並實現super方法,如下:

super(simpleconv3,self).__init__()

這個就當作一個標準執行就可以了。

(2)網路結構的定義都在nn包裡,舉例說明:

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

完整的介面如上,定義的第一個卷積層如下:

nn.Conv2d(3, 12, 3, 2)

即輸入通道為3,輸出通道為12,卷積核大小為3,stride=2,其他的層就不一一介紹了,大家可以自己去看nn的API。

(3)forward

backward方法不需要自己實現,但是forward函式是必須要自己實現的,從上面可以看出,forward 函式也是非常簡單,串接各個網路層就可以了。

對比Caffe和TensorFlow可以看出,Pytorch的網路定義更加簡單,初始化方法都沒有顯示出現,因為 Pytorch已經提供了預設初始化。

如果我們想實現自己的初始化,可以這麼做:

init.xavier_uniform(self.conv1.weight)init.constant(self.conv1.bias, 0.1)

它會對conv1的權重和偏置進行初始化。如果要對所有conv層使用 xavier 初始化呢?可以定義一個函式:

def weights_init(m):    
   if isinstance(m, nn.Conv2d):
       xavier(m.weight.data)
       xavier(m.bias.data)  
   net = Net()   
   net.apply(weights_init)

03 模型訓練

網路定義和資料載入都定義好之後,就可以進行訓練了,老規矩先上程式碼:

def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
       for epoch in range(num_epochs):
           print('Epoch {}/{}'.format(epoch, num_epochs - 1))
           for phase in ['train', 'val']:
               if phase == 'train':
                   scheduler.step()
                   model.train(True)  
               else:
                   model.train(False)  
                   running_loss = 0.0                running_corrects = 0.0
               for data in dataloders[phase]:
                   inputs, labels = data
                   if use_gpu:
                       inputs = Variable(inputs.cuda())
                       labels = Variable(labels.cuda())
                   else:
                       inputs, labels = Variable(inputs), Variable(labels)

                   optimizer.zero_grad()
                   outputs = model(inputs)
                   _, preds = torch.max(outputs.data, 1)
                   loss = criterion(outputs, labels)
                   if phase == 'train':
                       loss.backward()
                       optimizer.step()

                   running_loss += loss.data.item()
                   running_corrects += torch.sum(preds == labels).item()

               epoch_loss = running_loss / dataset_sizes[phase]
               epoch_acc = running_corrects / dataset_sizes[phase]

               if phase == 'train':
                   writer.add_scalar('data/trainloss', epoch_loss, epoch)
                   writer.add_scalar('data/trainacc', epoch_acc, epoch)
               else:
                   writer.add_scalar('data/valloss', epoch_loss, epoch)
                   writer.add_scalar('data/valacc', epoch_acc, epoch)

               print('{} Loss: {:.4f} Acc: {:.4f}'.format(
               phase, epoch_loss, epoch_acc))
       writer.export_scalars_to_json("./all_scalars.json")
       writer.close()
       return model

分析一下上面的程式碼,外層迴圈是epoches,然後利用 for data in dataloders[phase] 迴圈取一個epoch 的資料,並塞入variable,送入model。需要注意的是,每一次forward要將梯度清零,即optimizer.zero_grad(),因為梯度會記錄前一次的狀態,然後計算loss進行反向傳播。

loss.backward()
optimizer.step()

下面可以分別得到預測結果和loss,每一次epoch 完成計算。

epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects / dataset_sizes[phase]
_, preds = torch.max(outputs.data, 1)
loss = criterion(outputs, labels)

視覺化是非常重要的,鑑於TensorFlow的視覺化非常方便,我們選擇了一個開源工具包,tensorboardx,安裝方法為pip install tensorboardx,使用非常簡單。

第一步,引入包定義建立:

from tensorboardX import SummaryWriter
writer = SummaryWriter()

第二步,記錄變數,如train階段的 loss,writer.add_scalar('data/trainloss', epoch_loss, epoch)。

按照以上操作就完成了,完整程式碼可以看配套的Git 專案,我們看看訓練中的記錄。Loss和acc的曲線圖如下:

網路的收斂沒有Caffe和TensorFlow好,大家可以自己去除錯除錯引數了,隨便折騰吧。

04 Pytorch 測試

上面已經訓練好了模型,接下來的目標就是要用它來做inference了,同樣給出程式碼。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.autograd import Variable
import torchvision
from torchvision import datasets, models, transforms
import time
import os
from PIL import Image
import sys
import torch.nn.functional as F

from net import simpleconv3
data_transforms =  transforms.Compose([
               transforms.Resize(48),
               transforms.ToTensor(),
               transforms.Normalize([0.5,0.5,0.5], [0.5,0.5,0.5])])

net = simpleconv3()
modelpath = sys.argv[1]
net.load_state_dict(torch.load(modelpath,map_location=lambda storage,loc: storage))

imagepath = sys.argv[2]
image = Image.open(imagepath)
imgblob = data_transforms(image).unsqueeze(0)
imgblob = Variable(imgblob)
torch.no_grad()
predict = F.softmax(net(imgblob))
print(predict)

從上面的程式碼可知,做了幾件事:

定義網路並使用torch.load和load_state_dict載入模型。

用PIL的Image包讀取圖片,這裡沒有用OpenCV,因為Pytorch預設的圖片讀取工具就是PIL的Image,它會將圖片按照RGB的格式,歸一化到 0~1 之間。讀取圖片之後,必須轉化為Tensor變數。

evaluation的時候,必須設定torch.no_grad(),然後就可以呼叫 softmax 函式得到結果了。

05 總結

本節講了如何用 Pytorch 完成一個分類任務,並學習了視覺化以及使用訓練好的模型做測試。

同時,在我的知乎專欄也會開始同步更新這個模組,歡迎來交流

注:部分圖片來自網路

—END—

相關推薦

caffe速成caffe影象分類模型定義測試

文章首發於微信公眾號《與有三學AI》 這是給大家準備的caffe速成例子 這一次我們講講 Caffe 這個主流的開源框架從訓練到測試出結果的全流程。到此,我必須假設大家已經有了深度學習的基礎知識並瞭解卷積網路的工作原理。 相關的程式碼、資料都在我們 Git 上,

pytorch速成Pytorch影象分類模型定義測試

文章首發於微信公眾號《與有三學AI》 前面已跟大家介紹了Caffe和TensorFlow,連結如下。 今天說說Pytorch。 01 什麼是 Pytorch 一句話總結 Pytorch = Python + Torch。 Torch 是紐約大

機器學習機器學習分類模型評價指標 機器學習分類模型評價指標

機器學習分類器模型評價指標 分類器評價指標主要有: 1,Accuracy 2,Precision  3,Recall  4,F1 score  5,ROC 曲線

深度學習深度學習分類模型評估

內容大綱 分類和迴歸之外的機器學習形式 評估機器學習模型的規範流程 為深度學習準備資料 特徵工程 解決過擬合問題 處理機器學習問題的通用流程 監督學習的主要種類及其變種 主要包括兩大類問題: 分類 迴歸

TP5.1建立通用的基類定義命令

author:咔咔 wechat:fangkangfk   在之前我們一直在做admin下的業務,在設定自定義模板的時候沒有考慮到一些情況   下面我們來改動一下 這樣做就ok了,不管是建立admin下的控制器,還是index的控制器,這一個模板就可以

Android Studio AS 使用記錄04(定義打包apk名)

Android Studio打包應用預設生成的apk名稱是:app-release.apk 、 如果我們要讓生成的apk名跟我們版本包名有聯絡,那我們就要自定義生成的apk名了, 在其Model b

git配置配置詳解&快捷命令(定義短命令)

開發十年,就只剩下這套架構體系了! >>>   

深度學習Pytorch 學習筆記

chang www. ans 如何 ret == 筆記 etc finished 目錄 Pytorch Leture 05: Linear Rregression in the Pytorch Way Logistic Regression 邏輯回歸 - 二分類 Lect

Gans入門Pytorch實現Gans程式碼詳解70+程式碼

簡述 由於科技論文老師要求閱讀Gans論文並在網上找到類似的程式碼來學習。 程式碼來源 程式碼含義概覽 這個大致講講這個程式碼實現了什麼。 這個模型的輸入為:一些資料夾雜在x2x^2x2和2x2+12x^2+12x2+1這個兩個函式之間的一些資料。這個用線性

pytorch + visdom 處理cifar10影象分類

執行環境 系統:win10 cpu:i7-6700HQ gpu:gtx965m python : 3.6 pytorch :0.3 資料集使用 Cifar-10 由60000張32*32的 RGB 彩色圖片構成,

DeepLearningPyTorch (1)PyTorch官方教程個人筆記

PyTorch 官方教程 Getting Started 第一部分 Deep Learning with PyTorch: A 60 Minute Blitz 筆記 文章目錄 1. What is PyTorch? 2. Autogr

DeepLearningPyTorch (0)PyTorch 個人筆記

TensorFlow的靜態圖方式不易於研究,於是開始轉戰PyTorch。 PyTorch 具有和 NumPy 直接互動的良好特性,適合敏捷部署神經網路,提高實驗工作效率。 本文開始記錄 PyTorch 學習心得與一些關鍵問題。 文章目錄 1.

機器學習PAI實踐十深度學習Caffe框架實現影象分類模型訓練

背景 我們在之前的文章中介紹過如何通過PAI內建的TensorFlow框架實驗基於Cifar10的影象分類,文章連結:https://yq.aliyun.com/articles/72841。使用Tensorflow做深度學習做深度學習的網路搭建和訓練需要通過

資料平臺Pytorch庫初識

PyTorch是使用GPU和CPU優化的深度學習張量庫。 1、安裝,參考官網:http://pytorch.org/ conda install pytorch torchvision -c pytorch 2、認識,參考: https://github.com/yunj

機器學習---密度聚類初識到應用

max 一個 eight log div 指定 聚類 空間 mar 一.前述 密度聚類是一種能降噪的算法。 二.相關概念 先看些抽象的概念(官方定義): 1.:對象O的是與O為中心,為半徑的空間,參數,是用戶指定每個對象的領域半徑值。 2.MinPts(領域密度閥值):對象

產品案例我是如何零搭建起一款健身O2O產品的?

作者: Wander_Yang 我在年初參與到“SHAPE”這款健身產品的研發中,也算是第一次以產品經理的身份,從0開始負責一個產品的建立。 產品是一款O2O的智慧健身連鎖店,目前產品已經上線8個月,線下店鋪也在迅速擴充套件,正是回顧梳理的好時機~ 專案/競品調研 目前線上健

線上直播轉型產品經理何開始?

講師:楊三豐   講師簡介: 楊三豐,畢業於軍中北大的中國人民解放軍資訊工程大學,現任上海木木機器人技術有限公司產品總監。上海祥程資訊科技有限公司創始人CTO。曾開發和設計過的系統包括政府稅務、生活服務、社交、電商、金融、服務機器人等多個領域。獨立開發多個網站和App,曾

LeetCode題解動態規劃:新手到專家(一)

【LeetCode題解】動態規劃:從新手到專家(一) 文章標題借用了Hawstein的譯文《動態規劃:從新手到專家》。 1. 概述 動態規劃( Dynamic Programming, DP)是最優化問題的一種解決方法,本質上狀態空間的狀態轉移。所謂狀態轉移是指每個階段的最優狀態(對應於

SVG學習SVG 影象入門教程

一、概述 SVG 是一種基於 XML 語法的影象格式,全稱是可縮放向量圖(Scalable Vector Graphics)。其他影象格式都是基於畫素處理的,SVG 則是屬於對影象的形狀描述,所以它本質上是文字檔案,體積較小,且不管放大多少倍都不會失真。 SVG 檔案可以直接插入網頁,

NOJ1145演算法實驗二回溯演算法影象的周長

1145.求影象的周長 時限:1000ms 記憶體限制:10000K  總時限:3000ms 描述 給一個用 ‘ . ’ 和 ' X ' 表示的圖形,圖形在上、下、左、右、左上、左下、右上、右下8個方向都被看作是連通的,並且影象中間不會出現空洞,求這個圖形的邊長。