Tensor基础

Tensor——张量

tensor可以看作一个多维数组,标量是0维张量,向量是1维张量,矩阵看作二维张量
torch.Tencer是存储和变换数据的主要工具,类似于Numpy,而Tensor提供GPU计算和自动求梯度等更多的功能,因而更适合深度学习任务

创建Tensor

使用 empty 创建一个未初始化的tensor
# 导入torch
import torch
# 创建一个5x3的 未初始化 的Tensor
tensor = torch.empty(5,3)
tensor
tensor([[9.2755e-39, 1.0561e-38, 6.6123e-39],
        [8.4490e-39, 9.6428e-39, 1.1112e-38],
        [9.5511e-39, 1.0102e-38, 1.0286e-38],
        [1.0194e-38, 9.6429e-39, 9.2755e-39],
        [9.1837e-39, 9.3674e-39, 1.0745e-38]])
使用 rand 创建一个随机初始化的tensor
# 创建一个5x3的 随机初始化 的Tensor
tensor = torch.rand(5,3)
tensor
tensor([[0.0382, 0.7174, 0.2924],
        [0.2784, 0.7799, 0.7862],
        [0.2426, 0.1755, 0.1579],
        [0.5902, 0.1025, 0.8453],
        [0.5292, 0.4720, 0.2294]])
使用 zeros 创建一个全0的tensor
# 创建一个5x3的 全部初始化为0 的Tensor
tensor = torch.zeros(5,3)
tensor
tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])
使用 ones 创建一个全1的tensor
tensor = torch.ones(5,3)
tensor
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
使用rand()创建一个均匀分布的tensor
tensor = torch.rand(5,3)
tensor
tensor([[0.2607, 0.3371, 0.2242],
        [0.3591, 0.1004, 0.8683],
        [0.1021, 0.5884, 0.6595],
        [0.4889, 0.6538, 0.5106],
        [0.0143, 0.8322, 0.0849]])
使用randn()创建一个标准分布的tensor
tensor = torch.randn(5,3)
tensor
tensor([[ 0.8349,  0.4898,  0.6729],
        [-0.2988, -0.4673, -1.2728],
        [-0.4344, -0.8004, -1.0311],
        [-0.7575, -0.1988, -1.2069],
        [-1.0390,  0.4296, -0.6993]])
使用 eye 创建一个对角线为1其余为0的tensor
tensor = torch.eye(3,3)
tensor
tensor([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]])
使用tensor直接根据数据创建 tensor
# 直接创建一个元素为5.5 和 3的张量
tensor = torch.tensor([5.5,3])
tensor
tensor([5.5000, 3.0000])
new_ones()
# new_ones 在已经存在的张量(例如x)的基础上快速创建一个新的张量(例如x2),
# 那么x2具有和x1相同的数据类型(torch.dtype)和设备(torch.device)

# 默认重用输入`Tensor`的一些属性,例如数据类型,除非自定义数据类型
print('original tensor:',tensor.dtype,tensor.device)
print('tensor:',tensor)

tensor1 = tensor.new_ones(5,3,dtype=torch.float64)
print('tensor1:',tensor1.dtype,tensor1.device)
print('tensor1:',tensor1)

# 自定义数据类型为float32
tensor2 = tensor.new_ones(5,3,dtype = torch.float32)
print('tensor2:',tensor2.dtype,tensor2.device)
print('tensor2:',tensor2)
original tensor: torch.float32 cpu
tensor: tensor([5.5000, 3.0000])
tensor1: torch.float64 cpu
tensor1: tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
tensor2: torch.float32 cpu
tensor2: tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
randn_like(intput_tensor)
# 返回一个和输入的张量(此处输入tensor2 --> (5,3))大小相同的张量,填充了来自均值为 0 且方差为 1 的正态分布的随机数
tensor = torch.randn_like(tensor2)
tensor
tensor([[-1.0363,  0.4599, -0.1938],
        [ 1.4657,  0.4905,  0.0049],
        [ 0.6425, -0.5205, -2.7419],
        [ 1.6636, -1.4791, -0.7599],
        [ 0.4845,  1.3453,  1.0725]])

获取Tensor形状

使用 shape
tensor.shape # 注意不要写成 tensor.shape() 
torch.Size([5, 3])
使用size()
tensor.size()
torch.Size([5, 3])

操作——Tensor的各种常用操作

算术操作
加法操作
# 两个测试tensor
t1 =  torch.rand(5,3)
print(t1)
t2 = torch.rand(5,3)
print(t2)
tensor([[0.7700, 0.2527, 0.7854],
        [0.2529, 0.4505, 0.1423],
        [0.8534, 0.0141, 0.6260],
        [0.7263, 0.5366, 0.2349],
        [0.6167, 0.3870, 0.4339]])
tensor([[0.4644, 0.0766, 0.7044],
        [0.3266, 0.8935, 0.5278],
        [0.7959, 0.3624, 0.6834],
        [0.5171, 0.6444, 0.5704],
        [0.4169, 0.0182, 0.4759]])
1.直接相加
t1+t2
tensor([[1.2344, 0.3293, 1.4899],
        [0.5795, 1.3440, 0.6700],
        [1.6493, 0.3765, 1.3094],
        [1.2434, 1.1811, 0.8053],
        [1.0337, 0.4052, 0.9098]])
2.使用 add()
torch.add(t1,t2)
tensor([[1.2344, 0.3293, 1.4899],
        [0.5795, 1.3440, 0.6700],
        [1.6493, 0.3765, 1.3094],
        [1.2434, 1.1811, 0.8053],
        [1.0337, 0.4052, 0.9098]])
3.使用inplace版本——带下划线后缀的方法

注:PyTorch操作inplace版本都有后缀_, 例如x.copy_(y), x.t_()

t2.add_(t1)
tensor([[1.2344, 0.3293, 1.4899],
        [0.5795, 1.3440, 0.6700],
        [1.6493, 0.3765, 1.3094],
        [1.2434, 1.1811, 0.8053],
        [1.0337, 0.4052, 0.9098]])
索引

可以使用类似NumPy的索引操作来访问Tensor的一部分,需要注意的是:索引出来的结果与原数据共享内存,也即修改一个,另一个会跟着修改

test_tensor = torch.rand(5,3)
print('test_tensor:\n',test_tensor)
# 获取某一行内容
index_tensor1 = test_tensor[0,:]
index_tensor2 = test_tensor[1,:]
 # 获取指定位置的单个元素,例如第2行第2个元素
index_tensor3 = test_tensor[1,1:2] # 索引从0开始,前面的1代表第二行,后面的1:2相当于一个切片操作,获取第2行中的第二个元素
print('index(1,1):',index_tensor3)
print('index_tensor1:',index_tensor1)
print('index_tensor2:',index_tensor2)
index_tensor1 += 1
print('index_tensor1:',index_tensor1)
print('test_tensor[0,:]:',test_tensor[0,:])
test_tensor:
 tensor([[0.2057, 0.7814, 0.9296],
        [0.3824, 0.0040, 0.3460],
        [0.4090, 0.7394, 0.9397],
        [0.3415, 0.2694, 0.5211],
        [0.7107, 0.7032, 0.1176]])
index(1,1): tensor([0.0040])
index_tensor1: tensor([0.2057, 0.7814, 0.9296])
index_tensor2: tensor([0.3824, 0.0040, 0.3460])
index_tensor1: tensor([1.2057, 1.7814, 1.9296])
test_tensor[0,:]: tensor([1.2057, 1.7814, 1.9296])

改变形状

使用 view() 改变Tensor的形状

注意view()返回的新Tensor与源Tensor虽然可能有不同的size,但是是共享data的,也即更改其中的一个,另外一个也会跟着改变。(顾名思义,view仅仅是改变了对这个张量的观察角度,内部数据并未改变)

如果想要返回一个新的副本而不共享数据,可以先使用clone()创造一个副本然后使用view
tensor_copy = test_tensor.clone().view(?)

tensor = torch.rand(5,3) # 原来的tensor 5x3
print('tensor:\n',tensor)
tensor_change = tensor.view(15) # 修改形状 改为一维的15个,1x15
print('tensor_change:\n',tensor_change)
tensor_change2 = tensor.view(-1,5) # -1所指的维度可以通过其他维度推测出来,--> 3x5
print('tensor_change2:\n',tensor_change2)

print(tensor.size(),tensor_change.size(),tensor_change2.size())
tensor:
 tensor([[0.2423, 0.9519, 0.9906],
        [0.2997, 0.7124, 0.4299],
        [0.5868, 0.5261, 0.1628],
        [0.0075, 0.1174, 0.5508],
        [0.8232, 0.8728, 0.9864]])
tensor_change:
 tensor([0.2423, 0.9519, 0.9906, 0.2997, 0.7124, 0.4299, 0.5868, 0.5261, 0.1628,
        0.0075, 0.1174, 0.5508, 0.8232, 0.8728, 0.9864])
tensor_change2:
 tensor([[0.2423, 0.9519, 0.9906, 0.2997, 0.7124],
        [0.4299, 0.5868, 0.5261, 0.1628, 0.0075],
        [0.1174, 0.5508, 0.8232, 0.8728, 0.9864]])
torch.Size([5, 3]) torch.Size([15]) torch.Size([3, 5])

使用clone还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源Tensor

item() 可以将一个Tensor标量转换成一个python number
tensor = torch.randn(1)
print(tensor)
tensor.item()
tensor([-1.1877])





-1.1877024173736572

线性函数

trace()——对角线元素之和(矩阵的迹)
tensor = torch.ones(3,3)
print(tensor)
tensor.trace()
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])





tensor(3.)
diag()——对角线元素
tensor = torch.rand(3,3)
print(tensor)
tensor.diag()
tensor([[0.0308, 0.7154, 0.0386],
        [0.2303, 0.5764, 0.7461],
        [0.9273, 0.2662, 0.8488]])





tensor([0.0308, 0.5764, 0.8488])
t()——转置
print(tensor)
tensor.t()
tensor([[0.0308, 0.7154, 0.0386],
        [0.2303, 0.5764, 0.7461],
        [0.9273, 0.2662, 0.8488]])





tensor([[0.0308, 0.2303, 0.9273],
        [0.7154, 0.5764, 0.2662],
        [0.0386, 0.7461, 0.8488]])
inverse()——求逆矩阵
print(tensor)
tensor.inverse()
tensor([[0.0308, 0.7154, 0.0386],
        [0.2303, 0.5764, 0.7461],
        [0.9273, 0.2662, 0.8488]])





tensor([[ 0.8404, -1.7263,  1.4792],
        [ 1.4356, -0.0280, -0.0407],
        [-1.3684,  1.8948, -0.4252]])
dot() / cross()——内积、外积

注意: dot()只支持一维张量计算

# 注意 dot()只支持一维张量计算
t1 = torch.tensor([3,2])
t2 = torch.tensor([4,1])
print(t1,t2)
print(torch.dot(t1,t2))

# 使用二维张量进行dot()操作会报错如下:
# RuntimeError: 1D tensors expected, but got 2D and 2D tensors

tensor1 = torch.eye(3,3)
tensor2 = torch.ones(3,3)
print(tensor1)
print(tensor2)
# print(torch.dot(tensor1,tensor2)) # 此操作会产生上述错误
tensor([3, 2]) tensor([4, 1])
tensor(14)
tensor([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]])
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
# cross()
print(torch.cross(tensor1,tensor2))
tensor([[ 0.,  1., -1.],
        [-1.,  0.,  1.],
        [ 1., -1.,  0.]])

广播机制

当对两个形状不同的Tensor按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个Tensor形状相同后再按元素运算。

# tensor1  1x2
t1 = torch.arange(1,3).view(1,2)
# tensor2 3x1
t2 = torch.arange(1,4).view(3,1)
print(t1)
print(t2)
t1+t2
tensor([[1, 2]])
tensor([[1],
        [2],
        [3]])





tensor([[2, 3],
        [3, 4],
        [4, 5]])

说明: 由于tensor1和tensor2分别是1x23x1的,计算tensor1+tensor2,那么tensor1中第一行被广播(复制)到第二三行,变成一个3x2的,tensor2中第一列被广播到第二列变成一个3x2的,那么就变成了两个3x2的按元素相加
广播后的tensor1:[[1,2],[1,2],[1,2]]
广播后的tensor2:[[1,1],[2,2],[3,3]]

Tensor和Numpy转换

numpy()from_numpy()Tensor和NumPy中的数组相互转换。但是需要注意的一点是:
这两个函数所产生的Tensor和NumPy中的数组共享相同的内存(所以他们之间的转换很快),改变其中一个时另一个也会改变

numpy()——将Tensor转换为Numpy数组
tensor = torch.ones(5)
np = tensor.numpy()
print(tensor,np)
# 对tensor进行+1操作,可以看到numpy内容也发生改变
tensor += 1
print(tensor,np)
# 对numpy进行+1操作,可以看到tensor内容也发生改变
np += 1
print(tensor,np)

tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]
from_nump()——将Numpy数组转换为Tensor
import numpy as np
np_test = np.ones(5)
tensor_test = torch.from_numpy(np_test)
print(np_test,tensor_test)

np_test += 1
print(np_test,tensor_test)
tensor_test += 1
print(np_test,tensor_test)
[1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
[3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)
torch.tensor()——将NumPy数组转换成Tensor

需要注意的是该方法总是会进行数据拷贝,返回的Tensor和原来的数据不再共享内存

import numpy as np
np_test = np.ones(5)
tensor_test = torch.tensor(np_test)
print(np_test,tensor_test)

np_test += 1
print(np_test,tensor_test)
tensor_test += 1
print(np_test,tensor_test)
[1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

Tensor on GPU

使用to() 可以将Tensor在CPU和GPU(需要硬件支持)之间移动
x = torch.tensor([1,2])
if torch.cuda.is_available():
    device = torch.device("cuda")
    y = torch.ones_like(x,device = device)
    x = x.to(device)
    z = x+y
    print(z)
    print(z.to("cpu",torch.double))
tensor([2, 3], device='cuda:0')
tensor([2., 3.], dtype=torch.float64)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值