0. 前言
最近正在学习pytorch,边学习边整理了一下笔记。笔记将会按照各个模块来进行整理,从Tensor,Variable到nn,Module,Function等。将会有更多底层实现的细节,以及自己的理解。希望能够以最形象直白的方式阐述自己的理解,并在每章后综合应用该章知识,以实现灵活应用Pytorch。同时,将会在期间穿插一些有用的工具,如网络可视化等。
1. 本章结构
在本章中,将会主要介绍Pytorch最基本的模块,将包括以下内容:
- Tensor的直观理解
- Tensor的基本操作:
- 生成Tensor
- 基本运算
- 与Num平移的转换
- 在GPU上计算
2. Tensor直观理解
- 数值计算:直观理解Tensor就类似Numpy中的array,是一个n维数组,专门用于在pytorch中做数值计算,不涉及深度学习网络结构、计算图、梯度计算等。
- GPU加速:不同于Numpy中的array,torch.Tensor能够使用GPU进行加速,一般GPU速度是CPU的50倍
- 总结:Tensor是一个单纯的可以用GPU加速的科学计算工具,应与后面介绍的Variable区分开
3. Tensor基本操作
Tensor生成
import torch
import numpy as np
# 生成未初始化矩阵
x = torch.Tensor(5, 3)
# 生成随机矩阵
x = torch.rand(5, 3)
# 得到Tensor size
print('x.size(): ', x.size())
# out:('x.size(): ', torch.Size([5, 3]))
# 指定生成的Tensor的数据类型
dtype = torch.FloatTensor # 使用CPU
# dtype = torch.cuda.FloatTensor # 使用GPU
x = torch.rand(5, 3).type(dtype)
print('x.type(): ',x.type())
# out: ('x.type(): ', 'torch.FloatTensor')
Tensor基本运算
Tensor的运算有多种语法实现 具体计算详见:torch – PyTorch 0.1.12 documentation
# 生成Tensor
x = torch.randn(2, 3)
y = torch.randn(2, 3)
print 'x, y:', x, y
print
# 下面用4种语法进行Tensor加法
# 语法1
print 'x + y: ', x + y
print
# 语法2
print 'torch.add(x, y): ', torch.add(x, y)
print
# 语法3
result = torch.Tensor(2, 3)
torch.add(x, y, out=result)
print 'torch.add(x, y, result): ', result
print
# 语法4:in-place计算,类似'+='运算,此时直接赋值给y。in-place操作都使用`_`作为后缀。例如,x.copy_(y)
y.add_(x)
print 'y.add_(x)', y
Tensor与Numpy进行转换
- torch Tensor可以转换成Numpy arry,反之亦然
- Tensor与numpy进行转换后,两者的内存位置共享,也就是说Tensor的值改变了,对应Numpy的值也改变,反之亦然
# 生成Tensor与numpy arrya
x_tensor = torch.randn(2, 3)
y_numpy = np.random.randn(2, 3)
# Tensor转换为Numpy
x_numpy = x_tensor.numpy()
print 'type(x_numpy):', type(x_numpy)
# Numpy转换为Tensor
y_tensor = torch.from_numpy(y_numpy)
print 'y_tensor.type(): ', y_tensor.type()
# 各自对应的Tensor与Numpy共享内存,一变俱变
x_tensor.add_(1)
print 'x_tensor after add 1: \n', x_tensor
print
print 'x_numpy after add 1: \n', x_numpy
print
np.add(y_numpy, 2, out=y_numpy)
print 'y_tensor after add 2: ', y_tensor
print
print 'y_numpy after add 2: \n', y_numpy
print
# 如果没有使用in-place运算,则无法共享内存
y_numpy = y_numpy + 1
print 'y_numpy after add 1 without in-place op: \n', y_numpy
print
print 'y_tensor after add 1 without in-place op: ', y_tensor
在GPU上使用Tensor
x = x.cuda()
y = y.cuda()
print 'x + y on GPU: ', x + y
4. 用Tensor建立简单的神经网络
- Tensor提供了最基本的数值运算,但神经网络运算就是张量计算,因此可以直接利用Tensor来搭建神经网络
- 但由于单纯的Tensor是不具备自动求导的,因此,反向传播需要自己根据梯度公式来实现
- 下面我们就简单实现一个3层神经网络
from sklearn.datasets import load_boston
from sklearn import preprocessing
dtype = torch.FloatTensor
# dtype = torch.cuda.FloatTensor
# 载入数据,并预处理
X, y = load_boston(return_X_y=True)
X = preprocessing.scale(X[:100,:])
y = preprocessing.scale(y[:100].reshape(-1, 1))
# 定义超参数
data_size, D_input, D_output, D_hidden = X.shape[0], X.shape[1], 1, 50
lr = 1e-5
epoch = 200000
# 转换为Tensor
# X = torch.Tensor(X).type(dtype)
# y = torch.Tensor(y).type(dtype)
X = torch.from_numpy(X).type(dtype)
y = torch.from_numpy(y).type(dtype)
# 定义训练参数
w1 = torch.randn(D_input, D_hidden).type(dtype)
w2 = torch.randn(D_hidden, D_output).type(dtype)
# 进行训练
for i in range(epoch):
# 前向传播
h = torch.mm(X, w1) # 计算隐层
h_relu = h.clamp(min=0) # relu
y_pred = torch.mm(h_relu, w2) # 输出层
# loss计算,使用L2损失函数
loss = (y_pred - y).pow(2).sum()
if i % 10000 == 0:
print('epoch: {} loss: {}'.format(i, loss))
# 反向传播,计算梯度
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h < 0] = 0
grad_w1 = X.t().mm(grad_h)
# 更新计算的梯度
w1 -= lr * grad_w1
w2 -= lr * grad_w2
5. 总结
- Tensor是pytorch中最基本的模块
- Tensor实现了多种数值运算,一个Tensor就像是一个能通过GPU加上的Numpy array
- 但Tensor不具备自动求导机制,因此无法通过Tensor实现自动求导
- 后续的Variable为了自动求导而实现的,需要与Tensor进行区分
所有代码都可以在我的github中找到XavierLinNow/pytorch_note_CN