PyTorch, 16个超强转换函数总结 ! !

Python
41
0
0
2024-07-08
本文介绍了关于pytorch的转换函数。在平常的使用中又多又重要 ! 当然,在Pytorch中,转换函数的意义主要是用于对进行数据的预处理和数据增强,使其适用于深度学习模型的训练和推理。

前言

简单来说,Pytorch的转换函数其重要意义有6个方面:

1. 数据格式转换: 将不同格式的数据(如PIL图像、NumPy数组)转换为PyTorch张量,以便能够被深度学习模型处理。例如,transforms.ToTensor() 将图像转换为张量。

2. 数据标准化: 将输入数据的值缩放到某个特定范围。标准化对于提高模型的训练效果和收敛速度很重要。例如,transforms.Normalize() 可用于标准化图像数据。

3. 数据增强: 数据增强是指在数据集上应用一系列变换,以生成更多、更多样化的训练样本,从而提高模型的泛化能力。例如,transforms.RandomCrop()transforms.RandomHorizontalFlip() 等。

4. 输入大小调整: 深度学习模型通常对输入的大小有一定的要求。转换函数可以用于调整输入数据的大小,以适应模型的输入尺寸。例如,transforms.Resize()

5. 灰度化、归一化等操作: 转换函数还可以执行其他各种操作,如将图像灰度化、进行归一化等。这些操作有助于提供更好的输入数据。

6. 简化数据处理流程: 转换函数可以将数据预处理和数据增强操作整合到一个流程中,使数据处理的代码更加清晰和可维护。

十六个转换函数

  • view()
  • t()
  • permute()
  • unsqueeze()
  • squeeze()
  • transpose()
  • cat()
  • stack()
  • chunk()
  • flip()
  • relu()
  • dropout()
  • interpolate()
  • masked_select()
  • softmax()

具体介绍

view()

view() 用于改变张量的形状,类似于NumPy中的reshape

这个函数不会修改原始张量的数据,而是返回一个具有新形状的张量。

import torch

# 创建一个张量
x = torch.arange(12)

# 使用 view() 改变形状
y = x.view(3, 4)

参数:

  • size(tuple or int): 期望的新形状。可以是整数或表示维度的元组。元组中的一个元素可以是-1, 表示由其他维度推断。

示例:

import torch

# 创建一个张量
x = torch.arange(12)

# 使用 view() 改变形状
y = x.view(3, 4)

print(x)
# Output: tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

print(y)
# Output: tensor([[ 0,  1,  2,  3],
#                  [ 4,  5,  6,  7],
#                  [ 8,  9, 10, 11]])

# 使用 view() 改变形状,其中一个维度为-1,表示由其他维度推断
z = x.view(2, -1)

print(z)
# Output: tensor([[ 0,  1,  2,  3,  4,  5],
#                  [ 6,  7,  8,  9, 10, 11]])

注意点:

1. 形状的总元素个数必须与原张量的总元素个数相同,否则会抛出错误。

2. view() 返回的新张量与原张量共享内存,即它们指向相同的数据,因此对一个张量的修改会影响另一个。

3. 在某些情况下,view()无法创建新形状,可以使用reshape() 函数来代替:。

z = x.reshape(2, -1)

4. view() 在深度学习中的常见用途包括将输入数据整形以适应神经网络的输入层,或者在处理图像数据时重新排列通道维度。

t()

torch.Tensor.t() 函数是Pytorch中用于计算张量转置的方法。但是方法仅适用于2D张量(矩阵),并且会返回输入矩阵的转置。当然不会对原始矩阵进行修改,而是返回一个新的张量。

import torch

# 创建一个2D张量(矩阵)
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

# 计算矩阵的转置
y = x.t()

示例:

import torch

# 创建一个2D张量(矩阵)
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

# 计算矩阵的转置
y = x.t()

print(x)
# Output: tensor([[1, 2, 3],
#                  [4, 5, 6]])

print(y)
# Output: tensor([[1, 4],
#                  [2, 5],
#                  [3, 6]])

注意点:

1. t() 只适用于2D张量,对于具有更高维度的张量,应该使用transpose() permute()

