目录
[标量(0D 张量)](#标量(0D 张量))
[向量(1D 张量)](#向量(1D 张量))
[3D 张量与高维张量](#3D 张量与高维张量)
[1. 从列表或NumPy数组创建](#1. 从列表或NumPy数组创建)
[2. 使用特定的初始化方法](#2. 使用特定的初始化方法)
[3. 从已有的Tensor创建](#3. 从已有的Tensor创建)
[2. 改变 Tensor 的形状](#2. 改变 Tensor 的形状)
[3. 移除和增加Tensor 的维度](#3. 移除和增加Tensor 的维度)
[4.交换Tensor 维度](#4.交换Tensor 维度)
[3.通过索引和切片修改 Tensor](#3.通过索引和切片修改 Tensor)
[(3).使用 torch 的索引函数](#(3).使用 torch 的索引函数)
前言
PyTorch可以说是三大主流框架中最适合初学者学习的了,相较于其他主流框架,PyTorch的简单易用性使其成为初学者们的首选。这样我想要强调的一点是,框架可以类比为编程语言,仅为我们实现项目效果的工具,也就是我们造车使用的轮子,我们重点需要的是理解如何使用Torch去实现功能而不要过度在意轮子是要怎么做出来的,那样会牵扯我们太多学习时间。以后就出一系列专门细解深度学习框架的文章,但是那是较后期我们对深度学习的理论知识和实践操作都比较熟悉才好开始学习,现阶段我们最需要的是学会如何使用这些工具。
深度学习的内容不是那么好掌握的,包含大量的数学理论知识以及大量的计算公式原理需要推理。且如果不进行实际操作很难够理解我们写的代码究极在神经网络计算框架中代表什么作用。不过我会尽可能将知识简化,转换为我们比较熟悉的内容,我将尽力让大家了解并熟悉神经网络框架,保证能够理解通畅以及推演顺利的条件之下,尽量不使用过多的数学公式和专业理论知识。以一篇文章快速了解并实现该算法,以效率最高的方式熟练这些知识。
博主专注数据建模四年,参与过大大小小数十来次数学建模,理解各类模型原理以及每种模型的建模流程和各类题目分析方法。此专栏的目的就是为了让零基础快速使用各类数学模型、机器学习和深度学习以及代码,每一篇文章都包含实战项目以及可运行代码。博主紧跟各类数模比赛,每场数模竞赛博主都会将最新的思路和代码写进此专栏以及详细思路和完全代码。希望有需求的小伙伴不要错过笔者精心打造的专栏。
一、PyTorch数据结构-Tensor
1.什么是Tensor
Tensor是PyTorch中最基本的数据结构,可以看作是一个多维数组(矩阵的扩展)。与NumPy中的数组类似,与其不同的是ndarrays不能使用GPU加速计算但Tensor可以在GPU上运行,这使得它在深度学习领域特别强大,归根结底还是得依赖庞大的算力支持我们才能尽可能得到更加精准的数据,通常我们叫它张量。
2.数据Tensor使用场景
没有引入张量这个概念之前,大家其实就在很多场景接触到了这些数据。了解到张量以后大家自然而然的就会明白了。张量这一概念的核心在于,它是一个数据容器。它包含的数据几乎总是数值数据,因此它是数字的容器。你可能对矩阵很熟悉,它是二维张量。张量是矩阵向任意维度的推广[注意,张量的维度(dimension)通常叫作轴(axis)]。
以下是一些常见的使用场景:
- 神经网络的构建和训练:神经网络的输入、权重、输出、梯度等都是以Tensor的形式表示。PyTorch、TensorFlow等深度学习框架都是基于Tensor进行运算的。
- 图像处理:图像通常以多维数组的形式表示,例如RGB图像可以表示为高度、宽度和3个颜色通道的Tensor。
- 自然语言处理:在处理文本数据时,可以将文本编码成Tensor,每个单词可以映射为一个数字或一个词向量。
- 时间序列分析:例如股票价格、天气数据等,可以表示成时间、特征维度的Tensor。
- 推荐系统:用户-物品交互矩阵可以表示为一个二维的Tensor。
- 强化学习:在Q-learning等算法中,状态、动作、奖励等信息都可以用Tensor表示。
- 计算机视觉任务:如目标检测、分割、人脸识别等任务,输入图像、特征图、目标框坐标等都可以用Tensor表示。视频为5D张量,形状为 (samples, frames, height, width, channels) 或 (samples,frames, channels, height, width) ,图片4D张量形状为 (samples, height, width, channels) 或 (samples, channels,height, width) 。
- 自动驾驶和机器人控制:传感器数据(如摄像头、激光雷达等)可以表示成Tensor,用于训练和实时控制。
- 生成对抗网络(GAN):GAN中的生成器和判别器都是基于神经网络和Tensor进行训练和推断的。
- 聚类和降维:在数据挖掘和特征工程中,Tensor可以用于聚类、主成分分析(PCA)等算法。
总的来说,Tensor作为多维数组,适用于几乎所有涉及到大规模数值计算和深度学习的领域。
这里借助numpy给大家更加直观的认识张量。
3.张量形态
标量(0D 张量)
一个只包含单个数字的张量被称为标量(scalar),也叫做标量张量、零维张量或0D张量。在NumPy中,一个float32或float64类型的数字就是一个标量张量(或标量数组)。你可以通过查看一个NumPy张量的ndim属性来了解它的轴数。标量张量具有0个轴(ndim == 0)。轴的数量也被称为阶数(rank)。以下是一个NumPy标量的例子。
python
import numpy as np
x = np.array(1)
print("数组中轴的个数:{}".format(x.ndim))
print(x)
数组中轴的个数:0 1
向量(1D 张量)
数字组成的数组叫作向量(vector)或一维张量(1D 张量)。一维张量只有一个轴。下面是一个 Numpy 向量。
python
x = np.array([1, 4, 7, 10, 13])
print("数组中轴的个数:{}".format(x.ndim))
print(x)
数组中轴的个数:1 [ 1 4 7 10 13]
这里需要注意一下,这个数组成为5D向量但不是5D张量,前者是数量上的数量,后者是轴的数量,大家不要搞混。
矩阵(2D张量)
向量组成的数组叫作矩阵(matrix)或二维张量(2D 张量)。矩阵有 2 个轴(通常叫作行和列)。你可以将矩阵直观地理解为数字组成的矩形网格。下面是一个 Numpy 矩阵。
python
x = np.array([[1, 8, 21, 3, 78],
[8, 12, 13, 32, 11],
[7, 3, 5, 6, 2]])
print("数组中轴的个数:{}".format(x.ndim))
print(x)
数组中轴的个数:2 [[ 1 8 21 3 78] [ 8 12 13 32 11] [ 7 3 5 6 2]]
3D 张量与高维张量
将多个矩阵组合成一个新的数组,可以得到一个 3D 张量,你可以将其直观地理解为数字组成的立方体。下面是一个 Numpy 的 3D 张量。
python
x = np.array([[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]]])
print(x.ndim)
print(x)
3 [[[ 5 78 2 34 0] [ 6 79 3 35 1] [ 7 80 4 36 2]] [[ 5 78 2 34 0] [ 6 79 3 35 1] [ 7 80 4 36 2]] [[ 5 78 2 34 0] [ 6 79 3 35 1] [ 7 80 4 36 2]]]
以后我们接触到相应的数据进行张量转换的时候大家会了解的更为清晰,那么我们现在知道张量的基础概念和形式了,可以尝试着用Torch进行创建。
二、Tensor的创建
在PyTorch中,我们可以通过多种方式创建Tensor:
1. 从列表或NumPy数组创建
python
import torch
import numpy as np
# 从列表创建
tensor_from_list = torch.Tensor([1, 2, 3, 4])
# 从NumPy数组创建
numpy_array = np.array([1, 2, 3, 4])
tensor_from_numpy = torch.Tensor(numpy_array)
tensor_from_numpy
tensor([1., 2., 3., 4.])
2. 使用特定的初始化方法
python
# 创建一个形状为(3, 2)的随机Tensor
random_tensor = torch.randn(3, 2)
# 创建一个全零的Tensor
zero_tensor = torch.zeros(3, 2)
# 创建一个全1的Tensor
ones_tensor = torch.ones(3, 2)
# 创建一个从 0 到 9 的等差数列
tensor5 = torch.arange(0, 10, 1)
# 创建一个从 0 到 1 的 5 个数的均匀间隔的数列
tensor6 = torch.linspace(0, 1, 5)
print(tensor6)
print(random_tensor)
print(zero_tensor)
print(ones_tensor)
print(tensor5)
print(tensor6)
tensor([0.0000, 0.2500, 0.5000, 0.7500, 1.0000]) tensor([[ 0.9255, 1.3031], [-1.2245, -0.5758], [-1.2821, -0.3471]]) tensor([[0., 0.], [0., 0.], [0., 0.]]) tensor([[1., 1.], [1., 1.], [1., 1.]]) tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) tensor([0.0000, 0.2500, 0.5000, 0.7500, 1.0000])
3. 从已有的Tensor创建
python
# 从已有的Tensor创建新的Tensor(共享内存)
new_tensor = torch.Tensor(random_tensor.size())
print(new_tensor)
tensor([[0., 0.], [0., 0.], [0., 1.]])
三、Tensor的形状操作
1.查看大小和维度
有两个函数size()和shape都可以查看:
python
random_tensor.size()
#random_tensor.shape 二者结果一致
torch.Size([3, 2])
2. 改变 Tensor 的形状
python
# 创建一个大小为 (2, 3) 的 Tensor
tensor = torch.arange(6).view(2, 3)
# 或者使用 reshape
# tensor = torch.arange(6).reshape(2, 3)
print(tensor)
tensor([[0, 1, 2], [3, 4, 5]])
3. 移除和增加Tensor 的维度
python
# squeeze 用于移除大小为 1 的维度
tensor = torch.arange(6).view(1, 2, 3)
squeezed_tensor = tensor.squeeze()
print(squeezed_tensor)
# unsqueeze 用于增加维度
tensor = torch.arange(6).view(2, 3)
unsqueeze_tensor = tensor.unsqueeze(0)
print(unsqueeze_tensor)
tensor([[0, 1, 2], [3, 4, 5]]) tensor([[[0, 1, 2], [3, 4, 5]]])
4.交换Tensor 维度
python
# 交换维度
tensor = torch.arange(6).view(2, 3)
transposed_tensor = tensor.transpose(0, 1) # 交换维度 0 和 1
print(transposed_tensor)
tensor([[0, 3], [1, 4], [2, 5]])
5.拼接和堆叠Tensor
python
# cat 用于在指定维度上连接多个 Tensor
tensor1 = torch.arange(3)
tensor2 = torch.arange(3, 6)
concatenated_tensor = torch.cat((tensor1, tensor2), dim=0)
print(concatenated_tensor)
# stack 用于在新的维度上堆叠多个 Tensor
stacked_tensor = torch.stack((tensor1, tensor2), dim=0)
print(stacked_tensor)
6.拆分Tensor
原Tensor:
python
tensor = torch.arange(10).view(2, 5)
print(tensor)
拆分结果
python
# split 用于在指定维度上拆分 Tensor
tensor = torch.arange(10).view(2, 5)
split_tensors = torch.split(tensor, 2, dim=1)
print(split_tensors)
# chunk 用于在指定维度上将 Tensor 拆分成相等的几块
chunked_tensors = torch.chunk(tensor, 2, dim=0)
print(chunked_tensors)
(tensor([[0, 1], [5, 6]]), tensor([[2, 3], [7, 8]]), tensor([[4], [9]])) (tensor([[0, 1, 2, 3, 4]]), tensor([[5, 6, 7, 8, 9]]))
四、Tensor索引和切片
1.索引
python
import torch
# 创建一个二维 Tensor
tensor = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 访问单个元素
print(tensor[0, 0]) # 输出 1
# 访问某一行
print(tensor[1]) # 输出 [4, 5, 6]
# 访问某一列
print(tensor[:, 1]) # 输出 [2, 5, 8]
# 使用逗号分隔访问多个不连续的元素
print(tensor[0, 0], tensor[1, 1], tensor[2, 2]) # 输出 1, 5, 9
tensor(1.) tensor([4., 5., 6.]) tensor([2., 5., 8.]) tensor(1.) tensor(5.) tensor(9.)
2.切片
python
# 使用切片获取子张量
print(tensor[0:2, 1:3]) # 输出 [[2, 3], [5, 6]]
# 使用步长获取间隔元素
print(tensor[::2]) # 输出 [[1, 2, 3], [7, 8, 9]]
# 使用负数索引倒序访问
print(tensor[-1]) # 输出 [7, 8, 9]
tensor([[2., 3.], [5., 6.]]) tensor([[1., 2., 3.], [7., 8., 9.]]) tensor([7., 8., 9.])
3.通过索引和切片修改 Tensor
(1).修改单个元素的值
python
# 创建一个二维 Tensor
tensor = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 修改单个元素的值
tensor[0, 0] = 0
tensor
tensor([[0., 2., 3.], [4., 5., 6.], [7., 8., 9.]])
(2).修改整行或整列
整行修改:
python
# 创建一个二维 Tensor
tensor = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 修改整行或整列
tensor[1] = torch.Tensor([10, 11, 12])
tensor
整列修改:
python
# 创建一个二维 Tensor
tensor = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 修改整行或整列
tensor[:, 2] = torch.Tensor([30, 31, 32])
tensor
tensor([[ 1., 2., 30.], [ 4., 5., 31.], [ 7., 8., 32.]])
4.高级索引
(1).使用列表作为索引
python
idx = [0, 2]
print(tensor[idx]) # 输出第 0 和第 2 行
tensor([[ 1., 2., 30.], [ 7., 8., 32.]])
(2).使用布尔值作为索引(掩码)
python
mask = tensor > 5
print(tensor[mask]) # 输出所有大于 5 的元素
tensor([30., 31., 7., 8., 32.])
(3).使用 torch 的索引函数
python
# 使用 torch 的索引函数
idx = torch.LongTensor([0, 2])
print(torch.index_select(tensor, 0, idx)) # 输出第 0 和第 2 行
tensor([[ 1., 2., 30.], [ 7., 8., 32.]])
点关注,防走丢,如有纰漏之处,请留言指教,非常感谢
以上就是本期全部内容。我是fanstuck ,有问题大家随时留言讨论 ,我们下期见。