相比TensorFlow的静态图开发,Pytorch的动态图特性使得开发起来更加人性化
    数据类型
    标量/张量 torch.tensor(1.)
    类型:通用/float/double/int/long/byte型
    Tensor/torch.FloatTensor/torch.DoubleTensor/torch.IntTensor/torch.LongTensor/torch.ByteTensor
    GUP下 torch.cuda.FloatTensor/…..
    索引 a=torch.rang(2,3) a[0]
    切片 a[0,::2] 第一行三列
    shap()/size() 张量形状
    dim()维数
    numel()张量
    type()获取张量类型
    cuda() 类型转换 x=torch.IntTensor(1)
    x=x.cuda()
    判断是否使用GPU torch.cuda.is_available()
    获取gpu数量 torch.cuda.device_count()
    使用编号为0的GPU torch.cuda.set_device(0)
    GPU转CPU a.cpu()
    view()/reshape() 修改张量形状
    t() 装置
    pow() 对张量进行幂运算,也可以用**代替
    sqrt()/ rsqrt() 对张量取平方根/平方根的倒数
    exp() 取e为底的幂次方
    log() 取log以e为底的对数
    round()/floor()/ceil() 四舍五入、向下取整和向上取整
    trunc()/frac() 取整数/小数部分
    max()/min()/median()/mean() 取最大值、最小值、中位数和平均值
    argmax()/argmin() 返回最大/小值的索引
    argsort()/argsort(descending=True) 从小到大索引/相反
    topk()返回前几大的值
    norm()张量的范数,默认是l2范数(即欧氏距离)
    transpose()将指定维度对调

    1. >>> a = torch.rand(2, 3, 1)
    2. >>> a
    3. tensor([[[0.8327],
    4. [0.7932],
    5. [0.7497]],
    6. [[0.2347],
    7. [0.7611],
    8. [0.5529]]])
    9. >>> a.transpose(0, 2)
    10. tensor([[[0.8327, 0.2347],
    11. [0.7932, 0.7611],
    12. [0.7497, 0.5529]]])
    13. # 将第1维和第3维对调
    14. >>> a.transpose(0, 2).shape
    15. torch.Size([1, 3, 2])

    permute()和transpose类似也是对调维度

    1. >>> a = torch.rand(2, 3, 1)
    2. >>> a
    3. tensor([[[0.6857],
    4. [0.4819],
    5. [0.3992]],
    6. [[0.7477],
    7. [0.8073],
    8. [0.1939]]])
    9. >>> a.permute(2, 0, 1)
    10. tensor([[[0.6857, 0.4819, 0.3992],
    11. [0.7477, 0.8073, 0.1939]]])
    12. # 将a修改成原来第3个维度放在第1个维度,第1个维度放在第2个维度,第2个维度放在第3个维度
    13. >>> a.permute(2, 0, 1).shape
    14. torch.Size([1, 2, 3])

    squeeze()/unsqueeze() 在指定索引位置删减维度/在指定索引位置增加维度
    expand() 扩展数据,但仅限于维度是1的地方
    repeat() 复制数据
    split() 根据长度切分数据
    chunk() 根据数量切分数据,也就是自定义要切成多少份
    常用方法
    数组转张量 torch.from_numpy(a)
    张量转数组 data.numpy()
    基本运算
    张量torch.add()/torch.sub()/torch.mul()/torch.div()/
    矩阵torch.matmul()
    逻辑操作
    torch.equal/torch.all与/torch.any或
    torch.where

    1. >>> a = torch.tensor([[1., 2.], [3., 4.]])
    2. >>> b = torch.tensor([[5., 6.], [7., 8.]])
    3. >>> c = torch.rand(2, 2)
    4. >>> c
    5. tensor([[0.3821, 0.6138],
    6. [0.2323, 0.2675]])
    7. >>> torch.where(c>0.3, a, b)
    8. tensor([[1., 2.],
    9. [7., 8.]])

    数据生成
    torch.zeros/torch.ones/torch.eye/torch.full()生成固定尺寸的值全为指定值的张量
    torch.arange生成指定等差数列的张量
    torch.linspace生成等差数列的张量

    1. torch.linspace(-1, 1, steps=21)

    torch.rand随机生成一个固定尺寸的张量,并且数值范围都在0~1之间
    torch.randn随机生成固定尺寸的张量,数值符合正态分布
    torch.randint随机生成一个固定尺寸的张量,并且数值为自定义范围的整数
    数据处理
    torch.masked_select 取出指定条件数据

    torch.masked_select(a, a>0.5)
    

    torch.cat在指定维度合并数据

    >>> a = torch.rand(1,2,3)
    >>> b = torch.rand(2,2,3)
    >>> torch.cat((a,b))
    tensor([[[0.0132, 0.4118, 0.5814],
             [0.8034, 0.8765, 0.8404]],
            [[0.7860, 0.6115, 0.4745],
             [0.0846, 0.4158, 0.3805]],
            [[0.9454, 0.3390, 0.3802],
             [0.6526, 0.0319, 0.7155]]])
    >>> torch.cat((a,b)).shape
    torch.Size([3, 2, 3])
    

    torch.stack在指定维度创建一个新维度合并两个数据

    >>> a = torch.rand(1,2,3)
    >>> b = torch.rand(1,2,3)
    >>> a
    tensor([[[0.5239, 0.0540, 0.0213],
             [0.9713, 0.5983, 0.1413]]])
    >>> b
    tensor([[[0.3397, 0.0976, 0.3744],
             [0.5080, 0.7520, 0.1759]]])
    >>> torch.stack((a, b))
    tensor([[[[0.5239, 0.0540, 0.0213],
              [0.9713, 0.5983, 0.1413]]],
            [[[0.3397, 0.0976, 0.3744],
              [0.5080, 0.7520, 0.1759]]]])
    

    one-hot编码

    >>> label = torch.tensor([[0], [1], [2], [3]])
    # 标签内容
    >>> label_number = len(label)
    # 标签长度
    >>> label_range = 10
    # 标签总数
    >>> torch.zeros(label_number, label_range).scatter_(1, label, 1)
    tensor([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
            [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
            [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
            [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.]])
    

    工具集 torch.utils下面
    通过torch.utils.data.random_split()方法随机切分数据集,然后通过torch.utils.data.DataLoader来载入数据
    函数API和类API
    神经网络层、激活函数、损失函数等都提供了两种API调用方式,分别是函数式API和类API,前者基本都在torch.nn.functional下,后者基本都在torch.nn下,前者一般直接调用即可,适合函数式编程;后者一般是先实例化,然后通过其内置的方法进行调用,适合面向对象编程。
    网络层
    全连接 函数式API:torch.nn.functional.linear,类API:torch.nn.Linear
    Dropout
    随机选取一部分节点使用,忽略一部分节点,函数式API:torch.nn.functional.dropout,类API:torch.nn.Dropout
    批标准化层
    函数式API:torch.nn.functional.batch_norm,类API:torch.nn.BatchNorm2d
    卷积层
    函数式API:torch.nn.functional.conv2d,类API:torch.nn.Conv2d

    layer = torch.nn.Conv2d(1, 3, kernel_size=3, stride=1, padding=0)
    
    >>> x = torch.rand(1, 1, 28, 28)
    >>> w = torch.rand(3, 1, 3, 3)
    # 输出3通道,输入1通道,尺寸3x3
    >>> b = torch.rand(3)
    # 偏置长度要和通道数一样
    >>> layer = torch.nn.functional.conv2d(x, w, b, stride=1, padding=1)
    

    池化层
    函数式API:torch.nn.functional.max_pool2d,类API:torch.nn.MaxPool2d

    >>> x = torch.rand(1, 1, 28, 28)
    >>> layer = torch.nn.MaxPool2d(3, stride=2)
    

    还有个avgpool(函数式API:torch.nn.functional.avg_pool2d,类API:torch.nn.AvgPool2d

    >>> torch.nn.functional.avg_pool2d(x, 3, stride=2)
    

    flatten将张量转成一维

    >>> torch.flatten(torch.rand(2,2))
    

    向上取样
    将图片放大/缩小成原来的几倍,函数式API:torch.nn.functional.interpolate
    还有如UpsamplingUpsamplingNearest2d也是向上采样,现在已经逐渐被interpolate给取代。上面interpolate示例参数中mode='nearest'时,相当于该UpsamplingNearest2d,函数式API:torch.nn.functional.upsample_nearest,函数式API:torch.nn.UpsamplingNearest2d,类API举例:

    >>> x = torch.rand(1, 1, 2, 2)
    >>> x
    tensor([[[[0.9977, 0.9778],
              [0.4167, 0.6936]]]])
    >>> torch.nn.functional.upsample_nearest(x, scale_factor=2).shape
    torch.Size([1, 1, 4, 4])
    >>> torch.nn.functional.upsample_nearest(x, scale_factor=2)
    

    嵌入层
    常用于定义词向量
    函数式API:torch.nn.functional.embedding,类API:torch.nn.Embedding
    RNN层
    类API:torch.nn.RNN,会返回计算后总体的输出,以及最后一个时间戳上的输出
    LSTM层
    类API:torch.nn.LSTM,因为LSTM是基于RNN并添加了门控制,因此返回的时候比RNN要多返回一个cell单元,格式和hidden一样
    序列化模型
    定义神经网络模型(每一层都要是继承于torch.nn下的网络),类API:torch.nn.Sequential

    >>> net = torch.nn.Sequential(
        torch.nn.Linear(100, 10),
        torch.nn.Dropout(0.7),
        torch.nn.ReLU(),
        torch.nn.Linear(10, 1)
        )
    >>> net
    Sequential(
      (0): Linear(in_features=100, out_features=10, bias=True)
      (1): Dropout(p=0.7)
      (2): ReLU()
      (3): Linear(in_features=10, out_features=1, bias=True)
    # 可以直接查看网络结构
    

    序列化模型修改
    序列化模型可以理解成一个列表,里面按顺序存放了所有的网络层,官方也提供了添加往序列化模型里添加网络层的方法add_module(name, layer),而修改则可以索引到对应的层直接修改,删除可以通过del关键字删除

    >>> seq.add_module("tanh", nn.Tanh())
    

    修改网络参数
    对于网络层中的参数,其是一个Parameter类型,因此如果我们需要手动修改其参数时,可以通过定义一个该类的数据来赋值修改
    自定义神经网络
    自己定义神经网络层的时候,首先需要继承于torch.nn.Module,并在初始化时调用父类的初始化方法,同时也要在forward方法里实现数据的前向传播

    import torch
    class Dense(torch.nn.Module):
        # 实现一个自定义全连接+relu层,继承torch.nn.Module
        def __init__(self, input_shape, output_shape):
            super(Dense, self).__init__()
            # 首先初始化时执行父类的初始化,这句话可以看
            # 在父类初始化中会初始化很多变量
            self.w = torch.nn.Parameter(torch.randn(output_shape, input_shape))
            # 初始化权重和偏置参数
            # 使用Parameter其会自动将参数设置为需要梯度信息,并且可以通过内置的parameters方法返回这些参数
            self.b = torch.nn.Parameter(torch.rand(output_shape))
            self.relu = torch.nn.ReLU()
            # 初始化relu层
        def forward(self, x):
            # 定义前向传播方法
            x = x @ self.w.t() + self.b
            # 全连接层的功能就是矩阵相乘计算
            x = self.relu(x)
            # 进行relu层计算
            return x
        def __call__(self, x):
            # 调用该类对象执行时,调用前向传播方法
            # 这个可以不写,直接通过调用forward方法也一样
            return self.forward(x)
    layer = Dense(10, 1)
    x = torch.rand(2, 10)
    output = layer(x)
    print(output)
    # 输出结果:
    # tensor([[0.1780],
    #         [0.0000]], grad_fn=<ThresholdBackward0>)
    

    冻结网络层
    对某些网络层的权重不进行训练的话,可以设置该层的权重、偏差等属性为False
    保存和载入网络
    对于所有继承自torch.nn.Module下的网络,保存时首先通过内置的方法state_dict()返回当前模型的所有参数,然后通过torch.save()方法保存成文件,载入时通过torch.load()方法载入文件,并通过内置的load_state_dict()方法载入所有的参数
    优化器
    torch.optim定义了各种优化器,将优化器实例化后(传入需要求导的参数和学习率),通过step()方法进行梯度下降
    对于实例化的优化器,其参数都将存放到一个属性param_groups[0]

    optim = torch.optim.Adam(model.parameters(), lr=0.01)
    print(optim)
    # 结果:
    # Adam (
    # Parameter Group 0
    #     amsgrad: False
    #     betas: (0.9, 0.999)
    #     eps: 1e-08
    #     lr: 0.01
    #     weight_decay: 0
    # )
    

    激活函数
    函数式API:torch.nn.functional.sigmoid,类API:torch.nn.Sigmoid,pytorch自带:torch.sigmoid
    函数式API:torch.nn.functional.relu,类API:torch.nn.ReLU
    损失函数
    均方差:计算的y与实际y之差的平方取平均值,函数式API:torch.nn.functional.mse_loss,类API:torch.nn.MSELoss,第一个参数是y,第二个参数是y对应的公式
    交叉熵:通过含有的信息量大小来进行判断,一般用于分类,函数式API:torch.nn.functional.cross_entropy,类API:torch.nn.CrossEntropyLoss
    求导机制
    自动机制torch.autograd.grad
    定义了自动求导,传入第一个参数是对应的公式,第二个参数是一个列表,里面存放所有要求导的变量,并且在求导前的变量需要通过require_grad()方法来声明该公式的某个变量是需要求导的(或者在定义时就设置requires_grad参数为True),返回一个元组,里面是对应每个变量的求导信息

    >>> x = torch.tensor(1.)
    >>> w = torch.tensor(2.)
    >>> b = torch.tensor(0.)
    >>> y = torch.tensor(1.)
    >>> mse = torch.nn.functional.mse_loss(y, w*x+b)
    # 模拟一个y=wx+b的函数
    >>> mse
    tensor(1.)
    

    反向传播
    torch.backward反向传播,也能实现求导,通过设置该tensor允许求导,那么该方法会对计算过程中所有声明了求导信息的变量进行求导,然后在对应的变量上通过grad属性获取求导结果

    >>> x = torch.tensor(1.)
    >>> b = torch.tensor(0.)
    >>> w = torch.tensor(2., requires_grad=True)
    >>> y = torch.tensor(1.)
    >>> mse = torch.nn.functional.mse_loss(y, w*x+b)
    >>> mse.backward()
    # 对mse公式里需要求导的变量都进行求导
    >>> w.grad
    tensor(2.)
    # w的求导结果为2
    >>> x.grad
    # 因为x没有声明需要求导,所以为空
    

    可视化
    在TensorFlow里有tensorboard可以进行训练过程的可视化,而在Pytorch里也提供了tensorboardX几乎和tensorboard一样
    visdom pytorch提供的另一个可视化

    深度学习程序实现如下功能:

    • 模型定义
    • 数据处理和加载
    • 训练模型(Train&Validate)
    • 训练过程的可视化
    • 测试(Test/Inference)