Pytorch——一個簡單卻強大的深度學習庫

簡介python

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

在過去的一段時間裏,我研究了Pytorch,我驚歎於它的操做簡易。Pytorch是我迄今爲止所使用的深度學習庫中最靈活的,最輕鬆的。編程

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

提示:本文假設你已經對深度學習有必定的瞭解。若是你想深刻學習深度學習,請先閱讀本文。網絡

內容目錄架構

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

Pytorch概述app

Pytorch的創做者說他們有一種理念——他們但願工具可以即時運做,這也就覺得這咱們必須及時進行運算。這也很是適用於python的編程方式,由於咱們沒必要去等到程序都編完而肯定整個代碼是否有效。咱們能夠輕鬆得運行部分代碼而且能夠實時檢查。這個神經網絡的軟件,對我來講是很是好用的。框架

PyTorch是一個基於python的庫,旨在提供靈活性做爲深度學習開發平臺。PyTorch的工做流程也儘量接近python的科學計算庫——numpy。dom

如今你可能會問,爲何咱們會使用PyTorch來構建深度學習模型?我能夠列出三個可能有助於回答這個問題的事情:機器學習

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

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

自2016年1月初發布以來,許多研究人員將其做爲首選庫,由於它易於構建新穎甚至極其複雜的圖形。話雖如此,由於它比較新而且正在發展中,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使用了一種自動微分的技術。也就是說,咱們有一個記錄器記錄咱們執行過的操做,而後它會將操做日後執行以計算梯度。這種技術在構建神經網絡時很是有用,由於咱們經過計算前向傳播自己的參數差別來節省一個週期的時間。

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 :n', y, 'n') print('predicted :n', 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 :n', y, 'n') print('predicted :n', 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()

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()

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網站上的文檔與教程。

相關文章
相關標籤/搜索