PyTorch基础(Numpy & Tensor)
Numpy与Tensor是PyTorch的重要内容
Numpy的使用
Numpy是Python中科学计算的一个基础包,提供了一个多维度的数组对象,数组是由numpy.ndarray类来实现的,是Numpy的核心数据结构,其索引从0开始,和Python列表不同的是,Numpy没办法动态地改变,创建时就具有固定的大小,如果改变Numpy数组的长度,会创建一个新的数组并且删除原数组,并且数组中的数据类型必须是一样的,但消耗的内存更少,运行速度更快
创建数组
将一个任意维度的列表传入np.array()或np.asarray()中就可以创建一个数组,如下创建一个一维数组:
import numpy as np
arr1 = np.asarray([1, 2, 3])
print(arr1)
输出:
[1, 2, 3]
如下创建一个二维数组:
import numpy as np
arr2 = np.asarray([[1, 2], [3, 4]])
print(arr2)
输出:
[[1 2]
[3 4]]
np.ones()可以创建一个全1的数组,必须指定数组的形状,可选参数是数组的数据类型
arr = np.ones(shape=(2, 3))
print(arr)
输出:
[[1. 1. 1.]
[1. 1. 1.]]
指定数据类型:
arr = np.ones(shape=(2, 3), dtype='int32')
print(arr)
输出:
[[1 1 1]
[1 1 1]]
np.zeros()创建一个全0数组,用法与ones类似,使用np.ones()*n可以创建一个全n数组
np.arange()可以创建一个区间内的数组,格式为np.arrange([start,]stop,[step,]dtype=None)
,创建一个在[start,stop)区间的数组
arr1 = np.arange(5)
print(arr1)
arr2 = np.arange(2, 5)
print(arr2)
arr3 = np.arange(2, 9, 3)
print(arr3)
输出:
[0 1 2 3 4]
[2 3 4]
[2 5 8]
np.linerspace()可以创建一个从开始数值到结束数值的等差数列
参数 | 说明 |
---|---|
start | 必要参数,序列的起始值 |
stop | 必须参数,序列的终点 |
num | 序列中元素个数,默认50 |
endpoint | 默认为True,如果为True则最后一个元素是stop(包含终点) |
restep | 默认为False,如果为True,返回数组与公差 |
arr = np.linspace(start=2, stop=10, num=3)
print(arr)
输出:
[ 2. 6. 10.]
数组属性
Numpy数组具有一些固有属性,如下是一些常用属性
nidm
表示数组维度的个数
打印上述代码中的arr2.ndim得到的就是2,arr1.ndim的结果就是1
shape
表示数组的形状,是一个整数的元组,长度为ndim
arr1 = np.asarray([1, 2, 3])
print(arr1.shape)
arr2 = np.asarray([[1, 2], [3, 4]])
print(arr2.shape)
上述这段代码的输出:
(3,)
(2, 2)
可以使用reshape对数组的形状进行变换,但是变换前和变换后的数组元素个数必须一样:
arr2 = np.asarray([[1, 2], [3, 4]])
print(arr2.shape)
arr2 = arr2.reshape((4, 1))
print(arr2)
输出:
(2, 2)
[[1]
[2]
[3]
[4]]
还可以使用np.reshape(a,newshape,order)来对数组进行形状的改变,新的形状在newshape中指定,order参数指定以什么样的顺序读写元素,其中有几个参数:
名称 | 说明 |
---|---|
C | 默认参数,使用C-like语言(行优先)中的索引方式进行读写 |
F | 使用类似Fortan-like语言(列优先)中的索引方式进行读写 |
A | 原数组如果是按照'C'的方式存储数组,则用'C'的索引对数组进行reshape,否则使用'F' |
示例:
a = np.arange(6).reshape((2, 3), order='C')
print(a)
输出:
[[0 1 2]
[3 4 5]]
将数组a按照'C'的方式reshape成(3,2),方式首先将原数组展开,因为是行优先,所以最后一个维度优先改变
a = np.arange(6).reshape((2, 3), order='F')
print(a)
输出:
[[0 2 4]
[1 3 5]]
size
表示数组元素的总数,等于shape属性中元素的乘积
a = np.arange(12).reshape((3, 4), order='C')
print(a.size)
输出12
dtype
描述数组中元素类型的对象,使用dtype可以查看数组所属的数据类型
a = np.arange(12).reshape((3, 4), order='C')
print(a.dtype)
输出int64
在创建数组时,Numpy会自动判断类型,然后给一个默认的数据类型,也直接可以指定:
arr = np.asarray([[1, 2], [3, 4]], dtype='float')
print(arr.dtype)
数组的数据类型可以用astype改变,但会创建一个新的数组,并不会改变原数组的数据类型:
arr = np.asarray([[1, 2], [3, 4]], dtype='float')
print(arr.dtype)
arr2 = arr.astype("int32")
print(arr2.dtype)
print(arr.dtype)
输出:
float64
int32
float64
事实上,不能通过直接修改数据类型来修改数组的数据类型,这样会改变数据
数组的轴
数组的轴即数组的维度,从0开始。对于二维数组来说有两个轴,分别是代表行的0轴与代表列的1轴
随机赋值一个3×4的数组,按0轴方向进行累加:
arr = np.random.randint(10, size=(4, 3))
print(arr)
ans = np.sum(arr, axis=0) # 按0轴方向进行累加
print(ans)
输出:
[[0 0 2]
[2 3 2]
[7 8 6]
[0 5 4]]
[ 9 16 14]
可以看到0轴方向元素的累加结果为[9 16 14],下面按1轴方向:
arr = np.random.randint(10, size=(4, 3))
print(arr)
ans = np.sum(arr, axis=1)
print(ans)
输出:
[[2 2 5]
[5 8 2]
[5 7 4]
[7 0 4]]
[ 9 15 16 11]
如果是更高维度的数组,axis=i就意味着按照第i个轴的方向进行计算,第i个轴的数据将会被折叠或聚合到一起,示例:
a = np.arange(18).reshape((3, 2, 3))
print(a)
print("0 axis:\n", a.max(axis=0))
print("1 axis:\n", a.max(axis=1))
print("2 axis:\n", a.max(axis=2))
输出:
[[[ 0 1 2]
[ 3 4 5]]
[[ 6 7 8]
[ 9 10 11]]
[[12 13 14]
[15 16 17]]]
0 axis:
[[12 13 14]
[15 16 17]]
1 axis:
[[ 3 4 5]
[ 9 10 11]
[15 16 17]]
2 axis:
[[ 2 5]
[ 8 11]
[14 17]]
Numpy在深度学习中的应用
深度学习的项目可以分为数据加载、训练与模型评估三部分,Numpy在数据加载和模型评估中经常会被使用到
数据加载
在这个阶段要做的是将模型训练要用的数据读取进来,训练数据无外乎: 图片、文本以及类似二维表那样的结构化数据
PyTorch中对于图片的操作大多基于Pillow,可以用Pillow或OpenCV读入图片然后转化为Numpy数组
下面就对如上的图片进行处理
Pillow加载图片
Pillow使用二进制形式读取图片,使用Numpy的asarray方法即可转换数据格式:
import numpy as np
from PIL import Image
image = Image.open("./apple.jpg")
image_pillow = np.asarray(image)
print(image_pillow.shape)
输出:
(424, 568, 3)
OpenCV加载图片
OpenCV读入图片后就是以Numpy数组形式保存的
import cv2
image = cv2.imread('./apple.jpg')
print(type(image))
print(image.shape)
输出:
<class 'numpy.ndarray'>
(424, 568, 3)
可以发现,数组的最后一个维度是3,这是因为图片的格式是RGB格式,表示有R、G、B三个通道
值得注意的是,Pillow读入后通道的顺序是R、G、B,而OpenCV读入后顺序是B、G、R
Numpy索引和切片
现在利用Numpy的索引和切片来分出图片的3个通道
image = Image.open("./apple.jpg")
image_pillow = np.asarray(image)
image_pillow_c1 = image_pillow[:, :, 0]
image_pillow_c2 = image_pillow[:, :, 1]
image_pillow_c3 = image_pillow[:, :, 2]
:
表示全部选中,上述分别选中了第三个维度为0 1 2的数组,这样就获得了每个通道的数据
使用Numpy的contatenate函数可对数组进行拼接,现在将上述分离出的一个数据与全0数组进行拼接:
zeros = np.zeros(shape=(424, 568, 1), dtype='uint8')
image_pillow_c1 = image_pillow_c1[:, :, np.newaxis]
image_pillow_c1_3ch = np.concatenate((image_pillow_c1, zeros, zeros), axis=2)
print(image_pillow_c1_3ch.shape)
输出 (424, 568, 3)
代码中使用了np.newaxis,因为image_pillow_c1是一个二维的数据,要增加一个维度变成3维
利用直接赋值也可以对数组进行升维,生成一个和image_pillow形状一样的全0数组,然后每个通道的数值赋值为image_pillow_c1、image_pillow_c2与image_pillow_c3即可
按照这个方式将RGB三个通道都取出,和原图一起输出到一张图片上
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
image = Image.open("./apple.jpg")
image_pillow = np.asarray(image)
image_pillow_c1 = image_pillow[:, :, 0]
image_pillow_c2 = image_pillow[:, :, 1]
image_pillow_c3 = image_pillow[:, :, 2]
zeros = np.zeros(shape=(424, 568, 1), dtype='uint8') # 创建全0数组
image_pillow_c1 = image_pillow_c1[:, :, np.newaxis]
image_pillow_c1_3ch = np.concatenate((image_pillow_c1, zeros, zeros), axis=2) # 沿着2轴合并
image_pillow_c2 = image_pillow_c2[:, :, np.newaxis]
image_pillow_c2_3ch = np.concatenate((zeros, image_pillow_c2, zeros), axis=2)
image_pillow_c3 = image_pillow_c3[:, :, np.newaxis]
image_pillow_c3_3ch = np.concatenate((zeros, zeros, image_pillow_c2), axis=2)
plt.subplot(2, 2, 1)
plt.title('Origin Image')
plt.imshow(image_pillow)
plt.axis('off')
plt.subplot(2, 2, 2)
plt.title('Red Channel')
plt.imshow(image_pillow_c1_3ch)
plt.axis('off')
plt.subplot(2, 2, 3)
plt.title('Green Channel')
plt.imshow(image_pillow_c2_3ch)
plt.axis('off')
plt.subplot(2, 2, 4)
plt.title('Red Channel')
plt.imshow(image_pillow_c3_3ch)
plt.axis('off')
plt.savefig('./rgb_pillow.png', dpi=150)
最终得到的图片:
深拷贝(副本)与浅拷贝(视图)
还有一种方式获得RGB 3个通道,只需将图片读入后,直接将其中两个通道赋值为0即可,但得使用深拷贝,完全复制原有数组,创建一个新的数组,这样修改新的数组才不会影响原有数组,因此就使用array来加载数据
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
image = Image.open("./apple.jpg")
image_pillow = np.array(image)
image_pillow_c1 = np.array(image)
image_pillow_c1[:, :, 1:] = 0
image_pillow_c2 = np.array(image)
image_pillow_c2[:, :, 0] = 0
image_pillow_c2[:, :, 2] = 0
image_pillow_c3 = np.array(image)
image_pillow_c3[:, :, 0:2] = 0
plt.subplot(2, 2, 1)
plt.title('Origin Image')
plt.imshow(image_pillow)
plt.axis('off')
plt.subplot(2, 2, 2)
plt.title('Red Channel')
plt.imshow(image_pillow_c1)
plt.axis('off')
plt.subplot(2, 2, 3)
plt.title('Green Channel')
plt.imshow(image_pillow_c2)
plt.axis('off')
plt.subplot(2, 2, 4)
plt.title('Red Channel')
plt.imshow(image_pillow_c3)
plt.axis('off')
plt.savefig('./rgb_pillow.png', dpi=150)
Tensor的使用
深度学习中,从数据的组织到模型内部的参数,都是一种叫做张量(Tensor)的数据结构进行表示和处理
Tensor是深度学习框架中极为基础的概念,是一种数据的存储和处理结构
标量、向量和矩阵都是张量,是秩不同的张量,标量是秩为0阶的Tensor,向量是秩为1阶的Tensor,矩阵是秩为2阶的Tensor
创建Tensor
PyTorch可以通过多种方式创建一个任意形状的Tensor
torch.tensor(data,dtype=None,device=None,requires_grad=False)
参数的含义:
data是要传入模型的数据,PyTorch支持通过list、tuple、numpy array、scalar等多种类型进行数据传入,并转换为Tensor,接着是dtype,它声明了要返回一个怎样的类型的Tensor,之后的device,这个参数指定了数据要返回到的设备,目前并不关心,最后一个参数是requires_grad,用于说明当前量是否需要在计算中保留对应的梯度信息,在PyTorch中,只有当一个Tensor设置requires_grad为True的情况下,才会对这个Tensor以及由这个Tensor计算出来的其他Tensor进行求导,然后将导数值存在Tensor进行求导,然后将导数值存在Tensor的grad属性中,便于优化器来更新参数
训练过程中设置为true,目的是方便求导和更新参数。而到了验证或者测试过程,目的是检查当前模型的泛化能力,那就要把requires_grad设置为False,避免这个参数根据loss自动更新
从Numpy中创建
实际应用中,在处理数据的阶段多用Numpy,而数据处理好之后想要传入PyTorch的深度学习模型中,则需要借助Tensor,所以PyTorch提供了一个从Numpy转到Tensor的语句:
torch.from_numpy(ndarry)
示例:
import numpy
import torch
arr = numpy.arange(6).reshape((2, 3))
res = torch.from_numpy(arr)
print(res)
输出:
tensor([[0, 1, 2],
[3, 4, 5]])
创建特殊形式的Tensor
创建全0矩阵Tensor,其中用得比较多的size参数和dtype参数,size定义输出张量形状的整数序列:
res = torch.zeros((2,3))
print(res)
输出:
tensor([[0., 0., 0.],
[0., 0., 0.]])
该函数的参数还有很多
创建单位矩阵Tensor,单位矩阵就是指主对角线上元素都为1的矩阵:
res = torch.eye(3, 4)
print(res)
输出:
tensor([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.]])
创建全1矩阵Tensor,就是所有元素都为1的矩阵
res = torch.ones(3, 4)
print(res)
输出:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
创建随机矩阵Tensor: 在PyTorch中有几种较为经常使用的随机矩阵创建方式,分别如下:
函数 | 说明 |
---|---|
torch.rand(size) | 生成浮点类型且维度指定的随机Tensor,数据在0~1间分布 |
torch.randn(size) | 生成浮点类型且维度指定的随机Tensor,数据满足均值为0且方差为1的标准正态分布 |
torch.normal(mean,std,size) | 生成浮点类型且维度制定的随机Tensor,可以指定均值和标准差 |
torch.randint(low,high,size) | 生成随机整数的Tensor,其内部填充的是在[low,high)均匀生成的随机整数 |
转换Tensor数据类型
int与Tensor转换:
a = torch.tensor(1)
b = a.item()
上述代码先将一个数字转换为Tensor,又通过item()函数将Tensor转换为数字,item函数的作用就是将Tensor转换为一个python数字
list与Tensor转换:
a = [1, 2, 3]
b = torch.tensor(a)
c = b.numpy().tolist()
现将一个list转化为tensor,但要转化回来要先转为Numpy结构,之后在使用tolist得到list
Tensor常用操作
常用的操作包括: 获取形状、维度转换、形状变换以及增减维度
获取形状
使用shape或size来获取形状,shape是一个属性,size()是一个方法:
a = torch.zeros(2, 3, 5)
print(a.shape)
print(a.size())
输出:
torch.Size([2, 3, 5])
torch.Size([2, 3, 5])
知道了Tensor的形状,就可以通过所有维度相乘来计算出Tensor所包含的数量,也可以通过numel()函数直接统计元素数量
a.numel()
矩阵转秩
使用permute和transpose可以用来实现矩阵的转秩,或者说交换不同维度的数据
使用permute函数可以对任意高维矩阵进行转秩:
import torch
x = torch.rand(2, 3, 5)
print(x.shape)
x = x.permute(2, 1, 0)
print(x.shape)
输出:
torch.Size([2, 3, 5])
torch.Size([5, 3, 2])
permute中的0表示原来的第0个维度放在了现在的第二个维度,形状变成了[5, 3, 2]
而另外一个函数transpose不同于permute,每次只能转换两个维度,或者说交换两个维度的数据:
x = torch.rand(2, 3, 5)
print(x.shape)
x = x.transpose(1, 0)
print(x.shape)
输出:
torch.Size([2, 3, 5])
torch.Size([3, 2, 5])
经过transpose或者permute处理之后的数据,在内存中变得不再连续
形状变换
在PyTorch中有两个常用的改变形状的函数,分别是view和reshape
view:
x = torch.randn(4, 4)
print(x.shape)
x = x.view(2, 8)
print(x.shape)
先声明了一个[4,4]大小的Tensor,然后通过view函数,将其修改为[2,8]形状的Tensor,但是这个操作不能作用于内存不连续的Tensor(比如permute交换过的数据),这时使用reshape函数可以避免这个问题:
x = torch.randn(4, 4)
print(x.shape)
x = x.permute(1, 0)
x = x.reshape(2, 8)
print(x.shape)
输出:
torch.Size([4, 4])
torch.Size([2, 8])
增减维度
对Tensor增加或者删除某些维度,使用squeeze()或者unsqueeze()函数
x = torch.rand(2, 1, 3)
print(x.shape)
y = x.squeeze(1)
print(y.shape)
z = y.squeeze(1)
print(z.shape)
新建了一个维度[2, 1, 3]的Tensor,然后将第1维度的数据删除,得到y,squeeze执行成功是因为是第1维度的大小为1,,然而在y上打算进一步删除第1维度的时候,就会发现删除失败了,因为y此刻的第1维度的大小为3,所以suqeeze不能删除
unsqueeze(): 这个函数主要是对数据维度进行扩充。给指定位置加上维数为1的维度,同样结合代码例:
x = torch.rand(2, 1, 3)
y = x.unsqueeze(2)
print(y.shape)
输出:
torch.Size([2, 1, 1, 3])
Tensor的变形
Tensor连接和切分都是必不可少的操作
Tensor连接
连接操作函数:
torch.cat(tensors,dim=0,out=None)
cat是concatnate,意思为拼接和联系
第一个参数是tensors,是准备进行连接的Tensor
第二个参数是dim,Tensor的维度有多种情况,比如两个3维的Tensor,可以有几种不同的拼接方式
先看二维情况:
A = torch.ones(3, 3)
B = 2*torch.ones(3, 3)
print(A)
print(B)
C = torch.cat((A, B), 0)
print(C)
D = torch.cat((A, B), 1)
print(D)
输出:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
tensor([[2., 2., 2.],
[2., 2., 2.],
[2., 2., 2.]])
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[2., 2., 2.],
[2., 2., 2.],
[2., 2., 2.]])
tensor([[1., 1., 1., 2., 2., 2.],
[1., 1., 1., 2., 2., 2.],
[1., 1., 1., 2., 2., 2.]])
上述展示了将dim指定为0或1,得到的结果,dim的数值是多少,两个矩阵就会按照相应维度进行连接
利用stack函数进行升维:
torch.stack(inputs, dim=0)
其中inputs表示要拼接的Tensor,dim表示新建立维度的方向
A = torch.arange(0, 4)
B = torch.arange(5, 9)
print(A)
print(B)
C = torch.stack((A, B), 0)
print(C)
D = torch.stack((A, B), 1)
print(D)
输出:
tensor([0, 1, 2, 3])
tensor([5, 6, 7, 8])
tensor([[0, 1, 2, 3],
[5, 6, 7, 8]])
tensor([[0, 5],
[1, 6],
[2, 7],
[3, 8]])
构建了4元素向量A和B,维度为1。在dim=0上建立一个维度,这样维度成了2,也就得到了C。而对于则是在dim=1,即列方向上建立维度
Tensor切分
切分就是连接的逆过程,切分的操作主要分为3种: chunk、split和unbind
chunk
torch.chunk(input, chunks, dim=0)
input是要做chunk操作的Tensor,chunks代表要被划分的块的数量,而不是每组的数量,chunks必须是整型,dim表示按照哪个维度进行chunk
A = torch.tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
B = torch.chunk(A, 2, 0)
print(B)
chunk函数将原来10位长度的Tensor,切分成了两个一样5位长度的向量
输出:
(tensor([1, 2, 3, 4, 5]), tensor([ 6, 7, 8, 9, 10]))
如果chunk参数不能够整除的话:
A = torch.tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
B = torch.chunk(A, 3, 0)
print(B)
输出:
(tensor([1, 2, 3, 4]), tensor([5, 6, 7, 8]), tensor([ 9, 10]))
先优先分出若干长度为n的向量(n为总长度除以个数再向上取整),最后不够分的就作为最后一个向量
如果chunk参数大于Tensor可以切分的长度:
A = torch.tensor([1, 2, 3])
B = torch.chunk(A, 5, 0)
print(B)
输出:
(tensor([1]), tensor([2]), tensor([3]))
被切分的Tensor只能分成若干个长度为1的向量
对于二维矩阵Tensor也是类似的情形:
A = torch.ones(4, 4)
print(A)
B = torch.chunk(A, 2, 0)
print(B)
输出:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
(tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.]]), tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.]]))
split
上述的chunk函数是按照"切分成确定的份数"来进行切分的,如果要按"每份的大小"来进行切分,则使用split函数
torch.split(tensor,split_size_or_sections,dim=0)
首先是tensor,也就是待切分的Tensor,对于split_size_of_sections参数,当它为整数时,表示将tensor按照每块大小为这个整数的数值来切割,当这个参数为列表时,则表示将此tensor切成和列表中元素一样大小的块,最后一个dim定义了按哪个维度切分
示例:
A = torch.rand(4, 4)
print(A)
B = torch.split(A, 2, 0)
print(B)
输出:
tensor([[0.0595, 0.3272, 0.8546, 0.0235],
[0.9919, 0.7146, 0.8096, 0.0890],
[0.5487, 0.9408, 0.4592, 0.3705],
[0.4732, 0.8606, 0.9022, 0.3976]])
(tensor([[0.0595, 0.3272, 0.8546, 0.0235],
[0.9919, 0.7146, 0.8096, 0.0890]]), tensor([[0.5487, 0.9408, 0.4592, 0.3705],
[0.4732, 0.8606, 0.9022, 0.3976]]))
将一个4×4的Tensor从0轴按照每组两行的切分,得到2个2×4的Tensor
如果不能整除的话,如下:
A = torch.rand(4, 4)
print(A)
B = torch.split(A, 3, 0)
print(B)
输出:
tensor([[0.3061, 0.6316, 0.6293, 0.7099],
[0.4281, 0.3687, 0.7680, 0.8685],
[0.0606, 0.9907, 0.9463, 0.8688],
[0.2345, 0.8496, 0.6657, 0.6714]])
(tensor([[0.3061, 0.6316, 0.6293, 0.7099],
[0.4281, 0.3687, 0.7680, 0.8685],
[0.0606, 0.9907, 0.9463, 0.8688]]), tensor([[0.2345, 0.8496, 0.6657, 0.6714]]))
显然在这种情况下,会尽量凑够每一个结果,剩下的不够凑了则作为一组
如果split_size_or_sections为列表:
A = torch.rand(5, 4)
print(A)
B = torch.split(A, (2, 3), 0)
print(B)
将 Tensor A,沿着第 0 维进行切分,每一个结果对应维度上的尺寸或者说大小,分别是 2(行),3(行)。
unbind
一种降维切分的方法,将原数组拆解
torch.unbind(input, dim=0)
input表示待处理的Tensor,dim依然表示切片的方向
A = torch.arange(0, 16).view(4, 4)
B = torch.unbind(A, 0)
print(B)
输出:
(tensor([0, 1, 2, 3]), tensor([4, 5, 6, 7]), tensor([ 8, 9, 10, 11]), tensor([12, 13, 14, 15]))
从第0维开始切分,因为有4行,所以切出4个结果,将unbind中第二个参数改成1则按列切分:
A = torch.arange(0, 16).view(4, 4)
B = torch.unbind(A, 1)
print(B)
输出:
(tensor([ 0, 4, 8, 12]), tensor([ 1, 5, 9, 13]), tensor([ 2, 6, 10, 14]), tensor([ 3, 7, 11, 15]))
索引
最常用的两个索引操作就是 index_select 和 masked_select
index_select
torch.index_select(tensor, dim, index)
示例:
A = torch.arange(0, 16).view(4, 4)
print(A)
B = torch.index_select(A, 0, torch.tensor([1, 3]))
C = torch.index_select(A, 1, torch.tensor([0, 3]))
print(B)
print(C)
输出:
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
tensor([[ 4, 5, 6, 7],
[12, 13, 14, 15]])
tensor([[ 0, 3],
[ 4, 7],
[ 8, 11],
[12, 15]])
第一次从0维按行选择,选择了第1行和第3行,第二次按从1维选择,选择了第0行和第3行
masked_select
还可通过一些判断条件来进行选择,比如提取深度学习网络中某一层中数值大于 0 的参数
torch.masked_select(input, mask, out=None)
input 表示待处理的 Tensor。mask 代表掩码张量,也就是满足条件的特征掩码。mask 须跟 input 张量有相同数量的元素数目,但形状或维度不需要相同。
A = torch.rand(5)
print(A)
B = torch.masked_select(A, A > 0.3)
print(B)
mask就是根据要筛选的条件,得到一个掩码张量,然后用这个张量去提取 Tensor 中的数据
输出:
tensor([0.2524, 0.4978, 0.9570, 0.0738, 0.5051])
tensor([0.4978, 0.9570, 0.5051])
PyTorch基础(Numpy & Tensor)的更多相关文章
- [人工智能]Pytorch基础
PyTorch基础 摘抄自<深度学习之Pytorch>. Tensor(张量) PyTorch里面处理的最基本的操作对象就是Tensor,表示的是一个多维矩阵,比如零维矩阵就是一个点,一维 ...
- pytorch基础学习(一)
在炼丹师的路上越走越远,开始入手pytorch框架的学习,越炼越熟吧... 1. 张量的创建和操作 创建为初始化矩阵,并初始化 a = torch.empty(, ) #创建一个5*3的未初始化矩阵 ...
- Python数据分析基础——Numpy tutorial
参考link https://docs.scipy.org/doc/numpy-dev/user/quickstart.html 基础 Numpy主要用于处理多维数组,数组中元素通常是数字,索引值为 ...
- pytorch基础(1)
基本数据类型和tensor import torch import numpy as np #array 和 tensor的转换 array = np.array([,]) tensorArray = ...
- 【新生学习】第一周:深度学习及pytorch基础
DEADLINE: 2020-07-25 22:00 写在最前面: 本课程的主要思路还是要求大家大量练习 pytorch 代码,在写代码的过程中掌握深度学习的各类算法,希望大家能够坚持练习,相信经度过 ...
- Pytorch基础-tensor数据结构
torch.Tensor Tensor 数据类型 Tensor 的属性 view 和 reshape 的区别 Tensor 与 ndarray 创建 Tensor 传入维度的方法 参考资料 torch ...
- pytorch基础学习(二)
在神经网络训练时,还涉及到一些tricks,如网络权重的初始化方法,优化器种类(权重更新),图片预处理等,继续填坑. 1. 神经网络初始化(Network Initialization ) 1.1 初 ...
- PyTorch基础——词向量(Word Vector)技术
一.介绍 内容 将接触现代 NLP 技术的基础:词向量技术. 第一个是构建一个简单的 N-Gram 语言模型,它可以根据 N 个历史词汇预测下一个单词,从而得到每一个单词的向量表示. 第二个将接触到现 ...
- pytorch 基础内容
一些基础的操作: import torch as th a=th.rand(3,4) #随机数,维度为3,4的tensor b=th.rand(4)print(a)print(b) a+b tenso ...
- Pytorch 基础
Pytorch 1.0.0 学习笔记: Pytorch 的学习可以参考:Welcome to PyTorch Tutorials Pytorch 是什么? 快速上手 Pytorch! Tensors( ...
随机推荐
- OSIDP-内存管理-07
专业术语 页框:内存中固定长度的块. 页:外存中固定长度的块. 段:外存中可变长度的块. 内存管理需求 重定位:程序从内存换出到外存后,再换回内存时,在内存空间中的位置和原先的位置有极大可能不相同.此 ...
- Eclipse离线安装svn插件下载
site-1.4.8.zip site-1.6.18.zip site-1.8.22.zip site-1.10.9.zip site-1.10.13-1.9.x.zip site-1.10.13-1 ...
- 【基础知识】C++算法基础(快速排序)
快速排序: 1.执行流程(一趟快排): 2.一趟快排的结果:获得一个枢纽,在此左边皆小于此数,在此右边皆大于此数,因此可以继续使用递归获得最终的序列.
- HashMap记录
1.HashMap接收null的键值 2.HashMap是非synchronized的 3.HashMap使用hashCode找到bucket的位置.bucket中存储的是键和值 4.当HashCod ...
- 使用NTC计算温度,增加计算精度的算法
uint16_t uGetPCB_Temperature(void) { uint16_t x; float Adcn; float k; Adcn = userADC_var.ADCMeasureV ...
- Js:当前日期格式化与比较大小
//日期格式转换 getCurrentTime() { var date = new Date();//当前时间 var year = date.getFullYear() //返回指定日期的年份 v ...
- JavaScript数组常用的方法总结
数组常用方法 concat() 方法 concat() 方法用于连接两个或多个数组. 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. var arr = new Array(3) arr ...
- Qt 5.15.2 QTextEdit无法设置新字体的处理方式
首发于我的个人博客:xie-kang.com 博客内有更多文章,欢迎大家访问 原文地址 在使用QT 5.15.2 开发的过程中碰到了件怪事,下列代码无法给QTextEdit选中的文字设置字体: QTe ...
- C#重点语法——特性
特性的基本理解 ************************************************************************************* 一.含义 特 ...
- 使用react-vite-antd,修改antd主题,报错 [vite] Internal server error: Inline JavaScript is not enabled. Is it set in your options? It is hacky way to make this function will be compiled preferentially by less
一般报错 在官方文档中,没有关于vite中如何使用自定义主题的相关配置,经过查阅 1.安装less yarn add less (已经安装了就不必再安装) 2.首先将App.css改成App.les ...