【深度学习】S1 预备知识 P1 张量

目录

  • 张量
  • 创建第一个张量
    • 张量的下载与引入
    • 创建第一个张量
  • 张量的大小和形状
    • 张量的形状
    • 张量的大小
  • 改变张量的形状
  • 创建特殊张量
  • 张量的基本运算
    • 按元素运算
    • 张量连结
    • 逻辑运算
    • 张量求和
  • 张量的广播机制
  • 张量的索引与切片
    • 索引、切片访问张量
    • 通过切片方式节省内存占用
  • 张量转换为其他对象

张量

张量(Tensor)是深度学习中用于表示和处理多维数据的数据结构。张量与 Numpy 类似,但是不同的是深度学习框架专门为张量提供了丰富的操作API,包括创建张量、数据转换、数学运算、索引和切片等,使张量可以使用 GPU 加速,大大提高处理大量数据时的计算速度;同时提供自动微分 Autograd,自动计算和应用梯度。

简单的说,张量(Tensor)就是为深度学习框架量身定制的数据结构。使用张量,深度学习在处理数据和模型计算上更加方便和高效。


创建第一个张量

张量的下载与引入

张量是深度学习框架的数据结构,读者首先需要选择一种深度学习框架(TensorFlow、PyTorch…)并下载,本博文基于 PyTorch 深度学习框架。

  1. 下载 PyTorch 框架:
# 首先下载PyTorch框架
pip install torch==1.12.0
pip install torchvision==0.13.0
# 本bash执行于Anaconda Prompt
  1. 引入 Tensor 张量:
# 建议读者使用PyCharm或者VSCode IDE工具
import torch

创建第一个张量

第一个张量我们使用 arange 创建一个行向量 x:

x = torch.arange(12)
print(x)
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

x 为创建的包含 12 个整数元素的张量。


张量的大小和形状

张量的形状

通过张量的 shape 属性来访问张量的形状。

print(x.shape)
torch.Size([12])

张量的大小

如果只想知道张量中元素的数量,可以使用 numel() 函数。

print(x.numel())
12

改变张量的形状

如果只想改变张量的形状而不改变张量元素数量和值,可以通过使用 reshape() 函数。

y = x.reshape(3,4)
print(y)
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])

把张量x从形状(12,)的行向量转换为形状为(3,4)的矩阵y。新的张量形状发生改变,但是元素值并没有改变。

张量的转换也支持自动计算维度的功能,比如:

# 下列 z_1, z_2 张量同上述 reshape(3, 4) 函数功能
z_1 = x.reshape(-1, 4)
z_2 = x.reshape(3, -1)

创建特殊张量

有时,我们希望创建全0、全1张量,或者从特定随机分布中随机采样的数字来初始化矩阵,如下。

创建全 0 张量:

# 创建一个形状为 (2, 3, 4) 、值全部为 0 的三维张量
import torch
x_1 = torch.zeros(2,3,4)
print(x_1)
tensor([[[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]],

        [[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]]])

创建全 1 张量:

import torch
x_2 = torch.ones(2,3,4)
print(x_2)
print(x_2.shape)
tensor([[[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]],

        [[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]]])
torch.Size([2, 3, 4])

创建正态分布随机采样张量:
创建一个形状为(3,4)的张量,其中每个元素从均值为 0, 标准差为 1 的标准高斯分布中随机采样。

import torch
x = torch.randn(3,4)
print(x)
tensor([[ 0.8532, -0.9053, -0.6921,  0.9674],
        [-0.8108, -1.4881, -0.0434,  0.1967],
        [-1.7507, -0.4498,  1.3718, -0.6994]])

张量的基本运算

按元素运算

数学运算中最常见的标准算数运算符(+,-,*,/和**)。将两个张量数组作为输入,按元素运算将二元运算符应用于两个数组中的每对位置对应的元素:

import torch

x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
print("x+y=", x+y, "\nx-y=", x-y, "\nx*y=", x*y, "\nx/y=", x/y, "\nx**y=", x**y)
x+y= tensor([ 3.,  4.,  6., 10.]) 
x-y= tensor([-1.,  0.,  2.,  6.]) 
x*y= tensor([ 2.,  4.,  8., 16.]) 
x/y= tensor([0.5000, 1.0000, 2.0000, 4.0000]) 
x**y= tensor([ 1.,  4., 16., 64.])

按元素计算很重要的一点就是两个张量的形状 shape 必须相同,否则将因找不到对应位置的张量从而无法计算。

