【PyTorch与深度学习】1、PyTorch介绍与张量的创建

devtools/2024/11/10 12:13:46/

课程地址
最近做实验发现自己还是基础框架上掌握得不好,于是开始重学一遍PyTorch框架,这个是课程笔记

1. 张量Tensor

张量是一种特殊的数据结构,与数组和矩阵非常相似。在 PyTorch 中,我们使用张量对模型的输入和输出以及模型的参数进行编码。张量与NumPy 的ndarray类似,不同之处在于张量可以在 GPU 或其他硬件加速器上运行。事实上,张量和 NumPy 数组通常可以共享相同的底层内存(原地操作),从而无需复制数据。张量还针对自动微分进行了优化。
PyTorch导入包的过程:

import torch
import numpy as np

1.1 创建张量

1.1.1 从列表中创建一个张量tensor

data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)

x_data的结果:
tensor([[1, 2],
[3, 4]])

创建一个浮点型的列表:

import torch
import numpy as np
data = [[1, 2.0],[3, 4]]
x_data = torch.tensor(data)
print(x_data)
print(type(x_data))  # 打印存储张量的变量的类型
print(x_data.dtype)  # 打印张量中每一个元素的类型

运行结果:
tensor([[1., 2.],
[3., 4.]])
<class ‘torch.Tensor’>
torch.float32

1.1.2 从numpy数组中创建张量tensor

import torch
import numpy as np
a = np.random.normal((2, 3)) # 按正态分布创建一个ndarray
tensor_a = torch.tensor(a)
print(tensor_a)

运行结果:
tensor([0.5312, 3.4150], dtype=torch.float64)

import torch
import numpy as np
a = np.random.normal((2, 3)) # 按正态分布创建一个ndarray
tensor_a = torch.from_numpy(a)
print(tensor_a)

运行结果:
tensor([2.1416, 2.2480], dtype=torch.float64)

【提问】上述两种方式从numpy数组中创建的tensor有何不同?
【chatGPT回答】在PyTorch中,从numpy数组创建张量主要有两种方式:torch.Tensor() 和 torch.from_numpy()。这两种方法虽然都可以从numpy数组转换成PyTorch张量,但它们之间有一些重要的不同点:

  1. 内存共享
  • torch.from_numpy(): 这个方法创建的张量与原始的numpy数组共享相同的内存。这意味着如果你修改了numpy数组的内容,相应的PyTorch张量的内容也会随之改变,反之亦然。这种方法效率很高,因为它避免了数据复制,但也需要注意数据在numpy数组和张量间是同步的。
  • torch.Tensor():使用这个构造函数时(或者 torch.tensor(),它更加推荐用于创建新张量),PyTorch会创建一个复制了numpy数组数据的新张量。这种方式不会与原始numpy数组共享内存,因此,修改原numpy数组不会影响到PyTorch张量,反之亦然。
  1. 数据类型自动转换:
  • torch.Tensor(): 在使用这个方法时,PyTorch通常会自动推断出一个合适的数据类型。如果numpy数组的数据类型与PyTorch默认的数据类型不匹配,PyTorch可能会自动转换数据到一个新的数据类型。
  • torch.from_numpy(): 使用这种方法时,创建的PyTorch张量将直接采用numpy数组的数据类型。不会进行数据类型的自动转换。
    用法:
  • torch.Tensor():这是一个更一般的构造函数,可用于从列表、numpy数组等创建张量,但因为它涉及到数据的复制,可能不如 > - torch.from_numpy() 高效。
  • torch.from_numpy(): 专门用于从numpy数组直接创建张量,效率更高,因为避免了数据复制。

总结来说,选择哪种方式取决于你是否需要原始数据和张量之间的内存共享以及对数据类型的处理方式。如果你希望避免不必要的数据复制并且可以管理内存共享带来的副作用,torch.from_numpy() 是一个更好的选择。如果你需要从一个数组创建一个独立的张量,并可能需要转换数据类型,torch.Tensor() 或 torch.tensor() 可能更适合你的需求。

