简介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。可是,文字有限,这里咱们仅仅展现了很小的一方面。