张量连结

除了按元素计算外,还可以将多个张量连结在一起 cat(tensors, dim=),端对端叠起来形成更大的张量。

import torch

x = torch.arange(12).reshape(3, 4)
y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
print(torch.cat((x,y), dim=1))

将张量 x(3,4)与张量 y(3,4)横向连结形成更大的张量,形状(3,8)。

tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
        [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
        [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]])

dim=0 的连结结果将为形状(6,4)。

逻辑运算

通过逻辑运算构建张量,对于两个张量的每个位置,如果对照位置相同,则对应位置值为 True,否则为 False;

import torch

x = torch.arange(12).reshape(3, 4)
y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

print("x:", x)
print("y:", y)
print("x==y:", x==y)
x: tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
y: tensor([[2., 1., 4., 3.],
        [1., 2., 3., 4.],
        [4., 3., 2., 1.]])
x==y: tensor([[False,  True, False,  True],
        [False, False, False, False],
        [False, False, False, False]])

张量求和

如果想对张量中所有元素进行求和,使用 sum() 函数;

print("x:", x)
print(x.sum())
x: tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
tensor(66)

张量的广播机制

在上述张量的基本运算中,我们很多操作都规定需要两个张量保持相同的形状才能完成运算。但是在广播机制中,则不同。张量的广播机制用于扩展张量,虽然不要求两个向量完全相同,但是要求两个向量要分别满足形状:(x, y)与(y, z)方才可以进行运算。

e . g . e.g. e.g.

import torch

a = torch.arange(3).reshape(3, 1)
b = torch.arange(2).reshape(1, 2)

print("a=", a)
print("b=", b)
print("a+b=", a+b)
print("a*b=", a*b)
a= tensor([[0],
        [1],
        [2]])
b= tensor([[0, 1]])
a+b= tensor([[0, 1],
        [1, 2],
        [2, 3]])
a*b= tensor([[0, 0],
        [0, 1],
        [0, 2]])

上述张量的广播机制操作中,我们将张量 a(3,1)与张量 b(1,2)广播扩展为一个更大的张量,形状(3,2)。


张量的索引与切片

索引、切片访问张量

如 Python 中数组一样,张量中的元素支持通过索引访问。与其他数组一样,张量中第一个元素的索引值为 0,最后一个元素的索引值为 -1。

import torch

x = torch.arange(12)
print("x=", x)
print("x[0]=", x[0], "\nx[-1]=", x[-1])
# 通过切片方式访问张量中的元素值
print("x[1:3]=", x[1:3])
x= tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
x[0]= tensor(0) 
x[-1]= tensor(11)
x[1:3]= tensor([1, 2])

当然张量的操作支持通过索引改变其中元素的值;

import torch

x = torch.arange(12)
print(x)
x[-2] = 22
print(x)
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 11])

通过切片方式节省内存占用

在张量中,运行一些操作可能会导致需要为新结果分配内存。在深度学习框架张量中,我们可以通过 id() 函数来访问一个张量占用内存的物理位置。

import torch

x = torch.arange(12)
print(id(x))
x = x + 1
print(id(x))
2606440820144
2606440818944

打印发展张量 x 在计算前后更换了占用的内存位置,或者说,新计算后为张量 x 新分配了内存空间存储其结果。

这种新分配内存空间不仅产生了不必要的内存占用,还会因为其他引用旧的内存位置导致出错。为了避免这种错误,通过切片方式原地更新;

import torch

x = torch.arange(12)
print(id(x))
x[:] = x + 1
print(id(x))
2296319225264
2296319225264

观察发现,运算前后占用的内存地址空间相同。


张量转换为其他对象

Torch 张量与 Numpy 数组共享底层内存,可以就地操作转换;

张量转换为数组:
a.item(), float(a), int(a)

import torch

a = torch.arange(12)
b = a.numpy()
print(type(a), type(int(a[1])), type(b))
<class 'torch.Tensor'> <class 'int'> <class 'numpy.ndarray'>

数组转换为张量:

import numpy as np
import torch

x = np.arange(12)
y = torch.tensor(x)
print(type(x), type(y))
<class 'numpy.ndarray'> <class 'torch.Tensor'>

以上内存便是预备知识的第一部分张量的相关介绍;
如有任何问题,请联系或者留言;

2024.2.12

你可能感兴趣的:(#,深度学习,深度学习,人工智能)