1.1.3 从其他张量创建张量tensor

新张量保留参数张量的属性(形状、数据类型),除非显式覆盖。

import torch
import numpy as np
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
x_ones = torch.ones_like(x_data) # 创建一个和x_data张量大小一样的全为1的张量
print(f"Ones Tensor: \n {x_ones} \n")x_ones = torch.zeros_like(x_data) # 创建一个和x_data张量大小一样的全为0的张量
print(f"Zeros Tensor: \n {x_ones} \n")x_rand = torch.rand_like(x_data, dtype=torch.float) # 创建一个和x_data张量大小一样的全为随机数的张量
print(f"Random Tensor: \n {x_rand} \n")

运行结果:
Ones Tensor:
tensor([[1, 1],
[1, 1]])

Zeros Tensor:
tensor([[0, 0],
[0, 0]])

Random Tensor:
tensor([[0.5124, 0.8001],
[0.8218, 0.9406]])

1.1.4 使用随机值或常数创建张量tensor

shape是张量维度的元组,如果将shape 改成列表也是可以的,但是不能写成集合{2,3},那样会报错。在下面的函数中,它确定输出张量的维数。

import torch
import numpy as np
shape = (2,3,)  # 张量维度的元组,最后一个逗号能去掉,这是一个2×3的张量
rand_tensor = torch.rand(shape)  # 按shape的维度大小创建一个随机值的张量
ones_tensor = torch.ones(shape)  # 按shape的维度大小创建一个全为1的张量
zeros_tensor = torch.zeros(shape)  # 按shape的维度大小创建一个全为0的张量print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")

运行结果:
Random Tensor:
tensor([[0.0758, 0.3495, 0.7840],
[0.9438, 0.8045, 0.4455]])

Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])

Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])

1.2 张量的属性

张量属性描述了它们的形状、数据类型以及存储它们的设备。

import torch
import numpy as np
tensor = torch.rand(3,4)print(f"张量的维度: {tensor.shape}")
print(f"张量的元素的数据类型: {tensor.dtype}")
print(f"存储当前张量的设备: {tensor.device}")

运行结果:
张量的维度: torch.Size([3, 4])
张量的元素的数据类型: torch.float32
存储当前张量的设备: cpu

1.3 张量的操作

PyTorch有 100 多种张量运算,包括算术、线性代数、矩阵操作(转置、索引、切片)、采样等。这些操作中的每一个都可以在 GPU 上运行(速度通常高于 CPU)。默认情况下,张量是在 CPU 上创建的。我们需要使用 .to方法显式地将张量移动到 GPU(在检查 GPU 可用性之后)。请记住,跨设备复制大张量在时间和内存方面可能会很昂贵!

import torch
import numpy as np
tensor = torch.rand(3,4)# 将张量移动到GPU(显卡)中,如果有独立显卡,可以移动
if torch.cuda.is_available():tensor = tensor.to("cuda")

正常运行代码不报错证明能移动到GPU中

1.3.1 常见的张量操作

(1) is_tensor:如果当前对象是 PyTorch 张量,则返回 True 。

import torch
import numpy as np
tensor = torch.rand(3,4)print(torch.is_tensor(tensor))

运行结果:
True
(2)is_complex:如果当前的数据类型input是复数类型,即torch.complex64或torch.complex128,则返回 True。
(3)is_floating_point:如果当前的数据类型input是浮点数据类型,即torch.float64、torch.float32、torch.float16或torch.bfloat16,则返回 True。
(4)is_nonzero:input如果是单元素张量且在类型转换后不等于 0,则返回 True。

