赞
踩
1. 函数名后加"_"会修改Tensor本身,如加法的两种表达形式:y.add(x) 和 y.add_(x),前者不改变y的值,后者改变了y的值。
2. Tensor和Numpy的数组之间的互操作非常容易且快速,对于Tensor不支持的操作,可以先转化为Numpy数组尽力,之后再转回Tensor。且二者的对象共享内存,使得其转换很快,几乎不会消耗什么资源,但是这也意味着其中一个变了,另外一个也会随之改变。
- import torch as t
- import numpy as np
-
- a = np.ones(5)
- b = t.from_numpy(a)
- print(a)
- print(b)
-
- b.add_(1)
- print(a)
- print(b)
3. 获取某个元素的值可以使用scalar.item。直接使用Tensor[idx]得到的还是一个Tensor,而scalar一般是指0-dim的tensor。
- scalar = b[0]
- scalar
- scalar.size()
- scalar.item()
-
- tensor = t.tensor([2])
- tensor, scalar #二者的区别
- tensor.size(), scalar.size()
- tensor.item(), scalar.item() #只有一个元素的tensor也可以使用item
4. torch.tensor接口yunp.array类似
5. torch.tensor()和tensor.clone()总会拷贝数据,新的tensor和原来的数据不共享内存;而想要共享内存,可以使用torch.from_numpy()或者tensor.detach()。
- old_tensor = tensor
- new_tensor = old_tensor.clone()
- new_tensor[0] = 1111
- old_tensor, new_tensor
-
- new_tensor = old_tensor.detach()
- new_tensor[0] = 1111
- old_tensor, new_tensor
6. Tensor可以通过.cuda的方式转化为GPU的Tensor,从而来加速:
- device = t.device("cuda:0" if t.cuda.is_available() else "cpu)
- x = x.to(device)
- y = y.to(device)
- z = x+y
1. 自动使用autograd功能,只需设置tensor.requires_grad=True。Variable主要包含三个属性:(1)data:保存Variable所包含的Tensor;(2)grad:保存data对应的梯度,它也是个Variable,而不是Tensor,与data的形状是一样的;(3)grad_fn:指向一个Function对象,这个Function用来反向传播计算输入的梯度。
- x = t.ones(2, 2, requires_grad=True)
- y = x.sum()
- y
- y.grad_fn
- y.backward() #反向传播,计算梯度,x内每个元素的梯度均为1
- x.grad
2. grad在反向传播的过程中是累加的,也就是说每一次运行反向传播,梯度都会累加之前的梯度,所以传播之前需要把梯度清零。
- y.backward()
- x.grad
- y.backward()
- x.grad
- x.grad.data.zero() #将x的梯度清零
- y.backward()
- x.grad
1. torch.nn是专门为神经网络设计的模块化接口,建立在 Autograd之上。其中nn.Module是nn中最重要的类,可看成是一个网络的封装,包含网络各层定义以及forward方法,且只要在nn.Module的子类中定义了forward函数,backward函数就会自动被实现(利用autograd)
2. 定义网络:
(1)继承nn.Module模块,需要把网络中具有可学习参数的层放在__init__中,如果某一层不具有可学习的参数,则既可以放在构造函数中,也可以不放,建议不放如,而是在forward函数中使用nn.functional代替。
- #Lenet网络:
- import torch.nn as nn
- import torch.nn.functional as F
-
- class Net(nn.Module):
- def __init__(self):
- super(Net, self).__init__() # nn.Module子类的函数必须在构造函数中执行父类的构造函数,该式等价于nn.Module.__init__(self)
-
- self.conv1 = nn.Conv2d(1, 6, 5) # 卷积层 '1'表示输入图片为单通道, '6'表示输出通道数,'5'表示卷积核为5*5
- self.conv2 = nn.Conv2d(6, 16, 5)
- self.fc1 = nn.Linear(16*5*5, 120) # 仿射层/全连接层,y = Wx + b
- 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(x.size()[0], -1) # reshape,‘-1’表示自适应
- x = F.relu(self.fc1(x))
- x = F.relu(self.fc2(x))
- x = self.fc3(x)
- return x
-
- net = Net()
- print(net)

(2)网络的学习参数可通过net.parameters()返回,或者采用net.named_parameters可同时返回学习的参数及名称
- params = list(net.parameters())
- print(len(params))
-
- for name, parameters in net.named_parameters():
- print(name, ':', parameters.size())
(3)forward函数的输入和输出都是Tensor
- input = t.randn(1, 1, 32, 32)
- out = net(input)
- out.size()
-
- net.zero_grad()
- out.backward(t.ones(1, 10))
(4) torch.nn只支持mini_batches,不支持一次只输入一个样本,若只想输入一个样本,可以用input.unsqueeze()将batch_size设为1。例如nn.Conv2d输入必须是4维的:nSample*nChannels*Height*Width,可以变为1*nChannels*Height*Width
3. 损失函数:
(1)nn实现了神经网络大多数的损失函数,例如nn.MSELoss用来计算均方误差,nn.CrossEntropyLoss用来计算交叉熵损失
- output = net(input)
- target = t.arrange(0,10).view(1,10).float()
- criterion = nn.MSELoss()
- loss = criterion(output, target)
- loss
(2)调用backward时,会生成动态图并自动微分,也即会自动计算图中参数的导数
- net.zero_grad()
- print("反向传播之前 conv1.bias的梯度")
- print(net.conv1.bias.grad)
- loss.backward()
- print("反向传播之后 conv1.biad的梯度")
- print(net.conv1.bias.grad)
4. 优化器
(1)反向传播计算参数的梯度后,还需要使用优化方法来更新网络的梯度,例如随机梯度下降法的更新策略: weight = weight - learning_rate * gradient,手动实现为:
- learning_rate = 0.01
- for f in net.parameters():
- f.data.sub_(f.grad.data * learning_rate)# inplace 减法
(2)torch.optim中实现了深度学习中的绝大多数优化方法,例如RMSProp、Adam、SGD等
- import torch.optim as optim
- optimizer = optim.SGD(net.parameters(), lr = 0.01)
-
- optimizer.zero_grad()
-
- output = net(input)
- loss = criterion(output, target)
-
- loss.backward
-
- optimizer.step()
四、CIFAR-10分类
1. 数据加载与预处理:torchvision实现了常用的图像数据加载功能,例如Imagenet、CIFAR10、MINIST,以及常用的数据转换操作,可极大地方便数据加载,并且代码具有可重用性。
- import torchvision as tv
- import torchvision.transforms as transforms
- from torchvision.transforms import ToPILImage
- show = ToPILImage() # 可以把Tensor转成Image,方便可视化
-
- # 定义对数据的预处理
- transform = transforms.Compose([
- transforms.ToTensor(), # 转为Tensor
- transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), # 归一化
- ])
-
- # 训练集
- trainset = tv.datasets.CIFAR10(
- root='/home/cy/tmp/data/',
- train=True,
- download=True,
- transform=transform)
-
- trainloader = t.utils.data.DataLoader(
- trainset,
- batch_size=4,
- shuffle=True,
- num_workers=2)
-
- # 测试集
- testset = tv.datasets.CIFAR10(
- '/home/cy/tmp/data/',
- train=False,
- download=True,
- transform=transform)
-
- testloader = t.utils.data.DataLoader(
- testset,
- batch_size=4,
- shuffle=False,
- num_workers=2)
-
- classes = ('plane', 'car', 'bird', 'cat',
- 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

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.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(x.size()[0], -1)
- x = F.relu(self.fc1(x))
- x = F.relu(self.fc2(x))
- x = self.fc3(x)
- return x
-
-
- net = Net()
- print(net)

3. 定义损失函数和优化器:
- from torch import optim
- criterion = nn.CrossEntropyLoss() # 交叉熵损失函数
- optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
4. 训练网络:
- t.set_num_threads(8)
- for epoch in range(2):
-
- running_loss = 0.0
- for i, data in enumerate(trainloader, 0):
- inputs, labels = data;
- optimizer.zero_grad()
- output = 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')

5. 查看效果:
- dataiter = iter(testloader)
- images, labels = dataiter.next()
- print('实际的label:', ' '.join('%08s'%classes[labels[j]] for j in range(4)))
- show(tv.utils.make_grid(images / 2 - 0.5)).resize((400,100))
-
- outputs = net(images)
- _, predicted = t.max(outputs.data, 1)
- print('预测结果:', ' '.join('%5s'%classes[predicted[j]] for j in range(4)))
6. 在这个测试集上的效果
- correct = 0 #预测正确的图片数
- total = 0 #总共的图片数
-
- with t.no_grad():
- for data in testloader:
- images, labels = data
- outputs = net(images)
- _, predicted = t.max(outputs, 1)
- total += labels.size(0)
- correct += (predicted == labels).sum()
-
- print('10000张测试集中的准确率为: %d %%' %(100 * correct / total))
7. 在GPU上训练:
- device = t.device('cuda;0' if t.cuda.is_available() else "cpu")
-
- net.to(device)
- images = images.to(device)
- labels = labels.to(device)
- output = net(images)
- loss = criterion(output, labelss)
-
- loss
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。