基于pytorch的视觉变换器-Vision Transformer(ViT)的介绍与应用

近年来,计算机视觉领域因变换器模型的出现而发生了革命性变化。最初为自然语言处理任务设计的变换器,在捕捉视觉数据的空间依赖性方面也显示出了惊人的能力。视觉变换器(Vision Transformer,简称ViT)就是这种变革的一个典型例子,它提出了一种新颖的架构,在各种图像分类任务上实现了最先进的性能。

在这篇文章中,我们将一起构建我们自己的视觉变换器模型,使用PyTorch进行实现。通过逐步分解实现过程,我们旨在提供对ViT架构的全面理解,并使您能够清晰地掌握其内部工作原理。当然,我们可以直接使用PyTorch内置的视觉变换器模型,但那样就没有乐趣了。

我们将从设置必要的依赖和库开始,确保整个项目的顺利进行。接下来,我们将进入数据获取阶段,获取适合训练我们的视觉变换器模型的数据集。

为了准备训练数据,我们将定义必要的转换操作,用于增强和标准化输入图像。随着数据转换的到位,我们将创建自定义数据集和数据加载器,为训练模型搭建舞台。

要理解视觉变换器架构,从零开始构建它至关重要。在后续部分,我们将逐一解析ViT模型的每个组件,并解释其作用。我们将从负责将输入图像划分为更小块并将其嵌入向量格式的Patch嵌入层开始。紧接着,我们将探索多头自注意力模块,它允许模型捕捉图像块之间的全局和局部关系。

此外,我们还将深入了解机器学习感知器模块,这是一个关键组件,使模型能够捕捉输入数据的层次性表示。通过组合这些组件,我们将构建变换器块,它构成了视觉变换器的核心构建块。

最后,我们将通过使用我们精心打造的组件来创建ViT模型。随着模型的完成,我们可以对其进行实验,微调,并在各种计算机视觉任务上发挥其潜力。

到本文结束时,您将获得对视觉变换器架构及其在PyTorch中的实现的扎实理解。有了这些知识,您将能够根据自己的具体需求修改和扩展模型,甚至在此基础上构建更高级的计算机视觉应用。让我们开始吧。

快速部署

第一步:安装并导入依赖项

!pip install -q torchinfo
import torch
from torch import nn
from torchinfo import summary

第二步:获取数据集

import requests
from pathlib import Path
import os
from zipfile import ZipFile# 定义zip文件的URL
url = "https://github.com/mrdbourke/pytorch-deep-learning/raw/main/data/pizza_steak_sushi.zip"# 发送GET请求以下载文件
response = requests.get(url)# 定义数据目录的路径
data_path = Path("data")# 定义图像目录的路径
image_path = data_path / "pizza_steak_sushi"# 检查图像目录是否已经存在
if image_path.is_dir():print(f"{image_path} 目录已存在。")
else:print(f"未找到 {image_path} 目录,正在创建...")image_path.mkdir(parents=True, exist_ok=True)# 将下载的内容写入一个zip文件
with open(data_path / "pizza_steak_sushi.zip", "wb") as f:f.write(response.content)# 解压zip文件到图像目录
with ZipFile(data_path / "pizza_steak_sushi.zip", "r") as zipref:zipref.extractall(image_path)# 删除下载的zip文件
os.remove(data_path / 'pizza_steak_sushi.zip')

第三步:定义转化器

1.调正图像大小
2.运用ToTensor()函数转化格式

from torchvision.transforms import Resize, Compose, ToTensor# 使用Compose定义train_transform
train_transform = Compose([Resize((224, 224)),  # 将图像调整为224x224像素ToTensor()           # 将图像转换为Tensor格式
])# 使用Compose定义test_transform
test_transform = Compose([Resize((224, 224)),  # 将图像调整为224x224像素ToTensor()           # 将图像转换为Tensor格式
])

第四步:创建数据集和数据加载器