import torch
import numpy as np
a = torch.tensor(1.0)  # 单一浮点数张量1.0
print(a)
print(torch.is_nonzero(a))  # 打印True就表明a张量是一个非0的标量a = torch.tensor(0)  # 单一浮点数张量0
print(a)
print(torch.is_nonzero(a))  #  打印False就表明a张量是一个值为0的标量

运行结果:
tensor(1.)
True
tensor(0)
False

(5)numel:返回张量中的元素总数input。

import torch
import numpy as npa = torch.rand([2, 2])  # 创建一个2X2的随机值张量
print(torch.numel(a))  # 返回2X2张量的元素个数4

运行结果:
4

1.3.2 常见的创建张量的操作

(1)tensor:通过复制构造一个没有自动求导过的张量,使用这个构造函数时(或者 torch.tensor(),它更加推荐用于创建新张量),PyTorch会创建一个复制了numpy数组数据的新张量。这种方式不会与原始numpy数组共享内存,因此,修改原numpy数组不会影响到PyTorch张量,反之亦然。

import torch
import numpy as npb = np.array([1, 1.2])
a = torch.tensor(b)
print(a)

运行结果:
tensor([1.0000, 1.2000], dtype=torch.float64)
(2)as_tensor:转换data为张量,共享数据并保留 自动求导的历史记录(如果可能)。
如果data已经是具有请求的 dtype 和设备的张量,则data返回其本身,但如果data是具有不同 dtype 或设备的张量,则将其复制,就像使用 data.to(dtype=dtype, device=device)一样。如果data是具有相同数据类型和设备的 NumPy 数组(ndarray),则使用 构造张量torch.from_numpy()。

import torch
import numpy as np# a默认在CPU中创建,t从a中创建,二者共享数据,所以修改一个,两个都变
a = np.array([1, 2, 3])
t = torch.as_tensor(a)
print(t)
t[0] = -1
print(a)# 但是将t送入GPU后,a在CPU,t在GPU,修改t,a不变
a = np.array([1, 2, 3])
t = torch.as_tensor(a, device=torch.device('cuda'))
print(t)
t[0] = -1
print(a)

运行结果:
tensor([1, 2, 3], dtype=torch.int32)
[-1 2 3]
tensor([1, 2, 3], device=‘cuda:0’, dtype=torch.int32)
[1 2 3]
(3)from_numpy:从numpy.ndarray.创建一个张量, 这个方法创建的张量与原始的numpy数组共享相同的内存。这意味着如果你修改了numpy数组的内容,相应的PyTorch张量的内容也会随之改变,反之亦然。这种方法效率很高,因为它避免了数据复制,但也需要注意数据在numpy数组和张量间是同步的。

import torch
import numpy as npa = np.array([1, 2, 3])
t = torch.from_numpy(a)
# a 和 t是共享相同的内存的,修改t,a也被修改
print(t)
t[0] = -1
print(a)

运行结果:
tensor([1, 2, 3], dtype=torch.int32)
[-1 2 3]
(4)zeros:返回一个全为0的张量,主要参数是整型序列,用来记录生成的张量的维度大小,
关键字参数

  • out ( Tensor ,可选) – 输出张量。
  • dtype ( torch.dtype, 可选) – 返回张量所需的数据类型。默认值:如果None,则使用全局默认值,通过 torch.set_default_dtype()这个API规定的。
  • layout ( torch.layout, 可选) – 返回张量的所需布局。默认:torch.strided。
  • device (torch.device, 可选) –返回张量所需的设备。默认值:如果None,则使用当前设备作为默认张量类型(请参阅torch.set_default_device())。
  • device对于CPU 张量类型,将是 CPU;对于 CUDA 张量类型,将是当前 CUDA 设备。
  • require_grad ( bool ,可选) – 自动求导 是否应记录对返回张量的操作。默认:False。
import torch
import numpy as npa = torch.zeros(5, 5)
print(a)
print(a.dtype)torch.set_default_dtype(torch.float64)  # 设置默认的数据类型为float64
a = torch.zeros(5, 5)
print(a)
print(a.dtype)