# 对于更高维度的张量,使用transpose()或permute()
x = torch.rand(2, 3, 4)
y = x.transpose(0, 2).contiguous()  # 这里交换了维度0和2

2. t() 返回的是一个新的张量,不会修改原始矩阵。

3. 在进行矩阵转置时,注意原始矩阵的维度和形状。

torch.Tensor.t() 主要用于处理矩阵的转置操作,是在处理线性代数运算时经常会用到的一个基础操作。

permute()

torch.Tensor.permute() 是Pytorch中用于交换张量维度的函数。它可以改变张量的维度顺序,并返回一个新的张量,不会修改原始张量的数据。

import torch

# 创建一个张量
x = torch.randn(2, 3, 4)

# 使用 permute() 交换维度顺序
y = x.permute(2, 0, 1)

参数:

  • dim(int...): 指定新维度顺序的整数序列。

示例:

import torch

# 创建一个张量
x = torch.randn(2, 3, 4)

# 使用 permute() 交换维度顺序
y = x.permute(2, 0, 1)

print(x.shape)
# Output: torch.Size([2, 3, 4])

print(y.shape)
# Output: torch.Size([4, 2, 3])

注意点:

1. 参数dims 应该是一个整数序列,用于指定新的维度顺序。这些整数应该是原始张量维度的有效索引。

2. permute() 返回的是一个新的张量,不会修改原始张量。

3. permute() 不会改变原始数据的存储顺序,只是改变了张量的视图。

4. 在某些情况下,可能需要使用contiguous() 函数来保证新张量是连续存储的。

y = x.permute(2, 0, 1).contiguous()

permute() 在深度学习中的常见用途包括在处理图像数据时交换通道维度,或者在神经网络中调整输入数据的维度以适应模型的期望输入。

unsqueeze()

torch.Tensor.unsqueeze() 是Pytorch中用于在指定维度上增加一个维度的函数。

可以在张量的指定位置插入一个大小为1的新维度,并返回一个新的张量,不会修改原始张量的数据。

import torch

# 创建一个张量
x = torch.tensor([1, 2, 3, 4])

# 使用 unsqueeze() 在指定维度上增加一个维度
y = x.unsqueeze(0)

参数:

  • dim(int): 指定要插入新维度的位置。

示例:

import torch

# 创建一个张量
x = torch.tensor([1, 2, 3, 4])

# 使用 unsqueeze() 在指定维度上增加一个维度
y = x.unsqueeze(0)

print(x.shape)
# Output: torch.Size([4])

print(y.shape)
# Output: torch.Size([1, 4])

注意点:

1. 参数dim 应该是一个整数,用于指定要插入新维度的位置。可以是负数,表示从最后一个维度开始计数。

2. unsqueeze() 返回的是一个新的张量,不会修改原始张量。

3. 插入的新维度大小为1。

4. unsqueeze() 可以用于在张量中的任何位置插入新维度。

# 在最后一个维度插入新维度
y = x.unsqueeze(-1)

unsqueeze() 在深度学习中的常见用途包括在处理图像数据时增加批次维度,或者在神经网络中调整输入数据的维度以适应模型的期望输入。

squeeze()

torch.Tensor.squeeze() 用于去除大小为1的维度的函数。它可以在张量中去除指定维度的大小为1的维度,并返回一个新的张量,不会修改原始张量的数据。

import torch

# 创建一个张量
x = torch.randn(1, 3, 1, 4)

# 使用 squeeze() 去除大小为1的维度
y = x.squeeze()

参数:

  • dim(int, optional): 指定要去除的维度,如果指定,只有在该维度大小为1时才会去除。

示例:

import torch

# 创建一个张量
x = torch.randn(1, 3, 1, 4)

# 使用 squeeze() 去除大小为1的维度
y = x.squeeze()

print(x.shape)
# Output: torch.Size([1, 3, 1, 4])

print(y.shape)
# Output: torch.Size([3, 4])

注意点:

1. 如果没用指定dim 参数,sequeeze() 将会去除所有大小为1的维度。

# 去除所有大小为1的维度
y = x.squeeze()

