文章目录
- Best
- 前言:什么是PyTorch?
- pytorch
- 文档
- 一.构建tensor
- 二.tensor运算
- 三.numpy和pytorch的tensor之间进行转换
- 四.使用GPU
- 4.1 tensor转移到gpu的两种方法
- 五.两层神经网络简单练习
- 5.1 pytorch求梯度
- 5.1.1 手动求梯度
- 5.1.2 pytorch自动算gradient
- 5.2 使用pytorch的nn(neural network)库
- 5.3 使用优化器更新参数(optim)
- 5.4 使用类的方法写模型(标准写法)
- 六 写神经网络过程总结
Best
最好是看教程:https://pytorch.org/tutorials/beginner/basics/intro.html
前言:什么是PyTorch?
pytorch
PyTorch是一个基于Python的科学计算库,它有以下特点:
- 基本数据tensor使用类似于NumPy的ndarray,但它可以被pytorch支持去进行计算,比如梯度
- 可以用它定义深度学习模型,可以灵活地进行深度学习模型的训练和使用
文档
一.构建tensor
import torch
构建一维的,以ones为例
x=torch.ones(3)
x
tensor([1., 1., 1.])
用empty构建一个未初始化的矩阵:
x=torch.empty(5,3)
x
tensor([[9.2755e-39, 1.0561e-38, 9.1837e-39],
[1.0653e-38, 4.2246e-39, 1.0286e-38],
[1.0653e-38, 1.0194e-38, 8.4490e-39],
[1.0469e-38, 9.3674e-39, 9.9184e-39],
[8.7245e-39, 9.2755e-39, 8.9082e-39]])
用rand构建一个随机初始化的矩阵
x=torch.rand(5,3)
x
tensor([[0.4299, 0.3554, 0.6924],
[0.0979, 0.2094, 0.3660],
[1.0000, 0.4666, 0.8967],
[0.9141, 0.9506, 0.1320],
[0.3213, 0.7118, 0.3338]])
用zeros构建一个全部为0的,类型为long的矩阵
x=torch.zeros(5,3)
print(x.dtype)
x
torch.float32
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
构建一个类型为long的矩阵
x=torch.zeros(5,3,dtype=torch.long)
x.dtype
torch.int64
从数据里直接构造tensor
x=torch.tensor([[5.2,3],[2,4],[0,1]])
x
tensor([[5.2000, 3.0000],
[2.0000, 4.0000],
[0.0000, 1.0000]])
根据已有的tensor构建一个tensor,新tensor会重用原来的tensor的特征(除非提供新的),比如数据类型
y=x.new_ones(5,3)
print(y.dtype,x.dtype)
y
torch.float32 torch.float32
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
用randn_like产生一个和原有tensor形状一样,但数字是随即产生的矩阵
x=torch.tensor([[5,3],[2,4],[0,1]])
print(x)
#此处使用randn_like好像不支持long类型,因此得指定dtype=torch.float
y=torch.randn_like(x,dtype=torch.float)
y
tensor([[5, 3],
[2, 4],
[0, 1]])
tensor([[ 0.0310, 1.4271],
[-0.9848, 0.4927],
[ 0.3195, 0.9557]])
得到tensor的形状
# 1
print(x.shape)
# 2
print(x.size())
torch.Size([3, 2])
torch.Size([3, 2])
二.tensor运算
加法运算
x=torch.rand(3,2)
print(x)
y=torch.rand(3,2)
print(y)
tensor([[0.3739, 0.4920],
[0.5229, 0.3832],
[0.3701, 0.8966]])
tensor([[0.0254, 0.2324],
[0.1292, 0.2256],
[0.9176, 0.8742]])
# 加法一
print("加法一:")
x+y
加法一:
tensor([[0.3994, 0.7243],
[0.6522, 0.6088],
[1.2877, 1.7708]])
# 加法二
print("加法二:")
torch.add(x,y)
加法二:
tensor([[0.3994, 0.7243],
[0.6522, 0.6088],
[1.2877, 1.7708]])
in-place加法(任何in-place运算都会以 _ 结尾,且in-place运算会改变外边值)
y=torch.rand(3,2)
x=torch.rand(3,2)
print(y)
y.add(x)#没加下划线,不会改变y的值(不过好像没加下划线这句话没啥意义)
print(y)
y.add_(x)#加了下划线,会改变y的值
print(y)
tensor([[0.5951, 0.3312],
[0.9888, 0.9005],
[0.0621, 0.2813]])
tensor([[0.5951, 0.3312],
[0.9888, 0.9005],
[0.0621, 0.2813]])
tensor([[1.3827, 0.8883],
[1.4221, 1.8106],
[0.5017, 0.8420]])
类似Numpy的indexing操作可以在pytorch的tensor上运算
y[1:,1:]
tensor([[1.8106],
[0.8420]])
改变tensor的形状
x=torch.randn(4,4)
x
tensor([[-1.1561, -0.6490, 2.2239, -1.1019],
[-0.8052, 1.4307, -0.0130, -0.1001],
[-1.4327, -0.6575, 0.8889, -0.9387],
[ 1.9800, 1.1328, 1.7042, 0.2872]])
#改变成1维的
y=x.view(16)
print(y)
#改成1行16列,但还是二维的
y=x.view(1,16)
print(y)
#用-1自动补全,比如2行8列
y=x.view(-1,8)
print(y)
y=x.view(2,-1)
print(y)
tensor([-1.1561, -0.6490, 2.2239, -1.1019, -0.8052, 1.4307, -0.0130, -0.1001,
-1.4327, -0.6575, 0.8889, -0.9387, 1.9800, 1.1328, 1.7042, 0.2872])
tensor([[-1.1561, -0.6490, 2.2239, -1.1019, -0.8052, 1.4307, -0.0130, -0.1001,
-1.4327, -0.6575, 0.8889, -0.9387, 1.9800, 1.1328, 1.7042, 0.2872]])
tensor([[-1.1561, -0.6490, 2.2239, -1.1019, -0.8052, 1.4307, -0.0130, -0.1001],
[-1.4327, -0.6575, 0.8889, -0.9387, 1.9800, 1.1328, 1.7042, 0.2872]])
tensor([[-1.1561, -0.6490, 2.2239, -1.1019, -0.8052, 1.4307, -0.0130, -0.1001],
[-1.4327, -0.6575, 0.8889, -0.9387, 1.9800, 1.1328, 1.7042, 0.2872]])
tensor只有一个元素时,用.item()可以把里面的value变成python数值
x=torch.randn(1)
x
tensor([2.0330])
x=x.item()
x
2.032999038696289
转置
x=torch.rand(2,3)
x
tensor([[0.8038, 0.9835, 0.5112],
[0.6364, 0.4693, 0.9986]])
x=x.transpose(1,0)
x
tensor([[0.8038, 0.6364],
[0.9835, 0.4693],
[0.5112, 0.9986]])
更多阅读
各种Tensor operations, 包括transposing, indexing, slicing,
mathematical operations, linear algebra, random numbers在<https://pytorch.org/docs/torch>
.
三.numpy和pytorch的tensor之间进行转换
pytorch的tensor转为numpy的array
x=torch.ones(3)
x
tensor([1., 1., 1.])
y=x.numpy()
y
array([1., 1., 1.], dtype=float32)
注意,上面pytorch的tensor和numpy的array是共享内存空间的
y[1]=2
y
array([1., 2., 1.], dtype=float32)
x
tensor([1., 2., 1.])
numpy的array转为pytorch的tensor
import numpy as np
x=np.ones(3)
print(x)
y=torch.from_numpy(x)
print(y)
[1. 1. 1.]
tensor([1., 1., 1.], dtype=torch.float64)
np.add(x,2,out=x)
print(x)
print(y)
[3. 3. 3.]
tensor([3., 3., 3.], dtype=torch.float64)
x=np.add(x,1)
print(x)
print(y)
[4. 4. 4.]
tensor([3., 3., 3.], dtype=torch.float64)
根据上面两块代码,可以知道用out才是存到原来的变量里,而x=np.add()则是重新生成一个新的变量叫x
四.使用GPU
使用GPU进行加速,则需要将所有tensor转移到gpu上,即模型(模型的参数也是tensor)和模型输入的数据
判断gpu是否可用,结果为true则可用
torch.cuda.is_available()
True
4.1 tensor转移到gpu的两种方法
- 使用.to()将tensor转移到gpu上去
device=torch.device(“cuda:0” if torch.cuda.is_available() else “cpu”)
model=model.to(device)
x=x.to(device)
y=y.to(device) - 使用.cuda()转移上去
model=model.cuda()
x=x.cuda()
y=y.cuda()
下面以.to()将tensor转移到gpu上去运行进行举例
x=torch.rand(3)
y=torch.rand(3)
device=torch.device("cuda")
y=torch.ones_like(y,device=device)#cuda是英伟达的一个gpu运算库,此处将tensor放到cuda上(本电脑的gpu就是英伟达的)
x=x.to(device)#将x搬到gpu上去
z=x+y # 此处x和y都得是在gpu上
z
tensor([1.9240, 1.4169, 1.3466], device='cuda:0')
再把z从gpu搬到cpu上,并且此刻还能转类型
print(z.to("cpu",torch.double))
tensor([1.9240, 1.4169, 1.3466], dtype=torch.float64)
注意:若tensor是在cpu上,可以直接住转为numpy;若tensor在gpu上则需要转到cpu上再转为numpy,因为numpy是在cpu上操作的库
x=torch.rand(3)
print(x.numpy())
if torch.cuda.is_available():
device=torch.device("cuda")
x=x.to(device)
print(x)
#下面这句会报这样的错误:TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.
#print(x.numpy())
x.to("cpu")
#再转回cpu就又可以用了
print(x)
[0.1902067 0.26630002 0.84085023]
tensor([0.1902, 0.2663, 0.8409], device='cuda:0')
tensor([0.1902, 0.2663, 0.8409], device='cuda:0')
五.两层神经网络简单练习
5.1 pytorch求梯度
PyTorch: Tensor和autograd
PyTorch的一个重要功能就是autograd,也就是说只要定义了forward pass(前向神经网络),计算了loss之后,PyTorch可以自动求导计算模型所有参数的梯度。
一个PyTorch的Tensor表示计算图中的一个节点。如果x
是一个Tensor并且x.requires_grad=True
那么x.grad
是另一个储存着x
当前梯度(相对于一个scalar,常常是loss)的向量。
5.1.1 手动求梯度
N,D_in,H,D_out=64,1000,100,10
#随机创建一些训练数据
x=torch.randn(N,D_in)
y=torch.randn(N,D_out)
w1=torch.randn(D_in,H)
w2=torch.randn(H,D_out)
learning_rate=1e-6
for it in range(500):
#forward pass
h=x.mm(w1)
h_relu=h.clamp(min=0)
y_pred=h_relu.mm(w2)
#compute loss
loss=(y_pred-y).pow(2).sum().item()
print(it,loss)
#backward pass
#compute the gradient
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)
#update weights of w1 and w2
w1-=learning_rate*grad_w1
w2-=learning_rate*grad_w2
0 42958784.0
1 46169804.0
2 48758020.0
(省略)
496 0.00026750023243948817
497 0.0002627377980388701
498 0.0002574215177446604
499 0.0002527687174733728
5.1.2 pytorch自动算gradient
求梯度(导数)例子
注:根据grad修改参数值后,必须把参数梯度清0,因为pytorch里不清0的话,会在下次计算参数梯度时把上次的梯度也带上
x=torch.tensor(1.0,requires_grad=True)
w=torch.tensor(2.0,requires_grad=True)
b=torch.tensor(3.0,requires_grad=True)
y=w*x+b # y = 2*1 + 3
#求y的所有中间参数的梯度
y.backward()
#求 y 对 x的导数,即dy/dx
print("dy/dx:",x.grad)
#求 y 对 w的导数,即dy/dw
print("dy/dw:",w.grad)
#求 y 对 b的导数,即dy/db
print("dy/db:",b.grad)
dy/dx: tensor(2.)
dy/dw: tensor(1.)
dy/db: tensor(1.)
N,D_in,H,D_out=64,1000,100,10
#随机创建一些训练数据
x=torch.randn(N,D_in)
y=torch.randn(N,D_out)
w1=torch.randn(D_in,H,requires_grad=True)
w2=torch.randn(H,D_out,requires_grad=True)
learning_rate=1e-6
for it in range(500):
#forward pass
y_pred=x.mm(w1).clamp(min=0).mm(w2)
#compute loss
loss=(y_pred-y).pow(2).sum()
print(it,loss.item())
#backward pass,compute the gradient
loss.backward()#求loss所有中间参数即w1和w2的grad
#update weights of w1 and w2
with torch.no_grad():#这行语句是使内存不记录w1和w2的梯度,要不会影响以后求梯度的结果
w1 -= learning_rate * w1.grad
w2 -= learning_rate * w2.grad
#根据grad修改w1和w2的值后,必须把梯度清0,因为pytorch里不清0的话,会在下次计算梯度时把上次的梯度也带上
w1.grad.zero_()
w2.grad.zero_()
0 33515288.0
1 28960210.0
2 25787898.0
(省略)
497 7.83200521254912e-05
498 7.704120071139187e-05
499 7.612317858729511e-05
5.2 使用pytorch的nn(neural network)库
import torch.nn as nn
N,D_in,H,D_out=64,1000,100,10
#随机创建一些训练数据
x=torch.randn(N,D_in)
y=torch.randn(N,D_out)
model=torch.nn.Sequential(
torch.nn.Linear(D_in,H),# w1*x+b1
torch.nn.ReLU(),
torch.nn.Linear(H,D_out),
)
#转到gpu上
#model=model.cuda()
loss_fn=nn.MSELoss(reduction='sum')
learning_rate=1e-3
for it in range(500):
#forward pass
y_pred=model(x)
#compute loss
loss=loss_fn(y_pred,y)
print(it,loss.item())
#backward pass,compute the gradient
loss.backward()#求loss所有中间参数即w1和w2的grad
#update weights of w1 and w2
with torch.no_grad():#这行语句是使内存不记录w1和w2的梯度,要不会影响以后求梯度的结果
#模型的所有参数都在parameters里
for param in model.parameters():
param -= learning_rate * param.grad
#清零梯度,清零所有参数,下一次求梯度前清零
model.zero_grad()
0 612.6693725585938
1 300.2776794433594
2 176.84945678710938
(省略)
497 1.6442732592159004e-12
498 1.673319469097656e-12
499 1.648422717770437e-12
model
Sequential(
(0): Linear(in_features=1000, out_features=100, bias=True)
(1): ReLU()
(2): Linear(in_features=100, out_features=10, bias=True)
)
5.3 使用优化器更新参数(optim)
import torch.nn as nn
N,D_in,H,D_out=64,1000,100,10
#随机创建一些训练数据
x=torch.randn(N,D_in)
y=torch.randn(N,D_out)
model=torch.nn.Sequential(
torch.nn.Linear(D_in,H),# w1*x+b1
torch.nn.ReLU(),
torch.nn.Linear(H,D_out),
)
#转到gpu上
#model=model.cuda()
loss_fn=nn.MSELoss(reduction='sum')
learning_rate=1e-4
#定义优化器
optimizer=torch.optim.Adam(model.parameters(),lr=learning_rate)
for it in range(500):
#forward pass
y_pred=model(x)#model(x)自动等于model.forward(x)
#compute loss
loss=loss_fn(y_pred,y)
print(it,loss.item())
#backward pass,compute the gradient
loss.backward()#求loss所有中间参数即w1和w2的grad
#更新参数
optimizer.step()
#梯度清零
optimizer.zero_grad()
0 676.9285888671875
1 659.3667602539062
2 642.3128051757812
(省略)
497 9.99489770947548e-07
498 9.476103173255979e-07
499 8.98813595995307e-07
5.4 使用类的方法写模型(标准写法)
import torch.nn as nn
N,D_in,H,D_out=64,1000,100,10
#随机创建一些训练数据
x=torch.randn(N,D_in)
y=torch.randn(N,D_out)
class TwoLayerNet(torch.nn.Module):#继承nn.Module
def __init__(self,D_in,H,D_out):#把有导数的层放到init里,定义模型框架
super(TwoLayerNet,self).__init__()#用super方法初始化
self.linear1=torch.nn.Linear(D_in,H,bias=False)
self.linear2=torch.nn.Linear(H,D_out,bias=False)
def forward(self,x):
y_pred=self.linear2(self.linear1(x).clamp(min=0))
return y_pred
model=TwoLayerNet(D_in,H,D_out)
#转到gpu上
device=torch.device("cuda")
model=model.cuda()
x=x.to(device)
y=y.to(device)
loss_fn=nn.MSELoss(reduction='sum')
learning_rate=1e-4
#定义优化器
optimizer=torch.optim.Adam(model.parameters(),lr=learning_rate)
for it in range(500):
#forward pass
y_pred=model(x)
#compute loss
loss=loss_fn(y_pred,y)
print(it,loss.item())
#backward pass,compute the gradient
loss.backward()#求loss所有中间参数即w1和w2的grad
#更新参数
optimizer.step()
#梯度清零
optimizer.zero_grad()
0 666.7147216796875
1 649.9814453125
2 633.6069946289062
(省略)
497 8.311786103831764e-08
498 7.800667845003773e-08
499 7.324160833377391e-08
六 写神经网络过程总结
写一个神经网络的大体流程:
- 1.加载数据,并确定数据格式
- 2.创建模型
- 3.构造损失函数
- 4.定义优化器
- 5.开始训练,确定训练批次大小和总训练数据的训练次数
- forward pass
- compute loss
- backward pass
- update weights
- clear gradient