Pytorch下的张量操作
Tensors与NumPy中的 ndarrays类似,下面实现一些简单的操作,首先导入相应的包
from __future__ import print_function
import torch
张量
构造一个5X3的矩阵
x=torch.empty(5,3)
print(x)
输出:
tensor([[9.1837e-39, 4.6837e-39, 9.2755e-39],
[1.0837e-38, 8.4490e-39, 1.1112e-38],
[1.0194e-38, 9.0919e-39, 8.4490e-39],
[9.6429e-39, 8.4490e-39, 9.6429e-39],
[9.2755e-39, 1.0286e-38, 9.0919e-39]])
构造一个随机矩阵
x = torch.rand(5,3)
print(x)
输出:
tensor([[0.7028, 0.6747, 0.9585],
[0.1216, 0.7152, 0.2926],
[0.7292, 0.6155, 0.5695],
[0.5835, 0.8147, 0.2758],
[0.0413, 0.8445, 0.4681]])
构造类型为long的全零矩阵
x = torch.zeros(5,3,dtype=torch.long)
print(x)
输出:
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
用数据直接构造张量
x = torch.tensor([5.5,3])
print(x)
输出:
tensor([5.5000, 3.0000])
使用new_*方法构造张量
x = torch.zeros(5,3,dtype=torch.long)
x = x.new_ones(5,3,dtype=torch.double)
print(x)
x = torch.randn_like(x,dtype=torch.float)
print(x)
输出:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
tensor([[ 0.7960, 0.3521, -0.6110],
[-1.3932, -0.4911, -0.7206],
[ 0.1605, 0.5626, -0.5002],
[-0.7352, 0.0382, -0.7809],
[ 1.2041, 1.5645, 0.2425]])
基本操作
Addition:syntax 1
x = torch.rand(5,3)
y = torch.rand(5,3)
print(x+y)
输出:
tensor([[1.2324, 0.6507, 1.3211],
[1.2938, 1.2007, 0.5592],
[1.5900, 1.0517, 1.1385],
[0.4266, 1.0057, 0.9490],
[1.0860, 0.2747, 1.6411]])
Addition: syntax 2
print(torch.add(x,y))
输出:
tensor([[1.2324, 0.6507, 1.3211],
[1.2938, 1.2007, 0.5592],
[1.5900, 1.0517, 1.1385],
[0.4266, 1.0057, 0.9490],
[1.0860, 0.2747, 1.6411]])
Addition:in-place(就地操作)
print(y.add_(x))
输出:
tensor([[1.2324, 0.6507, 1.3211],
[1.2938, 1.2007, 0.5592],
[1.5900, 1.0517, 1.1385],
[0.4266, 1.0057, 0.9490],
[1.0860, 0.2747, 1.6411]])
将Torch张量转换为NumPy
a=torch.ones(5)
print(a)
输出:
tensor([1., 1., 1., 1., 1.])
转换为numpy
b = a.numpy()
print(b)
输出:
[1. 1. 1. 1. 1.]
注意:转换为a和b占用同一空间,一个改变,另一个也跟着改变
a.add_(1)
print(a)
print(b)
输出:
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]
将NumPy转换为Torch张量
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a,1,out=a)
print(a)
print(b)
输出:
[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
梯度
后向传播
x = torch.ones(2,2,requires_grad=True)
y = x+2
z = y*y*3
out = z.mean()
out.backward()
打印梯度d(out)/dx
print(x.grad)
输出:
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
神经网络
在pytorch中,可以使用torch.nn
包构造神经网络,其中nn.Module
包含层,方法forward(input)
返回output
。
对于一个神经网络而言,典型的训练过程如下:
- 定义带有超参数的神经网络;
- 在训练集上进行迭代;
- 在网络上处理输入数据;
- 计算损失;
- 后向传播梯度到网络;
- 更新权重。
定义一个网络
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1 = nn.Conv2d(1,6,5)
self.conv2 = nn.Conv2d(6,16,5)
self.fc1 = nn.Linear(16*5*5,120)
self.fc2 = nn.Linear(120,84)
self.fc3 = nn.Linear(84,10)
def forward(self,x):
x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
x = F.max_pool2d(F.relu(self.conv2(x)),2)
x = x.view(-1,self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self,x):
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net)
输出:
Net(
(conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
上面尽管只定义了forward
函数,backward
函数将在使用autograd
函数时自动定义。模型需要学习的参数可以使用net.parameters()
查看
params = list(net.parameters())
print(len(params))
print(params[0].size())
输出:
10
torch.Size([6, 1, 5, 5])
损失函数
在nn
包中有各种各样的损失函数,常见的比如:nn.MSELoss
。
例如:
input = torch.randn(1,1,32,32)
output = net(input)
target = torch.randn(10)
target = target.view(1,-1)
criterion = nn.MSELoss()
loss = criterion(output,target)
print(loss)
输出:
tensor(0.9953, grad_fn=<MseLossBackward>)
训练一个分类器
将从下面几个步骤执行
- 使用
torchvision
加载CIFAR10
训练和测试样本集,帮对其进行归一化处理 - 定义卷积神经网络
- 定义损失函数
- 在训练集上训练网络
- 在测试集上测试网络
1.加载和归一化CIFAR10
import torch
import torchvision
import torchvision.transforms as transforms
torchvison
数据集的输出时PILImage
图像,其范围在[0,1]
,因此需归一化到[-1,1]
。
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data',train=True,download=True,transform=transform)
trainloader = torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform)
testloader=torch.utils.data.DataLoader(testset,batch_size=4,shuffle=False,num_workers=2)
classes = ('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')
输出:
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data\cifar-10-python.tar.gz
100.0%Files already downloaded and verified
显示部分训练集图像
import matplotlib.pyplot as plt
import numpy as np
def imshow(img):
img = img/2+0.5
npimg = img.numpy()
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
dataiter = iter(trainloader)
images,labels = dataiter.next()
imshow(torchvision.utils.make_grid(images))
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
输出:
frog frog dog plane
2.定义卷积神经网络
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2,2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16*5*5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
3.定义损失函数和优化器
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
4.训练网络
for epoch in range(2):
running_loss=0.0
for i,data in enumerate(trainloader,0):
inputs,labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss=criterion(outputs,labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i%2000==1999:
print('[%d,%5d] loss:%.3f' %(epoch+1,i+1,running_loss/2000))
running_loss=0.0
print('Finished Training')
输出
[1, 2000] loss:2.186
[1, 4000] loss:1.822
[1, 6000] loss:1.639
[1, 8000] loss:1.550
[1,10000] loss:1.512
[1,12000] loss:1.453
[2, 2000] loss:1.400
[2, 4000] loss:1.344
[2, 6000] loss:1.336
[2, 8000] loss:1.305
[2,10000] loss:1.284
[2,12000] loss:1.279
Finished Training
5.在测试集上测试网络
dataiter = iter(testloader)
images,labels=dataiter.next()
imshow(torchvision.utils.make_grid(images))
print('GroundTruth:',' '.join('%5s' %classes[labels[j]] for j in range(4)))
输出:
GroundTruth: cat ship ship plane
outputs = net(images)
_,predicted = torch.max(outputs,1)
print('Predicted: ',' '.join('%5s' %classes[predicted[j]] for j in range(4)))
输出:
Predicted: cat ship car plane
6.下面展示在整个数据集上的性能
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
image,labels=data
outputs=net(images)
_,predicted=torch.max(outputs.data,1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (100*correct/total))
输出:
Accuracy of the network on the 10000 test images: 51 %
从结果来看,模型并不是很好。
7.在GPU上训练
device = torch.device("cuda:0" if torch.cuda.is_available() else "cup")
print(device)
输出:
cuda:0
同时需要将inputs
和targets
送入GPU,即
inputs,labels = inputs.to(device),labels.to(device)