PyTorch如何構建深度學習模型?


簡介

每過一段時間,就會有一個深度學習庫被開發,這些深度學習庫往往可以改變深度學習領域的景觀。Pytorch就是這樣一個庫。

在過去的一段時間里,我研究了Pytorch,我驚嘆於它的操作簡易。Pytorch是我迄今為止所使用的深度學習庫中最靈活的,最輕松的。

在本文中,我們將以實踐的方式來探索Pytorch,包括基礎知識與案例研究。我們會使用numpy和Pytorch分別從頭開始構建神經網絡,看看他們的相似之處。

提示:本文假設你已經對深度學習有一定的了解。如果你想深入學習深度學習,請先閱讀本文。

內容目錄

  • Pytorch概述
  • 深層技術
  • 在Numpy和Pytorch中構建神經網絡
  • 與其他深度學習庫的比較
  • 案例研究——使用Pytorch解決圖像識別問題

Pytorch概述

Pytorch的創作者說他們有一種理念——他們希望工具能夠即時運作,這也就以為這我們必須及時進行運算。這也非常適用於python的編程方式,因為我們不必去等到程序都編完而確定整個代碼是否有效。我們可以輕松得運行部分代碼並且可以實時檢查。這個神經網絡的軟件,對我來說是非常好用的。

PyTorch是一個基於python的庫,旨在提供靈活性作為深度學習開發平台。PyTorch的工作流程也盡可能接近python的科學計算庫——numpy。

現在你可能會問,為什么我們會使用PyTorch來構建深度學習模型?我可以列出三個可能有助於回答這個問題的事情:

  • 易於使用API——它就像python一樣簡單。
  • 支持Python——就像上面所介紹的,Pytorch與python數據科學堆棧平滑集成。它跟numpy非常相似,你可能都沒有注意到它們的區別。
  • 動態計算圖形——Pytorch不是使用特定功能的預定義圖形,而是為我們提供了構建計算圖形的框架,甚至可以在運行的時候更改它們。這對於我們不知道創建神經網絡需要多少內存的情況非常有用。

使用Pytorch還有一些其他的優點,例如它的multiGPU支持,自定義數據加載器和簡化的預處理器。

自2016年1月初發布以來,許多研究人員將其作為首選庫,因為它易於構建新穎甚至極其復雜的圖形。話雖如此,因為它比較新並且正在發展中,PyTorch仍然需要一段時間才能被大多數數據科學從業者采用。

深層技術

在深入了解工作細節之前,讓我們來看看Pytorch的工作流程。

Pytorch構建圖形所需的每行代碼都定義了該圖形的一個組件。即使在完全構建圖形之前,我們也可以獨立地對這些組件進行計算。這叫做“按運行定義”的方法。

知識圖譜,Pytorch——一個簡單卻強大的深度學習庫

安裝PyTorch非常簡單。您可以按照官方文檔中提到的步驟操作,並根據您的系統規范運行命令。例如,這是我根據我選擇的選項使用的命令:

知識圖譜,Pytorch——一個簡單卻強大的深度學習庫

conda install pytorch torchvision cuda91 -c pytorch

開始使用Pytorch時我們應該知道的主要元素是:

  • Pytorch 張量
  • 數學運算
  • Autograd 模塊
  • Optim 模塊
  • nn 模塊

下面,我們具體看看每塊元素是什么情況。

Pytorch 張量

張量只不多是多維數組。Pytorch中的張量類似於numpy的ndarray,另外張量也可以在GPU上使用。Pytorch支持各種類型的張量。

你可以定義一個簡單的一位矩陣,如下所示:

# import pytorch

import torch

# define a tensor

torch.FloatTensor([2])

2

[torch.FloatTensor of size 1]

數學運算

與numpy一樣,科學計算庫能夠有效得實現數學函數是非常有效的。Pytorch為你提供了類似的交互界面,你可以在這里使用200多個數學運算。

下面是Pytorch中的一個簡單加法操作的例子:

a = torch.FloatTensor([2])

b = torch.FloatTensor([3])

a + b

5

[torch.FloatTensor of size 1]

這是python中的一個重要部分。我們還可以在我們定義的Pytorch張量上執行各種矩陣運算。例如:我們來轉置二維矩陣:

matrix = torch.randn(3, 3)

matrix

0.7162 1.0152 1.1525

-0.3503 -0.9452 -1.0861

-0.1093 -0.0927 -0.0476

[torch.FloatTensor of size 3x3]

matrix.t()

0.7162 -0.3503 -0.1093

1.0152 -0.9452 -0.0927

1.1525 -1.0861 -0.0476

