文章目录

  • 1. 张量(Tensors)
  • 定义张量
  • 张量操作
  • 2.自动求导(autograd)
  • 变量Variable
  • 3.神经网络
  • 4. 训练一个分类器
  • 载入数据
  • 5.数据并行




1. 张量(Tensors)

tensors和numpy的ndarray类似,但是tensors可以使用GPU加快运算

张量定义的matrix在未使用前的初始值就是那个内存地址保存的值

定义张量

#定义未初始化的张量
x = torch.empty(5,3);
#定义初始化的张量
x = torch.rand(5,3);#随机初始化
x = torch.zeros(5,3,dtype=torch.long);#全零初始化
x = torch.tensor([5.5,3])#直接从数值构建tensor
#从已有的张量构建新的张量,会复用已有张量的property,除非指定新的
x = x.new_ones(5,3,dtype=torch.double)
#输出张量矩阵的大小
print(x.size())#返回torch.Size([5, 3]),是tuple类型

张量操作

相加:

#语法一
y = torch.rand(5,3)
print(x+y)
#语法二
print(torch.add(x,y));
#语法三:指定out张量
result = torch.empty(5,3)
torch.add(x,y,out=result)
print(result)
#语法四:in-place(原地改变张量的操作都有一个下杠_后缀)
y.add_(x)
print(y)

张量上也可以使用所有numpy索引操作:x[:,1]

resizing:
调整改变张量的shape,使用torch.view

x = torch.randn(4,4)
y = x.view(16)
z = x.view(-1,8)#这里-1具体是多少是从另一个维度值8推断而来的,(2,8)

只有一个值的张量可以使用x.item()直接得到他的数值

numpy桥:
torch张量与numpy数组的相互转换。如果张量在CPU上,张量和对应的numpy数组会共享内存,所有CPU上的张量,除了字符串张量都支持相互转化。

#张量--> numpy数组
a = torch.ones(5)
b = a.numpy()#得到numpy数组b
#numpy数组-->张量
a = numpy.ones(5)
b = torch.from_numpy(a)

CUDA Tensors
张量可通过to()方法转移任何device上

if torch.cuda.is_avilable():
	device = torch.device("cuda")
	y = torch.ones_like(x,device=device)#直接在GPU上创建张量
	x = x.to(device)#或者这样移动到GPU上
	x = x.to("cpu",torch.double)#移动到CPU上,同时改变数据类型

2.自动求导(autograd)

pytorch的核心包,为张量上的所有操作定义了自动求导,是一个运行时定义的框架,意味着反向传播是根据你的代码如何运行来定义,并且每次迭代可以不同。下面看一下这个包的具体内容:

变量Variable

autograd.Variable:核心类,包装了张量Tensor,,一旦完成前向计算,可以通过backward方法来自动计算所有的梯度。通过.data属性访问原始张量,.grad属性访问变量的梯度

x = torch.ones(2,2,requires_grad=True)#追踪他的计算过程
y = x+2
print(y.grad_fn)#grad_fn是创造这个张量的函数
z = y * y * 3
out = z.mean()
out.backward()#相当于out.backward(torch.tensor(1.)),不是单元素tensor要指定
print(x.grad)#d(out)/dx

#stop autograd
with torch.no_grad():
	print((x**2).requires_grad)
#或者使用detach获得一个内容一样的tensor,但是不用求梯度
y = x.detach()

3.神经网络

torch.nn包来构建神经网络,nn包依赖autograd包来定义模型并求导,一个nn.Module包含各个层和一个forward(input)方法,该方法返回output。

神经网络的典型训练过程:
1.定义神经网络模型,他有一些可学习的参数(或者权重)
2.在数据集上迭代
3.通过神经网络处理输入
4.计算loss(输出结果与正确值的差距大小)
5.将梯度反向传播回网络的参数
6.更新网络参数,简单的更新原则:weight = weight - learning_rate*gradient

例子:
MNIST网络实践,见jupyter notebook中的pytorch文件夹
注意:torch.nn只支持小批量输入,而不支持单个样本,例如nn.Conv2d将接受一个四维的张量:nSamples x nChannels x Height x Width,如果只有单个样本数据 ,只需使用input.unsqueeze(0)来添加其他维数。

out = net(input)
target = torch.randn(10)#a dummy target
target = target.view(1,-1)#resize to the same shape of output
criterion = nn.MSELoss()
loss = criterion(output,target)
print(loss)

反向传播:

loss.backward()
#整个计算图
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
      -> view -> linear -> relu -> linear -> relu -> linear
      -> MSELoss
      -> loss

整个图关于损失求导,图中所有变量将拥有.grad来累计他们的梯度,反向传播之前,要清除已存在的梯度

更新权重:
最简单的更新规则SDG(随机梯度下降)

learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)

要使用其他的更新规则,可以使用torch.optim包

import torch.optim as optim
#create optimizer
optimizer = optim.SDG(net.paramters(), lr=0.01)
#in your training loop
optimizer.zero_grad()#因为梯度是累积的,所有需要手动清零
output = net(input)
loss = criterion(output,target)
loss.backward()
optimizer.step()#update weight

4. 训练一个分类器

载入数据

可以通过标准的python包来加载数据到numpy数组,然后转换成tensor
● 对于图像,可使用pillow,opencv
● 对于音频,scipy,librosa
● 对于文本,原始python,NLTK

pytorch为视觉创建了一个torchvision包,通过torchvision.datasets 和torch.utils.data.DataLoader 实现包含常见数据集的加载,比如imagenet,MNIST,和数据转换

案例:图像分类,基于CIFAR10数据集,见jupyter notebook 中的pytorch文件夹

在GPU上训练:

device = torch.device('cuda:0' if torch.cuda.is_avaliable() else 'cpu')
print(device)
#将神经网络移动到GPU上训练,会遍历所有模块,并将其参数和缓冲区转换为CUDA张量
net.to(device)
#同时,必须在每一步中将输入和目标值转换到GPU上
inputs,labels = data[0].to(device),data[1].to(device)