运行结果:
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., 0.]])
torch.float32
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., 0.]])
torch.float64
(5)zeros_like:返回一个用标量值0填充的张量,其大小与 相同input。(下面的与上面的类似,不试了)
(6)ones:返回一个用标量值1填充的张量,其形状由变量声明定义size(参数是int整型序列,写的是所要生成的张量的维度size。
(7)ones_like:返回一个用标量值1填充的张量,其大小与 相同input。
(8)arange:返回大小为 ⌈ start-end s t e p ⌉ \left\lceil\frac{\text { start-end}}{step}\right\rceil step start-end的1维张量,[start,end),左闭右开
参数:

  • start ( Number ) – 点集的起始值。默认:0。
  • end ( Number ) – 点集的结束值
  • step ( Number ) – 每对相邻点之间的间隙。默认:1。
import torcha = torch.arange(5)  # step为1,默认从0开始
print(a)a = torch.arange(start=2, end=5, step=2) 
print(a)

运行结果:
tensor([0, 1, 2, 3, 4])
tensor([2, 4])

(9)range:返回大小为 ⌊ end-start  step  ⌋ + 1 \left\lfloor\frac{\text { end-start }}{\text { step }}\right\rfloor+1  step  end-start +1的1维张量,

import torcha = torch.range(start=0, step=1, end=5)  # step为1,默认从0开始
print(a)

运行结果:
tensor([0., 1., 2., 3., 4., 5.])

【PyTorch官方的说明】该函数已被弃用,并将在未来版本中删除,因为它的行为与 Python 的 range 内置函数不一致。相反,请使用torch.arange(),它会在 [start, end) 中生成值。

(10)linspace:创建一个从start到end的均匀分布,step为步长
(11)logspace:创建一个从 l o g 底数 s t a r t log_{底数}^{start} log底数start l o g 底数 e n d log_{底数}^{end} log底数end的一维张量,step为步长,base为底数
(12)eye:创建一个二维张量,对角线上全为1,其他全为0,只传一个参数默认是方阵

import torcha = torch.eye(3)  # 只有一个参数,默认方阵
print(a)
a = torch.eye(3, 2)
print(a)

运行结果:
tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
tensor([[1., 0.],
[0., 1.],
[0., 0.]])

(13)full:创建一个大小size为的张量,并且这个张量是用value填充的。

import torcha = torch.full((3, 2), 10)  # 3x2张量,填充值为10
print(a)

运行结果:
tensor([[10, 10],
[10, 10],
[10, 10]])

(14)full_like:根据已有的维度大小创建一个填充值为value的张量。

import torchb = torch.tensor([[1, 2], [3, 4]])
a = torch.full_like(b, 10)  # 用10填充一个和b维度一样的tensor
print(a)

运行结果:
tensor([[10, 10],
[10, 10]])

1.3.3 索引、切片、连接等操作

(1)cat:连接给定维度中给定的张量序列。传入的是一个多个张量的列表,这些张量除了被连接的那个维度以外,需要有同样的张量,dim参数是指定在哪个维度将这两个张量连接起来。

import torcha = torch.rand([2, 2])  # 2x2拼左边
print(a)
b = torch.rand([2, 3])  # 2x3拼右侧
print(b)
print(torch.cat([a, b], dim= 1))

运行结果:
tensor([[0.3435, 0.4823],
[0.3059, 0.4247]])
tensor([[0.2637, 0.9875, 0.9034],
[0.5850, 0.1321, 0.2106]])
tensor([[0.3435, 0.4823, 0.2637, 0.9875, 0.9034],
[0.3059, 0.4247, 0.5850, 0.1321, 0.2106]])

在0维度拼接相当于上下拼接(2维):

import torcha = torch.rand([2, 2])
print(a)
b = torch.rand([3, 2])
print(b)
print(torch.cat([a, b], dim= 0))

运行结果:
tensor([[0.5723, 0.7480],
[0.7629, 0.4247]])
tensor([[0.5585, 0.0881],
[0.6640, 0.8015],
[0.8188, 0.3602]])
tensor([[0.5723, 0.7480],
[0.7629, 0.4247],
[0.5585, 0.0881],
[0.6640, 0.8015],
[0.8188, 0.3602]])

此处我去年看李沐老师视频的时候有一段写的和这个类似,但是比较详细:按特定轴求和


http://www.ppmy.cn/devtools/26810.html

相关文章

Meta-Llama-3-8B-Instruct本地推理

Meta-Llama-3-8B-Instruct 本地推理 基础环境信息&#xff08;wsl2安装Ubuntu22.04 miniconda&#xff09; 使用miniconda搭建环境 (base) :~$ conda create --name pytorch212 python3.10 Retrieving notices: ...working... done Channels:- defaults Platform: linux-64 C…

git 的使用教程规范以及示例

1、安装Git&#xff1a;你可以访问Git官网来下载并安装Git。 2、初始化Git仓库&#xff1a; git init这条命令将在当前目录下创建一个新的Git仓库。如果目录已经是一个仓库&#xff0c;它不会覆盖现有的内容。3、 克隆Git仓库&#xff1a; git clone <url>这条命令将克隆…

.NET操作 Access (MSAccess)

注意&#xff1a;新项目推荐 Sqlite &#xff0c;Access需要注意的东西太多了&#xff0c;比如OFFICE版本&#xff0c;是X86还是X64 连接字符串 ProviderMicrosoft.ACE.OleDB.15.0;Data Source"GetCurrentProjectPath"\\test.accdb//不同的office版本 连接字符串有…

PotatoPie 4.0 实验教程(32) —— FPGA实现摄像头图像浮雕效果

什么是浮雕效果&#xff1f; 浮雕效果是一种图像处理技术&#xff0c;用于将图像转换为看起来像浮雕一样的效果&#xff0c;给人一种凸起或凹陷的立体感觉&#xff0c;下面第二张图就是图像处理实现浮雕效果。 不过这个图是用Adobe公司的PS人工P图实现的&#xff0c;效果比较…

C# WinForm —— 12 ListBox绑定数据

ListBox加载大量数据时&#xff0c;避免窗体闪烁的方法&#xff1a; 在加载语句的前后分别加上 BeginUpdate()方法 和 EndUpdate()方法 指定一个集合为绑定的数据源 1. 首先&#xff0c;右键项目&#xff0c;添加类 2. 在新建的类文件中添加属性值信息 3. 构建初始化的对象…

夏天一到,手机越用越烫?怎样降低持久使用手机时的温度?

夏季来临&#xff0c;手机的温度也随着使用环境的温度升高变得更容易发热。 虽说属于正常的物理现象&#xff0c;但手机过热用起来还是不太舒服&#xff0c;还容易出现过热提醒&#xff0c;导致除“拨号”和“联系人”外&#xff0c;无法使用其它应用。 分享几个减少功耗的小技…

2.小土堆——tensorboard使用

1.tensorboard是啥&#xff1f; TensorBoard 是一个用于可视化 TensorFlow 训练过程和模型的工具。它可以帮助你以图形和图表的形式查看训练过程中的指标&#xff0c;比如损失和准确率的变化。你可以使用 TensorBoard 来监视模型的性能&#xff0c;并且更直观地理解模型的工作原…

时序分析之setup/hold时钟path requirement解疑

目录 一、前言 二、时钟边沿选取 2.1 setup和hold 2.2 path requirement 2.3 同频率同相位 2.4 同频率不同相 2.5 倍频或分频关系 2.5 异步时钟 2.6 无公共周期 一、前言 在时序报告中&#xff0c;任选一条时序分析结果查看路径详细延时&#xff0c;会看到在source pa…