簡介python
每過一段時間,就會有一個深度學習庫被開發,這些深度學習庫每每能夠改變深度學習領域的景觀。Pytorch就是這樣一個庫。算法
在過去的一段時間裏,我研究了Pytorch,我驚歎於它的操做簡易。Pytorch是我迄今爲止所使用的深度學習庫中最靈活的,最輕鬆的。編程
在本文中,咱們將以實踐的方式來探索Pytorch,包括基礎知識與案例研究。咱們會使用numpy和Pytorch分別從頭開始構建神經網絡,看看他們的類似之處。數組
提示:本文假設你已經對深度學習有必定的瞭解。若是你想深刻學習深度學習,請先閱讀本文。網絡
內容目錄架構
Pytorch的創做者說他們有一種理念——他們但願工具可以即時運做,這也就覺得這咱們必須及時進行運算。這也很是適用於python的編程方式,由於咱們沒必要去等到程序都編完而肯定整個代碼是否有效。咱們能夠輕鬆得運行部分代碼而且能夠實時檢查。這個神經網絡的軟件,對我來講是很是好用的。app
PyTorch是一個基於python的庫,旨在提供靈活性做爲深度學習開發平臺。PyTorch的工做流程也儘量接近python的科學計算庫——numpy。框架
如今你可能會問,爲何咱們會使用PyTorch來構建深度學習模型?我能夠列出三個可能有助於回答這個問題的事情:dom
使用Pytorch還有一些其餘的優勢,例如它的multiGPU支持,自定義數據加載器和簡化的預處理器。機器學習
自2016年1月初發布以來,許多研究人員將其做爲首選庫,由於它易於構建新穎甚至極其複雜的圖形。話雖如此,由於它比較新而且正在發展中,PyTorch仍然須要一段時間才能被大多數數據科學從業者採用。
在深刻了解工做細節以前,讓咱們來看看Pytorch的工做流程。
Pytorch構建圖形所需的每行代碼都定義了該圖形的一個組件。即便在徹底構建圖形以前,咱們也能夠獨立地對這些組件進行計算。這叫作「按運行定義」的方法。
安裝PyTorch很是簡單。您能夠按照官方文檔中提到的步驟操做,並根據您的系統規範運行命令。例如,這是我根據我選擇的選項使用的命令:
conda install pytorch torchvision cuda91 -c pytorch
開始使用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]
Pytorch使用了一種自動微分的技術。也就是說,咱們有一個記錄器記錄咱們執行過的操做,而後它會將操做日後執行以計算梯度。這種技術在構建神經網絡時很是有用,由於咱們經過計算前向傳播自己的參數差別來節省一個週期的時間。
from torch.autograd import Variable
x = Variable(train_x)
y = Variable(train_y, requires_grad=False)
torch.optim是一個實現用於構建神經網絡的各類優化算法的模塊。已經支持了大多數的經常使用算法,因此咱們能夠免去從頭開始構建它們的麻煩。
下面是使用Adam optimizer 的代碼:
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
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()
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。可是,文字有限,這裏咱們僅僅展現了很小的一方面。