pytorch实战 第4章 Pytorch基础

第4章 Pytorch基础

内部数据保存在张量对象上,所有的运算操作也都是基于张量对象进行的.

4.1 数据类型

  • 数值类型
  • 布尔类型

4.1.1 数值类型

  • 标量:维度为0,shape为[]
  • 向量:维度为1,shape为[n]
  • 矩阵:[[1,2 ],[2,2]],维度为2,shape为[n,m]
  • 张量:维度dim>2,张量的每一个维度也叫做轴.
print(torch.tensor(1.1).shape) # 是0维的   loss一般使用的就是这种类型
print(torch.tensor([1.1]).shape) # 是一维的


a = 1.2
aa = torch.tensor(1.2)
print('a :', type(a), ' aa:', type(aa), torch.is_tensor(aa))
# a : <class 'float'>  aa: <class 'torch.Tensor'> True

x = torch.tensor([1.2,3.3]) # 创建张量
print(x)
print(x.shape,x.device,x.dtype) # 打印形状,设备,精度
#torch.Size([2])  cpu  torch.float32

# 将Pytorch张量的数据导出为numpy数组格式
print(x.numpy())
# [1.2 3.3]

# 创建三维张量
a = torch.tensor([[[1,2],[3,4]],[[5,6],[7,8]]])
print(a,a.shape)
'''
tensor([[[1, 2],
         [3, 4]],

        [[5, 6],
         [7, 8]]]) torch.Size([2, 2, 2])
'''

4.1.2 布尔类型


a = torch.tensor(True)
print(a,a.dtype)
# tensor(True) torch.bool
python_true = True
if python_true == a:
    print('===')
# ===

注意:Pytorch的布尔类型和python语言的布尔类型并不定价,不能通用,在进行==运算对比时,会自动转化为张量对象

4.2数值精度

# 创建指定精度的张量
a = torch.tensor(1234567809,dtype=torch.int16)
b = torch.tensor(1234567809,dtype=torch.int32)
print(a,b,a==b)
#tensor(641, dtype=torch.int16) tensor(1234567809, dtype=torch.int32) tensor(False)

