PyTorch实战 01 - Tensor

432 阅读5分钟

Tensor & Introduction

一、引言

之前操作过torch,是一个lua编写的深度学习训练框架,后来facebook发布了pytorch,使用python语言进行开发

pytorch是在torch的基础上发展而来的,它继承了许多内容,包括各种包的命名和类的定义,比如张量(tensor)

1. 优势

  1. 替代NumPY进行GPU的运算
  2. 提供最大灵活性和速度的深度学习平台

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

官方文档:pytorch.org/tutorials/b…

1. 定义

Tensor(张量)是pytorch最重要的数据结构,类似与numpy库中的ndarray,能够实现多维数据的加/减/乘/除以及更加复杂的操作

  1. 创建tensor
  2. 重置大小
  3. 加/减/乘/除
  4. 矩阵运算
  5. 访问单个元素
  6. in_place操作
  7. numpy格式转换
  8. cuda tensor

2. 常用函数

  1. Torch:pytorch.org/docs/stable…
  2. 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 操作是直接改变给定线性代数、向量、矩阵(张量)的内容而不需要复制的运算。 原地操作直接覆盖
  • 就地操作缺点:
    1. 可能会覆盖计算梯度所需的值,这意味着破坏了模型的训练过程。
    2. 每个就地操作实际上都需要实现来重写计算图。异地操作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)