2. squeeze() 返回的是一个新的张量,不会修改原始张量。

3. 在某些情况下,可能需要使用unsqueeze() 函数来增加维度,以避免对张量进行过度的维度操作。

# 避免过度的维度操作
y = x.unsqueeze(0).squeeze(2)

squeeze() 在深度学习中的常见用途包括处理网络输出中不必要的维度,使其更易于后续处理,或者在构建输入数据时去除不必要的维度。

transpose()

torch.Tensor.transpose() 用于交换张量维度顺序的函数。与permute() 不同,transpose() 只能用于二维张量(矩阵)的维度交换。它返回一个新的张量,不会修改原始张量的数据。

import torch

# 创建一个2D张量(矩阵)
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

# 使用 transpose() 交换维度顺序
y = x.transpose(0, 1)

参数:

  • dim0(int): 要交换的维度之一的索引。
  • dim1(int): 要交换的维度之二的索引。

示例:

import torch

# 创建一个2D张量(矩阵)
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

# 使用 transpose() 交换维度顺序
y = x.transpose(0, 1)

print(x)
# Output: tensor([[1, 2, 3],
#                  [4, 5, 6]])

print(y)
# Output: tensor([[1, 4],
#                  [2, 5],
#                  [3, 6]])

注意点:

1. 参数dim0 参数和dim1 应该是维度的有效索引。

2. transpose() 返回的是一个新的张量,不会修改原始张量。

3. 对于更高维度的张量,可以使用permute() transpose() 结合 contiguous()

# 对于更高维度的张量,使用transpose()结合contiguous()
x = torch.rand(2, 3, 4)
y = x.transpose(0, 2).contiguous()  # 这里交换了维度0和2

4. 如果要在不同维度上交换元素,可以使用索引操作。

# 在不同维度上交换元素
y = x[:, [2, 1, 0]]

transpose() 主要用于处理二维张量的维度交换,是在处理矩阵运算时常用的操作。

cat()

torch.cat() 是PyTorch中用于沿指定轴连接张量的函数。它能够将多个张量沿指定维度进行拼接,返回一个新的张量,不会修改原始张量的数据。

import torch

# 创建两个张量
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

y = torch.tensor([[7, 8, 9],
                  [10, 11, 12]])

# 使用 cat() 沿指定轴连接张量
z = torch.cat((x, y), dim=0)

参数:

  • tensor(sequence): 要连接的张量序列。
  • dim(int): 指定沿哪个轴进行连接的维度。

示例:

import torch

# 创建两个张量
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

y = torch.tensor([[7, 8, 9],
                  [10, 11, 12]])

# 使用 cat() 沿指定轴连接张量
z = torch.cat((x, y), dim=0)

print(x)
# Output: tensor([[1, 2, 3],
#                  [4, 5, 6]])

print(y)
# Output: tensor([[ 7,  8,  9],
#                  [10, 11, 12]])

print(z)
# Output: tensor([[ 1,  2,  3],
#                  [ 4,  5,  6],
#                  [ 7,  8,  9],
#                  [10, 11, 12]])

注意点:

1. dim 参数指定了沿哪个轴进行连接,可以是负数,表示从最后一个维度开始计数。

2. 连接的张量在指定维度上的大小必须一致,否则会引发错误。

# 张量大小不一致会引发错误
z = torch.cat((x, y), dim=1)  # 会抛出错误

3. cat() 返回的是一个新的张量,不会修改原始张量。

4. 如果连接的张量维度相同,也可以使用stack() 函数。

# 使用 stack() 进行连接
z = torch.stack((x, y), dim=0)

torch.cat() 在深度学习中的常见用途包括在模型的训练过程中将不同批次的数据连接在一起,以提高训练效率。

stack()

torch.stack() 用于在新的轴上堆叠张量的函数。它可以将一组张量沿着一个新的维度进行堆叠,返回一个新的张量,不会修改原始张量的数据。

import torch

# 创建两个张量
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6])

# 使用 stack() 在新的轴上堆叠张量
z = torch.stack((x, y), dim=0)

