pytorch基本使用

1 安装

环境:ubuntu20 + conda + pip

命令:

pip install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple

2 Tensor 的创建

  • 由 numpy 转换

    a = np.array([1,2,3])
    b = torch.from_numpy(a)
    
  • torch 直接创建

    a = torch.tensor([[1,2,3],[4,5,6]])      # 数据类型 int64
    a = torch.IntTensor([[1,2,3],[4,5,6]])   # 数据类型 int32
    a = torch.FloatTensor([[1,2,3],[4,5,6]]) # 数据类型 float32
    
  • tensor 数据类型的转换

    tensor = torch.Tensor(2, 5)
    torch.char()          # 将 tensor 投射为  int8
    torch.byte()          # 将 tensor 投射为 uint8
    torch.short()         # 将 tensor 投射为  int16
    torch.int()           # 将 tensor 投射为  int32
    torch.long()          # 将 tensor 投射为  int64
    torch.half()          # 将 tensor 投射为  float16
    torch.float()         # 将 tensor 投射为  float32
    torch.double()        # 将 tensor 投射为  float64
    
  • 随机数

    a = torch.rand(3,3)    # 取 0 ~ 1 之间的随机数
    a = torch.rand_like(a) #  创建一个 shape 与 a 相同的 tensor
    a = torch.randint(1, 10, (3, 3)) # [0, 10) 区间内的随机数
    
  • 正太分布

    a = torch.randn(3,3) # 正态分布(0,1)
    
  • 全 0、全 1、全 n、对角矩阵

    a = torch.ones(3, 3)  # 全 1
    a = torch.zeros(3, 3) # 全 0 
    a = torch.full([3, 3], 100) # 全 100
    a = torch.eye(3, 3)   # 对角矩阵
    
  • 线性分布

    a = torch.arange(0, 10, 2)         # [0, 10),步长为 2
    # 输出 tensor([0, 2, 4, 6, 8])
    a = torch.arange(10)               # [0, 10),步长为 1
    a = torch.range(10)                # [0, 10],步长为 1
    
    a = torch.linspace(0, 10, steps=5) # 从 0 到 10,平分为 5 份
    # 输出 tensor([ 0.0000,  2.5000,  5.0000,  7.5000, 10.0000])
    
  • tensor 索引

    a = torch.randn(5, 3, 28, 28)
    
    b = a[:, :, 0:28, 0:20:2]  # : 表示所有,0:28 表示 0~27,0:28:2 表示 0~27,步长为 2
    
    c = a.index_select(2, torch.tensor([0,1])) # 根据第 2 维的index,筛选出 [0, 1] 的数据
    # 等同于 a[:, :, [0, 1], :]
    
  • … 表示所有

    a = torch.randn(5, 3, 28, 28)
    
    b = a[..., 0:28]
    # 等同于 a[:, :, :, 0:28]
    
  • reshape 更改维度
    用于改变数据的维度,是否穿件新的数据区存储空间有两种情况:
    a. 若要操作的 tensor 数据区为连续分布,则不创建,reshape 后指向原数据区;
    b. 若要操作的 tensor 数据区不连续(被permut、transpose操作过),则创建新的数据区;

    a = torch.rand(1,2,3,3)
    b = a.reshape( 6, 3) # 将 shape 1*2*3*3 改成了 6*3
    b = a.reshpae(-1, 3) # -1 表示该维度的大小自动计算,当然,不能同时出现两个 -1
    
  • view 更改维度
    不创建新数据区存储空间,更改维度(的描述)。
    注意:操作的 tensor 需要是数据连续分布,如果 tensor 使用 permut()、transpose() 操作过,数据区就不是连续分布的了,不能使用 view(),但可以使用 reshape()。

    a = torch.rand(1,2,3,3)
    b = a.view( 6, 3) # 将 shape 1*2*3*3 改成了 6*3
    b = a.view(-1, 3) # -1 表示该维度的大小自动计算,当然,不能同时出现两个 -1
    
  • permute 重新排列维度(会改变数据分布)

    a = torch.tensor(2,3,4)
    
    b = a.permute(2,1,0) # 维度排列从原来的 0,1,2 改成 2,1,0
    # shape: [4,3,2]
    
  • transpose 交换两个维度

    a = torch.tensor(2,3,4)
    
    b = a.transpose(0, 1) # 交换第 0 维和第 1 维
    # shape: [3,2,4]
    
  • unsqueeze 增加1维度、squeeze 去掉1维度
    不改变数据存储空间,更改维度(的描述)

    a = torch.rand(2,3)
    
    b = a.unsqueeze(1) # 在第 1 维处(0维后面)增加一维
    # shape 变成:[2,1,3]
    
    c = b.squeeze(1)  # 去掉第 1 维(前提是该处维数为1,否则不生效)
    # shape 变为:[2,3]
    
  • expand 扩展维度
    注意:expand 不改变数据存储空间,虽然增加了维数,但新增的维数是指针,指向原来的数据区;并且,要扩展的维数只能是 1,大于 1 的维数不能扩展。

    a = torch.tensor([[0, 1, 2]])
    # a:
    #   tensor([[0, 1, 2]])
    
    b = a.expand(2, 3) # 维数从原来的 1*3 扩展到 2*3
    #   tensor([[0, 1, 2],
    #           [0, 1, 2]])
    # 这两行 [0, 1, 2] 的内存指向同一个地址,更改其中一个数据,另一个也会改变
    
    c = a.expand_as(b) # 扩展的 shape 和 b 保持一致
    
  • repeat 扩展数据(同时扩展维度)
    存储空间会发生改变,有复制数据的操作。

    a = torch.tensor([0, 1, 2])
    # a:
    #   tensor([0, 1, 2])
    
    b = a.repeat(3, 2) # 表示对应维度重复的次数
    #   tensor([[0, 1, 2, 0, 1, 2],
    #           [0, 1, 2, 0, 1, 2],
    #           [0, 1, 2, 0, 1, 2]])
    
  • cat 拼接维数

    a = torch.rand(1,3,3)
    b = torch.rand(1,3,3)
    c = torch.cat([a,b], 0) # 在第 0 维上拼接
    # shape: [2,3,3]
    