我们可以使用PyTorch的ImageFolder数据集库来创建我们的数据集。
为了使ImageFolder工作,您的数据文件夹需要按照这种方式进行结构化。

data
└── pizza_steak_sushi├── test│   ├── pizza│   ├── steak│   └── sushi└── train├── pizza├── steak└── sushi

所有的比萨图片将位于train和test子文件夹下的pizza文件夹中,其他类别的图片也是如此。
在创建的training_dataset和test_dataset上,有两个有用的方法可以调用:

  1. training_dataset.classes,它会返回['pizza', 'steak', 'sushi']
  2. training_dataset.class_to_idx,它会返回{'pizza': 0, 'steak': 1, 'sushi': 2}
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoaderBATCH_SIZE = 32# 定义数据目录
data_dir = Path("data/pizza_steak_sushi")# 使用ImageFolder创建训练数据集
training_dataset = ImageFolder(root=data_dir / "train", transform=train_transform)# 使用ImageFolder创建测试数据集
test_dataset = ImageFolder(root=data_dir / "test", transform=test_transform)# 使用DataLoader创建训练数据加载器
training_dataloader = DataLoader(dataset=training_dataset,shuffle=True,                # 开启随机打乱batch_size=BATCH_SIZE,       # 批量大小设置为32num_workers=2                # 使用2个工作进程
)# 使用DataLoader创建测试数据加载器
test_dataloader = DataLoader(dataset=test_dataset,shuffle=False,               # 关闭随机打乱batch_size=BATCH_SIZE,       # 批量大小设置为32num_workers=2                # 使用2个工作进程
)

我们可以可视化一些训练数据集图像,并查看它们的标签

import matplotlib.pyplot as plt
import randomnum_rows = 5
num_cols = num_rows# 创建一个包含多个子图的图形
fig, axs = plt.subplots(num_rows, num_cols, figsize=(10, 10))# 遍历子图并展示训练数据集中的随机图片
for i in range(num_rows):for j in range(num_cols):# 从训练数据集中随机选择一个索引image_index = random.randrange(len(training_dataset))# 在子图中显示图片axs[i, j].imshow(training_dataset[image_index][0].permute((1, 2, 0)))# 设置子图的标题为对应的类名axs[i, j].set_title(training_dataset.classes[training_dataset[image_index][1]], color="white")# 禁用坐标轴以获得更好的视觉效果axs[i, j].axis(False)# 设置图形的超标题
fig.suptitle(f"训练数据集中随机{num_rows * num_cols}张图片", fontsize=16, color="white")# 将图形的背景色设置为黑色
fig.set_facecolor(color='black')# 展示绘图
plt.show()

在这里插入图片描述

理解视觉变换器架构

让我们现在花些时间来理解视觉变换器架构。这是原始视觉变换器论文的链接:https://arxiv.org/abs/2010.11929。
下面,您可以看到论文中提出的架构图。
在这里插入图片描述

视觉变换器(ViT)是一种为图像处理任务设计的变换器架构类型。与传统的变换器不同,后者主要处理词嵌入序列,ViT处理的是图像嵌入序列。换句话说,它将输入图像分割成多个小块,并将这些小块视为一系列可学习的嵌入。

ViT的基本操作步骤包括:

  1. 创建补丁嵌入:它将图像分割成补丁,并将每个补丁转换成嵌入向量。
  2. 通过变换器块传递嵌入
    • 补丁嵌入连同一个分类令牌一起,被送入多个变换器块。
    • 每个变换器块由一个多头自注意力模块(MultiHead Self-Attention Block,简称MSA块)和一个多层感知器块(Multi-Layer Perceptron Block,简称MLP块)组成。
    • 在变换器块的输入和MSA块的输入之间,以及MLP块的输入和MLP块的输出之间建立跳过连接,以缓解梯度消失问题。
  3. 执行分类
    • 变换器块的最终输出通过一个MLP块进行处理。
    • 使用其中的分类令牌,该令牌包含有关输入图像类别的信息,来进行预测。