参数:

  • tensor(sequence): 要堆叠的张量序列。
  • dim(int): 指定新的轴的维度。

示例:

import torch

# 创建两个张量
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6])

# 使用 stack() 在新的轴上堆叠张量
z = torch.stack((x, y), dim=0)

print(x)
# Output: tensor([1, 2, 3])

print(y)
# Output: tensor([4, 5, 6])

print(z)
# Output: tensor([[1, 2, 3],
#                  [4, 5, 6]])

注意点:

1. dim 参数指定新的轴的维度,可以是负数,表示从最后一个维度开始计数。

2. 堆叠的张量在指定维度上的大小必须一致,否则会引发错误。

# 张量大小不一致会引发错误
z = torch.stack((x, y), dim=1)  # 会抛出错误

3. stack() 返回的是一个新的张量,不会修改原始张量。

4. 如果需要在现有维度上连接张量,可以使用cat() 函数。

# 使用 cat() 在现有维度上连接张量
z = torch.cat((x.unsqueeze(0), y.unsqueeze(0)), dim=0)

torch.stack() 在深度学习中的常见用途包括在处理序列数据时将不同时间步的数据堆叠在一起,或者在构建输入数据时在新的轴上堆叠不同的特征。

chunk()

torch.chunk() 是PyTorch中用于将张量沿指定维度分割为多个子张量的函数。它允许将一个张量分割成若干块.返回一个包含这些块的元组,不会修改原始张量的数据。

import torch

# 创建一个张量
x = torch.arange(10)

# 使用 chunk() 将张量分割为多个子张量
chunks = torch.chunk(x, chunks=3, dim=0)

参数:

  • input(tensor): 要分割的输入张量。
  • chunks(int): 要分割的块数。
  • dim(int): 指定分割的维度。

示例:

import torch

# 创建一个张量
x = torch.arange(10)

# 使用 chunk() 将张量分割为多个子张量
chunks = torch.chunk(x, chunks=3, dim=0)

print(x)
# Output: tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(chunks)
# Output: (tensor([0, 1, 2]), tensor([3, 4, 5]), tensor([6, 7, 8, 9]))

注意点:

1. chunks 参数指定了要分割的块数,这些块在指定维度上的大小会尽量保持均匀。如果无法均匀分割,最后一个子张量的大小会比其他的小。

2. dim 参数指定了要分割的维度,可以是负数,表示从最后一个维度开始计数。

3. chunk() 返回的是一个元组,包含分割后的子张量。

4. 分割后的子张量在指定维度上的大小相同。

# 分割后的子张量在指定维度上的大小相同
chunk1, chunk2, chunk3 = torch.chunk(x, chunks=3, dim=0)
print(chunk1.size(), chunk2.size(), chunk3.size())  # 输出 torch.Size([3])

# 最后一个子张量的大小小于其他的
chunk1, chunk2, chunk3 = torch.chunk(x, chunks=4, dim=0)
print(chunk1.size(), chunk2.size(), chunk3.size())  # 输出 torch.Size([2])

5. 如果需要在不同维度上分割张量,可以使用split() 函数。

# 在不同维度上分割张量
chunks = torch.split(x, split_size_or_sections=3, dim=0)

torch.chunk() 在深度学习中的常见用途包括在模型训练时对输入数据进行分块处理,以适应内存或模型的需求。

flip()

torch.flip() 用于沿指定维度翻转张量的函数。它可以将张量在指定维度上进行翻转,返回一个新的张量,不会修改原始张量的数据。

import torch

# 创建一个张量
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

# 使用 flip() 在指定维度上翻转张量
y = torch.flip(x, dims=[1])

参数:

  • input(tensor): 要翻转的输入张量。
  • dims (tuple of ints): 指定要翻转的维度。

示例:

import torch

# 创建一个张量
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

# 使用 flip() 在指定维度上翻转张量
y = torch.flip(x, dims=[1])

print(x)
# Output: tensor([[1, 2, 3],
#                  [4, 5, 6]])

print(y)
# Output: tensor([[3, 2, 1],
#                  [6, 5, 4]])

注意点:

1. dims 参数是一个整数元组,用于指定要翻转的维度。可以是负数,表示从最后一个维度开始计数。

2. flip() 返回的是一个新的张量,不会修改原始张量。

3. 在翻转时,元素的相对顺序会发生变化。

# 元素的相对顺序发生变化
x = torch.tensor([1, 2, 3, 4, 5])
y = torch.flip(x, dims=[0])
print(y)  # 输出 tensor([5, 4, 3, 2, 1])

4. 对于多维张量,可以在不同维度上进行翻转。

# 在不同维度上进行翻转
x = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
y = torch.flip(x, dims=[1, 2])

torch.flip() 在深度学习中的常见用途包括在处理图像数据时翻转图像,或者在神经网络中调整输入数据的方向以适应模型的期望输入。

relu()

torch.nn.functional.relu() 用于应用修正线性单元(ReLU)激活函数的函数。ReLU 是深度学习中常用的激活函数之一,它在正输入值上返回输入值本身,而在负输入值上返回零。

import torch
import torch.nn.functional as F

# 创建一个张量
x = torch.tensor([-1, 0, 1, 2], dtype=torch.float32)

# 使用 relu() 应用修正线性单元激活函数
y = F.relu(x)

参数:

  • input(tensor): 输入张量,可以包含任何形状。

示例:

import torch
import torch.nn.functional as F

# 创建一个张量
x = torch.tensor([-1, 0, 1, 2], dtype=torch.float32)

# 使用 relu() 应用修正线性单元激活函数
y = F.relu(x)

print(x)
# Output: tensor([-1.,  0.,  1.,  2.])

print(y)
# Output: tensor([0., 0., 1., 2.])

注意点:

1. ReLU 激活函数对于正值直接输出,而对于负值输出零。

2. torch.nn.functional.relu() 返回的是一个新的张量,不会修改原始张量。

3. ReLU 是一种常用的激活函数,用于增强神经网络的非线性特性。在深度学习中,ReLU 激活函数被广泛应用于隐藏层。

4. 在 PyTorch 中,也可以通过torch.relu() 函数来应用 ReLU 激活函数。

# 使用 torch.relu() 应用 ReLU 激活函数
y = torch.relu(x)

这个激活函数的使用可以帮助网络更好地学习非线性模式,是深度学习中非常重要的组成部分之一。

dropout()

torch.nn.functional.dropout() 用于在训练时应用随机的丢弃(dropout)操作的函数。丢弃是一种正则化技术,通过在前向传播期间随机将一些神经元的输出置零,从而减少过拟合的风险。

import torch
import torch.nn.functional as F

# 创建一个张量
x = torch.randn(5, 10)

# 使用 dropout() 应用随机丢弃操作
y = F.dropout(x, p=0.5, training=True)

参数:

  • input(tensor): 输入张量,代表前一层的输出。
  • p(float, optional): 丢弃概率,即神经元被置零的概率。默认为0.5。
  • training(bool, optional): 表示当前是否处于训练模式。默认为True,表示进行丢弃操作;如果设置为False,则不会进行丢弃操作,直接返回输入张量。

示例:

import torch
import torch.nn.functional as F

# 创建一个张量
x = torch.randn(5, 10)

# 使用 dropout() 应用随机丢弃操作
y = F.dropout(x, p=0.5, training=True)

print(x)
# Output: tensor([[ 0.1357, -0.5290, -0.6198, -0.1593,  0.3808, -0.5411,  0.4195, -0.8948, -1.0767, -0.0122],
#                 [ 0.0671,  1.4331, -0.0803, -1.0338, -0.3833,  1.0944, -0.6839, -0.1487, -0.1711, -0.5047],
#                 [-0.4161,  0.4712, -0.2137, -0.5391, -0.4167, -0.2875,  0.1237, -1.4729, -0.5049, -1.2634],
#                 [ 0.0446,  0.7522,  1.2084, -0.0793, -0.4469,  0.5371,  0.5293,  0.0559, -0.3813,  1.7271],
#                 [-0.0413, -0.2323,  1.1559,  1.5406, -1.0513,  0.5805,  0.5156, -1.1534,  0.5279, -0.2373]])

