pytorch 2 张量操作

张量的创建

直接创建

torch.tensor

torch.tensor(data,dtype=None,device=None,requires_grad=False,pin_memory=False)

  • data(array_like) - tensor的初始数据,可以是list, tuple, numpy array, scalar或其他类型。

  • dtype(torch.dtype, optional) - tensor的数据类型,如torch.uint8, torch.float, torch.long等

  • device (torch.device, optional) – 决定tensor位于cpu还是gpu。如果为None,将会采用默认值,默认值在torch.set_default_tensor_type()中设置,默认为 cpu。

  • requires_grad (bool, optional) – 决定是否需要计算梯度。

  • pin_memory (bool, optional) – 是否将tensor存于锁页内存。这与内存的存储方式有关,通常为False。

l = [[1,2,3],[4,5,6],[7,8,9]]  
t = torch.tensor(l)  
print(t)  
print(t.dtype)  
ll = [[1.,-1.],[1.,-1.]]  
t2 = torch.tensor(ll,dtype=torch.float64) 
print(t2)  
print(t2.dtype)  
t3 = torch.tensor(ll)  
print(t3)  
print(t3.dtype)

![[Pasted image 20240809213925.png]]
浮点数默认是torch.float32类型,可以指定参数dtype进行指定数据类型

arr = np.array([[1,2,3],[4,5,6]])
t_from_arr = torch.tensor(arr,dtype=torch.uint8)
print(t_from_arr)
torch.from_numpy

还有一种常用的通过numpy创建tensor方法是torch.from_numpy()。这里需要特别注意的是,创建的**tensor和原array共享同一块内存(**The returned tensor and ndarray share the same memory. ),即当改变array里的数值,tensor中的数值也会被改变。

arr = np.array([[1,2,3],[4,5,6],[7,8,9]])  
t_from_numpy = torch.from_numpy(arr)  
print("numpy array:",arr)  
print("torch tensor:",t_from_numpy)  
print("\n修改arr")  
arr[0,0]=0  
print("numpy array:",arr)  
print("torch tensor:",t_from_numpy)  
print("\n修改tensor")  
t_from_numpy[0,1]=1  
print("numpy array:",arr)  
print("torch tensor:",t_from_numpy)

![[Pasted image 20240809215934.png]]

依数值创建

torch.zeros