'''

在保存整数时,一般使用torch.int32,torch.int64
对于一般的深度学习算法,一般使用torch.int32和torch.float32可满足大部分的运算精度,某些强化学习算法,可以选择使用torch.int64和torch.float64

4.2.1 读取精度

a = torch.tensor(np.pi,dtype=torch.float64)
print('before: ',a.dtype)
if a.dtype != torch.float32:
    a = a.type(torch.float32) # tensor.type函数可以完成精度转化
print('after: ',a.dtype)
'''
before:  torch.float64
after:  torch.float32
### 4.2.2类型转换
`tensor.type()`
```python
# tensor.type 类型转换
a = torch.tensor(np.pi,dtype=torch.float16)
print(a.type(torch.double))
# tensor(3.1406, dtype=torch.float64)

# 高精度 ---> 低精度 可能发生数据溢出
a = torch.tensor(123456789,dtype=torch.int32)
print(a.type(torch.int16))
# tensor(-13035, dtype=torch.int16)


# 布尔类型  <--> 整型
a = torch.tensor([True,False])
print(a.type(torch.int))
# tensor([1, 0], dtype=torch.int32)

# 整型 --> 布尔
a = torch.tensor([-1,0,1,2])
print(a.type(torch.bool))
# tensor([ True, False,  True,  True])
print(a)
# tensor([-1,  0,  1,  2])

4.3 待优化张量

  1. requires_grad默认为False
from torch import autograd # 导入自动梯度子库
x = torch.tensor(1., requires_grad= False) # 创建输入张量
w = torch.tensor(2., requires_grad= True) # 创建 w 权值张量
b = torch.tensor(3., requires_grad= True) # 创建 b 偏置张量
y = x * w + b # 计算输出
dy_dw, dy_db = autograd.grad(y, [w,b]) # y 对 w,b 的偏导数
print(dy_dw, dy_db) # 打印偏导数   tensor(1.) tensor(1.)

上述代码需要计算输出对 w 和 b 的偏导数,故在创建 w 和 b 张量时设置为待优化张量
fa = autograd.grad(y,[x]) #RuntimeError: One of the differentiated Tensors does not require grad

上述代码需要计算输出对 w 和 b 的偏导数,故在创建 w 和 b 张量时设置为待优化张量。

4.4创建张量

4.4.1从数组,列表对象创建

  1. 通过torch.form_numpy()函数将numpy数组导入
a = torch.from_numpy(np.array([1,2,3.]))
print(a.dtype)
# torch.float64

注意:Numpy浮点数组默认使用64位精度保存,转换后为torch.float64

4.4.2 创建全0或者全1张量


print(torch.zeros([2,3]))

a = torch.ones([2,3,4])
print(a.shape)
b = torch.zeros_like(a)
print(b.shape)
'''
tensor([[0., 0., 0.],
        [0., 0., 0.]])
torch.Size([2, 3, 4])
torch.Size([2, 3, 4])
'''
  • 通过 torch.zeros_like, torch.ones_like 可以方便地新建与某个张量 shape 一致,且内容为
    全 0 或全 1 的张量。

4.4.3创建自定义数值张量

  • 通过 torch.full(shape, value)可以创建全为自定义数值 value 的张量,形状由 shape 参数
    指定。
# 创建 3*3的全为100的矩阵
a = torch.full([3,3],100)
print(a)
'''
tensor([[100, 100, 100],
        [100, 100, 100],
        [100, 100, 100]])
'''

4.4.4创建已知分布的张量

  • 通过 torch.randn(*shape)可以创建形状为 shape,均值为 0,标准差为 1 的正态分布
print(torch.randn(2, 2))
'''
tensor([[ 0.1990,  0.6568],
        [-0.4170,  0.4825]])
'''
  • 创建均值和标准差符合要求的张量
a = torch.empty(2,3)
a = a.normal_(mean=1,std=0.5)
print(a)
'''
tensor([[1.2078, 1.0383, 0.7952],
        [1.3353, 1.0643, 1.7718]])
'''
  • 创建(0,1)区间的均匀分布的张量

a = torch.randn(2,3)
print(a)
  • 创建指定区间的分布
a = torch.empty(2,3)
a = a.uniform_(0,10)
print(a)
'''
tensor([[3.5308, 9.0467, 5.5398],
        [5.8256, 8.7092, 6.0698]])
'''

4.4.5创建序列

  • 通过torch.arange()函数实现。torch.arange(start, end, step)可以创建[start, end)之间,步长为 step
    的整型序列,不包含 end 本身。例
a = torch.arange(0,10,step=2)
print(a)
torch.FloatTensor(2) # 创建1*2维度的随机的float类型的张量

建议:torch.tensor([1,2,3])来创建已知到的元素的tensor,使用torch.Tensor或者torch.FloatTensor(x,y)来根据维度来创建tensor

设置 默认数据类型

torch.tensor([1,2]).type()  # torch.FloatTensor
torch.set_default_tensor_type(torch.DoubleTensor)

4.5张量的典型应用

4.5.1 标量

  • 经过 F.mse_loss 函数返回每个样本上的误差值,最后取误差的
    均值作为当前 Batch 的误差,它是一个标量

from torch.nn import functional as F
out = torch.randn(4,10)  # 随机模拟网络输出
y = torch.tensor([2,3,2,0]) # 随机构造样本的真实标签
y = F.one_hot(y,num_classes=10)
loss = F.mse_loss(y,out)
print(loss)

4.5.2向量

  • 通过高层接口类 Linear()方式创建的网络层,张量𝑾和𝒃存储在类的内部,由类自动创
    建并管理。可以通过全连接层的 bias 成员变量查看偏置变量b

  • 例如:例如创建输入节点数为 4,输出节点数为 3 的线性层网络

from torch import  nn

# 创建一层 Wx+b 输如入点维,输出节点维位4
fc = nn.Linear(3,4)
print(fc.bias)
 # tensor([-0.3322, -0.2867, -0.3817,  0.1789], requires_grad=True)

 # 类的偏置成员 bias 为长度为 4 的向量

4.5.3矩阵


from torch import  nn
# 模拟4个输入节点,3个输出节点
x = torch.ones(2,4)
b = torch.zeros(3)
w = torch.ones(4,3)
o = x@w + b
print(o)
'''
tensor([[4., 4., 4.],
        [4., 4., 4.]])
'''

4.5.4三维张量

4.5.5 四维张量

# 创建32*32的彩色图片输入个数为4
x = torch.randn(4,3,32,32)
# 创建CNN
layer = nn.Conv2d(3,16,kernel_size=3)
out = layer(x) # 前向计算
print(out.shape) # torch.Size([4, 16, 30, 30])
print(layer.weight.shape) # 访问卷积核权值张量

4.6索引与切片

4.6.1索引


# 创建4d张量 4张32*32大小的彩色图片
x = torch.randn(4,32,32,3)
# 去第一张图片
print(x[0])
#  取第 3 张图片,第 2 行,第 1 列的像素,B 通道(第 2 个通道)颜色强度值,下面两种方式等价
print(x[2][1][0][1])
print(x[2,1,0,1])

4.6.2 切片

  1. 由于Pytorch目前不支持负数切片
# 逆序读取元素
# 法一:
x = torch.arange(9)
print(x)
inv_idx = torch.arange(8,1,-1)
print(inv_idx) # tensor([8, 7, 6, 5, 4, 3, 2])
print(x[inv_idx]) # tensor([8, 7, 6, 5, 4, 3, 2])

#法二:
print(torch.flip(x,[0])) # 0参数为维度,逆序取全部元素
x = torch.arange(9)
print(x.size(0))  # 9
# 逆序间隔2采样
inv_idx = torch.arange(x.size(0)-1,-1,-2)
print(torch.arange(9,-1,-2)) # tensor([9, 7, 5, 3, 1])
inv_tensor = x[inv_idx]
print('逆序间隔2采样:',inv_tensor)
  • 读取每张图片的所有通道,其中行按着逆序隔行采样,列按着逆序隔行采样
    方法一:
# 读取每张图片的所有通道,其中行按着逆序隔行采样,列按着逆序隔行采样
x = torch.randn(4,32,32,3)
count = 0
for per_pict in range(x.size(0)):
    for channel in range(x.size(3)):
        for i in torch.arange(x.size(1)-1,-1,-2):
            for j in torch.arange(x.size(2)-1,-1,-2):
                # print(x[per_pict,i,j,channel])
                count+=1
print(count)
print(4*32*32*3)

方法二: ----------- 看不太懂

x = torch.randn(4,32,32,3)
# 高逆序间隔索引号
h_idx = torch.arange(x.size(1)-1,-1,-2)
# 宽逆序间隔索引号
w_idx = torch.arange(x.size(2)-1,-1,-2)
# 采样所有图片的高
x = x[:,h_idx]
# 采样所有图片的宽
x = x[:,:,w_idx]
print(x)
  • 为了避免出现像 [: , : , : ,1]这样过多冒号的情况,可以使用⋯符号表示取多个维度上所
    有的数据,其中维度的数量需根据规则自动推断:当切片方式出现⋯符号时,⋯符号左边
    的维度将自动对齐到最左边,⋯符号右边的维度将自动对齐到最右边,此时系统再自动推
    断⋯符号代表的维度数量
    在这里插入图片描述
x = torch.randn(4,32,32,3)
# 读取1~2张图片的G/B通道
print(x[0:2,...,1:])
# 采取最后两张图片
print(x[2:,...])
# 读取R/G通道数据
print(x[...,:2])

4.6.3小结

4.7维度变换

  • 假设𝑿包含了 2 个样本,每个样本的特征长度为 4,𝑿的 shape 为[2,4]。线性层的输
    出为 3 个节点,即𝑾的 shape 定义为[4,3],偏置𝒃的 shape 定义为[3]。那么𝑿@𝑾的运算结
    果张量 shape 为[2,3],最后叠加上 shape 为[3]的偏置𝒃。
  • 基本的维度变换操作函数包含了改变视图 reshape ,view()操作、插入新维度 expand_dims
    作、删除维度 squeeze 操作、交换维度 transpose 操作、复制数据 tile 操作等
  • 注意reshape的参数是列表

4.7.1改变视图函数(reshape==view)

  • 张量的视图:人们理解张量的方式
  • 张量的存储:张量在内存上保存为一段连续的内存区域,它类似于向量的一维结构
  • 同一个存储,从不同的角度观察数据,可以产生不同的视图,这就是存储与视图的关系。视图的产生是非常
    灵活的,但需要人为保证是合理且合法的。
    为了方便表达,这里把张量 shape 列表中相对靠左侧的维度叫作大维度,shape 列表中相对靠右侧的维度叫作小维度,
  • view方法没有拷贝新的张量,没有开辟新内存,与原张量共享内存;
  • view方法只是重新定义了访问张量的规则,使得取出的张量按照我们希望的形状展现。
  • 数据的存储/维度顺序非常重要,如下所示
a = torch.rand(4,1,28,28);
b = a.view(4,28*28);  #  小心对于b来说,丢失了后面维度的信息
b = b.view(4,28,28,1)  # logic Bug

4.7.2增删维度

  • 增加和删除维度操作可以在原有张量结构上增加和删除一个维度定义,并不会改变数据的存储,使用的非常频繁。
增加维度
  • 增加一个长度为 1 的维度相当于给原有的数据添加一个新维度的概念,维度长度为 1,存储并不需要改变,仅仅是改变数据的理解方式,因此它其实可以理解为改变视图的一种特殊方式。— unsqueeze

一张28 × 28大小的灰度图片的数据保存为 shape 为[28,28]的张
在 batch 维度后插入一新维度,定义为通道数维度 channel,此时张量的 shape 变为
[1,28,28]
通过 torch.unsqueeze(x, dim)可在指定的 dim 轴前(dim ≥ 0时)可以插入一个新的维度

x = torch.randint(0,10,[28,28])
print(x.shape) # torch.Size([28, 28])
x = torch.unsqueeze(x,0)  # dim=0表示在维度0前面插入维度为1的维度
print(x.shape)  # torch.Size([1, 28, 28])

需要注意的是,参数 dim 为非负时,表示在当前维度之前插入一个新维度;为负时,表示当前维度之后插入一个新的维度 dim=0表示在第一个维度之前,正的是在这个索引之前插入,负的是在这个索引之后插入
在这里插入图片描述

b = torch.rand(32)
f = torch.rand(4,32,14,14)
# f+b  # error The size of tensor a (14) must match the size of tensor b (32) at non-singleton dimension 3
print('b.shape',b.shape) # b.shape torch.Size([32])
print('f.shape',f.shape) # f.shape torch.Size([4, 32, 14, 14])

b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
print(b.shape) # torch.Size([1, 32, 1, 1])
f+b
删除维度

是增加维度的逆操作,与增加维度一样,删除维度只能删除长度为 1 的维 度,也不会改变张量的存储 ----- squeeze

x = torch.randint(0,10,[1,28,28])
print(x.shape) # torch.Size([1, 28, 28])
x = torch.squeeze(x,0)
print(x.shape) # torch.Size([28, 28])

特别地,如果不指定维度参数 dim,即 torch.squeeze(x),那么它会默认删除所有长度 为 1 的维度
建议使用 torch.squeeze()时逐一指定需要删除的维度参数 dim,防止 PyTorch 意外删除某些 长度为 1 的维度,导致计算结果不合法。

  • 注意指定的维度只能是1,超过1的不挤压,返回原值
f = torch.rand(4,32,14,14)
print('f.shape',f.shape) # f.shape torch.Size([4, 32, 14, 14])
f = f.squeeze(0)
print('f.shape',f.shape) # f.shape torch.Size([4, 32, 14, 14])

4.7.3交换维度

  • 通过交换维度操作,改变了张量的存储顺序,同时也改变了张量的视图。
  • 考虑图片张量 shape 为[2,3,32,32],“图片数量、通道数、行、列”的维度索引分别为 0、1、2、3,如果需要交换为[𝑏, ℎ, w, 𝑐]格式,则新维度的排序为“图片数量、行、列、通道数”,新维度对应到旧维度的索引号为[0,2,3,1],因此参数 perm 需设置为[0,2,3,1]
  • permute()函数其实是对矩阵的块行列进行交换里面的参数并不是具体数值而是块行列的代指.
参数dims用矩阵的维数代入,一般默认从0开始。即第0维,第1维等等
也可以理解为,第0块,第1块等等。当然矩阵最少是两维才能使用permute
如是两维,dims分别为是0和1
可以写成permute(0,1)这里不做任何变化,维数与之前相同
如果写成permute(1,0)得到的就是矩阵的转置
如果三维是permute(0,1,2)
0代表共有几块维度:本例中0对应着3块矩阵
1代表每一块中有多少行:本例中1对应着每块有2行
2代表每一块中有多少列:本例中2对应着每块有5列
所以是3块2行5列的三维矩阵
这些0,1,2并没有任何实际的意义,也不是数值,只是用来标识区别。有点类似于x,y,z来区分三个坐标维度,是人为规定好的

注意permute

x = torch.randint(0,10,[2,3,32,32])
print(x.shape)
x = x.permute(0,2,3,1)
print(x.shape)
'''
torch.Size([2, 3, 32, 32])
torch.Size([2, 32, 32, 3])
'''
  • 仅是两个维度交换
x = x.transpose(2,3)# 交换23维度
  • 对于矩阵的转置
x = torch.arange(4).view(2,2)
x = x.t() # 矩阵转置

需要注意的是,完成维度交换操作后,张量的存储顺序已发生改变,视图也随之改 变,后续的所有操作必须基于新的存续顺序和视图进行。相对于改变视图操作,维度交换 操作的计算代价更高。

如何交换保证数据不会混乱,即会恢复


# 为什么transpose之后需要contiguous?
a = torch.rand(4,3,32,32)
# a1 = a.transpose(1,3).view(4,3*32*32).view(4,3,32,32) # error : at least one dimension spans across two contiguous subspaces

# 由于python中矩阵式按行存储的transpose后会打乱原有数据,而因为view()操作需要连续的tensor,这样使用transpose交换后,原来的张量被打乱,view无法使用
'''
可以这样理解view是站在语义上去理解张量的,一旦transpose过后,是张量的语义(即我们理解张量的方式发生改变而实际内存没有变换)发生改变,而view理解了这次语义变化,在按照我们的要求去改变时,会导致出错(内部没有改变)
可以看出contiguous方法改变了多维数组在内存中的存储顺序,以便配合view方法使用
torch.contiguous()方法首先拷贝了一份张量在内存中的地址,然后将地址按照形状改变后的张量的语义进行排列。contuguous没有改变维度及shape,只是是语义上的维度和实际内存的顺序保持一致
'''


# 如下交换会数据混乱
a = torch.rand(4,3,32,32)
a1 = a.transpose(1,3).contiguous().view(4,3*32*32).view(4,3,32,32)  #
# [4,3,32,32]  --transpose(1,3)--> [4,32,32,3]--view-->[4,3*32*32]--view-->[4,3,32,32]
# [b c h w]                        [b w h c]            [b whc]             [h w h c ]
print(torch.all(torch.eq(a,a1))) # tensor(False)
# 数据已经混乱,无法恢复



#如下交换不会刀子数据混乱
a = torch.rand(4,3,32,32)
a2 = a.transpose(1,3).contiguous().view(4,3*32*32).view(4,32,32,3).transpose(1,3)
## [4,3,32,32]  --transpose(1,3)--> [4,32,32,3]--view-->[4,3*32*32]--view-->[4,3,32,32] --transpose(1,3)-->[4,32,32,3]
# # [b c h w]                        [b w h c]            [b whc]             [b w h c ]           [b c h w]
# 恢复了
print(torch.all(torch.eq(a,a2))) # tensor(True)

4.7.4复制数据

在这里插入图片描述


b = torch.tensor([1,2,3]) # 创建向量 b
print(b.shape) # torch.Size([3])
b = torch.unsqueeze(b,dim=0) # 插入新维度,编程矩阵
print(b.shape) # torch.Size([1, 3])
b = b.repeat([2,1])  # 在batch维度上复制一份数据,dim=1不复制
print(b.shape) # torch.Size([2, 3])

需要注意的是,x.repeat()函数会创建一个新的内存区来保存复制后的张量,由于复制
操作涉及大量数据的读写 IO 运算,计算代价相对较高,因此数据复制操作较为昂贵。神
经网络中不同 shape 之间的张量复制操作十分频繁,那么有没有轻量级的复制操作呢?这
就是接下来要介绍的 Broadcasting 操作

expand()只是改变了我们理解张量的方式,其存储没有改变,而repeat改变了内存

4.8 Broadcasting机制

expand

# expand扩展的前提
'''
1. 维度相同
2.扩展的维度是1
'''
f = torch.rand(1,32,1,1)
print('f.shape',f.shape) # f.shape torch.Size([1, 32, 1, 1])
f = f.expand(4,32,14,14)
print('f.shape',f.shape) # f.shape torch.Size([4, 32, 14, 14])

# 不想扩展的维度可以填-1;
  • 是一种轻量级的张量复制手段,在逻辑上扩展张量数据的形状,但是只会在需要时才会执行实际存储复制操作
  • 继续考虑上述的𝒀 = 𝑿@𝑾 + 𝒃的例子,𝑿@𝑾的 shape 为[2,3],𝒃的 shape 为[3],上一
    节通过结合 unsqueeze 和 repeat 函数手动完成复制数据操作,将𝒃的 shape 变换[2,3],然后与𝑿@𝑾完成相加运算。但实际上,直接将 shape 为[2,3]与[3]的𝒃相加在 PyTorch 里也是合法的
x = torch.randn(2,4) # 线性层的输入
w = torch.randn(4,3) # 线性层的权值矩阵
b = torch.randn(3) # 线性层的偏执
y = x@w + b

上面本质上是在调用:

y = x@w+b.expand([2,3]) 
  • Broadcasting 机制的核心思想是普适性,即同一份数据能普遍适合于其他维度。在验证
    普适性之前,需要先将张量 shape 靠右对齐,然后进行普适性判断:对于长度为 1 的维
    度,默认这个数据普遍适合于当前维度的其他位置;对于不存在的维度,则在增加新维度
    后默认当前数据也是普适于新维度的,从而可以扩展为更多维度数、任意长度的张量形
    状。
    在这里插入图片描述
    首先将 2 个张量的 shape 靠右对齐,对于通道维度𝑐,张量的现长度为 1,则默认此数据同样适合当前维度的其他位置,从而可将数据在逻辑上复制𝑐 − 1份,长度变为𝑐;对于不存在的𝑏和ℎ维度,则自动插入新维度,新维度长度为 1,同时默认当前的数据普适于新维度的其他位置,即对于其它的图片、其它的行来说,与当前的这一行的数据完全一致。因此将数据𝑏和ℎ维度的长度自动扩展为𝑏和ℎ
A = torch.arange(32).view(32,1)
print(A.shape) # torch.Size([32, 1])
A = A.expand(2,32,32,3)
print(A.shape) # torch.Size([2, 32, 32, 3])

不满足普适性的例子
在这里插入图片描述

A = torch.arange(64).view(32,2)  # 创建矩阵  
XW = torch.randn(2, 32,32,3) # 创建另外一个4D张量 
XW + A # 无法自动Broadcasting  The size of tensor a (3) must match the size of tensor b (2) at non-singleton dimension 3

A = A.expand(32,3) # 无法显示调用expand函数扩张形状
print(A.shape) # torch.Size([2, 32, 32, 3])

在这里插入图片描述

a = torch.tensor([1,2,3])
b = torch.tensor([3])
print(a+b) # tensor([4, 5, 6])


a = torch.tensor([1,2,3])
b = torch.tensor([4])
print(a+b) # tensor([5, 6, 7])



a = torch.tensor([1,2,3])
print(a+4) # tensor([4, 5, 6])

上述两个例子是不同的


a = torch.rand(1,2,3)
b = torch.rand(3)
print(a.shape) # torch.Size([1, 2, 3])
print(b.shape) # torch.Size([3])
print((a+b).shape) # torch.Size([1, 2, 3])


a = torch.rand([1,2,3])
b = torch.rand([4])
print((a+b).shape) # error:  The size of tensor a (3) must match the size of tensor b (4) at non-singleton dimension 2

注意下面都是shape不是数据,Broadcasting默认都是从低纬开始匹配
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.9 数学运算

4.9.1加减乘除运算

  • * 对应元素相乘
  • tensor.matmul() === @ 矩阵乘法

4.9.2乘方运算

torch.pow()
a2
a
0.5

4.9.3指数和对数运算

特别地,对于自然指数e^𝑥,可以通过 tf.exp(x)实现
注意在pytorch默认降维的维度在前: 例如[4,784] --> [512,784]

x@w.t()

4.9.4 矩阵相乘运算

  • 矩阵相乘:a@b = torch.matmul(a, b)
  • 当张量𝑨和𝑩维度数大于 2时,PyTorch 会默认选择𝑨和𝑩的最后两个维度进行矩阵相乘,前面所有的维度都视作
  • 矩阵𝑨和𝑩能够完成矩阵相乘的条件是,𝑨的倒数第一个维度长度(列)和𝑩的倒数第二个维度长度(行)必须相等
  • Broadcasting机制:
a = torch.randn(4,28,32)
b = torch.randn(32,16)
print(a.shape,b.shape)
print(torch.matmul(a, b).shape)
'''
torch.Size([4, 28, 32]) torch.Size([32, 16])
torch.Size([4, 28, 16])
'''

上述变量b扩展为[4,32,16]
注意:mm(只能用于二维)
注意多维矩阵相乘只去后两维相乘,剩余维度必须相同.
[1,2,3,4]@[1,2,4,10]
[1 1 3 4]@[1 2 4 10] --Broadcasting–>[1 2 3 4]@[1 2 4 10]
[2 3 3 4]@[1111 4 10] --BroadCasting–>[2 3 3 4]@[1 1111 4 10]由于第二个维度不能继续扩展.

clamp

grad = torch.rand(2,3) * 15
print(grad)
print(grad.clamp(10))
'''
clamp(min) 小于min的置为min
clamp(min,max)

tensor([[13.4315,  4.0888,  7.5753],
        [ 5.2417,  4.8863, 14.7393]])
tensor([[13.4315, 10.0000, 10.0000],
        [10.0000, 10.0000, 14.7393]
'''

4.10向传播实战

  • 完成三层神经网络的实现:这里采用的数据集是 MNIST 手写数字图片集,输入节点数为 784,第一层的输出节点数是256,第二层的输出节点数是 128,第三层的输出节点是 10,也就是当前样本属于 10 类别的概率
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值