[torch.FloatTensor of size 3x3]

Autograd 模塊

Pytorch使用了一種自動微分的技術。也就是說,我們有一個記錄器記錄我們執行過的操作,然后它會將操作往后執行以計算梯度。這種技術在構建神經網絡時非常有用,因為我們通過計算前向傳播本身的參數差異來節省一個周期的時間。

知識圖譜,Pytorch——一個簡單卻強大的深度學習庫

from torch.autograd import Variable

x = Variable(train_x)

y = Variable(train_y, requires_grad=False)

Optim 模塊

torch.optim是一個實現用於構建神經網絡的各種優化算法的模塊。已經支持了大多數的常用算法,所以我們可以免去從頭開始構建它們的麻煩。

下面是使用Adam optimizer 的代碼:

optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

nn模塊

Pytorch中的autograd可以很容易定義圖形並計算梯度,但原始的autograd對於定義復雜的神經網絡來說可能有點過於低級了。這就是nn模塊可以提供幫助的地方。

nn擴展包定義了一組模塊,我們可以把它看做成一個能從輸入產生輸出並且包含一些可訓練的權重的神經網絡層。

你其實可以把nn模塊視作Pytorch的keras!

import torch

# define model

model = torch.nn.Sequential(

torch.nn.Linear(input_num_units, hidden_num_units),

torch.nn.ReLU(),

torch.nn.Linear(hidden_num_units, output_num_units),

)

loss_fn = torch.nn.CrossEntropyLoss()

現在你已經了解了Pytorch的基本組件,你可以輕松地從頭開始構建自己的神經網絡。下面讓我們繼續吧!

使用Numpy與Pytorch分別構建一個神經網絡

在上文中提到,Pytorch和Numpy非常相似,那我們來看看為什么。在本節中,我們將利用一個簡單的神經網絡來實現二進制分類的問題。

## Neural network in numpy

import numpy as np

#Input array

X=np.array([[1,0,1,0],[1,0,1,1],[0,1,0,1]])

#Output

y=np.array([[1],[1],[0]])

#Sigmoid Function

def sigmoid (x):

return 1/(1 + np.exp(-x))

#Derivative of Sigmoid Function

def derivatives_sigmoid(x):

return x * (1 - x)

#Variable initialization

epoch=5000 #Setting training iterations

lr=0.1 #Setting learning rate

inputlayer_neurons = X.shape[1] #number of features in data set

hiddenlayer_neurons = 3 #number of hidden layers neurons

output_neurons = 1 #number of neurons at output layer

#weight and bias initialization

wh=np.random.uniform(size=(inputlayer_neurons,hiddenlayer_neurons))

bh=np.random.uniform(size=(1,hiddenlayer_neurons))

wout=np.random.uniform(size=(hiddenlayer_neurons,output_neurons))

bout=np.random.uniform(size=(1,output_neurons))

for i in range(epoch):

#Forward Propogation

hidden_layer_input1=np.dot(X,wh)

hidden_layer_input=hidden_layer_input1 + bh

hiddenlayer_activations = sigmoid(hidden_layer_input)

output_layer_input1=np.dot(hiddenlayer_activations,wout)

output_layer_input= output_layer_input1+ bout

output = sigmoid(output_layer_input)

#Backpropagation

E = y-output

slope_output_layer = derivatives_sigmoid(output)

slope_hidden_layer = derivatives_sigmoid(hiddenlayer_activations)

d_output = E * slope_output_layer

Error_at_hidden_layer = d_output.dot(wout.T)

d_hiddenlayer = Error_at_hidden_layer * slope_hidden_layer

wout += hiddenlayer_activations.T.dot(d_output) *lr

bout += np.sum(d_output, axis=0,keepdims=True) *lr

wh += X.T.dot(d_hiddenlayer) *lr

bh += np.sum(d_hiddenlayer, axis=0,keepdims=True) *lr

print('actual : ', y, ' ')

print('predicted : ', output)

現在,讓我們試試來尋找我們的簡單案例在兩種庫中的不同(不同之處已注釋)。

## neural network in pytorch

import torch #不同

#Input array

X = torch.Tensor([[1,0,1,0],[1,0,1,1],[0,1,0,1]]) #不同

#Output

y = torch.Tensor([[1],[1],[0]]) #不同

#Sigmoid Function

def sigmoid (x):

return 1/(1 + torch.exp(-x)) #不同

#Derivative of Sigmoid Function

def derivatives_sigmoid(x):

return x * (1 - x)

#Variable initialization

epoch=5000 #Setting training iterations

lr=0.1 #Setting learning rate