接下来,我们将详细探讨每个步骤,首先从创建补丁嵌入的关键过程开始。

第五步:创建补丁嵌入层

根据ViT论文,我们需要对图像执行以下操作,然后才能传递给多头自注意力变换器层:

  1. 将图像转换为16x16像素大小的补丁。
  2. 将每个补丁嵌入768维空间。因此,每个补丁变成一个[1 x 768]向量。每张图像将有KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲N = H \times W …个这样的补丁。这样会得到形状为[14 x 14 x 768]的图像。
  3. 将图像沿着一个向量展平,得到一个[196 x 768]矩阵,即我们的图像嵌入序列。
  4. 在上述输出前加上类别令牌嵌入。
  5. 将位置嵌入添加到类别令牌和图像嵌入中。
PATCH_SIZE = 16
IMAGE_WIDTH = 224
IMAGE_HEIGHT = IMAGE_WIDTH
IMAGE_CHANNELS = 3
EMBEDDING_DIMS = IMAGE_CHANNELS * PATCH_SIZE**2
NUM_OF_PATCHES = int((IMAGE_WIDTH * IMAGE_HEIGHT) / PATCH_SIZE**2)# 图像宽度和高度应该能被补丁大小整除。这是一个检查以确保这一点。
assert IMAGE_WIDTH % PATCH_SIZE == 0 and IMAGE_HEIGHT % PATCH_SIZE == 0, print("图像宽度不是补丁大小的整数倍")
4.1 将图像转换为16x16大小的补丁,并为每个大小为768的补丁创建一个嵌入向量。

这可以通过使用一个Conv2D层来实现,其kernel_size(核大小)等于patch_size(补丁大小),stride(步长)也等于patch_size。
在这里插入图片描述

conv_layer = nn.Conv2d(in_channels = IMAGE_CHANNELS, out_channels = EMBEDDING_DIMS, kernel_size = PATCH_SIZE, stride = PATCH_SIZE)

我们可以将随机图像传递到卷积层中,看看会发生什么

random_images, random_labels = next(iter(training_dataloader))
random_image = random_images[0]# 创建一个新的图形
fig = plt.figure(1)# 展示随机选取的图像
plt.imshow(random_image.permute((1, 2, 0)))# 禁用坐标轴以获得更好的视觉效果
plt.axis(False)# 设置图像的标题
plt.title(training_dataset.classes[random_labels[0]], color="white")# 将图形的背景色设置为黑色
fig.set_facecolor(color="black")

在这里插入图片描述
我们需要将形状更改为[1,14,14,768],并将输出扁平化为[1,196,768]