3 Tensor 的运算

  • 乘法
    torch.mm(a, b)     # 矩阵乘法
    a * b              # 矩阵对应元素相乘
    a * 3              # 矩阵所有元素乘以 3
    
  • 加法、减法、除法
    a + b # 对应元素相加
    a + 2 # 所有元素加 2
    
  • n x n^x nx x \sqrt{x} x
    a**2      # 幂
    a.rsqrt() # 平方
    
  • e x e^x ex l o g ( x ) log(x) log(x)
    torch.exp(a)
    torch.log(a)
    
  • 截断
    a.clamp(4)     # 元素小于 4 的都等于 4
    a.clamp(4, 10) # 元素小于 4 的都等于 4,大于 10 的都等于 10
    
  • 四舍五入
    a.round() # float 的四舍五入
    
  • 向上取整
    a.ceil()  # float 的
    
  • 绝对值
    a.abs(0)
    
  • 最大、最小值
    a.max() # 返回矩阵中的最大值
    values, indices = a.max(0) # 返回指定维度最大值
    
    a.argmax() # 返回最大值的索引
    a.argmax(dim=0) # 返回指定维度最大值的索引
    
    a.min() # 同上
    a.argmin()
    
  • 均值、求和
    a.mean()
    a.mean(dim=0) # 指定维度的均值
    a.sun()
    a.sun(dmi=0)
    
  • 范数
    ∣ ∣ x ∣ ∣ = ( ∣ x 1 ∣ p + ∣ x 2 ∣ p + . . . + ∣ x n ∣ p ) 1 p ||x|| = (|x_1|^p + |x_2|^p +...+ |x_n|^p)^{\frac{1}{p}} x=(x1p+x2p+...+xnp)p1
    a.norm()  # 默认 p = 2
    a.norm(3) # p = 3
    
  • 统计 TOPn
    a = torch.rand(10,3,3)
    values, indeces = a.topk(2, dim=0) # 指定维度中,统计 TOP2 的数据
    # shape: [2, 3, 3]
    
  • 判断相等、不相等
    torch.eq(a, b)   # 判断对应元素相等,返回 bool
    torch.eq(a, 0)   # 判断与 1 相等,返回 bool
    torch.equal(a,b) # 判断不等
    