print(y)
# Output: tensor([[ 0.0000, -1.0580, -1.2397, -0.0000,  0.7616, -0.0000,  0.8390, -1.7897, -2.1534, -0.0243],
#                 [ 0.1342,  2.8661, -0.0000, -0.0000, -0.0000,  2.1887, -0.0000, -0.2974, -0.3422, -1.0095],
#                 [-0.8322,  0.9423, -0.0000, -1.0783, -0.8334, -0.5751,  0.2474, -2.9458, -1.0097, -0.0000],
#                 [ 0.0892,  0.0000,  2.4168, -0.1585, -0.8938,  1.0743,  1.0586,  0.1118, -0.7627,  3.4542],
#                 [-0.0826, -0.4647,  2.3117,  3.0813, -2.1026,  1.1610,  1.0311, -2.3068,  1.0557, -0.4745]])

注意点:

1. p 参数表示丢弃概率,即每个神经元被置零的概率。一般而言,典型的值为 0.2 到 0.5。

2. 在训练模式下(training=True)才会应用 dropout 操作。在评估模型时,通常设置training=False来避免 dropout。

3. dropout 操作有助于防止神经网络过拟合训练数据。

4. 在 PyTorch 中,也可以通过torch.nn.dropout 类来使用 dropout 操作。

import torch.nn as nn

# 创建 Dropout 层
dropout_layer = nn.Dropout(p

interpolate()

torch.nn.functional.interpolate() 用于对张量进行插值操作的函数。这个函数通常用于调整图像或特征图的大小,以适应模型的输入要求。

import torch
import torch.nn.functional as F

# 创建一个图像张量
x = torch.rand(1, 3, 64, 64)

# 使用 interpolate() 调整图像大小
y = F.interpolate(x, size=(128, 128), mode='bilinear', align_corners=False)

参数:

  • input(tensor): 输入张量,可以是任何形状的图像或特征图。
  • size(int or Tuple[int]): 目标大小,可以是一个整数或包含两个整数的元组。
  • scale_factor(float or Tuple[float]): 尺度因子,可以是一个浮点数或包含两个浮点数的元组。
  • mode(str, optional): 插值模式,可以是 'nearest', 'linear', 'bilinear', 'bicubic', 'trilinear', 'area' 中的一个。默认为 'nearest'。
  • align_corners(bool, optional): 是否在计算插值时保持角点对齐。默认为False

示例:

import torch
import torch.nn.functional as F

# 创建一个图像张量
x = torch.rand(1, 3, 64, 64)

# 使用 interpolate() 调整图像大小
y = F.interpolate(x, size=(128, 128), mode='bilinear', align_corners=False)

print(x.shape)
# Output: torch.Size([1, 3, 64, 64])

print(y.shape)
# Output: torch.Size([1, 3, 128, 128])

注意点:

1. size 参数指定了目标大小,可以是一个整数或包含两个整数的元组。如果sizescale_factor 都没有指定,那么输入张量的大小不会改变。

2. scale_factor参数指定了尺度因子,可以是一个浮点数或包含两个浮点数的元组。如果 sizescale_factor都没有指定,那么输入张量的大小不会改变。

3. mode参数指定了插值模式,常用的有 'nearest', 'linear', 'bilinear', 'bicubic', 'trilinear', 'area'。其中 'bilinear' 在二维图像上常用,'trilinear' 在三维体积上常用。

4. align_corners 参数在使用 'bilinear' 或 'bicubic' 插值模式时影响插值的准确性。在图像处理中,通常将其设置为False

# 设置 align_corners=True
y_true = F.interpolate(x, size=(128, 128), mode='bilinear', align_corners=True)

# 设置 align_corners=False
y_false = F.interpolate(x, size=(128, 128), mode='bilinear', align_corners=False)

# y_true 和 y_false 在结果上可能有轻微的差异

torch.nn.functional.interpolate() 在深度学习中的常见用途包括在模型输入前对图像或特征图进行大小调整,以适应网络的输入尺寸。

masked_select()

torch.masked_select() 是 PyTorch 中用于根据掩码从输入张量中选择元素的函数。它会返回一个新的张量,其中包含满足掩码条件的元素。

import torch

# 创建一个张量
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])