*torch.zeros(size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:依给定的size创建一个全0的tensor,默认数据类型为torch.float32(也称为torch.float)。

*size 是 Python 中的一种特殊语法,表示“可变长度参数”。
具体来说,*size 的作用是允许函数接收任意数量的参数,并将这些参数作为一个元组传递给函数。在 torch.zeros 中,size 表示张量的形状(即它的维度)。通过使用 *size,你可以传递一个或多个整数来指定张量的每一维的大小。

  1. 单个参数:

    torch.zeros(3)
    

    这会创建一个一维的张量,其大小为3。

  2. 多个参数:

    torch.zeros(3, 4)
    

    这会创建一个二维的张量,其形状为3x4。

  3. 使用元组解包:

    你也可以通过传递一个元组并使用 * 操作符解包参数:

    size = (3, 4, 5)
    torch.zeros(*size)
    

    这会创建一个三维的张量,其形状为3x4x5。

主要参数:

  1. out (tensor, optional)
  • 作用: out 参数允许你指定一个已有的张量,用于接收 torch.zeros 创建的张量结果。这意味着函数的输出不会生成一个新的张量,而是将结果直接存储到 out 参数指定的张量中。

  • 使用场景:

    • 内存优化: 在高效计算和节省内存分配方面非常有用。如果你已经有一个张量,并且希望在相同的内存位置存储新的数据(例如,全零的张量),可以使用 out 参数。
    • 避免不必要的内存分配: 对于大型张量,避免了重复分配内存的开销。
  • 使用示例:

existing_tensor = torch.empty(2, 3) # 创建一个未初始化的张量
torch.zeros(2, 3, out=existing_tensor) # 使用 out 参数将全零的张量结果存储在 existing_tensor 中
print(existing_tensor)

n = np.random.randint(0, 10, size=(3, 3)) #生成一个 3x3 的矩阵,每个元素是 [0, 10) 之间的随机整数
print(n)
#转为张量
nn = torch.from_numpy(n)
#使用 torch.zeros 并将结果存储在 nn 中
torch.zeros(3,3,out=nn)
print(nn)


![[Pasted image 20240809221307.png]]
2. `layout (torch.layout, optional)`

- **作用**: `layout` 参数决定张量在内存中的存储布局方式。PyTorch 支持不同的内存布局,适用于不同的计算需求。

- **常见布局**:
- **`torch.strided`**: 默认的内存布局。数据以密集格式存储,张量元素按照一定的步长(stride)在内存中排列。
- **`torch.sparse_coo`**: 稀疏张量的布局方式,适用于大部分元素为零的稀疏矩阵。这种布局只存储非零元素及其索引,节省内存。

- **使用场景**:
- **默认密集存储**: 如果你的数据是密集的(大多数元素非零),使用默认的 `torch.strided` 布局。
- **稀疏数据**: 如果你的数据是稀疏的(大多数元素为零),使用 `torch.sparse_coo` 布局更为高效。

- **使用示例**:

(1) 默认布局(连续存储):

```python
import torch

# 创建一个形状为 (2, 3) 的默认连续布局零张量
default_tensor = torch.zeros(2, 3)
print(default_tensor)
print(default_tensor.is_contiguous())  # 输出: True

![[Pasted image 20240809222238.png]]
(2) 指定 strided 布局:

# 创建一个形状为 (2, 3) 的 strided 布局零张量
strided_tensor = torch.zeros(2, 3, layout=torch.strided)
print(strided_tensor)
print(strided_tensor.is_contiguous())  # 输出: True

![[Pasted image 20240809222245.png]]
(3) 稀疏布局:

# 创建一个稀疏布局的零张量
sparse_tensor = torch.zeros(2, 3, layout=torch.sparse_coo)
print(sparse_tensor)
print(sparse_tensor.is_sparse)  # 输出: True

![[Pasted image 20240809222349.png]]
解释:
1. indices=tensor([], size=(2, 0)):
- 这表示稀疏张量中非零元素的索引。
- size=(2, 0) 表示这是一个2D张量,但目前没有任何索引(因为张量是空的)。
- 第一个维度 (2) 对应于张量的维数(在这里是2D)。
- 第二个维度 (0) 表示没有非零元素。

2. `values=tensor([], size=(0,))`: 
   - 这表示非零元素的值。
   - 当前为空,因为没有非零元素。

3. `size=(2, 3)`: 
   - 这是整个稀疏张量的形状。
   - 它表示这个稀疏张量在稠密形式下会是一个 2x3 的矩阵。

4. `nnz=0`: 
   - "nnz" 代表 "number of non-zero elements"(非零元素的数量)。
   - 这里为0,表示没有非零元素。

5. `layout=torch.sparse_coo`: 
   - 这指定了张量的布局。
   - `sparse_coo` 表示这是一个 COO(Coordinate)格式的稀疏张量。

(4) 使用 as_strided 创建非连续布局:

# 创建一个非连续布局的零张量
non_contiguous_tensor = torch.zeros(4, 4).as_strided((2, 2), (2, 1))
print(non_contiguous_tensor)
print(non_contiguous_tensor.is_contiguous())  # 输出: False

![[Pasted image 20240809222532.png]]
解释:

  1. torch.zeros(4, 4):

    • 首先,创建一个 4x4 的全零张量。
    • 这个张量在内存中是连续存储的。
  2. .as_strided((2, 2), (2, 1)):

    • 然后,使用 as_strided 方法重新解释这个张量的存储。

    • as_strided 接受两个主要参数:新的形状和新的步长(stride)。

    • 新的形状 (2, 2):
      这表示我们要将原来的 4x4 张量重新解释为一个 2x2 的张量。

    • 新的步长 (2, 1):

      • 步长定义了在内存中如何"跳跃"以获取下一个元素。
      • 2 表示在第一个维度上,每次需要跳过2个元素。
      • 1 表示在第二个维度上,每次只需要移动到下一个相邻元素。

结果是什么样的?

原始的 4x4 张量(用索引表示):

0  1  2  3
4  5  6  7
8  9  10 11
12 13 14 15

应用 as_strided((2, 2), (2, 1)) 后,我们得到:

0  1
4  5

这个新的 2x2 张量是通过以下方式从原始张量中"提取"的:

  • 第一行:取原始张量的 (0,0) 和 (0,1) 元素
  • 第二行:取原始张量的 (1,0) 和 (1,1) 元素

这个新张量是非连续的,因为它在内存中不是连续存储的。它跳过了原始张量中的一些元素。

使用 as_strided 可以创建对原始数据的新视图,而不需要复制数据。这在某些情况下可以提高效率,但也需要小心使用,因为不正确的使用可能导致意外的结果。

(5) 指定设备和数据类型:

# 在 CUDA 设备上创建一个 float16 类型的零张量
if torch.cuda.is_available():
    cuda_tensor = torch.zeros(2, 3, dtype=torch.float16, device='cuda', layout=torch.strided)
    print(cuda_tensor)
    print(cuda_tensor.device)  # 输出: cuda:0

![[Pasted image 20240809222710.png]]

torch.zeros_like

torch.zeros_like(input, dtype=None, layout=None, device=None, requires_grad=False)

功能:依input的size创建全0的tensor。

主要参数:

input(Tensor) - 创建的tensor与intput具有相同的形状。

除了创建全0还有创建全1的tensor,使用方法是一样的,这里就不赘述。

torch.ones

torch.ones(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:依给定的size创建一个全1的tensor。

torch.ones_like

torch.ones_like(input, dtype=None, layout=None, device=None, requires_grad=False)
功能:依input的size创建全1的tensor。

torch.full

torch.full(size, fill_value, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
功能:依给定的size创建一个值全为fill_value的tensor。

主要参数:

  • siz (int…) - tensor的形状。

  • fill_value - 所创建tensor的值

  • out(tensor, optional) - 输出的tensor,即该函数返回的tensor可以通过out进行赋值。

example:

import torch
print(torch.full((2, 3), 3.141592))
torch.full_like

torch.full_like(input, fill_value, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

torch.full_like之于torch.full等同于torch.zeros_like之于torch.zeros,因此不再赘述。

torch.arange

torch.arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

**==功能:创建等差的1维张量,长度为 (end-start)/step,需要注意数值区间为[start, end)。

主要参数:

  • start (Number) – 数列起始值,默认值为0。the starting value for the set of points. Default: 0.

  • end (Number) – 数列的结束值。

  • step (Number) – 数列的等差值,默认值为1。

  • out (Tensor, optional) – 输出的tensor,即该函数返回的tensor可以通过out进行赋值。

example:

import torch
print(torch.arange(1, 2.51, 0.5))

![[Pasted image 20240810100747.png]]
torch.range()函数就不推荐了,因为官网说了“This function is deprecated in favor of torch.arange().”

torch.linspace

torch.linspace(start, end, steps=100, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:创建均分的1维张量,长度为steps,区间为[start, end]。

主要参数:

  • start (float) – 数列起始值。

  • end (float) – 数列结束值。

  • steps (int) – 数列长度。

example:

print(torch.linspace(3, 10, steps=5))
print(torch.linspace(1, 5, steps=3))

![[Pasted image 20240810100909.png]]
![[Pasted image 20240810100925.png]]

torch.logspace

torch.logspace(start, end, steps=100, base=10.0, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:创建对数均分的1维张量,长度为steps, 底为base。这边的end是闭区间

主要参数:

  • start (float) – 确定数列起始值为base^start

  • end (float) – 确定数列结束值为base^end

  • steps (int) – 数列长度。

  • base (float) - 对数函数的底,默认值为10,此参数是在pytorch 1.0.1版本之后加入的。

example:

#这五个值分别是 `10^0.1`, `10^0.325`, `10^0.55`, `10^0.775`, 和 `10^1.0`,它们在对数空间中均匀分布。
torch.logspace(start=0.1, end=1.0, steps=5)
torch.logspace(start=2, end=2, steps=1, base=2)

![[Pasted image 20240810101321.png]]

torch.eye

torch.eye(n, m=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:创建单位对角矩阵。

主要参数:

  • n (int) - 矩阵的行数

  • m (int, optional) - 矩阵的列数,默认值为n,即默认创建一个方阵

example:

import torch
print(torch.eye(3))
print(torch.eye(3, 4))
torch.empty

*torch.empty(size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False)

功能:依size创建“空”张量,这里的“空”指的是不会进行初始化赋值操作。

主要参数:

  • size (int…) - 张量维度

  • pin_memory (bool, optional) - pinned memory 又称page locked memory,即锁页内存,该参数用来指示是否将tensor存于锁页内存,通常为False,若内存足够大,建议设置为True,这样在转到GPU时会快一些。

torch.empty_like

torch.empty_like(input, dtype=None, layout=None, device=None, requires_grad=False)

功能:torch.empty_like之于torch.empty等同于torch.zeros_like之于torch.zeros,因此不再赘述。

torch.empty_strided

torch.empty_strided(size, stride, dtype=None, layout=None, device=None, requires_grad=False, pin_memory=False)

功能:依size创建“空”张量,这里的“空”指的是不会进行初始化赋值操作。

主要参数:

  • stride (tuple of python:ints) - 张量存储在内存中的步长,是设置在内存中的存储方式。

  • size (int…) - 张量维度

  • pin_memory (bool, optional) - 是否存于锁页内存。

依概率分布创建

torch.normal

正态分布(也称为高斯分布)的概率密度函数公式如下:
f ( x ) = 1 σ 2 π exp ⁡ ( − ( x − μ ) 2 2 σ 2 ) f(x) = \frac{1}{\sigma \sqrt{2\pi}} \exp\left(-\frac{(x - \mu)^2}{2\sigma^2}\right) f(x)=σ2π 1exp(2σ2(xμ)2)

其中:

  • f(x) 是概率密度函数
  • x 是随机变量
  • μ(mu)是分布的均值
  • σ(sigma)是分布的标准差
  • e 是自然对数的底(约等于 2.71828)
  • π 是圆周率(约等于 3.14159)
    性质:
  1. 对称性: 正态分布是对称的,中心点是均值 ( \mu )。
  2. 68-95-99.7 规则: 在正态分布中,约 68% 的数据落在均值 ( \mu ) 的 1 个标准差 ( \sigma ) 内,约 95% 的数据落在 2 个标准差内,约 99.7% 的数据落在 3 个标准差内。

torch.normal(mean, std, out=None) 函数中:

  • mean 对应于公式中的 μ
  • std 对应于公式中的 σ

torch.normal 函数使用这个分布来生成随机数。具体来说:

  1. 对于给定的 meanstd,函数会创建一个以 mean 为中心,std 为标准差的正态分布。

  2. 然后,函数从这个分布中随机采样,生成符合该分布的随机数。

  3. 如果 meanstd 是标量,所有生成的随机数都来自同一个分布。

  4. 如果 meanstd 是张量,每个元素位置都有自己的均值和标准差,相当于从多个不同的正态分布中采样。

举个例子来说明:

import torch

# 从均值为0,标准差为1的标准正态分布中采样
samples = torch.normal(mean=0.0, std=1.0, size=(1000,))

# 计算样本的实际均值和标准差
print("Sample Mean:", samples.mean().item())
print("Sample Std:", samples.std().item())

# 从不同的正态分布中采样
means = torch.tensor([0.0, 1.0, 2.0])
stds = torch.tensor([1.0, 2.0, 0.5])
samples = torch.normal(means, stds)
print("Samples:", samples)

在这个例子中,第一部分从标准正态分布(μ=0, σ=1)中采样。第二部分从三个不同的正态分布中各采样一个值。

torch.normal(mean, std, out=None)

功能:为每一个元素以给定的mean和std用高斯分布生成随机数

主要参数:

  • mean (Tensor or Float) - 高斯分布的均值,

  • std (Tensor or Float) - 高斯分布的标准差

特别注意事项:

  1. mean为张量,std为张量:
    torch.normal(mean, std, out=None)
    
    • 数学公式:对于每个位置 i,
      f_i(x) = (1 / (std[i] * √(2π))) * e^(-(x - mean[i])^2 / (2 * std[i]^2))
    • 行为:每个元素从不同的高斯分布采样,分布的均值和标准差由 mean 和 std 对应位置元素的值确定。
    • 输出形状:与 mean 和 std 中较大的那个相匹配。
      ![[Pasted image 20240810104210.png]]
  2. mean为张量,std为标量:
    torch.normal(mean, std=1.0, out=None)
    
    • 数学公式:对于每个位置 i,
      f_i(x) = (1 / (std * √(2π))) * e^(-(x - mean[i])^2 / (2 * std^2))
    • 行为:每个元素采用相同的标准差,不同的均值。
    • 输出形状:与 mean 张量的形状相匹配。
      ![[Pasted image 20240810104228.png]]
  3. mean为标量,std为张量:
    torch.normal(mean=0.0, std, out=None)
    
    • 数学公式:对于每个位置 i,
      f_i(x) = (1 / (std[i] * √(2π))) * e^(-(x - mean)^2 / (2 * std[i]^2))
    • 行为:每个元素采用相同均值,不同标准差。
    • 输出形状:与 std 张量的形状相匹配。
      ![[Pasted image 20240810104251.png]]
  4. mean为标量,std为标量:
    torch.normal(mean, std, size, *, out=None)
    
    • 数学公式:对所有生成的元素,
      f(x) = (1 / (std * √(2π))) * e^(-(x - mean)^2 / (2 * std^2))
    • 行为:从一个高斯分布中生成大小为 size 的张量。
    • 输出形状:由 size 参数指定。
      ![[Pasted image 20240810104334.png]]
      在所有这些情况下:
  • torch.normal 函数是从这些定义的分布中进行采样,而不是直接计算概率密度。
  • 采样过程通常使用特定的算法(如 Box-Muller 变换或 Marsaglia 极坐标方法)来生成符合指定正态分布的随机数。
  • out 参数被指定时,结果将被写入这个预先分配的张量中。
组合情况
  1. mean 为张量,std 为张量:

    • 每个元素使用不同的均值和标准差,即 meanstd 张量的每个对应元素决定了相应位置的正态分布。

    • 示例:

      import torch
      
      mean = torch.tensor([0.0, 1.0, 2.0])
      std = torch.tensor([1.0, 0.5, 0.1])
      result = torch.normal(mean, std)
      print(result)
      
  2. mean 为张量,std 为标量:

    • 每个元素使用不同的均值和相同的标准差,即 std 是一个标量,表示所有位置的标准差相同。
    • 示例:
      import torch
      
      mean = torch.tensor([0.0, 1.0, 2.0])
      std = 1.0
      result = torch.normal(mean, std)
      print(result)
      
  3. mean 为标量,std 为张量:

    • 每个元素使用相同的均值和不同的标准差,即 mean 是一个标量,表示所有位置的均值相同。
    • 示例:
      import torch
      
      mean = 0.0
      std = torch.tensor([1.0, 0.5, 0.1])
      result = torch.normal(mean, std)
      print(result)
      
  4. mean 为标量,std 为标量:

    • 整个张量的每个元素都从相同的正态分布中采样,这个正态分布由 meanstd 决定。
    • 示例:
      import torch
      
      mean = 0.0
      std = 1.0
      result = torch.normal(mean, std, size=(3, 3))
      print(result)
      
特别注意事项
  • meanstd 都是张量时,它们的形状必须相同,以便在元素级别进行操作。
  • 如果 meanstd 是混合的(即一个是张量,一个是标量),那么标量值会应用于张量中的每个元素。
  • 输出张量的形状取决于输入张量的形状,或者当 meanstd 都是标量时,由 size 参数决定。
torch.rand

*torch.rand(size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:在区间[0, 1)上,生成均匀分布。

主要参数:

  • size (int…) - 创建的张量的形状
torch.rand_like

torch.rand_like(input, dtype=None, layout=None, device=None, requires_grad=False)

torch.rand_like之于torch.rand等同于torch.zeros_like之于torch.zeros,因此不再赘述。

torch.randint

torch.randint(low=0, high, size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:在区间[low, high)上,生成整数的均匀分布。

主要参数:

  • low (int, optional) - 下限。

  • high (int) – 上限,主要是开区间。

  • size (tuple) – 张量的形状。

example

print(torch.randint(3, 10, (2, 2)))
torch.randint_like

torch.randint_like(input, low=0, high, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:torch.randint_like之于torch.randint等同于torch.zeros_like之于torch.zeros,因此不再赘述。

torch.randn

*torch.randn(size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)

功能:生成形状为size的标准正态分布张量。

主要参数:

  • size (int…) - 张量的形状
torch.randn_like

torch.randn_like(input, dtype=None, layout=None, device=None, requires_grad=False)

功能:torch.rafndn_like之于torch_randn等同于torch.zeros_like之于torch.zeros,因此不再赘述。

torch.randperm

torch.randperm(n, out=None, dtype=torch.int64, layout=torch.strided, device=None, requires_grad=False)

功能:生成从0到n-1的随机排列。perm == permutation

torch.bernoulli

*torch.bernoulli(input, , generator=None, out=None)

功能:以input的值为概率,生成伯努力分布(0-1分布,两点分布)。

主要参数:

  • input (Tensor) - 分布的概率值,该张量中的每个值的值域为[0-1]

example:

import torch
p = torch.empty(3, 3).uniform_(0, 1)
b = torch.bernoulli(p)
print("probability: \n{}, \nbernoulli_tensor:\n{}".format(p, b))

总结

1. 是否自动计算梯度

关于张量的创建方式以及是否会自动计算梯度的表格如下:

创建方式描述是否自动计算梯度
torch.tensor(data)创建一个包含数据的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.zeros(size)创建一个全0的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.ones(size)创建一个全1的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.full(size, value)创建一个张量,并用指定值填充,默认不启用梯度计算。否(除非设置requires_grad=True
torch.arange(start, end)创建一个包含从start到end的序列的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.linspace(start, end)创建一个包含线性间隔的序列的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.rand(size)创建一个包含均匀分布随机数的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.randn(size)创建一个包含正态分布随机数的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.empty(size)创建一个未初始化的张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.eye(size)创建一个单位矩阵张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.autograd.Variable()创建一个变量(旧版本),可以设置是否启用梯度计算(通过requires_grad=True)。是(如果设置requires_grad=True
torch.from_numpy(ndarray)将一个NumPy数组转换为张量,默认不启用梯度计算。否(除非设置requires_grad=True
torch.tensor(data, requires_grad=True)创建一个启用梯度计算的张量。
并非所有的张量操作函数都有 device 参数。以下是关于 device 参数的一些关键点:
2. device 参数的作用

device 参数通常用于指定张量所在的计算设备,可以是 CPU 或 GPU。在某些创建张量的函数中,device 参数允许你直接指定张量应在哪个设备上创建。

3. 哪些函数有 device 参数
  • 张量创建函数: 大多数创建张量的函数,比如 torch.tensor, torch.zeros, torch.ones, torch.empty,都有 device 参数。你可以使用它来指定新创建的张量应位于 CPU 还是 GPU 上。例如:

    tensor = torch.zeros(3, 3, device='cuda')  # 在 GPU 上创建一个 3x3 的全零张量
    
  • 张量生成函数: 一些生成特定值的函数,比如 torch.arange, torch.linspace, torch.rand, torch.randn,也包含 device 参数。

    tensor = torch.linspace(0, 1, steps=5, device='cuda')  # 在 GPU 上生成一个线性间隔的张量
    
4. 哪些函数没有 device 参数
  • 张量操作函数: 大多数操作现有张量的函数,比如加法、乘法、矩阵乘法、索引、切片等,是不需要 device 参数的。这些函数依赖于输入张量的设备属性,并且在同一设备上执行操作。

    x = torch.tensor([1, 2, 3], device='cuda')
    y = x + 1  # y 也将位于 GPU 上
    
  • 非创建型函数: 函数如 torch.cat, torch.stack, torch.matmul 等,不接受 device 参数,因为它们操作的是已经存在的张量,并继承输入张量的设备属性。

5. 如何处理没有 device 参数的函数

如果你想在 GPU 上操作张量,但该函数没有 device 参数,可以先在 CPU 上创建张量,然后使用 to() 方法将其移动到 GPU:

tensor = torch.zeros(3, 3).to('cuda')  # 在 CPU 上创建,然后移动到 GPU
  • device 参数的函数: 主要是用于创建或生成张量的函数。
  • device 参数的函数: 大多数操作现有张量的函数没有 device 参数,它们在操作时继承输入张量的设备属性。
    以下是一些常见的没有 device 参数的 PyTorch 函数。这些函数通常用于操作现有张量,而不是创建新张量,因此它们不需要 device 参数。
函数描述
torch.add(tensor1, tensor2)逐元素加法
torch.sub(tensor1, tensor2)逐元素减法
torch.mul(tensor1, tensor2)逐元素乘法
torch.div(tensor1, tensor2)逐元素除法
torch.matmul(tensor1, tensor2)矩阵乘法
torch.cat(tensors, dim=0)在指定维度上连接张量
torch.stack(tensors, dim=0)在指定维度上叠加张量
torch.mean(tensor, dim=None)计算张量的均值(可以指定维度)
torch.sum(tensor, dim=None)计算张量的和(可以指定维度)
torch.max(tensor, dim=None)计算张量的最大值(可以指定维度)
torch.min(tensor, dim=None)计算张量的最小值(可以指定维度)
torch.transpose(tensor, dim0, dim1)转置张量的两个维度
torch.permute(tensor, dims)根据给定的维度顺序重新排列张量
torch.unsqueeze(tensor, dim)在指定位置增加一个维度
torch.squeeze(tensor, dim=None)删除指定位置的单维度
torch.view(tensor, shape)将张量重塑为指定形状
torch.reshape(tensor, shape)重新调整张量形状,返回新张量
torch.norm(tensor, p=2)计算张量的范数(默认 L2 范数)
torch.argmax(tensor, dim=None)返回指定维度上最大值的索引
torch.argmin(tensor, dim=None)返回指定维度上最小值的索引
torch.exp(tensor)计算张量中每个元素的指数
torch.log(tensor)计算张量中每个元素的自然对数
torch.sqrt(tensor)计算张量中每个元素的平方根
torch.pow(tensor, exponent)对张量中的每个元素进行幂运算
torch.eq(tensor1, tensor2)比较两个张量的逐元素相等性
torch.gt(tensor1, tensor2)比较两个张量的逐元素大于关系
torch.lt(tensor1, tensor2)比较两个张量的逐元素小于关系
torch.ge(tensor1, tensor2)比较两个张量的逐元素大于等于关系
torch.le(tensor1, tensor2)比较两个张量的逐元素小于等于关系

张量的操作

可以按照函数的主要用途将这些 PyTorch 函数分类,帮助更好地理解和使用它们。下面是一些常见的分类方式:

1. 张量创建和变形

  • reshape: 变换张量形状。
  • squeeze: 移除为1的轴。
  • unsqueeze: 增加一个轴。
  • flatten: 展平张量。
  • permute: 交换轴(根据指定顺序)。
  • transpose / swapaxes / swapdims: 交换两个轴。
  • movedim / moveaxis: 移动一个或多个轴到指定位置。
  • narrow: 在指定轴上进行索引,并返回切片。
  • tile: 沿多个维度重复张量。
  • stack: 在新的轴上拼接张量。

2. 张量拼接与堆叠

  • cat / concat: 沿指定轴拼接张量。
  • hstack / column_stack: 沿第二个维度水平堆叠张量。
  • vstack / row_stack: 沿第一个维度垂直堆叠张量。
  • dstack: 沿第三个维度(depthwise)堆叠张量。

3. 张量切分

  • split: 按给定大小切分张量。
  • chunk: 在指定维度上分成多个张量。
  • vsplit: 垂直切分张量(第一个维度)。
  • hsplit: 水平切分张量(第二个维度)。
  • dsplit: 深度切分张量(第三个维度)。
  • tensor_split: 按给定索引或份数切分张量。

4. 张量索引与选择

  • gather: 根据索引从指定轴上选择数据。
  • index_select: 在指定维度上根据索引选择数据。
  • masked_select: 根据布尔掩码选择数据。
  • nonzero: 返回张量中非零元素的索引。
  • where: 根据条件从两个张量中选择元素。
  • take: 根据索引从张量中取出元素,返回一维张量。
  • take_along_dim: 从指定维度按索引取值,保持维度不变。

5. 张量元素操作

  • scatter: 根据索引在指定轴上写入数据。
  • scatter_add: 根据索引在指定轴上进行加法操作。
  • conj: 返回共轭复数。

6. 张量移除与分解

  • unbind: 移除指定轴,返回一个张量列表。
  • narrow: 在指定轴上提取一个窄视图(切片)。

7. 张量的基本操作

  • t: 张量转置(对二维张量)。
  • row_stack: 按行堆叠(等同于 vstack)。

8. 高级操作

  • take_along_dim: 高级索引操作,与 gather 类似,用于在指定维度上按索引提取数据。

9. 特定维度上的操作

  • hstack / column_stack: 水平堆叠(第二维度)。
  • vstack / row_stack: 垂直堆叠(第一维度)。
  • dstack: 深度堆叠(第三维度)。

10. 函数别名

  • concat: cat 的别名。
  • moveaxis: movedim 的别名。
  • swapaxes: transpose 的别名。
  • swapdims: transpose 的别名。
  • row_stack: vstack 的别名。

scater_

scater是将input张量中的部分值进行替换。公式如下:

self[index[i][j][k]][j][k] = src[i][j][k]  # if dim == 0
self[i][index[i][j][k]][k] = src[i][j][k]  # if dim == 1
self[i][j][index[i][j][k]] = src[i][j][k]  # if dim == 2

设计两个核心问题:

  1. input哪个位置需要替换?
  2. 替换成什么?

答:

  1. 从公式可知道,依次从index中找到元素放到dim的位置,就是input需要变的地方。
  2. 变成什么呢? 从src中找,src中与index一样位置的那个元素值放到input中。

案例1:

>>> src = torch.arange(1, 11).reshape((2, 5))
>>> src
tensor([[ 1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10]])
>>> index = torch.tensor([[0, 1, 2, 0]])
>>> torch.zeros(3, 5, dtype=src.dtype).scatter_(0, index, src)
tensor([[1, 0, 0, 4, 0],
        [0, 2, 0, 0, 0],
        [0, 0, 3, 0, 0]])

dim=0, 所以行号跟着index的元素走。其它跟index的索引走。

第一步:找到index的第一个元素index[0, 0]是0, 那么把src[0, 0](是1)放到input[0, 0]
第二步:找到index的第二个元素index[0, 1]是1, 那么把src[0, 1](是2)放到input[1, 1]
第三步:找到index的第三个元素index[0, 2]是2, 那么把src[0, 2](是3)放到input[2, 2]
第四步:找到index的第四个元素index[0, 3]是0, 那么把src[0, 3](是4)放到input[0, 3]

案例2:


>>> src = torch.arange(1, 11).reshape((2, 5))
>>> src
tensor([[ 1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10]])
>>> index = torch.tensor([[0, 2, 4], [1, 2, 3]])
>>> index
tensor([[0, 2, 4],
        [1, 2, 3]])
>>> torch.zeros(3, 5, dtype=src.dtype).scatter_(1, index, src)
tensor([[1, 0, 2, 0, 3],
        [0, 6, 7, 8, 0],
        [0, 0, 0, 0, 0]])

dim=1:告诉input(零矩阵)的索引,沿着列进行索引,行根据index走。 index:2*3,告诉input(零矩阵),你的哪些行是要被替换的。 src:input要替换成什么呢?从src里找,怎么找?通过index的索引对应的找。

第一步:找到index的第一个元素index[0, 0]是0, 那么把src[0, 0](是1)放到input[0, 0]
第二步:找到index的第二个元素index[0, 1]是2, 那么把src[0, 1](是2)放到input[0, 2]
第三步:找到index的第三个元素index[0, 2]是4, 那么把src[0, 2](是3)放到input[0, 4]
第四步:找到index的第四个元素index[1, 0]是1, 那么把src[1, 0](是6)放到input[1, 1]
第五步:找到index的第五个元素index[1, 1]是2, 那么把src[1, 1](是7)放到input[1, 2]
第六步:找到index的第六个元素index[1, 2]是3, 那么把src[1, 2](是8)放到input[1, 3]

这里可以看到

  • index的元素是决定input的哪个位置要变
  • 变的值是从src上对应于index的索引上找。可以看到src的索引与index的索引保持一致的

案例3:one-hot的生成

>>> label = torch.arange(3).view(-1, 1)
>>> label
tensor([[0],
        [1],
        [2]])
>>> torch.zeros(3, 3).scatter_(1, label, 1)
tensor([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]])

第一步:找到index的第一个元素index[0, 0]是0, 那么把src[0, 0](是1)放到input[0, 0]

第二步:找到index的第二个元素index[1, 0]是1, 那么把src[1, 0](是1)放到input[1, 1]

第三步:找到index的第三个元素index[2, 0]是2, 那么把src[2, 0](是1)放到input[2, 2]

(one-hot的案例不利于理解scater函数,因为它的行和列是一样的。。。其实input[x, y] 中的x,y是有区别的,x是根据index走,y是根据index的元素值走的,而具体的值是根据src的值。)

张量的随机种子

随机种子(random seed)是编程语言中基础的概念,大多数编程语言都有随机种子的概念,它主要用于实验的复现。针对随机种子pytorch也有一些设置函数。

seed获取一个随机的随机种子。Returns a 64 bit number used to seed the RNG.
manual_seed手动设置随机种子,建议设置为42,这是近期一个玄学研究。说42有效的提高模型精度。当然大家可以设置为你喜欢的,只要保持一致即可。
initial_seed返回初始种子。
get_rng_state获取随机数生成器状态。Returns the random number generator state as a torch.ByteTensor.
set_rng_state设定随机数生成器状态。这两怎么用暂时未知。Sets the random number generator state.

以上均是设置cpu上的张量随机种子,在cuda上是另外一套随机种子,如torch.cuda.manual_seed_all(seed), 这些到cuda模块再进行介绍,这里只需要知道cpu和cuda上需要分别设置随机种子。

张量的数学操作

张量还提供大量数学操作,估计了一下,有快一百个函数,这里就不再一一分析,只需要知道有哪几大类,用到的时候来查吧。

  • Pointwise Ops: 逐元素的操作,如abs, cos, sin, floor, floor_divide, pow等
  • Reduction Ops: 减少元素的操作,如argmax, argmin, all, any, mean, norm, var等
  • Comparison Ops:对比操作, 如ge, gt, le, lt, eq, argsort, isnan, topk,
  • Spectral Ops: 谱操作,如短时傅里叶变换等各类信号处理的函数。
  • Other Operations:其它, clone, diag,flip等
  • BLAS and LAPACK Operations:BLAS(Basic Linear Algebra Subprograms)基础线性代数)操作。如, addmm, dot, inner, svd等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值