# 将图像通过卷积层
image_through_conv = conv_layer(random_image.unsqueeze(0))
print(f'通过卷积层的嵌入形状 -> {list(image_through_conv.shape)} <- [批大小, 补丁行数, 补丁列数, 嵌入维度]')# 调整image_through_conv的维度以匹配预期形状
image_through_conv = image_through_conv.permute((0, 2, 3, 1))# 使用nn.Flatten创建一个展平层
flatten_layer = nn.Flatten(start_dim=1, end_dim=2)# 将image_through_conv通过展平层
image_through_conv_and_flatten = flatten_layer(image_through_conv)# 打印嵌入图像的形状
print(f'通过展平层的嵌入形状 -> {list(image_through_conv_and_flatten.shape)} <- [批大小, 补丁数量, 嵌入维度]')# 将嵌入图像赋值给一个变量
embedded_image = image_through_conv_and_flatten
通过卷积层的嵌入形状 -> [1, 768, 14, 14] <- [批大小, 补丁行数, 补丁列数, 嵌入维度]
通过展平层的嵌入形状 -> [1, 196, 768] <- [批大小, 补丁数量, 嵌入维度]
4.2 添加类别标记嵌入和位置编码嵌入
class_token_embeddings = nn.Parameter(torch.rand((1, 1,EMBEDDING_DIMS), requires_grad  = True))
print(f'类别令牌嵌入的形状 --> {list(class_token_embeddings.shape)} <-- [批大小, 1, 嵌入维度]')embedded_image_with_class_token_embeddings = torch.cat((class_token_embeddings, embedded_image), dim = 1)
print(f'\n带有类别令牌嵌入的图像嵌入形状 --> {list(embedded_image_with_class_token_embeddings.shape)} <-- [批大小, 补丁数量+1, 嵌入维度]')position_embeddings = nn.Parameter(torch.rand((1, NUM_OF_PATCHES+1, EMBEDDING_DIMS ), requires_grad = True ))
print(f'\n位置嵌入的形状 --> {list(position_embeddings.shape)} <-- [批大小, 补丁数量+1, 嵌入维度]')final_embeddings = embedded_image_with_class_token_embeddings + position_embeddings
print(f'\n最终嵌入的形状 --> {list(final_embeddings.shape)} <-- [批大小, 补丁数量+1, 嵌入维度]')
`class_token_embeddings` 的形状 --> `[1, 1, 768]` <-- `[批大小, 1, 嵌入维度]`带有 `class_token_embeddings` 的图像嵌入形状 --> `[1, 197, 768]` <-- `[批大小, 补丁数量+1, 嵌入维度]``position_embeddings` 的形状 --> `[1, 197, 768]` <-- `[批大小, 补丁数量+1, 嵌入维度]``final_embeddings` 的形状 --> `[1, 197, 768]` <-- `[批大小, 补丁数量+1, 嵌入维度]`

将补丁嵌入层整合起来
我们将继承PyTorch的nn.Module来创建我们的自定义层,该层接收一张图像,并输出补丁嵌入,包括图像嵌入、类别标记嵌入和位置嵌入。

class PatchEmbeddingLayer(nn.Module):def __init__(self, in_channels, patch_size, embedding_dim,):super().__init__()self.patch_size = patch_sizeself.embedding_dim = embedding_dimself.in_channels = in_channelsself.conv_layer = nn.Conv2d(in_channels=in_channels, out_channels=embedding_dim, kernel_size=patch_size, stride=patch_size)self.flatten_layer = nn.Flatten(start_dim=1, end_dim=2)self.class_token_embeddings = nn.Parameter(torch.rand((BATCH_SIZE, 1, EMBEDDING_DIMS), requires_grad=True))self.position_embeddings = nn.Parameter(torch.rand((1, NUM_OF_PATCHES + 1, EMBEDDING_DIMS), requires_grad=True))def forward(self, x):output = torch.cat((self.class_token_embeddings, self.flatten_layer(self.conv_layer(x).permute((0, 2, 3, 1)))), dim=1) + self.position_embeddingsreturn output

让我们从我们的补丁嵌入层传递一批随机图像。