# 创建一个掩码
mask = torch.tensor([[0, 1, 0],
                     [1, 0, 1],
                     [0, 1, 0]], dtype=torch.bool)

# 使用 masked_select() 根据掩码选择元素
selected = torch.masked_select(x, mask)

参数:

  • input(tensor): 输入张量,可以是任何形状。
  • mask(Byte Tensor): 与输入张量相同形状的掩码张量,元素值为True 表示选择该位置的元素,元素值为False 表示不选择该位置的元素。

示例:

import torch

# 创建一个张量
x = torch.tensor([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])

# 创建一个掩码
mask = torch.tensor([[0, 1, 0],
                     [1, 0, 1],
                     [0, 1, 0]], dtype=torch.bool)

# 使用 masked_select() 根据掩码选择元素
selected = torch.masked_select(x, mask)

print(x)
# Output: tensor([[1, 2, 3],
#                  [4, 5, 6],
#                  [7, 8, 9]])

print(mask)
# Output: tensor([[False,  True, False],
#                  [ True, False,  True],
#                  [False,  True, False]])

print(selected)
# Output: tensor([2, 4, 6, 8])

注意点:

1. mask 参数参数的数据类型应为torch.bool torch.uint8

2. 返回的张量是一个一维张量,其中包含满足掩码条件的元素。元素的顺序是按照输入张量在内存中的顺序得到的。

3. 如果要根据某个条件选择元素,并保持原始张量的形状,可以使用torch.where() 函数。

# 根据条件选择元素,并保持原始张量的形状
result = torch.where(mask, x, torch.zeros_like(x))

torch.masked_select() 在深度学习中的常见用途包括对模型输出进行过滤,只选择满足某些条件的预测值。

softmax()

torch.nn.functional.softmax() 是 PyTorch 中用于计算 softmax 函数的函数。softmax 函数通常用于将模型的原始输出转换为概率分布,使得每个类别的概率值都在 (0, 1) 范围内,并且所有类别的概率之和为 1。

import torch
import torch.nn.functional as F

# 创建一个张量
x = torch.tensor([1.0, 2.0, 3.0])

# 使用 softmax() 计算 softmax 函数
y = F.softmax(x, dim=0)

参数:

  • input(tensor): 输入张量,包含模型的原始输出。
  • dim(int, optional): 指定 softmax 操作的维度。默认为 0。

示例:

import torch
import torch.nn.functional as F

# 创建一个张量
x = torch.tensor([1.0, 2.0, 3.0])

# 使用 softmax() 计算 softmax 函数
y = F.softmax(x, dim=0)

print(x)
# Output: tensor([1., 2., 3.])

print(y)
# Output: tensor([0.0900, 0.2447, 0.6652])

注意点:

1. dim 参数指定了 softmax 操作的维度。对于二维张量(通常是分类问题的输出),一般将dim 设为 1。

2. softmax 函数的输出是一个概率分布,所有类别的概率之和为 1。

3. softmax 函数对输入进行指数运算,因此可能受到数值不稳定性的影响。在实际应用中,可以使用 ​​​​​​torch.nn.functional.log_softmax() 来计算 log-softmax,以提高数值稳定性。

# 使用 log_softmax() 计算 log-softmax 函数
log_y = F.log_softmax(x, dim=0)

4. 对于模型的多分类输出,通常在训练时使用 softmax 函数,而在预测时使用模型输出的原始值,因为 softmax 不改变相对大小关系。

# 在训练时使用 softmax
y_train = F.softmax(model(x), dim=1)

# 在预测时使用原始输出值
y_pred = model(x)

torch.nn.functional.softmax() 在深度学习中常用于多分类问题,其中模型的输出需要转换为概率分布以进行交叉熵损失计算。

ToTensor()

transforms.ToTensor() 是 PyTorch 中的一个转换函数,主要用于将 PIL 图像或 NumPy 数组转换为 PyTorch 张量。这个转换函数是 torchvision 库的一部分,位于torchvision.transforms 模块中。