4 模型

4.1 nn.Sequential 与 nn.ModuleList

  • 不同点1
    nn.Sequential 内部实现了 forward 函数,因此可以不用写 forward 函数。而 nn.ModuleList 则没有实现内部 forward 函数。
    对于nn.Sequential:

    class net1(nn.Module):
        def __init__(self):
            super(net1, self).__init__()
            self.seq = nn.Sequential(
                            nn.Conv2d(1,20,5),
                             nn.ReLU(),
                              nn.Conv2d(20,64,5),
                           nn.ReLU()
                           )      
        def forward(self, x):
            return self.seq(x)
    
    input = torch.randn(16, 1, 20, 20)
    net1 = net1()
    print(net1(input).shape)
    

    而对于nn.ModuleList:

    class net2(nn.Module):
        def __init__(self):
            super(net2, self).__init__()
            self.modlist = nn.ModuleList([
                           nn.Conv2d(1, 20, 5),
                           nn.ReLU(),
                            nn.Conv2d(20, 64, 5),
                            nn.ReLU()
                            ])
    
        #注意:只能按照下面利用for循环的方式
        def forward(self, x):
            for m in self.modlist:
                x = m(x)
            return x
    
    input = torch.randn(16, 1, 20, 20)
    net2 = net2()
    print(net2(input).shape)
    
  • 不同点2:
    nn.Sequential可以使用OrderedDict对每层进行命名;

    from collections import OrderedDict
    
    class net_seq(nn.Module):
        def __init__(self):
            super(net_seq, self).__init__()
            self.seq = nn.Sequential(OrderedDict([
                            ('conv1', nn.Conv2d(1,20,5)),
                             ('relu1', nn.ReLU()),
                              ('conv2', nn.Conv2d(20,64,5)),
                           ('relu2', nn.ReLU())
                           ]))
        def forward(self, x):
            return self.seq(x)
    
  • 不同点3:
    nn.Sequential 里面的模块按照顺序进行排列的,而nn.ModuleList 模块之间并没有什么先后顺序可言。见下面代码:

    class net3(nn.Module):
        def __init__(self):
            super(net3, self).__init__()
            self.linears = nn.ModuleList([nn.Linear(10,20), nn.Linear(20,30), nn.Linear(5,10)])
        def forward(self, x):
            x = self.linears[2](x)
            x = self.linears[0](x)
            x = self.linears[1](x)
            return x
    
  • 不同点4:
    有的时候网络中有很多相似或者重复的层,我们一般会考虑用 for 循环来创建它们,而不是一行一行地写,比如:

    class net4(nn.Module):
        def __init__(self):
            super(net4, self).__init__()
            layers = [nn.Linear(10, 10) for i in range(5)]
            self.linears = nn.ModuleList(layers)
    
        def forward(self, x):
            for layer in self.linears:
                x = layer(x)
            return x
    

其他

  • 打印设置
    torch 打印浮点数时精度默认是 4 位,可以自行设定精度;
    torch.set_printoptions(	precision=None, # 保留位数
    						threshold=None, # 行数超过该值就折叠显示,默认4
    						edgeitems=None, # 折叠后显示出的行数,默认3
    						linewidth=None, # 显示宽度
    						profile=None,   # 数据显示的长度,有default、short、full,默认short
    						sci_mode=None)  # 科学计数显示,有True、False、None,如果为None则由框架选择方法
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值