inputlayer_neurons = X.shape[1] #number of features in data set

hiddenlayer_neurons = 3 #number of hidden layers neurons

output_neurons = 1 #number of neurons at output layer

#weight and bias initialization

wh=torch.randn(inputlayer_neurons, hiddenlayer_neurons).type(torch.FloatTensor) #不同

bh=torch.randn(1, hiddenlayer_neurons).type(torch.FloatTensor)

wout=torch.randn(hiddenlayer_neurons, output_neurons) #不同

bout=torch.randn(1, output_neurons) #不同

for i in range(epoch):

#Forward Propogation

hidden_layer_input1 = torch.mm(X, wh) #不同

hidden_layer_input = hidden_layer_input1 + bh

hidden_layer_activations = sigmoid(hidden_layer_input)

output_layer_input1 = torch.mm(hidden_layer_activations, wout) #不同

output_layer_input = output_layer_input1 + bout

output = sigmoid(output_layer_input1)

#Backpropagation

E = y-output

slope_output_layer = derivatives_sigmoid(output)

slope_hidden_layer = derivatives_sigmoid(hidden_layer_activations)

d_output = E * slope_output_layer

Error_at_hidden_layer = torch.mm(d_output, wout.t()) #不同

d_hiddenlayer = Error_at_hidden_layer * slope_hidden_layer

wout += torch.mm(hidden_layer_activations.t(), d_output) *lr #不同

bout += d_output.sum() *lr

wh += torch.mm(X.t(), d_hiddenlayer) *lr #不同

bh += d_output.sum() *lr

print('actual : ', y, ' ')

print('predicted : ', output)

與其他神經網絡庫對比

在一個基准測試腳本里,成功證明了Pytorch在訓練長短期記憶網絡(LSTM)方面由於所有其他主要的深度學習庫,在每個epoch下都具有最低的中值時間。

Pytorch中用於數據加載的API設計得很好。數據集,采樣器和數據加載器的接口都是特定的。

在比較TensorFlow中的數據加載工具(讀取器,隊列等)時,我發現Pytorch的數據加載模塊非常易於使用。此外,我們在構建神經網絡時,Pytorch毫無缺陷的,我們並不需要依賴像keras這樣的第三方高級庫。

另一方面,我不太建議使用Pytorch進行部署,因為Pytorch尚未發展到這一步。正如Pytorch的開發人員所說:“我們看到的是用戶首先創建一個Pytorch模型,當他們准備將他們的模型部署到生產中時,他們只需要將其轉換成Caffe2模型,然后將其運送到其他平台。”

案例研究——在Pytorch中解決一個圖像識別問題

我們下面來解決Analytics Vidhya社區里的深度學習問題——手寫數字識別。我們先來看看問題是什么樣子的:

我們的任務是識別圖像,圖像中是給定的28*28圖像的阿拉伯數字。我們有一組用於訓練的圖像,其他的圖像用於測試我們的模型。

首先,我們下載訓練集與測試集。數據集包含所有圖像的壓縮文件,訓練集和測試集對應的名字是train.csv和test.csv。數據集中沒有其他內容,僅僅是“.png”格式的原始圖像。

下面讓我們開始吧:

第一步:准備

a)導入所有會用到的庫

# import modules

%pylab inline

import os

import numpy as np

import pandas as pd

from scipy.misc import imread

from sklearn.metrics import accuracy_score

b)讓我們設置一個種子值,那么我們就可以控制我們的模型隨機數了。

# To stop potential randomness

seed = 128

rng = np.random.RandomState(seed)

c)第一步就是設置目錄路徑,方便妥善保管!

root_dir = os.path.abspath('.')

data_dir = os.path.join(root_dir, 'data')

# check for existence

os.path.exists(root_dir), os.path.exists(data_dir)

步驟1:數據加載與處理

a)現在讓我們來看我們的數據集,它是.csv的格式,文件名也是與標簽相對應的。

# load dataset

train = pd.read_csv(os.path.join(data_dir, 'Train', 'train.csv'))

test = pd.read_csv(os.path.join(data_dir, 'Test.csv'))

sample_submission = pd.read_csv(os.path.join(data_dir, 'Sample_Submission.csv'))

train.head()

知識圖譜,Pytorch——一個簡單卻強大的深度學習庫

b)我們來看看數據集是什么樣的,我們讀取數據集中的圖片並將它顯示出來。

# print an image

img_name = rng.choice(train.filename)

filepath = os.path.join(data_dir, 'Train', 'Images', 'train', img_name)

img = imread(filepath, flatten=True)

pylab.imshow(img, cmap='gray')