patch_embedding_layer = PatchEmbeddingLayer(in_channels=IMAGE_CHANNELS, patch_size=PATCH_SIZE, embedding_dim=IMAGE_CHANNELS * PATCH_SIZE ** 2)patch_embeddings = patch_embedding_layer(random_images)
patch_embeddings.shape
torch.Size([32, 197, 768])
summary(model=patch_embedding_layer,input_size=(BATCH_SIZE, 3, 224, 224), # (batch_size, input_channels, img_width, img_height)col_names=["input_size", "output_size", "num_params", "trainable"],col_width=20,row_settings=["var_names"])

在这里插入图片描述

第六步 创建多头自注意力(Multi-Head Self Attention,MSA)块。

理解MSA块
作为将变换器块整合进视觉变换器模型的第一步,我们将创建一个多头自注意力块。
让我们花一点时间来理解MSA块。MSA块本身包含一个层归一化(LayerNorm)层和多头注意力层。层归一化层基本上是在嵌入维度上对我们的补丁嵌入数据进行规范化。多头注意力层接受输入数据作为三种形式的可学习向量,即查询(query)、键(key)和值(value),统称为qkv向量。这些向量共同构建了输入序列中每个补丁与同一序列中其他所有补丁之间的关系(因此得名自注意力)。
因此,我们输入MSA块的形状将是我们使用补丁嵌入层制作的补丁嵌入的形状 -> [批大小, 序列长度, 嵌入维度]。而从MSA层的输出形状将与输入形状相同。
MSA块代码
现在让我们开始编写我们MSA块的代码。这将是简短的,因为PyTorch已经有了LayerNorm和MultiHeadAttention层的预构建实现。我们只需要传递正确的参数以适应我们的架构。我们可以在原始ViT论文中的这张表格中找到我们MSA块所需的各种参数。
在这里插入图片描述

class MultiHeadSelfAttentionBlock(nn.Module):def __init__(self,embedding_dims = 768, # 隐藏尺寸D,来自ViT论文表1num_heads = 12,  # 头的数量,来自ViT论文表1attn_dropout = 0.0 # 默认为零,因为根据ViT论文,MSA块没有dropout):super().__init__()self.embedding_dims = embedding_dimsself.num_head = num_headsself.attn_dropout = attn_dropoutself.layernorm = nn.LayerNorm(normalized_shape = embedding_dims)self.multiheadattention =  nn.MultiheadAttention(num_heads = num_heads,embed_dim = embedding_dims,dropout = attn_dropout,batch_first = True,)def forward(self, x):x = self.layernorm(x)output,_ = self.multiheadattention(query=x, key=x, value=x,need_weights=False)return output

测试

multihead_self_attention_block = MultiHeadSelfAttentionBlock(embedding_dims = EMBEDDING_DIMS,num_heads = 12)
print(f'Shape of the input Patch Embeddings => {list(patch_embeddings.shape)} <= [batch_size, num_patches+1, embedding_dims ]')
print(f'Shape of the output from MSA Block => {list(multihead_self_attention_block(patch_embeddings).shape)} <= [batch_size, num_patches+1, embedding_dims ]')
Shape of the input Patch Embeddings => [32, 197, 768] <= [batch_size, num_patches+1, embedding_dims ]
Shape of the output from MSA Block => [32, 197, 768] <= [batch_size, num_patches+1, embedding_dims ]

很好,看起来我们的MSA块正在工作。我们可以使用 torchinfo 获取有关 MSA 块的更多信息

summary(model=multihead_self_attention_block,input_size=(1, 197, 768), # (batch_size, num_patches, embedding_dimension)col_names=["input_size", "output_size", "num_params", "trainable"],col_width=20,row_settings=["var_names"])

在这里插入图片描述

第七步 创建机器学习感知器(Machine Learning Perceptron,MLP)块

理解MLP块

变换器中的机器学习感知器(MLP)块是一个全连接层(也称为线性层或密集层)和非线性层的组合。在ViT中,非线性层是一个GeLU层。
在这里插入图片描述

变换器还实现了一个Dropout层以减少过拟合。因此,MLP块将如下所示:
输入 → 线性 → GeLU → Dropout → 线性 → Dropout
根据论文,第一个线性层将嵌入维度扩展到3072维(对于ViT-16/Base)。Dropout设置为0.1,第二个线性层将维度缩减回嵌入维度。

MLP块代码

现在让我们组装我们的MLP块。根据ViT论文,从MSA块输出的内容加上输入到MSA块的内容(由模型架构图中的跳过/残差连接表示)作为输入传递给MLP块。所有层都由PyTorch库提供。我们只需要将它们组装起来。

class MachineLearningPerceptronBlock(nn.Module):def __init__(self, embedding_dims, mlp_size, mlp_dropout):super().__init__()self.embedding_dims = embedding_dimsself.mlp_size = mlp_sizeself.dropout = mlp_dropoutself.layernorm = nn.LayerNorm(normalized_shape = embedding_dims)self.mlp = nn.Sequential(nn.Linear(in_features = embedding_dims, out_features = mlp_size),nn.GELU(),nn.Dropout(p = mlp_dropout),nn.Linear(in_features = mlp_size, out_features = embedding_dims),nn.Dropout(p = mlp_dropout))def forward(self, x):return self.mlp(self.layernorm(x))

测试

mlp_block = MachineLearningPerceptronBlock(embedding_dims = EMBEDDING_DIMS,mlp_size = 3072,mlp_dropout = 0.1)summary(model=mlp_block,input_size=(1, 197, 768), # (batch_size, num_patches, embedding_dimension)col_names=["input_size", "output_size", "num_params", "trainable"],col_width=20,row_settings=["var_names"])

在这里插入图片描述

第八步:集成组合

class TransformerBlock(nn.Module):def __init__(self, embedding_dims = 768,mlp_dropout=0.1,attn_dropout=0.0,mlp_size = 3072,num_heads = 12,):super().__init__()self.msa_block = MultiHeadSelfAttentionBlock(embedding_dims = embedding_dims,num_heads = num_heads,attn_dropout = attn_dropout)self.mlp_block = MachineLearningPerceptronBlock(embedding_dims = embedding_dims,mlp_size = mlp_size,mlp_dropout = mlp_dropout,)def forward(self,x):x = self.msa_block(x) + xx = self.mlp_block(x) + xreturn x

测试

transformer_block = TransformerBlock(embedding_dims = EMBEDDING_DIMS,mlp_dropout = 0.1,attn_dropout=0.0,mlp_size = 3072,num_heads = 12)print(f'Shape of the input Patch Embeddings => {list(patch_embeddings.shape)} <= [batch_size, num_patches+1, embedding_dims ]')
print(f'Shape of the output from Transformer Block => {list(transformer_block(patch_embeddings).shape)} <= [batch_size, num_patches+1, embedding_dims ]')
Shape of the input Patch Embeddings => [32, 197, 768] <= [batch_size, num_patches+1, embedding_dims ]
Shape of the output from Transformer Block => [32, 197, 768] <= [batch_size, num_patches+1, embedding_dims ]
summary(model=transformer_block,input_size=(1, 197, 768), # (batch_size, num_patches, embedding_dimension)col_names=["input_size", "output_size", "num_params", "trainable"],col_width=20,row_settings=["var_names"])

在这里插入图片描述

第九步:创建ViT模型

最后,让我们来组装我们的ViT模型。这将是非常简单的,只需将我们到目前为止所做的所有工作结合起来。我们将稍微增加一个分类器层。在ViT中,分类器层是一个简单的线性层,配有层归一化。分类是在变换器输出的零索引处进行的。

class ViT(nn.Module):def __init__(self, img_size = 224,in_channels = 3,patch_size = 16,embedding_dims = 768,num_transformer_layers = 12, # from table 1 abovemlp_dropout = 0.1,attn_dropout = 0.0,mlp_size = 3072,num_heads = 12,num_classes = 1000):super().__init__()self.patch_embedding_layer = PatchEmbeddingLayer(in_channels = in_channels,patch_size=patch_size,embedding_dim = embedding_dims)self.transformer_encoder = nn.Sequential(*[TransformerBlock(embedding_dims = embedding_dims,mlp_dropout = mlp_dropout,attn_dropout = attn_dropout,mlp_size = mlp_size,num_heads = num_heads) for _ in range(num_transformer_layers)])self.classifier = nn.Sequential(nn.LayerNorm(normalized_shape = embedding_dims),nn.Linear(in_features = embedding_dims,out_features = num_classes))def forward(self, x):return self.classifier(self.transformer_encoder(self.patch_embedding_layer(x))[:, 0])
summary(model=vit,input_size=(BATCH_SIZE, 3, 224, 224), # (batch_size, num_patches, embedding_dimension)col_names=["input_size", "output_size", "num_params", "trainable"],col_width=20,row_settings=["var_names"])

在这里插入图片描述

就是这样。现在,您可以像训练PyTorch中的任何其他模型一样训练这个模型。请告诉我这对您来说效果如何。我希望这个逐步指南帮助您理解了视觉变换器,并激发您更深入地探索计算机视觉和变换器模型的世界。借助获得的知识,您已经具备了推动计算机视觉发展和解锁这些开创性架构潜能的能力。

所以,继续前进,基于您所学到的知识,让您的想象力在利用视觉变换器应对激动人心的视觉挑战时自由发挥。编码愉快!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/733963.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一代高通S7和S7 Pro音频平台:超旗舰性能,全面革新音频体验

以下文章来源于高通中国 如今&#xff0c;音频内容与形式日渐丰富&#xff0c;可满足人们放松心情、提升自我、获取资讯等需求。得益于手机、手表、耳机、车载音箱等智能设备的广泛应用&#xff0c;音频内容可以更快速触达用户。从《音频产品使用现状调研报告2023》中发现&…

幕译--本地字幕生成与翻译--Whisper客户端

幕译–本地字幕生成与翻译 本地离线的字幕生成与翻译&#xff0c;支持GPU加速。可免费试用&#xff0c;无次数限制 基于Whisper&#xff0c;希望做最好的Whisper客户端 功能介绍 本地离线&#xff0c;不用担心隐私问题支持GPU加速支持多种模型支持&#xff08;中文、英语、日…

连接时序分类 Connectionist Temporal Classification (CTC)

CTC全称Connectionist temporal classification&#xff0c;是一种常用在语音识别、文本识别等领域的算法&#xff0c;用来解决输入和输出序列长度不一、无法对齐的问题。在CRNN中&#xff0c;它实际上就是模型对应的损失函数(CTC loss)。 一、背景 字母和语音的对齐(align)非…

【数据通信】数据通信基础知识---信号

1. 信息、数据、信号 信息是人们通过施加于数据的一些规定而赋予数据的特定含义&#xff08;ISO定义&#xff09;通信就是在信源和信宿之间传递信息。 信息和消息的关系&#xff1a;消息中包含信息&#xff0c;消息不等于信息。 消息所包含信息的多少&#xff0c;与在收到消息…

transformer--使用transformer构建语言模型

什么是语言模型? 以一个符合语言规律的序列为输入&#xff0c;模型将利用序列间关系等特征&#xff0c;输出一个在所有词汇上的概率分布.这样的模型称为语言模型. # 语言模型的训练语料一般来自于文章&#xff0c;对应的源文本和目标文本形如: src1"Ican do",tgt1…

Revit-二开之不同个立面/剖面上点的处理-(8)

由上图我们可以知道,在不同的立面坐标系是不同的。在很多业务逻辑处理的时候,需要对不同的立面进行处理,在此封装了一个方法,便于处理不同立面上点的计算。 viewSection 立面或者剖面 point 立面或者剖面上的点 horizontalOffset 点在屏幕中水平方向上的偏移量 verticalOf…

Android14之解决报错:No module named sepolgen(一百九十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

推荐算法中经典排序算法GBDT+LR

文章目录 逻辑回归模型逻辑回归对于特征处理的优势逻辑回归处理特征的步骤 GBDT算法GBDTLR算法GBDT LR简单代码实现 逻辑回归模型 逻辑回归&#xff08;LR,Logistic Regression&#xff09;是一种传统机器学习分类模型&#xff0c;也是一种比较重要的非线性回归模型&#xff0…

浅谈Redis和分布式系统

浅谈Redis Redis用于存储数据&#xff0c;且在内存当中进行存储。 但是在日常编写代码中&#xff0c;定义一个变量也就属于在内存当中存储一个数据。 Redis主要会在分布式系统当中发挥重要作用&#xff0c;如果只是单机程序&#xff0c;直接通过变量存储数据的方式会比使用Re…

Listener(监听器)

文章目录 Listener和ServletContext1.0 ServletContext对象介绍1.1 Listener概述1.2 Listener快速入门① xml版本② 注解版本 1.3 案例&#xff1a;模拟spring框架 Listener和ServletContext 补充&#xff1a;1.ServletContext 表示上下文对象&#xff0c;属于接口&#xff0c…

MySQL主从读写分离之Proxysql(openEuler版)

实验目的&#xff1a; 基于proxysql实现MySQL的主从读写分离。 实验过程&#xff1a; 前期准备&#xff1a; 一共有四台虚拟机&#xff0c;其中三台为配置好的一主两从虚拟机&#xff0c;还有一台干净的虚拟机用来配置proxysql。 主机名地址master192.168.27.137node1192.…

bat文件给多个Android设备安装apk

本文是安装一个apk 1、确保以下3个文件在同一个目录下 1>要安装的apk&#xff0c;这里是mmb.apk 2>设备名单&#xff0c;保存在.txt文件中&#xff0c;一行一个设备名&#xff0c;设备名通过adb devices获取&#xff0c;截图中是两个设备 txt文件中的样式 3>要运行…

【Pytorch】进阶学习:深入解析 sklearn.metrics 中的 classification_report 函数---分类性能评估的利器

【Pytorch】进阶学习&#xff1a;深入解析 sklearn.metrics 中的 classification_report 函数—分类性能评估的利器 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合…

外包干了3个月,技术退步明显。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

定制repo(不再切换python和google源)

文章目录 定制repo&#xff08;不再切换python和google源&#xff09;前言各用各的repo定制repo2/repo3源码自动识别repo2/repo3项目完整解决方案&#xff1a; 定制repo&#xff08;不再切换python和google源&#xff09; 众知&#xff0c;Android/AOSP/ROM系统开发&#xff0c…

读算法的陷阱:超级平台、算法垄断与场景欺骗笔记05_共谋(中)

1. 默许共谋 1.1. 又称寡头价格协调&#xff08;Oligopolistic Price Coordination&#xff09;或有意识的平行行为&#xff08;Conscious Parallelism&#xff09; 1.1.1. 在条件允许的情况下&#xff0c;它会发生在市场集中度较高的行业当中 1.1.…

论文笔记 Where Would I Go Next? Large Language Models as Human Mobility Predictor

arxiv 2023 08的论文 1 intro 1.1 人类流动性的独特性 人类流动性的独特特性在于其固有的规律性、随机性以及复杂的时空依赖性 ——>准确预测人们的行踪变得困难近期的研究利用深度学习模型的时空建模能力实现了更好的预测性能 但准确性仍然不足&#xff0c;且产生的结果…

爬虫(五)

1. 前端JS相关 三元运算 v1 条件 ? 值A : 值B; # 如果条件成立v1值A&#xff0c;不成立v1等于值Bres 1 1 ? 99 : 88 # res99特殊的逻辑运算 v1 11 || 22 # Ture v2 9 || 14 # 9 v3 0 || 15 # 15 v3 0 || 15 || "zhangfei" # 15赋值和…

201909 青少年软件编程(Scratch)等级考试试卷(一级)

第1题&#xff1a;【 单选题】 小明在做一个采访的小动画&#xff0c;想让主持人角色说“大家好&#xff01;”3秒钟&#xff0c;用下列程序中的哪一个可以实现呢&#xff1f;&#xff08; &#xff09; A: B: C: D: 【正确答案】: B 【试题解析】 : 第2题&#xff1a…

领域模型设计-COLA架构

前言 当我们需要创建的新应用的时候&#xff0c;往往需要站在一个长远的角度来设计我们的系统架构。有时候我们接手一个老的应用的时候&#xff0c;会发现由于创建之初没有好好规划系统架构&#xff0c;导致我们后期开分成本和维护成本都非常高。近些年来领域模型的系统设计非常…