Task1-PyTorch的基础概念

Task 1-PyTorch的基本概念

1. 什么是PyTorch?为什么选择PyTorch?
  • PyTorch是一个深度学习框架,同时它也是一个科学计算库。**这是PyTorch的核心团队对PyTorch的描述。PyTorch的科学计算方面主要是PyTorch的张量库和相关张量运算的结果。PyTorch的Tensor(张量)可以在GPU上运行。PyTorch的最初版本是在2017年1月发布,其前身是机器学习框架Torch。Soumith Chintala因为引导了PyTorch项目而广受赞誉,而他创建PyTorch的原因也很简单:Lua版本的Torch正在老化,因此需要用Python编写更新版本。因此,PyTorch诞生了。我们可能听说过PyTorch是由Facebook创造和维护的,这是因为PyTorch被创建时Soumith Chintala正在Facebook的AI研究中心工作。
  • 对于深度学习和神经网络的初学者来说,学习PyTorch的最主要的原因就是它是一个简洁且高效快速的框架。使用PyTorch进行编程之后,我们将对神经网络和深度学习有一个更深的理解。PyTorch的顶级哲学之一就是不干涉,这使得我们可以更加专注于神经网络而不是实际框架。当我们在使用PyTorch写代码时,我们就只是在扩展标准Python类,当我们需要调试时,也是使用标准的Python调试器。PyTorch的设计是现代化的,其源码对于Python开发者来说非常容易阅读,因为其主要是由Python实现的,只对一些有性能瓶颈的操作使用了C++和CUDA的代码。总而言之,PyTorch是一个伟大的工具,它将加深我们对深度学习和神经网络的理解。
2. PyTorch的安装

首先介绍一下Anaconda,它是一个开源的包、环境管理器,可以用于在同一个机器上安装不同版本的软件包及其依赖,并能够在不同的环境之间切换。

安装分为以下几步:

  1. 下载并安装Anaconda

  2. 访问PyTorch官网

  3. 为特定环境指定适当的配置选项,例:

    • OS: Windows
    • Package Manager:conda
    • Language:Python3.7
    • CUDA:10.0
  4. 然后运行生成的命令:

    > conda install pytorch torchvision cudatoolkit=10.0 -c pytorch
    

验证PyTorch的安装:

  1. To use PyTorch we import torch.
  2. To check the vision, we use torch.__version__

验证GPU的功能:

> torch.cuda.is_available()
True

> torch.version.cuda
'10.0'
3. PyTorch的基础概念

分点陈述:

  • Tensor和Numpy的ndarrays类似,但PyTorch的tensor支持GPU加速。Tensor和numpy的数组间的互相操作非常容易且快速(他们共享内存)。就算numpy中有些操作在tensor中无法实现,也可以通过先转为numpy数组处理,之后再转回tensor。
  • PyTorch是一个灵活的深度学习框架,它允许通过动态神经网络(即if条件语句和while循环语句那样利用动态控制流的网络)自动分化。它支持GPU加速、分布式训练、多种优化以及更多的、更简洁的特性。
4. 通过代码实现流程(实现一个深度学习的代码流程)

本例取自PyTorch官网

在这里,我们使用PyTorch的Tensors将双层神经网络与随机数据进行匹配,我们需要手动实现网络中的前向和后向传播。

import torch

dtype = torch.float
device = touch.device("cpu")
# device = touch.device("cuda:0")  #当运行在GPU时,要加上这行代码

# N是batch size;D_in是输入的维度
# H是隐藏层的维度;D_out是输出的维度
N, D_in, H, D_out = 64, 1000, 100, 10

# 构造随机生成的输入和输出数据
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)

# 网络权重随机初始化
w1 = torch.randn(D_in, H, device=device, dtype=dtype)
w2 = torch.randn(H, D_out, device=device, dtype=dtype)

# 学习率
learing_rate = 1e-6
for t in range(500):
    # 前向传播:计算出预测的y
    h = x.mm(w1)
    h_relu = h.clamp(min=0)
    y_pred = h_relu.mm(w2)
    
    # 计算并打印损失
    loss = (y_pred - y).pow(2).sum.item()
    print(t, loss)
    
    # 后向传播,计算出w1和w2相对于损耗的梯度
    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)
    
    # 使用梯度下降更新权重
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

以上示例只是一个小的两层的网络,因此手动实现后向传播并不是一个困难的事情,但是对于一个大型且复杂的网络,这将不再是一个轻松的工作。PyTorch可以借用Autograd轻松解决这个问题。当使用autograd时,我们将定义一个计算图,图中的结点是tensors,图中的边是产生从输入张量到输出张量的函数。通过此图进行反向传播,我们可以轻松计算梯度。如果x是一个张量,并且x.requires_grad=True,那么x.grad就是另一个张量( x.grad is another Tensor holding the gradient of x with respect to some scalar value )。

import torch

