Tensor & Introduction
一、引言
之前操作过torch,是一个lua编写的深度学习训练框架,后来facebook发布了pytorch,使用python语言进行开发
pytorch是在torch的基础上发展而来的,它继承了许多内容,包括各种包的命名和类的定义,比如张量(tensor)
1. 优势
- 替代NumPY进行GPU的运算
- 提供最大灵活性和速度的深度学习平台
2. PyTorch的安装
直接去官网选择对应的CUDA版本进行安装即可
3. 载入torch
from __future__ import print_function
import torch
# 查看torch版本和能否使用GPU进行运算
torch.__version__
'1.11.0'
torch.cuda.is_available()
True
二、Tensor
1. 定义
Tensor(张量)是pytorch最重要的数据结构,类似与numpy库中的ndarray,能够实现多维数据的加/减/乘/除以及更加复杂的操作
- 创建tensor
- 重置大小
- 加/减/乘/除
- 矩阵运算
- 访问单个元素
- in_place操作
- numpy格式转换
- cuda tensor
2. 常用函数
- Torch:pytorch.org/docs/stable…
- Torch.Tensor:pytorch.org/docs/stable…
3. 创建Tensor
1. 创建一个5行3列的tensor
# 赋值为0
torch.zeros(5, 3)
# 赋值为1
x = torch.ones(5, 3)
y = x.new_ones(5)
z = torch.ones_like(x)
# 未初始化,不会赋初值值,分配所得的存储空间内是什么值就是什么值
torch.empty(5, 3)
# 赋值均匀分布的随机数,大小在[0,1)
torch.rand(5, 3)
torch.randn_like(x)
tensor([[ 2.1053, 0.7848, 0.7545],
[ 0.0237, -0.1103, 0.0283],
[ 0.4127, -0.8059, -0.7510],
[-1.2132, 1.5169, -0.1373],
[ 0.0527, 0.0875, -0.0274]])
y
tensor([1., 1., 1., 1., 1.])
torch.ones_like和torch.randn_like都需要传入Tensor参数,不能传入其他数据
2. 也可以使用列表来生成Tensor
# 先列后行,使用列表生成式
list = [[i+j for i in range(3)] for j in range(5) ]
list
[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
x = torch.tensor(list)
x
tensor([[0, 1, 2],
[1, 2, 3],
[2, 3, 4],
[3, 4, 5],
[4, 5, 6]])
3. 使用函数arange
# 创建一个连续列表,前开后闭
torch.arange(2, 10)
tensor([2, 3, 4, 5, 6, 7, 8, 9])
4. 使用已赋值的Tensor进行初始化
# 复制张量的大小一致
w=torch.ones(3,2)
# 使用列表生成式的结果也要用[]括起来
x = torch.tensor([[i*j for i in range(2)] for j in range(3)])
w.copy_(x)
w
tensor([[0., 0.],
[0., 1.],
[0., 2.]])
4. 设置数据类型
1. 在创建tensor的同时设置数据类型,比如
torch.zeros(5, 3, dtype=torch.float)
# 或
torch.tensor([[1 for i in range(3)] for j in range(5)], dtype=torch.float)
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
2. 常用数据类型包括
- torch.float
- torch.double
3. 查看数据类型
# 均值滤波
x = torch.ones((3,3))
x.dtype
torch.float32
可以看出Tensor的默认数据类型是float32,若要进行取整,那么应该选择uint32
5. 获取尺寸
x = torch.arange(3, 9)
x.size()
torch.Size([6])
torch.Size类型实际上是一个元组(tuple),可以执行所有元组操作
6. 重置尺寸
# 数据类型 float32 , 尺寸 : (4,4)
x = torch.randn(4, 4)
x
tensor([[-2.5465, 0.5438, -1.5152, 1.0715],
[-0.2969, -0.9630, -0.5485, 0.0130],
[-1.2639, -0.9325, 0.4830, 0.8374],
[ 0.5059, 0.0404, 0.9631, 0.5070]])
# 重置大小为16
y = x.view(16)
# 重置大小为2x8
z = x.view(-1, 8) # 输入-1值,那么该维度大小会参考其他维度
print(x.size(), y.size(), z.size())
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
或者使用函数torch.Tensor.reshape
y = x.reshape(16, 1)
y
tensor([[-2.5465],
[ 0.5438],
[-1.5152],
[ 1.0715],
[-0.2969],
[-0.9630],
[-0.5485],
[ 0.0130],
[-1.2639],
[-0.9325],
[ 0.4830],
[ 0.8374],
[ 0.5059],
[ 0.0404],
[ 0.9631],
[ 0.5070]])
7. 加减乘除运算
进行加/减/乘/除的张量大小相同,在对应位置上进行操作——阵列操作,而非矩阵操作
x = torch.ones(2, 3)
y = torch.randn(2, 3)
# 加
add = torch.add(x, y)
# 减 x - y
sub = torch.sub(x, y)
# 乘
mul = torch.mul(x, y)
# 除 x / y
div = torch.div(x,y)
print(x,'\n',y,'\n',add,'\n',sub,'\n',mul,'\n',div)
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[ 0.7922, 1.2851, 0.9056],
[-0.6557, -0.0830, -0.0858]])
tensor([[1.7922, 2.2851, 1.9056],
[0.3443, 0.9170, 0.9142]])
tensor([[ 0.2078, -0.2851, 0.0944],
[ 1.6557, 1.0830, 1.0858]])
tensor([[ 0.7922, 1.2851, 0.9056],
[-0.6557, -0.0830, -0.0858]])
tensor([[ 1.2623, 0.7781, 1.1043],
[ -1.5252, -12.0516, -11.6563]])
也可以使用参数out来复制结果
# 设置同样大小数组
re = torch.empty(2, 3)
# 加法,使用out传入re意味着使用re来存储运算结果
torch.add(x, y, out=re)
tensor([[1.7922, 2.2851, 1.9056],
[0.3443, 0.9170, 0.9142]])
re
tensor([[1.7922, 2.2851, 1.9056],
[0.3443, 0.9170, 0.9142]])
8. 矩阵运算
# 转置
x = torch.ones(2,3) # 生成一个2行3列
y = x.t() # 得到一个3行2列
y.size()
torch.Size([3, 2])
# 矩阵乘法
x = torch.ones((3,3))
y = torch.randn((3,3))
res1 = x.mm(y)
# 阵列乘法
res2 = x.mul(y)
print(x,'\n',y,'\n',res2,'\n',res1)
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
tensor([[-0.3411, -0.2925, -0.1778],
[ 0.8772, -0.0283, -1.3754],
[ 1.1416, -0.2044, -1.5349]])
tensor([[-0.3411, -0.2925, -0.1778],
[ 0.8772, -0.0283, -1.3754],
[ 1.1416, -0.2044, -1.5349]])
tensor([[ 1.6777, -0.5253, -3.0881],
[ 1.6777, -0.5253, -3.0881],
[ 1.6777, -0.5253, -3.0881]])
9. 访问单个元素
可以执行类似Numpy数组的取值操作
x = torch.tensor([x for x in range(6)])
print(x)
# 取值
print(x[0])
# 切片
print(x[:3])
tensor([0, 1, 2, 3, 4, 5])
tensor(0)
tensor([0, 1, 2])
# 高级切片
print(x[::2])
tensor([0, 2, 4])
使用函数item()将单个tensor转换成数值(标量,scalar)
y = x[0].item()
type(y)
int
10. in_place操作
tensor可以执行in_place操作,只需要在函数末尾添加下划线
- in-place 操作 in-place 操作是直接改变给定线性代数、向量、矩阵(张量)的内容而不需要复制的运算。 原地操作直接覆盖
- 就地操作缺点:
- 可能会覆盖计算梯度所需的值,这意味着破坏了模型的训练过程。
- 每个就地操作实际上都需要实现来重写计算图。异地操作Out-of-place分配新对象并保留对旧图的引用,而就地操作则需要更改表示此操作的函数的所有输入的创建者。
# 加
x.add_(y)
# 减
x.sub_(y)
# 转置
x.t_()
tensor([0, 1, 2, 3, 4, 5])
11. numpy格式转换
torch支持tensor和numpy数组的转换
1. tensor转换为numpy
a = torch.ones(5)
b = a.numpy()
b
array([1., 1., 1., 1., 1.], dtype=float32)
2. numpy转换成tensor
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
b
tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
除了CharTensor以外,CPU上的其他Tensor都支持和Numpy的转换
注意:转换前后的数组共享底层内存,改变会同时发生
12. cuda tensor
利用CUDA调用GPU进行tensor运算,需要使用函数to进行GPU和CPU的转换
x = torch.tensor(5)
if torch.cuda.is_available(): # 测试cuda是否有效
device = torch.device("cuda") # 生成一个cuda对象
y = torch.ones_like(x, device=device) # 直接在GPU中创建y
x = x.to(device) # 转换CPU数据到GPU中,也可直接使用函数`.to("cuda")`
z = x + y # GPU运算
print(x)
print(y)
print(z)
print(z.to('cpu', torch.double)) # 转换数据到CPU,同时转换类型
tensor(5, device='cuda:0')
tensor(1, device='cuda:0')
tensor(6, device='cuda:0')
tensor(6., dtype=torch.float64)