详解PyTorch框架Tensor基础操作
PyTorch是一个Python深度学习框架,它将数据封装成张量(Tensor)来进行计算。PyTorch中张量就是元素为同一种数据类型的多维矩阵。在PyTorch中,
张量以"类"的形式封装起来,对张量的一些运算、处理方法被封装在类中。
基本创建方式
1. torch.tensor 根据指定数据创建张量
2. torch.Tensor 根据形状创建张量,也可创建指定数据张量
3. torh.IntTensor,torch.FloatTensor,torch.DoubleTensor创建指定类型张量
import torch
import numpy as np
import random
# 1. 根据已有数据创建张量
def test01():
# 1. 创建张量标量
data = torch.tensor(10)
print(data)
# 2. numpy 数组, 由于 data 为 float64, 下⾯代码也使⽤该类型
data = np.random.randn(2, 3)
print(data)
data = torch.tensor(data)
print(data)
# 3. 列表, 下⾯代码使⽤默认元素类型 float32
data = [[10., 20., 30.], [40., 50., 60.]]
data = torch.tensor(data)
print(data)
test01() #也就是用numpy生成的数据,或者手动建一个list的二维列表,tensor都可以改成张量形成
tensor(10)
[[ 0.99729177 0.8347698 -0.19685624]
[ 0.31439596 -0.5259964 0.58403897]]
tensor([[ 0.9973, 0.8348, -0.1969],
[ 0.3144, -0.5260, 0.5840]], dtype=torch.float64)
tensor([[10., 20., 30.],
[40., 50., 60.]])
# 2. 创建指定形状的张量
def test02():
#程序输出结果:
# 1. 创建2⾏4列的张量, 默认 dtype 为 float32
data = torch.Tensor(2, 4)
print(data)
# 2. 注意: 如果传递列表, 则创建包含指定元素的张量
data = torch.Tensor([10])
print(data)
data = torch.Tensor([10, 20])
print(data)
test02()
tensor([[-1.2085e+21, 1.9716e-42, 0.0000e+00, 0.0000e+00],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00]])
tensor([10.])
tensor([10., 20.])
3. 使⽤具体类型的张量
def test03():
1. 创建2⾏3列, dtype 为 int32 的张量
data = torch.IntTensor(2, 3)
print(data)
2. 注意: 如果传递的元素类型不正确, 则会进⾏类型转换
data = torch.IntTensor([2.5, 3.3])
print(data)
3. 其他的类型
data = torch.ShortTensor(2,3) # int16
print(data)
data = torch.LongTensor(2,3) # int64
print(data)
data = torch.FloatTensor(2,3) # float32
print(data)
data = torch.DoubleTensor(2,3) # float64
print(data)
if name == ‘main’:
test03()
创建线性和随机张量
1. torch.arange和torch.linspace创建线性张量
2. torch.random.init_seed和torch.random.manual_seed随机种子设置
3. torch.randn 创建随机张量
# 1. 创建线性空间的张量
def test01():
# 1. 在指定区间按照步⻓⽣成元素 [start, end, step)
data = torch.arange(0, 10, 2)
print(data)
# 2. 在指定区间按照元素个数⽣成
data = torch.linspace(0, 11, 10)
print(data)
def test02():
1. 创建随机张量
data = torch.randn(2, 3) # 创建2⾏3列张量
print(data)
2. 随机数种⼦设置
print('随机数种⼦:', torch.random.initial_seed())
torch.random.manual_seed(100)
print('随机数种⼦:', torch.random.initial_seed())
torch.random.manual_seed(torch.initial_seed())
print('随机数种⼦:', torch.random.initial_seed())
if __name__ == '__main__':
test01()
tensor([0, 2, 4, 6, 8])
tensor([ 0.0000, 1.2222, 2.4444, 3.6667, 4.8889, 6.1111, 7.3333, 8.5556,
9.7778, 11.0000])
if __name__ == '__main__':
test02()
tensor([[ 0.3607, -0.2859, -0.3938],
[ 0.2429, -1.3833, -2.3134]])
随机数种⼦: 100
随机数种⼦: 100
随机数种⼦: 100
创建01张量
1. torhc.ones和torch.ones_like创建全1张量
2. torch.zeros和torch.zeros_like创建全0张量
3. torch.full和torch.full_like创建全为指定张量
# 创建全0张量
def test01():
# 1. 创建指定形状全0张量
data = torch.zeros(2, 3)
print(data)
# 2. 根据张量形状创建全0张量
data = torch.zeros_like(data)
print(data)
# 2. 创建全1张量
def test02():
# 1. 创建指定形状全1张量
data = torch.ones(2, 3)
print(data)
# 2. 根据张量形状创建全1张量
data = torch.ones_like(data)
print(data)
# 3. 创建全为指定值的张量
def test03():
# 1. 创建指定形状指定值的张量
data = torch.full([2, 3], 10)
print(data)
# 2. 根据张量形状创建指定值的张量
data = torch.full_like(data, 20)
print(data)
if __name__ == '__main__':
test01()
test02()
test03()
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[10, 10, 10],
[10, 10, 10]])
tensor([[20, 20, 20],
[20, 20, 20]])
张量元素类型转换
1. tensor.type(torch.Double Tensor)
2. torch.double()
def test():
data = torch.full([2, 3], 10)
print(data.dtype)
默认整型是64,和LongTensor一样
将 data 元素类型转换为 float64 类型
1. 第⼀种⽅法
data = data.type(torch.DoubleTensor)
print(data.dtype)
转换为其他类型
data = data.type(torch.ShortTensor)
print(data.dtype)
data = data.type(torch.IntTensor)
print(data.dtype)
data = data.type(torch.LongTensor)
print(data.dtype)
data = data.type(torch.FloatTensor)
print(data.dtype)
2. 第⼆种⽅法
data = data.double()
print(data.dtype)
转换为其他类型
data = data.short()
data = data.int()
data = data.long()
data = data.float()
if name == ‘main’:
test()
## 张量基本运算
### add,sub,mul,div,neg 等,如果是带下划线的就是修改原数据,不带的话就是不修改。
def test():
data = torch.randint(0, 10, [2, 3])
print(data)
print('-' * 50)
# 1. 不修改原数据
new_data = data.add(10) # 等价 new_data = data + 10
print(new_data)
print(data)
print('-' * 50)
# 2. 直接修改原数据
# 注意: 带下划线的函数为修改原数据本身
data.add_(10) # 等价 data += 10
print(data)
# 3. 其他函数
print(data.sub(100))
print(data.mul(100))
print(data.div(100))
print(data.neg())
if __name__ == '__main__':
test()
tensor([[0, 2, 5],
[9, 5, 1]])
--------------------------------------------------
tensor([[10, 12, 15],
[19, 15, 11]])
tensor([[0, 2, 5],
[9, 5, 1]])
--------------------------------------------------
tensor([[10, 12, 15],
[19, 15, 11]])
tensor([[-90, -88, -85],
[-81, -85, -89]])
tensor([[1000, 1200, 1500],
[1900, 1500, 1100]])
tensor([[0.1000, 0.1200, 0.1500],
[0.1900, 0.1500, 0.1100]])
tensor([[-10, -12, -15],
[-19, -15, -11]])
阿达玛积
矩阵对应位置元素相乘
import numpy as np
import torch
def test():
data1 = torch.tensor([[2, 5], [3, 4]])
data2 = torch.tensor([[3, 7], [7, 8]])
# 第⼀种⽅式
data = torch.mul(data1, data2)
print(data)
print('-' * 50)
# 第⼆种⽅式
data = data1 * data2
print(data)
print('-' * 50)
if __name__ == '__main__':
test()
tensor([[ 6, 35],
[21, 32]])
--------------------------------------------------
tensor([[ 6, 35],
[21, 32]])
--------------------------------------------------
## 点积运算
### 点积运算要求第⼀个矩阵 shape: (n, m),第⼆个矩阵 shape: (m, p), 两个矩阵点积运算 shape 为: (n, p)。
### 1. 运算符 @ ⽤于进⾏两个矩阵的点乘运算
### 2. torch.mm ⽤于进⾏两个矩阵点乘运算, 要求输⼊的矩阵为2维
### 3. torch.bmm ⽤于批量进⾏矩阵点乘运算, 要求输⼊的矩阵为3维
### 4. torch.matmul 对进⾏点乘运算的两矩阵形状没有限定.
import numpy as np
import torch
# 1. 点积运算
def test01():
data1 = torch.tensor([[1, 2], [3, 4], [5, 6]])
data2 = torch.tensor([[5, 6], [7, 8]])
# 第⼀种⽅式
data = data1 @ data2
print(data)
print('-' * 50)
# 第⼆种⽅式
data = torch.mm(data1, data2)
print(data)
print('-' * 50)
# 第三种⽅式
data = torch.matmul(data1, data2)
print(data)
print('-' * 50)
# 2. torch.mm 和 torch.matmull 的区别
def test02():
# matmul 可以两个维度可以不同
# 第⼀个张量: (3, 4, 5)
# 第⼆个张量: (5, 4)
# torch.mm 不可以相乘,⽽ matmul 则可以相乘
print(torch.matmul(torch.randn(3, 4, 5), torch.randn(5, 4)).shape)
print(torch.matmul(torch.randn(5, 4), torch.randn(3, 4, 5)).shape)
# 3. torch.mm 函数的⽤法
def test03():
# 批量点积运算
# 第⼀个维度为 batch_size
# 矩阵的⼆三维要满⾜矩阵乘法规则
data1 = torch.randn(3, 4, 5)
data2 = torch.randn(3, 5, 8)
data = torch.bmm(data1, data2)
print(data.shape)
if __name__ == '__main__':
test01()
test02()
test03()
tensor([[19, 22],
[43, 50],
[67, 78]])
--------------------------------------------------
tensor([[19, 22],
[43, 50],
[67, 78]])
--------------------------------------------------
tensor([[19, 22],
[43, 50],
[67, 78]])
--------------------------------------------------
torch.Size([3, 4, 4])
torch.Size([3, 5, 5])
torch.Size([3, 4, 8])
指定运算设备
PyTorch 默认会将张量创建在 CPU 控制的内存中, 即: 默认的运算设备为 CPU。我们也可以将张量创建在
GPU 上, 能够利⽤对于矩阵计算的优势加快模型训练。将张量移动到 GPU 上有两种⽅法:
1. 使⽤ cuda ⽅法
2. 直接在 GPU 上创建张量
3. 使⽤ to ⽅法指定设备
# 1. 使⽤ cuda ⽅法
def test01():
data = torch.tensor([10, 20 ,30])
print('存储设备:', data.device)
# 如果安装的不是 gpu 版本的 PyTorch
# 或电脑本身没有 NVIDIA 卡的计算环境
# 下⾯代码可能会报错
#data = data.cuda()
#print('存储设备:', data.device)
# 使⽤ cpu 函数将张量移动到 cpu 上
data = data.cpu()
print('存储设备:', data.device)
# 输出结果:
# 存储设备: cpu
# 存储设备: cuda:0
# 存储设备: cpu
test01()
存储设备: cpu
存储设备: cpu
# 2. 直接将张量创建在 GPU 上
def test02():
data = torch.tensor([10, 20, 30], device='cuda:0')
print('存储设备:', data.device)
# 使⽤ cpu 函数将张量移动到 cpu 上
data = data.cpu()
print('存储设备:', data.device)
# 输出结果:
# 存储设备: cuda:0
# 存储设备: cpu
test02()
存储设备: cpu
存储设备: cpu
def test03():
data = torch.tensor([10, 20, 30])
print('存储设备:', data.device)
data = data.to('cuda:0')
print('存储设备:', data.device)
# 输出结果:
# 存储设备: cpu
# 存储设备: cuda:0
# 4. 存储在不同设备的张量不能运算
def test04():
data1 = torch.tensor([10, 20, 30], device='cuda:0')
data2 = torch.tensor([10, 20, 30])
print(data1.device, data2.device)
# RuntimeError: Expected all tensors to be on the same device,
# but found at least two devices, cuda:0 and cpu!
data = data1 + data2
print(data)
张量类型转换
张量转换为numpy数组
使⽤ Tensor.numpy 函数可以将张量转换为 ndarray 数组,但是共享内存,可以使⽤ copy 函数避免共
享。
# 1. 将张量转换为 numpy 数组
def test01():
data_tensor = torch.tensor([2, 3, 4])
# 使⽤张量对象中的 numpy 函数进⾏转换
data_numpy = data_tensor.numpy()
print(type(data_tensor))
print(type(data_numpy))
# 注意: data_tensor 和 data_numpy 共享内存
# 修改其中的⼀个,另外⼀个也会发⽣改变
# data_tensor[0] = 100
data_numpy[0] = 100
print(data_tensor)
print(data_numpy)
if __name__ == '__main__':
test01()
<class 'torch.Tensor'>
<class 'numpy.ndarray'>
tensor([100, 3, 4])
[100 3 4]
numpy转换为张量
1. 使⽤ torch.from_numpy 可以将 ndarray 数组转换为 Tensor,默认共享内存,使⽤ copy 函数避免共享。
2. 使⽤ torch.tensor 可以将 ndarray 数组转换为 Tensor,默认不共享内存。
def test01():
data_numpy = np.array([2, 3, 4])
# 将 numpy 数组转换为张量类型
# 1. from_numpy
# 2. torch.tensor(ndarray)
# 浅拷⻉
data_tensor = torch.from_numpy(data_numpy)
# nunpy 和 tensor 共享内存
# data_numpy[0] = 100
data_tensor[0] = 100
print(data_tensor)
print(data_numpy)
print(data_tensor.dtype)
print(data_numpy.dtype)
data_numpy[1] = 200
print(data_tensor)
print(data_numpy)
test01()
#这个就很神奇,共享内存,一段数据,2个名字,一个numpy,一个tensor.改一种一个数据
#另一个也会改
tensor([100, 3, 4], dtype=torch.int32)
[100 3 4]
torch.int32
int32
tensor([100, 200, 4], dtype=torch.int32)
[100 200 4]
# 2. 使⽤ torch.tensor 函数
def test02():
data_numpy = np.array([2, 3, 4])
data_tensor = torch.tensor(data_numpy)
# nunpy 和 tensor 不共享内存
# data_numpy[0] = 100
data_tensor[0] = 100
print(data_tensor)
print(data_numpy)
if __name__ == '__main__':
test02()
tensor([100, 3, 4], dtype=torch.int32)
[2 3 4]
标量张量和数字的转换
可以通过item取出
def test03():
# 当张量只包含⼀个元素时, 可以通过 item 函数提取出该值
data = torch.tensor([30])
print(data.item())
data = torch.tensor(30)
print(data.item())
test03()
30
30
张量拼接操作
张量的拼接操作在神经⽹络搭建过程中是⾮常常⽤的⽅法,例如: 在后⾯将要学习到的残差⽹络、注意⼒机
制中都使⽤到了张量拼接
1. torch.cat 函数可以将两个张量根据指定的维度拼接起来.
2. torch.stack 函数可以将两个张量根据指定的维度叠加起来.
def test():
data1 = torch.randint(0, 10, [3, 5, 4])
data2 = torch.randint(0, 10, [3, 5, 4])
print(data1)
print(data2)
print('-' * 50)
# 1. 按0维度拼接
new_data = torch.cat([data1, data2], dim=0)
print(new_data.shape)
print('-' * 50)
# 2. 按1维度拼接
new_data = torch.cat([data1, data2], dim=1)
print(new_data.shape)
print('-' * 50)
# 3. 按2维度拼接
new_data = torch.cat([data1, data2], dim=2)
print(new_data.shape)
if __name__ == '__main__':
test()
tensor([[[9, 6, 3, 1],
[7, 4, 2, 6],
[7, 4, 4, 1],
[8, 9, 7, 5],
[4, 3, 3, 4]],
[[2, 0, 8, 6],
[3, 8, 7, 2],
[7, 4, 8, 9],
[1, 9, 7, 9],
[6, 1, 1, 2]],
[[2, 9, 7, 5],
[8, 7, 7, 0],
[9, 4, 6, 6],
[3, 3, 1, 7],
[6, 7, 1, 6]]])
tensor([[[3, 4, 2, 5],
[2, 3, 5, 3],
[0, 1, 5, 5],
[4, 9, 7, 4],
[4, 7, 6, 1]],
[[7, 0, 8, 2],
[0, 5, 0, 1],
[5, 7, 9, 4],
[4, 7, 0, 2],
[2, 2, 9, 7]],
[[0, 6, 3, 6],
[6, 7, 2, 7],
[1, 9, 2, 4],
[5, 2, 3, 6],
[9, 6, 5, 2]]])
--------------------------------------------------
torch.Size([6, 5, 4])
--------------------------------------------------
torch.Size([3, 10, 4])
--------------------------------------------------
torch.Size([3, 5, 8])
def test():
data1= torch.randint(0, 10, [2, 3])
data2= torch.randint(0, 10, [2, 3])
print(data1)
print(data2)
new_data = torch.stack([data1, data2], dim=0)
print(new_data.shape)
print(new_data)
new_data = torch.stack([data1, data2], dim=1)
print(new_data.shape)
print(new_data)
new_data = torch.stack([data1, data2], dim=2)
print(new_data.shape)
print(new_data)
if __name__ == '__main__':
test()
tensor([[1, 9, 1],
[9, 3, 6]])
tensor([[6, 8, 7],
[4, 8, 1]])
torch.Size([2, 2, 3])
tensor([[[1, 9, 1],
[9, 3, 6]],
[[6, 8, 7],
[4, 8, 1]]])
torch.Size([2, 2, 3])
tensor([[[1, 9, 1],
[6, 8, 7]],
[[9, 3, 6],
[4, 8, 1]]])
torch.Size([2, 3, 2])
tensor([[[1, 6],
[9, 8],
[1, 7]],
[[9, 4],
[3, 8],
[6, 1]]])