dtype = torch.float
device = torch.device("cpu")
# device = touch.device("cuda:0")  #当运行在GPU时,要加上这行代码

# N是batch size;D_in是输入的维度
# H是隐藏层的维度;D_out是输出的维度
N, D_in, H, D_out = 64, 1000, 100, 10

# 构造随机生成的输入和输出数据
# 设置requires_grad=False,表明在后向传播时,我们不需要计算关于这些张量的梯度
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(H, D_out, device=device, dtype=dtype)

# 网络权重随机初始化
# 设置requires_grad=True,表明在后向传播时,我们需要计算关于这些张量的梯度
w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)

# 学习率
learing_rate = 1e-6
for t in range(500):
    # 前向传播:这些与我们使用tensors计算正向传播的操作完全相同,但是我们不需要
    # 保留对中间值的引用,因为我们没有手动实现反向传播。
    y_pred = x.mm(w1).clamp(min=0).mm(w2)
    
    # 使用tensor操作计算并打印损失
    # 现在loss是一个shape(1,)类型的张量
    # loss.item()可以获取loss中保存的标量值
    loss = (y_pred - y).pow(2).sum()
    print(t, loss.item())
    
    # 使用autograd来计算后向传播;这个调用将计算相对于所有requires_grad=True的
    # 张量的损失的梯度。
    # After this call w1.grad and w2.grad will be Tensors holding the gradient
    # of the loss with respect to w1 and w2 respectively.
    loss.backward()
    
    # 使用梯度下降手动更新权重。之所以封装于torch.no_grad(),是因为权重的
    # requires_grad=True,而我们在自动微分中没有必要跟踪这些;
    # 另一种可选择的操作是operate on weight.data and weight.grad.data.
    # You can also use torch.optim.SGD to achieve this.
    with torch.no_grad():
        w1 -= learning_rate * w1.grad
        w2 -= learning_rate * w2.grad
        
        # 更新权重之后,手动将梯度设置为0
        w1.grad.zero_()
        w2.grad.zero_()
    

PyTorch: 定义新的autograd函数

Under the hood, each primitive autograd operator is really two functions that operate on Tensors. The forward function computes output Tensors from input Tensors. The backward function receives the gradient of the output Tensors with respect to some scalar value, and computes the gradient of the input Tensors with respect to that same scalar value.

In PyTorch we can easily define our own autograd operator by defining a subclass of torch.autograd.Function and implementing the forward and backward functions. We can then use our new autograd operator by constructing an instance and calling it like a function, passing Tensors containing input data.

In this example we define our own custom autograd function for performing the ReLU nonlinearity, and use it to implement our two-layer network:

import torch

class MyReLU(torch.autograd.Function):
    """
    我们可以实现自定义(定制的)autograd函数,通过继承torch.autograd.Function并实现运行	 Tensors上的前向和后向传播。
    """
    
    @staticmethod
    def forward(ctx, input):
        """
        前向传播里,我们接收到一个包含输入的张量并输出一个包含输出的张量。ctx是一个上下文		  对象,可用于存储信息以进行反向计算。You can cache arbitrary objects for use
        in the backward pass using the ctx.save_for_backward method.
        """
        ctx.save_for_backward(input)
        return input.clamp(min=0)
    
    @staticmethod
    def backward(ctx, grad_output):
        """"
        后向传播里,我们接收到一个包含关于输出的损失的梯度的张量,并且我们需要计算关于输入		的损失的梯度
        """"
        input, = ctx.saved_tensors
        grad_input = grad_output.clone()
        grad_input[input<0] = 0
        return grad_input

dtype = torch.float
device = torch.device("cpu")
# device = touch.device("cuda:0")  #当运行在GPU时,要加上这行代码

# N是batch size;D_in是输入的维度
# H是隐藏层的维度;D_out是输出的维度
N, D_in, H, D_out = 64, 1000, 100, 10

# 构造随机生成的输入和输出数据
# 设置requires_grad=False,表明在后向传播时,我们不需要计算关于这些张量的梯度
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(H, D_out, device=device, dtype=dtype)

# 网络权重随机初始化
# 设置requires_grad=True,表明在后向传播时,我们需要计算关于这些张量的梯度
w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)

# 学习率
learing_rate = 1e-6
for t in range(500):
    # 为了使用我们定义的函数,我们使用Function.apply函数。
    relu = MyReLU.apply
    
    # 前向传播:compute predicted y using operations; we compute
    # ReLU using our custom autograd operation.
    y_pred = relu(x.mm(w1)).mm(w2)
    
    # 计算并打印损失
    loss = (y_pred - y).pow(2).sum()
    print(t, loss.item())
    
    # 使用autograd计算后向传播
    loss.backward()
    
    # 使用梯度下降更新权值
    with torch.no_grad():
       w1 -= learning_rate * w1.grad
       w2 -= learning_rate * w2.grad
        
       # 更新权重之后,手动将梯度设置为0
       w1.grad.zero_()
       w2.grad.zero_()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值