pylab.axis('off')

pylab.show()

知識圖譜,Pytorch——一個簡單卻強大的深度學習庫

d)為了便於數據操作,我們將所有圖像存儲為numpy數組。

# load images to create train and test set

temp = []

for img_name in train.filename:

image_path = os.path.join(data_dir, 'Train', 'Images', 'train', img_name)

img = imread(image_path, flatten=True)

img = img.astype('float32')

temp.append(img)

train_x = np.stack(temp)

train_x /= 255.0

train_x = train_x.reshape(-1, 784).astype('float32')

temp = []

for img_name in test.filename:

image_path = os.path.join(data_dir, 'Train', 'Images', 'test', img_name)

img = imread(image_path, flatten=True)

img = img.astype('float32')

temp.append(img)

test_x = np.stack(temp)

test_x /= 255.0

test_x = test_x.reshape(-1, 784).astype('float32')

train_y = train.label.values

e)由於這是一個典型的機器學習問題,我們創建了一個測試集來測試我們的模型是否能夠正常運行。我們采用7:3的分割比例來設置訓練集與測試集。

# create validation set

split_size = int(train_x.shape[0]*0.7)

train_x, val_x = train_x[:split_size], train_x[split_size:]

train_y, val_y = train_y[:split_size], train_y[split_size:]

步驟二:建立模型

a)接下來就是主體部分了,讓我們先來定義神經網絡的架構。我們定義了一個具有輸入層,隱藏層和輸出層的3層神經網絡。輸入與輸出中的神經元的數量是固定的,因為輸入的是我們訓練集中28*28的圖像,輸出的是十個類別。在隱藏層中我們設置了50個神經元,這里,我們使用Adam算法作為我們的優化算法,這就是梯度下降法的有效變體。

import torch

from torch.autograd import Variable

# number of neurons in each layer

input_num_units = 28*28

hidden_num_units = 500

output_num_units = 10

# set remaining variables

epochs = 5

batch_size = 128

learning_rate = 0.001

b)下面該訓練我們的模型了。

# define model

model = torch.nn.Sequential(

torch.nn.Linear(input_num_units, hidden_num_units),

torch.nn.ReLU(),

torch.nn.Linear(hidden_num_units, output_num_units),

)

loss_fn = torch.nn.CrossEntropyLoss()

# define optimization algorithm

optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

## helper functions

# preprocess a batch of dataset

def preproc(unclean_batch_x):

"""Convert values to range 0-1"""

temp_batch = unclean_batch_x / unclean_batch_x.max()

return temp_batch

# create a batch

def batch_creator(batch_size):

dataset_name = 'train'

dataset_length = train_x.shape[0]

batch_mask = rng.choice(dataset_length, batch_size)

batch_x = eval(dataset_name + '_x')[batch_mask]

batch_x = preproc(batch_x)

if dataset_name == 'train':

batch_y = eval(dataset_name).ix[batch_mask, 'label'].values

return batch_x, batch_y

# train network

total_batch = int(train.shape[0]/batch_size)

for epoch in range(epochs):

avg_cost = 0

for i in range(total_batch):

# create batch

batch_x, batch_y = batch_creator(batch_size)

# pass that batch for training

x, y = Variable(torch.from_numpy(batch_x)), Variable(torch.from_numpy(batch_y), requires_grad=False)

pred = model(x)

# get loss

loss = loss_fn(pred, y)

# perform backpropagation

loss.backward()

optimizer.step()

avg_cost += loss.data[0]/total_batch

print(epoch, avg_cost)

# get training accuracy

x, y = Variable(torch.from_numpy(preproc(train_x))), Variable(torch.from_numpy(train_y), requires_grad=False)

pred = model(x)

final_pred = np.argmax(pred.data.numpy(), axis=1)

accuracy_score(train_y, final_pred)

# get validation accuracy

x, y = Variable(torch.from_numpy(preproc(val_x))), Variable(torch.from_numpy(val_y), requires_grad=False)

pred = model(x)

final_pred = np.argmax(pred.data.numpy(), axis=1)

accuracy_score(val_y, final_pred)

訓練結果是:

0.8779008746355685

另外,測試集上的結果是:

0.867482993197279

這是一個比較完美的結果了,尤其是當我們僅僅用了一個非常簡單的神經網絡模型並且只訓練了5個周期。

結語

我希望這篇文章能夠幫助你從如何構建神經網絡模型的角度去了解Pytorch。但是,文字有限,這里我們僅僅展示了很小的一方面。

 

來源商業新知網,原標題:Pytorch——一個簡單卻強大的深度學習


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM