PyTorch 入门笔记总结

PyTorch 入门笔记总结1、Tensor张量创建张量 Torch构造张量有如下几种形式:import torch#直接构造类似于numpy中ndarray的随机张量x = troch.rand(5,3)print(x)#利用已有数据构造张量x = torch.tensor([[[5,3,1],[6,4,2]])print(x)#根据已经存在的tensor创建x = x...
摘要由CSDN通过智能技术生成

PyTorch 入门笔记总结

1、Tensor张量

创建张量

Torch构造张量有如下几种形式:

import torch
#直接构造类似于numpy中ndarray的随机张量
x = troch.rand(5,3)
print(x)
#利用已有数据构造张量
x = torch.tensor([[[5,3,1],[6,4,2]])
print(x)
#根据已经存在的tensor创建
x = x.new_ones(5, 3, dtype=torch.double)     
print(x) 
x = torch.randn_like(x, dtype=torch.float32)    
print(x)                                      

#输出
tensor([[0.4041, 0.4289, 0.2413],
        [0.8269, 0.2149, 0.6988],
        [0.3254, 0.6165, 0.4514],
        [0.9963, 0.1263, 0.7608],
        [0.6543, 0.1745, 0.6938]])

tensor([[5, 3, 1],
        [6, 4, 2]])

tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
        
tensor([[-0.4634,  0.2839, -0.3666],
        [-0.5293,  0.2354,  0.6911],
        [-1.6419,  0.5335,  0.7720],
        [ 0.5266, -0.9511,  0.0539],
        [-2.4723,  0.4116, -0.3734]])

张量的运算

以加法运算为例,介绍几种张量的运算方法:

#+重载
y = torch.rand(5,3)
print(x+y)
#torch.add /可提供一个输出张量存储结果
print(torch.add(x,y))
result = torch.empty(5,3)
torch.add(x, y, out = result)
print(result) 
#in-place方式运算 改变y值
y.add_(x)
print(y)
#输出
tensor([[1.1657, 0.7392, 1.5607],
        [1.8393, 0.6036, 0.5653],
        [0.6798, 0.8985, 1.0473],
        [0.0417, 0.6784, 0.3095],
        [0.2775, 0.4266, 0.7707]])

切片与变形

张量可以跟numpy矩阵一样实现切片操作:

print(y[4,:])
#输出
tensor([0.2775, 0.4266, 0.7707])

若要改变tensor的形状,使用view函数,会将tensor按照索引顺序重新排列:

y.view(3,-1)
print(y)

#输出
tensor([[1.1657, 0.7392, 1.5607, 1.8393, 0.6036],
        [0.5653, 0.6798, 0.8985, 1.0473, 0.0417],
        [0.6784, 0.3095, 0.2775, 0.4266, 0.7707]])

2、Pytorch的自动微分

requires_grad

torch.Tensor 是包的核心类。如果将其属性 .requires_grad 设置为 True,则会开始跟踪针对 tensor 的所有操作。完成计算后,您可以调用 .backward() 来自动计算所有梯度。该张量的梯度将累积到 .grad 属性中。这意味着一个张量的requires_grad为True的情况下,接下来使用该张量进行计算的时候会追踪全部的计算过程,形成一张计算图。之后对输出进行反向传播计算的时候会自动的计算所有的梯度。如下所示:

import torch
x = torch.ones(2,2, requires_grad = True)
print(x)
y = x+2
print(y)
print(y.requires_grad)
z = y*y*3
out = z.mean()
print(z,out)

#输出
#x
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
#y and requires_grad
tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)
True
#z,out
tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>)
tensor(27., grad_fn=<MeanBackward0>)

同时可以通过requires_grad_()改变张量的可导性:

x = torch.ones(2,2)
print(x.requires_grad)
x.requires_grad_(True)
print(x.requires_grad)

#输出
False
True

反向传播

在获取到requires_grad张量计算后的输出out之后,我们可以采用.backward()进行自动的反向传播,计算出tensor图中涉及的变量导数:

out.backward()
print(x.grad)
#输出
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

需要注意的是,当输出张量不再是一个标量的时候,自动反向求导不能正常进行,我们需要传递简单向量给backward()作为参数。如下所示:

x = torch.randn(3, requires_grad=True)
print(x)
y = x * 2
while y.data.norm() < 1000:
    y = y * 2
print(y)
#输出
tensor([-0.6820, -1.6825,  1.3975], requires_grad=True)

tensor([-349.1966, -861.4306,  715.5014], grad_fn=<MulBackward0>)

可以看到当前的输出y不是一个标量,如果对其使用backward的时候会出现如下报错:
RuntimeError: grad can be implicitly created only for scalar outputs
因此需要给反向传播输入传递向量作为参数:

v = torch.tensor([1.0, 1.0, 0.1], dtype=torch.float)
y.backward(v)
print(x.grad)

#输出
tensor([512.0000, 512.0000,  51.2000])

停止跟踪

在评估模型时,停止跟踪特别有用,因为模型在训练阶段具有 requires_grad = True 的可训练参数有利于调参,但在评估阶段我们不需要梯度。您可以将代码块使用 with torch.no_grad(): 包装起来。如下所示:

x = torch.rand(5,3, requires_grad = True)
y = x*x
with torch.no_grad():
	z = x*2
print(x.requires_grad)
print(y.requires_grad)
print(z.requires_grad)

#输出
True
True
False

3、神经网络的构建

在了解PyTorch基本内容之后,我们开始着手搭建自己的神经网络。神经网络是基于自动梯度 (autograd)来定义一些模型,一个 nn.Module 包括层和一个方法 forward(input) 它会返回输出(output)。
手写识别网络LeNet

定义神经网络

import torch
import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 1 input image channel, 6 output channels, 5x5 square convolution
        # kernel
        self.conv1 = nn.Conv2d(1, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        # an affine operation: y = Wx + b
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
        
	#前向传播过程
    def forward(self, x):
        # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # If the size is a square you can only specify a single number
        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:]  # all dimensions except the batch dimension
        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)
)

对于网络当中可以训练的参数可以通过.parameters()获取,从输出中看到公有十组可以训练的网络参数(对应于五层结构每层的权重W和偏置b):

params = list(net.parameters())
print(len(params))
print(params[0].size())  # conv1's .weight
#输出
10
torch.Size([6, 1, 5, 5]) #第一层卷积层参数6个5*5*1卷积核

让我们尝试随机生成一个 32x32 的输入图片通过网络获取输出。

input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
#输出
tensor([[-0.0233,  0.0159, -0.0249,  0.1413,  0.0663,  0.0297, -0.0940, -0.0135,
          0.1003, -0.0559]], grad_fn=<AddmmBackward>)

在此,我们完成了:

1.定义一个神经网络

2.处理输入

还剩下:

1.计算损失值

2.调用反向传播

3.更新网络中的权重

损失函数

一个损失函数需要一对输入:模型输出和目标,然后计算一个值来评估输出距离目标有多远。
有一些不同的损失函数在 torch.nn 包中。一个简单的损失函数就是 nn.MSELoss ,这计算了均方误差。

output = net(input)
target = torch.randn(10)  # a dummy target, for example
target = target.view(1, -1)  # make it the same shape as output
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)

#输出
tensor(1.3389, grad_fn=<MseLossBackward>)

反向传播

为了实现反向传播损失,我们所有需要做的事情仅仅是使用 loss.backward()。你需要清空现存的梯度,要不然梯度将会和现存的梯度累计到一起
现在我们调用 loss.backward() ,然后看一下 con1 的偏置项在反向传播之前和之后的变化。

net.zero_grad()     # zeroes the gradient buffers of all parameters

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)
loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

#输出
conv1.bias.grad before backward
tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward
tensor([-0.0054,  0.0011,  0.0012,  0.0148, -0.0186,  0.0087])

参数更新

在torch.optim 中实现了许多的参数更新方法,例如SGD, Nesterov-SGD, Adam, RMSProp等。使用方法如下:

import torch.optim as optim
# 创建SGD来进行参数更新
optimizer = optim.SGD(net.parameters(), lr=0.01)

# 在训练的循环当中
optimizer.zero_grad()   # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()    # 参数更新
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值