import torch
from torchvision import transforms
from PIL import Image

# 读取图像
image_path = "path/to/your/image.jpg"
image = Image.open(image_path)

# 定义 ToTensor 转换
to_tensor = transforms.ToTensor()

# 应用 ToTensor 转换
tensor_image = to_tensor(image)

功能:

1. 通道顺序变换: 将图像的通道顺序从 H x W x C(Height x Width x Channels)转换为 C x H x W(Channels x Height x Width)。

2. 像素值缩放: 将像素值从 [0, 255] 范围缩放到 [0, 1] 范围内。即将图像中每个像素的值除以 255,以确保得到的张量中的值在 0 到 1 之间。

示例:

import torch
from torchvision import transforms
from PIL import Image

# 读取图像
image_path = "lenna.jpg"
image = Image.open(image_path)

# 定义 ToTensor 转换
to_tensor = transforms.ToTensor()

# 应用 ToTensor 转换
tensor_image = to_tensor(image)

print(tensor_image.shape)
# 输出:torch.Size([3, 64, 64])

在上述示例中,tensor_image 将是一个形状为 [3, 64, 64] 的张量,其中 3 表示图像的通道数(RGB),而 64 x 64 是图像的高度和宽度。

注意点:

1. 数据类型: 转换后的张量的数据类型是 torch.float32

2. 数值范围: 图像的每个通道的数值范围会被缩放到 [0, 1] 范围内。

3. 适用对象: 主要用于预处理图像数据以供神经网络处理。在训练神经网络时,通常会将图像转换为张量,以便进行后续的数据标准化、数据增强等操作。

案例: 分离图像的RGB通道

在这个项目中,我们用lenna的一张图片,分离图像的 RGB 通道,得到三个独立的通道图像,并保存它们为三张图片。案例中我们使用ToTensor()这个方法。

涉及原理:

RGB 图像由红色(R)、绿色(G)和蓝色(B)三个通道组成。每个通道的数值范围通常在 0 到 255 之间。

我们可以使用下面公式将一个像素的 RGB 值分离出来,得到三个独立的通道图数据:

  • 红色通道 (R):
  • 绿色通道 (G):
  • 蓝色通道 (B):

上述代码的具体实现,在下面的第3条。

案例代码:

import torch
import torchvision.transforms as transforms
from PIL import Image
import matplotlib.pyplot as plt

# 加载图像
image_path = 'lenna.jpg'  
image = Image.open(image_path)

# 定义图像转换
transform = transforms.Compose([
    transforms.ToTensor()
])

image_tensor = transform(image)

# 分离RGB通道
red_channel = image_tensor[0, :, :]
green_channel = image_tensor[1, :, :]
blue_channel = image_tensor[2, :, :]

# 转换回PIL图像
def tensor_to_image(tensor):
    tensor = torch.clamp(tensor, 0, 1)  # 将张量值限制在[0, 1]范围内
    image = transforms.ToPILImage()(tensor)
    return image

# 将各个通道的Tensor转换为PIL图像
red_image = tensor_to_image(red_channel)
green_image = tensor_to_image(green_channel)
blue_image = tensor_to_image(blue_channel)

# 显示原始图像和分离后的各个通道图像
plt.figure(figsize=(10, 5))

plt.subplot(2, 2, 1)
plt.title('Original Image')
plt.imshow(image)
plt.axis('off')

plt.subplot(2, 2, 2)
plt.title('Red Channel')
plt.imshow(red_image)
plt.axis('off')

plt.subplot(2, 2, 3)
plt.title('Green Channel')
plt.imshow(green_image)
plt.axis('off')

plt.subplot(2, 2, 4)
plt.title('Blue Channel')
plt.imshow(blue_image)
plt.axis('off')

plt.show()

代码中,我们使用经典的lenna图作为输入。最终的效果是显示原始图像和分离的红色、绿色和蓝色通道图像。

通过观察这些图像,可以更好地理解ToTensor()以及后续数据分割的使用和理解。

来源: 深夜努力写Python,作者 cos大壮。