导入pytorch包
import torch
查看版本号
torch.__version__
‘1.7.1’
张量的创建方法:torch.tensor()
通过列表创建张量:
t=torch.tensor([1,2])
t
tensor([1, 2])
通过元祖创建张量:
torch.tensor((1,2))
tensor([1, 2])
import numpy as np
a=np.array((1,2))
a
array([1, 2])
通过数组创建张量:
t1=torch.tensor(a)
t1
tensor([1, 2], dtype=torch.int32)
dtype指张量的type,d指dimension
type(t)
torch.Tensor
type(t1)
torch.Tensor
从上面的返回结果可以看出返回结果都是张量,即创建的类型都是张量
a
array([1, 2])
a.dtype #数组类型
dtype(‘int32’)
t
tensor([1, 2])
t.dtype
torch.int64
t1
tensor([1, 2], dtype=torch.int32)
t1.dtype
torch.int32
张量内部还会细分成具体类型。整数型的数组默认创建int32(整型)类型,而张量则默认创建int64(长整型)类型。
np如果创建浮点型对象,array默认为双精度浮点型float64,而tensor则默认为单精度浮点型float32
np.array([1.1,2.2]).dtype
dtype(‘float64’)
torch.tensor(np.array([1.1,2.2])).dtype#输入双精度浮点型的array,返回结果为双精度浮点型,输出继承了输入的类型
torch.float64
torch.tensor([1.11,2.2]).dtype#输入list创建tensor,返回结果为单精度浮点型
torch.float32
t2=torch.tensor([True,False])
t2
tensor([ True, False])
t2.dtype
torch.bool
还可以通过dtype参数,在创建张量时设置输出结果:
torch.tensor([1.1,2.7],dtype=torch.int16)
tensor([1, 2], dtype=torch.int16)
a = torch.tensor(1 + 2j) #1是实部,2是虚部
a
tensor(1.+2.j)
转化过程对于用户来说是隐藏的,不明显的,朝向尽可能保留有用信息的方向转化。
和numpy中array相同,当张量各元素属于不同类型时,系统会自动进行隐式转化。
浮点型和整数型的隐式转化 :
torch.tensor([1.1,2])
tensor([1.1000, 2.0000])
布尔型和数值型的隐式转化:
torch.tensor([True,2.0])
torch.tensor([False,2.0])
tensor([0., 2.])
t
tensor([1, 2])
转化为默认浮点型(32位):
t.float()
tensor([1., 2.])
转化为双精度浮点型:
t.double()
tensor([1., 2.], dtype=torch.float64)
t.dtype
torch.int64
转化为16位整数:
t.short()
tensor([1, 2], dtype=torch.int16)
当在torch函数中使用dtype参数的时候,需要输入torch.float表示精度。
在使用方法进行类型转化时,方法名称是double。(虽然torch.float和double都表示双精度浮点型)
用简单序列创建一维数组
t1 = torch.tensor([1,2])
t1
tensor([1, 2])
使用ndim查看张量的维度:
t1.ndim
1
使用shape查看形状:
t1.shape
torch.Size([2])
t1.size() #pytorch中size方法和shape函数返回结果相同
torch.Size([2])
还有两种方法查看张量
len(t1)#返回拥有N-1维元素
2
t1.numel()#返回一共有几个数
2
len([1,2,3])
3
一维张量的len和numel返回结果相同,而更高维则不同
用形状相同的序列构成新序列,进而将其转化为二维张量:
用list的list创建二维数组(list的嵌套):
t2 = torch.tensor([[1,2],[3,4]])
t2
tensor([[1, 2],
[3, 4]])
t2.ndim #2维的张量
2
t2.shape #2行2列l
torch.Size([2, 2])
t2.size()
torch.Size([2, 2])
len(t2)#此处len函数返回结果表示t2是由2个1维张量构成
2
t1 = torch.tensor([1])
t1
tensor([1])
t1.ndim
1
t1.shape
torch.Size([1])
t0 = torch.tensor(1)
t0
tensor(1)
t0.ndim
0
t0.shape
torch.Size([])
t0.size()
torch.Size([])
理解零维张量:可将零维张量视为拥有张量属性的单独的数。
例如:张量可以存在于GPU上,但python的原生数值对象不行。零维张量虽然是零维的,但因为是张量,所以可以存在于GPU上。
从学术名称来说,python中的数值是scalars(标量),零维张量是tensor
一般来说,称三维及三维以上的张量为高维张量。三维张量可以理解为二维数组或矩阵的组合。
a1 = np.array([[1,2,2],[3,4,4]])
a1
array([[1, 2, 2],
[3, 4, 4]])
a2 = np.array([[5,6,6],[7,8,8]])
a2
array([[5, 6, 6],
[7, 8, 8]])
由两个形状相同的二维数组创建一个三维的张量:
t3 = torch.tensor([a1,a2])
t3
tensor([[[1, 2, 2],
[3, 4, 4]],
[[5, 6, 6],
[7, 8, 8]]], dtype=torch.int32)
t3.ndim#查看维度
3
由两个矩阵(元素)构成,每个矩阵都是两行三列构成。torch.size([矩阵个数,行,列]):
t3.shape
torch.Size([2, 2, 3])
t3.size()
torch.Size([2, 2, 3])
len(t3)
2
t3.numel()#包含
12
t2
tensor([[1, 2],
[3, 4]])
t2.flatten() #按行排列,拉平
tensor([1, 2, 3, 4])
t3
tensor([[[1, 2, 2],
[3, 4, 4]],
[[5, 6, 6],
[7, 8, 8]]], dtype=torch.int32)
t3.flatten()
tensor([1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8], dtype=torch.int32)
如果将零维张量拉平,会变成一维张量:
t0=torch.tensor(1)
t0
tensor(1)
t0.ndim
0
t0.flatten()
tensor([1])
t0.flatten().ndim
1
t1 = torch.tensor([1,2])
t1.shape
torch.Size([2])
t1.reshape(2,1)
tensor([[1],
[2]])
t1.reshape(2,1).shape
torch.Size([2, 1])
reshape转化后的维度由该方法输入的参数个数决定
t1.reshape(2)
tensor([1, 2])
t1.reshape(2,)#另一种表达
tensor([1, 2])
t1.reshape(2).ndim
1
t1.reshape(1,2)
tensor([[1, 2]])
t1.reshape(1,2).ndim
2
t1.reshape(1,1,2)
tensor([[[1, 2]]])
t1.reshape(1,2,1)
tensor([[[1],
[2]]])
t1.reshape(1,2,1).ndim
3
t3
tensor([[[1, 2, 2],
[3, 4, 4]],
[[5, 6, 6],
[7, 8, 8]]], dtype=torch.int32)
t3.reshape(1,1,12)#利用Reshape的方法把t3拉平
tensor([[[1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8]]], dtype=torch.int32)
特殊张量:用于模拟特殊取值的矩阵,如全0矩阵、对角矩阵
torch.zeros([2,3]) #2行3列
tensor([[0., 0., 0.],
[0., 0., 0.]])
torch.ones([2,3])
tensor([[1., 1., 1.],
[1., 1., 1.]])
torch.eye(5)
tensor([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])
需要用一维张量去创建
t1
tensor([1, 2])
torch.diag(t1)
tensor([[1, 0],
[0, 2]])
不能直接使用list创建:
torch.diag([1,2])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 torch.diag([1,2])#不能直接使用list创建
TypeError: diag(): argument 'input' (position 1) must be Tensor, not list
torch.randn(2,3)#2行3列的随机数所构成的张量
tensor([[-0.8110, -1.1295, -0.2913],
[-1.1786, -0.8882, 0.2433]])
torch.randn(2,3)
tensor([[-0.9562, -2.0921, -0.1686],
[ 0.4361, 0.8800, 1.3416]])
torch.normal(2,3,size = (2,2)) #均值为2,标准差为3的张量
tensor([[ 3.0653, 6.2467],
[-1.5873, 2.1258]])
torch.randint(1,10,[2,4]) #在1到10之间随机抽取整数,组成两行四列的张量
tensor([[1, 8, 2, 3],
[8, 6, 7, 4]])
torch.arange(5)
tensor([0, 1, 2, 3, 4])
torch.arange(1,5,0.5) #从1到5,每隔0.5取一个数
tensor([1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000, 4.0000, 4.5000])
torch.linspace(1,5,3) #从1取到5,等距取三个数
tensor([1., 3., 5.])
torch.empty(2,3)
tensor([[0., 0., 0.],
[0., 0., 0.]])
torch.full([2,4],2) #2行4列,数值为2
tensor([[2, 2, 2, 2],
[2, 2, 2, 2]])
根据指定对象的形状进行数值填充,只需要在上述函数后面加上_like即可
t1
tensor([1, 2])
t2
tensor([[1, 2],
[3, 4]])
torch.full_like(t1,2) #根据t1的形状,填充数值2
tensor([2, 2])
torch.randint_like(t2,1,10) #在1到10中随机抽取一些整数,并将其填充进t2的形状中去
tensor([[2, 1],
[6, 8]])
torch.zeros_like(t1)
tensor([0, 0])
_like类型转化需要注意转化前后数据类型一致的问题
t1
tensor([1, 2])
torch.randn_like(t1) #t1是整数,而转化后变为浮点数,所以会报错
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in
----> 1 torch.randn_like(t1) #t1是整数,而转化后变为浮点数,所以会报错
RuntimeError: "normal_kernel_cpu" not implemented for 'Long'
t10 = torch.tensor([1.1,2.2]) #生成一个新的浮点数张量
t10
tensor([1.1000, 2.2000])
torch.randn_like(t10) #即可进行填充转化
tensor([-1.1196, -2.0447])
t1 = torch.tensor([1,2,3,4,5,6,7,8,9,10])
t1
tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
t1.numpy()
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=int64)
t1.tolist()
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list(t1)
[tensor(1),
tensor(2),
tensor(3),
tensor(4),
tensor(5),
tensor(6),
tensor(7),
tensor(8),
tensor(9),
tensor(10)]
需要注意的是,构成一维张量的是零维张量,而不是数值。
所以此时转化的列表是由一个个零维张量构成的列表,而不是数值构成的列表
n = torch.tensor(1)
n
tensor(1)
n.item()
1
只能一个元素一个元素进行转化:
t1.item()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in
----> 1 t1.item() #只能一个元素一个元素进行转化
ValueError: only one element tensors can be converted to Python scalars
等号赋值操作实际上是浅拷贝,需要进行深拷贝(使用clone方法)
t1
tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
t11 = t1
t11
tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
t1[1]
tensor(2)
t1[1] = 10#对“t1中的第二个元素”进行修改
t1
tensor([ 1, 10, 3, 4, 5, 6, 7, 8, 9, 10])
t11 #t11也会同步发生变化
tensor([ 1, 10, 3, 4, 5, 6, 7, 8, 9, 10])
要使得t11不随t1变化,需要对t11进行深拷贝
t11 = t1.clone()
t11
tensor([ 1, 10, 3, 4, 5, 6, 7, 8, 9, 10])
t1[0] = 100
t1
tensor([100, 10, 3, 4, 5, 6, 7, 8, 9, 10])
t11 #t11不随t1发生改变
tensor([ 1, 10, 3, 4, 5, 6, 7, 8, 9, 10])
[:] #all
[:n] #从0开始到n
[n:] #从n开始到结束
[start:end] #开始的索引:结束的索引
":"可以理解为→,即 从start→end
正向索引[0,1,2],反向索引[-3,-2,-1]
[start: end:采样步长step]
"…"代表任意多的维度,即全部维度。=a[:, :, :, :]:
a[...].shape
torch.Size([4, 3, 28, 28])
a[0,...].shape #=a[0,:,:,:]
torch.Size([3, 28, 28])
a[:,0,...].shape #=a[:,0,:,:]
torch.Size([4, 28, 28])
当有"…"出现时,右边的索引需要理解为最右边:
a[...,:2].shape #=a[:,:,:,:2]
torch.Size([4, 3, 28, 2])
a[0,...,::2].shape
torch.Size([3, 28, 14])
import torch
import numpy as np
t1 = torch.arange(1,11)
t1
tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
从左到右,从0开始。张量的索引结果是张量,不是单纯的数值:
t1[0]
tensor(1)
t1[0].item() # 张量转化成单纯的数,用item()
1
t1[1:8] # 切片
tensor([2, 3, 4, 5, 6, 7, 8])
t1[1:8:2]
tensor([2, 4, 6, 8])
t1[1::2]#从第二个元素开始索引,一直到结尾,并且每隔两个数取一个
tensor([ 2, 4, 6, 8, 10])
t1[:8:2]#从第一个元素开始索引,一直到第九个元素,并且每隔两个数取一个
tensor([1, 3, 5, 7])
t1[9:1:-1]#step必须大于0
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in
----> 1 t1[9:1:-1]#step必须大于0
ValueError: step must be greater than zero
t2 = torch.arange(1,10).reshape(3,3)
t2
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
[第1行,第2列的元素]:
t2[0,1]
tensor(2)
第一行,每隔两个元素取一列:
t2[0,::2]
tensor([1, 3])
第一行第1个和第三个元素:
t2[0,[0,2]]
tensor([1, 3])
每隔2行取一个,每隔2列取一个:
t2[::2,::2]
tensor([[1, 3],
[7, 9]])
第一行和第3行的第2列元素:
t2[[0,2],1]
tensor([2, 8])
t3 = torch.arange(1,28).reshape(3,3,3)
t3,t3.shape
(tensor([[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]]]),
torch.Size([3, 3, 3]))
索引第二个矩阵中,第二行,第二列的元素:
t3[1,1,1]
tensor(14)
索引第二个矩阵,行和列都是每隔两个取一个:
t3[1,::2,::2]
tensor([[10, 12],
[16, 18]])
每隔两个取一个矩阵,对于矩阵来说,行和列都是每隔两个取一个:
t3[::2,::2,::2]
tensor([[[ 1, 3],
[ 7, 9]],
[[19, 21],
[25, 27]]])
t1
tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
t1.ndim
1
indices = torch.tensor([1,2])
indices
tensor([1, 2])
torch.index_select(t1,0,indices) #对t1索引值为1和2的元素 (输入张量,维度,索引)
tensor([2, 3])
t2 = torch.arange(12).reshape(4,3)
t2,t2.shape
(tensor([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]]),
torch.Size([4, 3]))
indices
tensor([1, 2])
torch.index_select(t2,0,indices) #
tensor([[3, 4, 5],
[6, 7, 8]])
torch.index_select(t2,1,indices)
tensor([[ 1, 2],
[ 4, 5],
[ 7, 8],
[10, 11]])
返回一个类似视图的结果
通过.view还可以改变对象的结构
“视图”的作用是节省空间。接下来切分向量的很多方法,返回结果都是“视图”,而不是新生成的一个对象。
t = torch.arange(6).reshape(2,3)
t
tensor([[0, 1, 2],
[3, 4, 5]])
te = t.view(3,2) #构建一个数据相同但图像不同的“视图”
te
tensor([[0, 1],
[2, 3],
[4, 5]])
t[0]=1 #只修改一个,t和t.view()的值都会变化
t,te
(tensor([[1, 1, 1],
[3, 4, 5]]),
tensor([[1, 1],
[1, 3],
[4, 5]]))
tr = t.view(1,2,3) #维度也可以修改
tr
tensor([[[1, 1, 1],
[3, 4, 5]]])
按照某维度对张量进行均匀切分,并且返回结果是原张量的视图view。
t2 = torch.arange(12).reshape(4,3)
t2
tensor([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
在第0个维度上(按行),进行4等分。返回结果是一个视图,不是一个新对象:
tc = torch.chunk(t2,4,dim=0)
tc
(tensor([[0, 1, 2]]),
tensor([[3, 4, 5]]),
tensor([[6, 7, 8]]),
tensor([[ 9, 10, 11]]))
tc[0]
tensor([[0, 1, 2]])
tc[0][0]
tensor([0, 1, 2])
tc[0][0][0]
tensor(0)
修改tc的值,原张量也发生了变化
tc[0][0][0] = 1
t2
tensor([[ 1, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
当原张量不能均分时,chunk不会报错,但会返回其他均分的结果
torch.chunk(t2,3,dim=0) #次一级均分结果
(tensor([[1, 1, 2],
[3, 4, 5]]),
tensor([[ 6, 7, 8],
[ 9, 10, 11]]))
len(torch.chunk(t2,3,dim=0))
2
len(torch.chunk(t2,5,dim=0))#次一级均分结果
4
按长度len进行拆分,既能进行均分,也能进行自定义均分。当然,需要注意的是,split和chunk函数的返回结果一样,都是view。
t2 = torch.arange(12).reshape(4,3)
t2
tensor([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
第二个参数只输入一个数值时表示均分,第三个参数表示维度:
torch.split(t2,2,0)
(tensor([[0, 1, 2],
[3, 4, 5]]),
tensor([[ 6, 7, 8],
[ 9, 10, 11]]))
第二个参数输入一个序列时,表示按序列数值进行均分。并且1+3 == 4:
[1,3]表示“第一块长度为1,第二块长度为3
torch.split(t2,[1,3],0)
(tensor([[0, 1, 2]]),
tensor([[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]]))
torch.split(t2,[1,1,2],0)
(tensor([[0, 1, 2]]),
tensor([[3, 4, 5]]),
tensor([[ 6, 7, 8],
[ 9, 10, 11]]))
torch.split(t2,[1,2],1)
(tensor([[0],
[3],
[6],
[9]]),
tensor([[ 1, 2],
[ 4, 5],
[ 7, 8],
[10, 11]]))
c.shape为torch.Size([2, 32, 8]),第零维长度一共才2,但是要把长度拆分成2,就无法拆分:
aa,bb = c.split(2,dim=0)
ValueError Traceback (most recent call last)
in
----> 1 aa,bb = c.split(2,dim=0) #长度一共才2,但是要把长度拆分成2,就无法拆分
ValueError: not enough values to unpack (expected 2, got 1)
a = torch.zeros(2,3)
a
tensor([[0., 0., 0.],
[0., 0., 0.]])
b = torch.ones(2,3)
b
tensor([[1., 1., 1.],
[1., 1., 1.]])
c = torch.zeros(3,3)
c
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
默认按行(dim=0)【记住二维张量dim=0表示行】进行拼接:
torch.cat([a,b])
tensor([[0., 0., 0.],
[0., 0., 0.],
[1., 1., 1.],
[1., 1., 1.]])
按列进行拼接:
torch.cat([a,b],dim=1)
tensor([[0., 0., 0., 1., 1., 1.],
[0., 0., 0., 1., 1., 1.]])
合并时要确保a和b的dimension一样,其他维度数值一致。形状不匹配时会报错:
torch.cat([a,c],dim=1)
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in
----> 1 torch.cat([a,c],dim=1)#形状不匹配时会报错
RuntimeError: Sizes of tensors must match except in dimension 1. Got 2 and 3 in dimension 0 (The offending index is 1)
torch.stack([a,b])
tensor([[[0., 0., 0.],
[0., 0., 0.]],
[[1., 1., 1.],
[1., 1., 1.]]])
构成三维张量:
torch.stack([a,b]).shape
torch.Size([2, 2, 3])
维度不匹配:
torch.stack([a,c])
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in
----> 1 torch.stack([a,c])
RuntimeError: stack expects each tensor to be equal size, but got [2, 3] at entry 0 and [3, 3] at entry 1
x = torch.randn(3,4)
x
tensor([[ 0.6480, 1.5947, 0.6264, 0.6051],
[ 1.6784, 0.2768, -1.8780, -0.1133],
[-0.6442, 0.8570, 0.1677, 0.2378]])
ge(0.5)表示“>=0.5”:
mask = x.ge(0.5)
mask
tensor([[ True, True, True, True],
[ True, False, False, False],
[False, True, False, False]])
取出">=0.5"的数据:
torch.masked_select(x,mask)
tensor([0.6480, 1.5947, 0.6264, 0.6051, 1.6784, 0.8570])
torch.masked_select(x,mask).shape
torch.Size([6])
squeeze()把dimension=1的全部去掉:
t = torch.zeros(1,1,3,1)
t,t.shape
(tensor([[[[0.],
[0.],
[0.]]]]),
torch.Size([1, 1, 3, 1]))
torch.squeeze(t).shape#剔除所有属性为1的维度
torch.Size([3])
t1 = torch.zeros(1,1,3,2,1,2)
t1.shape
torch.Size([1, 1, 3, 2, 1, 2])
torch.squeeze(t1).shape
torch.Size([3, 2, 2])
例:torch.Size([1, 32, 1, 1])四维:
b.squeeze().shape #把dimension=1的全部去掉
torch.Size([32])
b.squeeze(0).shape #挤压掉第0维
torch.Size([32, 1, 1])
b.squeeze(-1).shape #挤压掉最后一维
torch.Size([1, 32, 1])
b.squeeze(1).shape #挤压掉第一维
torch.Size([1, 32, 1, 1])
b.squeeze(-4).shape #挤压掉-4维
torch.Size([32, 1, 1])
t = torch.zeros(1,2,1,2)
t.shape #四维
torch.Size([1, 2, 1, 2])
在第0位索引上升高一个维度变成五维:
torch.unsqueeze(t,dim=0).shape
torch.Size([1, 1, 2, 1, 2])
a.shape
torch.Size([4, 1, 28, 28])
对a升高维度。参数可以为(-5 ~ 0 ~ 4)。
在0索引前面插入了一个额外的维度,可以理解成第几组:
a.unsqueeze(0).shape
torch.Size([1, 4, 1, 28, 28])
在末尾插入一个额外的维度,可以理解为像素的属性:
a.unsqueeze(-1).shape
torch.Size([4, 1, 28, 28, 1])
a.unsqueeze(4).shape
torch.Size([4, 1, 28, 28, 1])
a.unsqueeze(-4).shape
torch.Size([4, 1, 1, 28, 28])
a.unsqueeze(-5).shape
torch.Size([1, 4, 1, 28, 28])
a.unsqueeze(5).shape #超过了维度允许范围
IndexError Traceback (most recent call last)
in
----> 1 a.unsqueeze(5).shape #超过了维度允许范围
IndexError: Dimension out of range (expected to be in range of [-5, 4], but got 5)
a = torch.tensor([1.2,2.3])
a
tensor([1.2000, 2.3000])
a.shape
torch.Size([2])
a.unsqueeze(-1)
tensor([[1.2000],
[2.3000]])
a.unsqueeze(-1).shape
torch.Size([2, 1])
a.unsqueeze(0)
tensor([[1.2000, 2.3000]])
a.unsqueeze(0).shape
torch.Size([1, 2])
b = torch.rand(32)
b.shape
torch.Size([32])
f = torch.rand(4,32,14,14)
bias相当于给每个channel上所有像素增加一个偏置
b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
b.shape
torch.Size([1, 32, 1, 1])
①expand仅限于原来维度是1的可以改变,原来不为1的数要复制:
b = torch.rand(1,32,1,1)
b.expand(4,32,14,14).shape
torch.Size([4, 32, 14, 14])
②-1表示维度保持不变
b.expand(-1,32,-1,-1).shape
torch.Size([1, 32, 1, 1])
③-4是bug,生成的结果是无意义的:
b.expand(-1,32,-1,-4).shape
torch.Size([1, 32, 1, -4])
b.shape
torch.Size([1, 32, 1, 1])
repeat的参数表示重复的次数:4表示对0维重复4次,32表示对1维重复32次。
b.repeat(4,32,1,1).shape
torch.Size([4, 1024, 1, 1])
b.repeat(4,1,1,1).shape
torch.Size([4, 32, 1, 1])
b.repeat(4,1,32,32).shape
torch.Size([4, 32, 32, 32])
a = torch.randn(3,4)
a.shape
torch.Size([3, 4])
a.t()
a.t().shape
torch.Size([4, 3])
a = torch.rand(4,3,32,32)
a1 = a.transpose(1,3).contiguous().view(4,3*32*32).view(4,3,32,32)
#这种写法会造成数据污染,是错误的,最后一个view里面应该是(4,32,32,3),然后用transpose变回去
#正确写法:要把维度信息跟踪住,view的时候要记住维度信息,展开的时候要按维度展开,不要错乱
a2 = a.transpose(1,3).contiguous().view(4,3*32*32).view(4,32,32,3).transpose(1,3)
#transpose包含了要交换的两个维度[b,c,h,w]→[b,w,h,c]
#数据的维度顺序必须与存储顺序一致,用.contiguous把数据变成连续的
#.view(4,33232) [b,whc]
#.view(4,3,32,32) [b,w,h,c]
#.transpose(1,3) [b,c,g,w]
a1.shape,a2.shape
(torch.Size([4, 3, 32, 32]), torch.Size([4, 3, 32, 32]))
torch.all(torch.eq(a,a1))
tensor(False)
torch.all(torch.eq(a,a2))
tensor(True)
a = torch.rand(4,3,28,28)
a.transpose(1,3).shape
torch.Size([4, 28, 28, 3])
b = torch.rand(4,3,28,32) #b c h w
b.transpose(1,3).shape #b w h c 交换一、三维
torch.Size([4, 32, 28, 3])
b.transpose(1,3).transpose(1,2).shape #b h w c
torch.Size([4, 28, 32, 3])
#通过上述几步,实现了把 [b,c,h,w] 变成 [b,h,w,c]
#可以通过permute,直接用索引完成转变
b.permute(0,2,3,1).shape #b h w c
torch.Size([4, 28, 32, 3])
#[b,h,w,c]是numpy储存图片的格式,需要转变为这种形式才可以导出numpy
1、如果前面没有维度,则需要在前面插入一个新的维度
2、把新加入的维度扩张成为相同的size。例:A,B。B没有内容,为B插入一个新维度,并把B扩张成和A相同的维度
3、经过卷积神经网络,生成feature maps:[4,32,14,14]
4、Bias:32,1,1=>1,32,1,1=>4,32,14,14
why broadcasting?
for actual demanding:
·regulation:[class,student,score],add bias for every students: +5score
·because [4,32,8]can only add with [4,32,8],
·on the contrary,we hope [4,32,8]can add with [5.0](0dimension tensor)
key:Match from last dim(从小维开始匹配)
situation 1:
·if current dim=1,expand to same
eg.A[4,32,8](four classes,32 students,8 lessons),now we want the score of each lesson be added 5.
B[1] => B[1,1,1] => B[4,32,8]
A[4,32,14,14]
B[1,32,1,1] => [4,32,14,14]
situation 2:
·if either has no dim,insert one dim and expand to same
now we just want the score of English be added 5
B[1,1,8] => [4,32,8] (through[0,0,5,0,0,0,0,0])
A[4,32,14,14]
B[14,14] => [1,1,14,14] =>[4,32,14,14]
situation 3:
·NOT broadcasting-able
A[4,32,14,14]
B[2,32,14,14]#dim 0 has distinct dim,NOT size 1,so cannot insert and expand to same
作为PyTorch中执行深度学习的基本数据类型,张量(Tensor) 也拥有非常多的数学运算函数和方法,以及对应的一系列计算规则。在PyTorch中, 能够作用与Tensor的运算,被统称作为算子。并且相比于NumPy, PyTorch给出 了更加规范的算子(运算)的分类,从而方便用户在不同场景下调用不同类型的算子(运算)。
PyToch总共为Tensor设计了六大类数学运算,分别是:
1.逐点运算(Pointwise Ops) :指的是针对Tensor中每个元素执行的相同运算操作;
2.规约运算(Reduction Ops) :指的是对于某一张量进行操作得出某种总结值;
3.比较运算(Comparison Ops) :指的是对多个张量进行比较运算的相关方法;
4.谱运算(Spectral Ops) :指的是涉及信号处理傅里叶变化的操作;
5.BLAS和LAPACK运算: 指的是基础线性代数程序集(Basic Linear Algeria Subprograms)和线性代数包(Linear Algeria Package)中定义的、主要用于线性代数科学计算的函数和方法;
6.其他运算(Other Ops) :其他未被归类的数学运算。
由于谱运算(Spectral Ops)前期不会涉及,而要理解傅里叶变换本身需要更多额外的数学基础,而很多其他运算,我们在前面介绍张量的基本方法时已经介绍,因此接下来将主要围绕逐点运算、规约运算、比较运算和线性代数运算四块进行讲解,而线性代数部分由于涉及到大量的数学内容,因此将放在本课中单独进行讲解。
广播的特性是在不同形状的张量进行计算时,一个或多个张量通过隐式转化,转化成相同形状的两个张量,从而完成计算的特性。但并非任何两个不同形状的张量都可以通过广播特性进行计算,因此,我们需要了解广播的基本规则及其核心依据。
2.1标量和任意形状的张量
标量可以和任意形状的张量进行计算,计算过程就是标量和张量的每一个元素进行计算。