transformer死亡9问

news2024/11/15 14:04:22

transformer死亡20问

  • 1. Transformer为何使用多头注意力机制?
  • 2. Transformer为什么Q和K使用不同的权重矩阵生成,为何不能使用同一个值进行自身的点乘
  • 3. Transformer计算attention的时候为何选择点乘而不是加法?两者计算复杂度和效果上有什么区别
  • 4. 为什么在进行softmax之前需要对attention进行scaled(为什么除以dk的平方根),并使用公式推导进行讲解
  • 5.在计算attention score的时候如何对padding做mask操作
  • 6. Transformer中的残差结构以及意义。
  • 7. 为什么transformer块使用LayerNorm而不是BatchNorm?LayerNorm 在Transformer的位置是哪里?
    • 7.1为什么使用LayerNorm而不是BatchNorm?
    • 7.2LayerNorm在Transformer中的位置
  • 8. 简单描述一下Transformer中的前馈神经网络?使用了什么激活函数?相关优缺点?
  • 9.Decoder阶段的多头自注意力和encoder的多头自注意力有什么区别?(为什么需要decoder自注意力需要进行 sequence mask)
    • 9.1 Encoder阶段的多头自注意力机制
    • 9.2 Decoder阶段的多头自注意力机制
    • 9.3 为什么Decoder的自注意力需要进行序列掩码(sequence mask)

1. Transformer为何使用多头注意力机制?

Transformer模型使用多头注意力机制(Multi-Head Attention)而不是单头注意力(Single-Head Attention),主要有以下几个原因:

  • 捕捉不同的特征:多头注意力机制可以通过不同的注意力头来学习输入序列的不同子空间中的不同特征。每个头都有自己的一组权重,这使得模型能够从不同的角度看待数据,从而捕捉到更多的信息和模式。

  • 更好的表示能力:通过并行计算多个注意力头,可以增强模型的表示能力。每个头可以关注不同的位置和上下文,综合起来的表示更丰富、更全面。

  • 降低计算复杂度:虽然多个头意味着更多的计算,但每个头的计算可以在较低维度的-子空间中进行。将输入分成多个子空间来计算注意力,然后再拼接起来,这样的方式在并行计算硬件上效率更高。

  • 缓解过拟合:单个注意力头可能会过度集中在某些特定的特征或模式上,而忽略其他重要的信息。多头注意力机制通过同时考虑多个头的输出,能够更好地泛化到不同的输入,从而缓解过拟合的问题。

  • 提升模型的稳定性:多头注意力机制有助于减小模型对某一个特定头的依赖,提高模型的鲁棒性和稳定性。

具体来说,在Transformer模型中,多头注意力机制的工作流程如下:

  • 线性变换:对于每个注意力头,将输入通过线性变换得到查询(Query)、键(Key)和值(Value)的向量。
  • 计算注意力权重:对于每个头,计算查询和键之间的点积,并通过softmax函数归一化得到注意力权重。
  • 加权求和:使用注意力权重对值进行加权求和,得到每个头的输出。
  • 拼接输出:将所有头的输出拼接起来,并通过线性变换得到最终的多头注意力输出。

这样,通过多头注意力机制,Transformer模型能够更好地处理序列数据中的复杂模式和关系,从而在自然语言处理等任务中取得优异的表现。

  • 多头注意力机制的代码例子
import torch
import torch.nn as nn
import torch.nn.functional as F

class MultiHeadAttention(nn.Module):
    def __init__(self, embed_size, heads):
        super(MultiHeadAttention, self).__init__()
        self.embed_size = embed_size
        self.heads = heads
        self.head_dim = embed_size // heads

        assert (
            self.head_dim * heads == embed_size
        ), "Embedding size needs to be divisible by heads"

        self.values = nn.Linear(self.head_dim, embed_size, bias=False)
        self.keys = nn.Linear(self.head_dim, embed_size, bias=False)
        self.queries = nn.Linear(self.head_dim, embed_size, bias=False)
        self.fc_out = nn.Linear(embed_size, embed_size)

    def forward(self, values, keys, query, mask):
        N = query.shape[0]
        value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1]

        # Split the embedding into self.heads different pieces
        values = values.reshape(N, value_len, self.heads, self.head_dim)
        keys = keys.reshape(N, key_len, self.heads, self.head_dim)
        queries = query.reshape(N, query_len, self.heads, self.head_dim)

        values = self.values(values)
        keys = self.keys(keys)
        queries = self.queries(queries)

        # Reshape for batch matrix multiplication
        queries = queries.permute(0, 2, 1, 3).reshape(N * self.heads, query_len, self.head_dim)
        keys = keys.permute(0, 2, 1, 3).reshape(N * self.heads, key_len, self.head_dim)

        # Attention score
        energy = torch.bmm(queries, keys.permute(0, 2, 1)).reshape(N, self.heads, query_len, key_len)

        if mask is not None:
            energy = energy.masked_fill(mask == 0, float("-1e20"))

        attention = torch.softmax(energy / (self.embed_size ** (1 / 2)), dim=3)

        # Reshape values for batch matrix multiplication
        values = values.permute(0, 2, 1, 3).reshape(N * self.heads, value_len, self.head_dim)
        
        out = torch.bmm(attention.reshape(N * self.heads, query_len, key_len), values).reshape(N, self.heads, query_len, self.head_dim)
        
        out = out.permute(0, 2, 1, 3).reshape(N, query_len, self.embed_size)

        out = self.fc_out(out)
        return out

# Testing the MultiHeadAttention
if __name__ == "__main__":
    embed_size = 256
    heads = 8
    values = torch.randn(1, 10, embed_size)
    keys = torch.randn(1, 10, embed_size)
    query = torch.randn(1, 10, embed_size)
    mask = None

    attention = MultiHeadAttention(embed_size, heads)
    out = attention(values, keys, query, mask)
    print(out.shape)

2. Transformer为什么Q和K使用不同的权重矩阵生成,为何不能使用同一个值进行自身的点乘

在Transformer模型中,查询(Q, Query)和键(K, Key)使用不同的权重矩阵生成是为了更灵活和有效地捕捉输入序列中的不同特征和关系。这种设计有几个重要的原因:

  1. 不同的功能需求
    查询(Query):用于获取输入序列中某个位置的信息。
    键(Key):用于表示输入序列中所有位置的信息,与查询进行对比来计算相似度。
    如果查询和键使用同一个权重矩阵,模型在区分和捕捉不同类型的信息时会受到限制。使用不同的权重矩阵允许模型更灵活地调整每个输入位置的信息,从而提高模型的表达能力。

  2. 增强模型的表达能力
    使用不同的权重矩阵能够让查询和键在不同的子空间中进行变换,从而捕捉到更丰富和多样的特征。如果使用相同的权重矩阵,查询和键在相同的子空间中进行变换,可能会丧失这种灵活性,影响模型的性能。

  3. 避免退化到简单的自相关
    如果查询和键使用相同的权重矩阵,注意力机制可能会退化成简单的自相关操作,丧失了对复杂模式和关系的捕捉能力。而使用不同的权重矩阵可以确保注意力机制能够有效区分和处理复杂的序列关系。

  4. 提高模型的鲁棒性和稳定性
    不同的权重矩阵能够提供更多的学习参数,增加模型的容量,使其在面对不同类型的输入数据时更加鲁棒和稳定。这样模型在训练时能够更好地适应和泛化。

  5. 总结
    使用不同的权重矩阵生成查询和键,使得模型可以在不同的子空间中变换输入,捕捉更丰富和多样的特征,并且避免退化成简单的自相关操作。这样不仅增强了模型的表达能力,还提高了模型的鲁棒性和稳定性

3. Transformer计算attention的时候为何选择点乘而不是加法?两者计算复杂度和效果上有什么区别

Transformer模型在计算注意力时选择点乘(点积)而不是加法有几个关键的原因,这涉及到计算复杂度、效果以及理论基础的差异。

  1. 点乘 vs 加法:计算复杂度
  • 点乘注意力(Scaled Dot-Product Attention):
    计算复杂度:O(n^2 * d)
    其中 n 是序列长度,d 是每个向量的维度。具体步骤包括:计算 Q 和 K 的点积,得到一个 n x n 的矩阵;进行缩放和 softmax 操作;将结果与 V 进行矩阵乘法。
  • 加法注意力(Additive Attention):
    计算复杂度:O(n^2 * d)
    加法注意力通常使用一个小的前馈神经网络来计算注意力分数。具体步骤包括:计算 Q 和 K 的加法,然后通过一个前馈神经网络(通常是一个单隐藏层的MLP);进行 softmax 操作;将结果与 V 进行矩阵乘法。

尽管两者的时间复杂度在形式上相同,但点乘注意力的计算更容易并行化,因为矩阵乘法可以通过优化的线性代数库高效实现。

  1. 点乘 vs 加法:效果
  • 点乘注意力:
    更适合在高维空间中操作。点乘注意力在高维空间中能更好地捕捉输入向量间的相似性,因为点乘计算的结果本质上是两个向量的相似度度量。
    计算简单,易于实现并行化,因此在实践中通常更高效。
  • 加法注意力:
    通常用于较低维度的表示(例如在 RNN 中),因为在低维空间中,点乘可能不太稳定或效果不好。
    计算复杂,需要通过前馈神经网络来计算相似性度量,增加了模型的复杂度和计算时间。
  1. 总结
    点乘注意力在计算复杂度、实现的并行化和高维度表示上具有优势,是Transformer模型的首选。
    加法注意力在低维度表示中表现较好,但计算复杂度更高,实现较为复杂。
    点乘注意力易于在现代硬件(如GPU和TPU)上高效实现,使其成为处理大规模数据和训练深度模型的更好选择。

4. 为什么在进行softmax之前需要对attention进行scaled(为什么除以dk的平方根),并使用公式推导进行讲解

在计算Transformer的注意力时,对点积注意力进行缩放(scaled)的主要原因是为了稳定训练过程,防止输入数据的范围过大,导致softmax输出的梯度变得非常小,从而影响训练效率和模型性能。
在这里插入图片描述

5.在计算attention score的时候如何对padding做mask操作

在计算注意力分数(attention scores)时,处理填充(padding)是一个重要的步骤,因为填充的部分应该对计算结果没有影响。通常,我们使用掩码(mask)来忽略这些填充位置。

  1. 掩码的作用
    • 防止填充位置影响计算:填充的位置不应该对注意力分数产生影响,因此在计算注意力分数时需要将这些位置的注意力权重设为0。
    • 保持模型的一致性:确保模型只关注实际的输入部分,而不是填充的部分。
  2. 掩码的实现
    通常,掩码是一个与注意力分数矩阵形状相同的矩阵,其中填充位置用特定值(如负无穷大)标记,这样在计算softmax时,填充位置的权重会变为0。
    • 创建掩码
      掩码通常是一个布尔矩阵,表示哪些位置是填充的。例如,掩码矩阵的形状为 (batch_size, seq_len, seq_len),其中填充的位置标记为 False,非填充的位置标记为 True。
    • 应用掩码
      在计算注意力分数时,将掩码应用于点积结果中。具体来说,将掩码中的填充位置设置为一个非常小的值(如 -1e9),这样在进行softmax时,这些位置的注意力权重会变为0
  3. 总结
    • 创建掩码:根据填充位置创建掩码矩阵,并将其扩展到正确的形状,以便与注意力分数矩阵对齐。
    • 应用掩码:在计算注意力分数时,将掩码应用于点积结果,将填充位置的分数设为一个非常小的值(如 -1e9),这样在进行softmax时,这些位置的注意力权重会变为0。

6. Transformer中的残差结构以及意义。

Transformer中的残差结构(Residual Connection)是一种关键的设计理念,用于提高深度神经网络的训练稳定性和收敛速度。它主要用于每个子模块(如自注意力机制和前馈神经网络)的输出中,将输入直接添加到输出上。

  • 残差结构的意义
    • 缓解梯度消失问题:
      在深度神经网络中,梯度可能在反向传播过程中逐渐消失,使得训练变得困难。残差连接通过直接将输入添加到输出上,使得梯度可以直接通过这些连接流动,从而缓解梯度消失问题。
    • 提高训练稳定性:
      残差结构使得每一层只需学习输入与输出之间的残差(即变化量),而不是学习完整的映射。这种方式可以更容易地训练深层网络,因为学习残差通常比直接学习完整映射要简单得多。
    • 加速收敛:
      残差连接可以让模型更快地收敛,因为它使得信息在网络中流动时更为顺畅。网络能够更快地找到合适的表示,进而提高训练效率。
    • 支持深层网络:
      使用残差连接,网络可以更容易地堆叠更多的层。残差连接通过提供直接路径,使得深层网络更容易训练,并保持较好的性能

7. 为什么transformer块使用LayerNorm而不是BatchNorm?LayerNorm 在Transformer的位置是哪里?

在Transformer中使用Layer Normalization(LayerNorm)而不是Batch Normalization(BatchNorm)主要是因为它们的工作原理和适用场景有所不同。以下是详细的解释以及LayerNorm在Transformer中的具体位置。

7.1为什么使用LayerNorm而不是BatchNorm?

  1. 适用场景不同:
  • BatchNorm:BatchNorm通过对每个mini-batch的特征进行归一化来稳定训练过程。这种方法依赖于mini-batch的大小和分布,在处理变长序列或不规则批次大小时可能会出现问题。
  • LayerNorm:LayerNorm对每个样本的特征进行归一化,不依赖于mini-batch的大小和分布。这使得LayerNorm在处理变长序列和不规则批次大小时更加稳定和有效。
  1. 计算方式:
  • BatchNorm:在mini-batch内计算均值和方差进行归一化。在RNN或Transformer这样的序列模型中,不同序列的长度可能不同,导致batch内的数据不一致,影响BatchNorm的效果。
  • LayerNorm:在单个样本的特征维度上计算均值和方差进行归一化。这使得LayerNorm在处理序列数据时更加一致和可靠。
  1. 处理序列数据:
  • BatchNorm的计算依赖于批次内的统计信息,而序列数据的长度和顺序可能会变化,这使得BatchNorm在处理序列数据时表现不佳。
  • LayerNorm在每个样本的特征维度上进行归一化,独立于序列的长度和顺序,因此在处理序列数据时更加适合。

7.2LayerNorm在Transformer中的位置

在Transformer中,LayerNorm通常用于每个子模块(子层)的输出和残差连接(Residual Connection)之间。具体来说,LayerNorm出现在以下两个主要位置:

  1. 自注意力机制之后:
    自注意力机制的输出通过残差连接加回到输入上,然后经过LayerNorm进行归一化。
attn_output, _ = self.multihead_attention(x, x, x, attn_mask=src_mask)
x = self.layer_norm1(x + self.dropout(attn_output))
  1. 前馈神经网络之后:
    前馈神经网络的输出通过残差连接加回到输入上,然后经过LayerNorm进行归一化。
ffn_output = self.ffn(x)
x = self.layer_norm2(x + self.dropout(ffn_output))

8. 简单描述一下Transformer中的前馈神经网络?使用了什么激活函数?相关优缺点?

Transformer中的前馈神经网络(Feed-Forward Neural Network,FFN)是每个Encoder和Decoder层中的一个重要组成部分。它用于对每个位置的特征表示进行进一步的非线性变换。以下是对Transformer中前馈神经网络的简单描述、所使用的激活函数以及其相关优缺点。

  1. 前馈神经网络的结构
    Transformer中的前馈神经网络通常由两个线性变换(全连接层)和一个激活函数组成。每个位置的特征表示都会独立地通过相同的前馈神经网络进行处理。其结构可以表示为:
    F F N ( x ) = m a x ( 0 , x W 1 + b 1 ) W 2 + b 2 FFN(x) = max(0, xW_1 + b_1)W_2 + b_2 FFN(x)=max(0,xW1+b1)W2+b2
    其中,
    x 是输入特征表示。
    W 1 , W 2 W_1, W_2 W1,W2是权重矩阵。
    b 1 , b 2 b_1, b_2 b1,b2是偏置向量。
    m a x ( 0 , . ) max(0, .) max(0,.) 表示ReLU激活函数。

在Transformer的前馈神经网络中,通常使用的是ReLU(Rectified Linear Unit)激活函数。ReLU激活函数的定义为:
在这里插入图片描述
ReLU函数将所有负值映射为零,并保留正值。

  1. 前馈神经网络的优点
  • 计算效率高:ReLU激活函数的计算非常简单,只需要比较输入值与零,计算效率高。
  • 减轻梯度消失问题:与传统的激活函数(如Sigmoid和Tanh)相比,ReLU激活函数在正值区间具有恒定的梯度,减轻了梯度消失问题,使得深层网络更容易训练。
  • 简单且效果好:前馈神经网络结构简单,但在实践中效果很好,能够有效地对特征表示进行非线性变换。
  1. 前馈神经网络的缺点
  • 稀疏激活:ReLU会将负值区域的激活设置为零,可能导致一些神经元永远不被激活,尤其是在初始权重设置不当的情况下。
  • 非平滑性:ReLU在零点处不可导,尽管这在大多数情况下不是问题,但在某些优化算法中可能会引发问题。
  1. 总结
    Transformer中的前馈神经网络由两个线性变换和一个ReLU激活函数组成,主要用于对每个位置的特征表示进行非线性变换。ReLU激活函数具有计算效率高、减轻梯度消失问题等优点,但也存在稀疏激活和非平滑性的问题。前馈神经网络在结构上非常简单,但在实践中效果显著,有助于模型提取更高层次的特征表示。

9.Decoder阶段的多头自注意力和encoder的多头自注意力有什么区别?(为什么需要decoder自注意力需要进行 sequence mask)

在Transformer模型中,Decoder阶段的多头自注意力机制和Encoder阶段的多头自注意力机制有一些关键区别,主要在于它们处理数据的方式和目的。以下是详细的解释:

9.1 Encoder阶段的多头自注意力机制

在Encoder阶段,每个位置的输入特征都可以在整个输入序列中进行自注意力计算。这意味着每个词(或标记)都能够关注输入序列中所有其他词的信息,以便更好地捕捉全局上下文信息。

  1. 主要特点:
  • 全局自注意力:每个词可以与输入序列中的任何其他词交互,没有遮掩(masking)。
  • 并行处理:所有位置可以并行处理,因为它们没有顺序依赖。

9.2 Decoder阶段的多头自注意力机制

在Decoder阶段,每个位置的输入特征只能关注目标序列中当前位置及其之前的位置。这是因为Decoder在生成每个词时,只能依赖于之前生成的词,而不能“看到”未来的词(即当前正在生成的词的后续部分)。这需要通过序列掩码(sequence mask)来实现。

  1. 主要特点:
  • 局部自注意力:每个词只能关注目标序列中当前位置及其之前的词,不能看到未来的词。
  • 顺序依赖:由于序列生成的顺序依赖,每个位置的计算依赖于之前的位置,因此需要使用序列掩码。

9.3 为什么Decoder的自注意力需要进行序列掩码(sequence mask)

序列掩码(sequence mask)在Decoder的自注意力机制中起到了关键作用,用于屏蔽未来的信息,以确保Decoder在生成目标序列时只能依赖于之前生成的词。这种屏蔽机制被称为causal masking或look-ahead masking。

  1. 原因:
  • 防止信息泄露:在序列生成任务中(如机器翻译),Decoder在生成当前词时,不应该看到未来的词,以避免信息泄露。这意味着,生成每个词时,Decoder只能访问该词之前的词。
  • 保持顺序依赖:生成目标序列时,Decoder需要按顺序逐词生成。因此,当前词的生成只能依赖之前生成的词,不能依赖未来的词。这需要通过掩码机制来实现。

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

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

相关文章

C#桌面开发(那些年你总走进误区的技术):异步多线程、异步事务与递归技术

1. 异步多线程 (Asynchronous Multithreading) 在C#桌面开发中,异步多线程是提高应用程序响应速度和性能的关键技术之一。以下是几个深入的技术点和示例代码。 1.1 使用async和await实现异步操作 C#的async和await关键字使得编写异步代码变得更加简单。以下是一个…

老司机也会翻车?通过自动建模技术轻松实现工程机械翻滚保护分析

什么是ROPS分析? ROPS分析,指的是"Roll-Over Protective Structure"(翻滚保护结构)的简称,这是一种用于评估和设计特殊设备(如前装载机、各种挖掘机、履带式推土机)的被动安全标准&am…

slam过程中每一帧的gt位姿如何计算

一般得到的每一帧数据类似如下: 4*4的变化矩阵,都属于相机到世界坐标系下的变化矩阵,如果是x,y,z和四元数也可以转换为这种4*4的矩阵。 第一帧为世界坐标系的原点,后续的位姿都基于这个原点进行变化。 def load_poses(path, n_im…

HCIA概述

一、OSI七层模型 1.物理层(七层) 定义物理设备的标准,主要对物理连接方式,电气特性,机械特性等制定统一标准,传输比特流,因此最小的传输单位——位(比特流)。 2.数据链…

差分专题的练习

神经&#xff0c;树状数组做多了一开始还想着用树状数组来查询差分数组&#xff0c;但是我们要进行所有元素的查询&#xff0c;直接过一遍就好啦 class Solution { public:int numberOfPoints(vector<vector<int>>& nums) {vector<int> c(105, 0);for (i…

Hadoop的安装和使用-2024年08月01日

Hadoop的安装和使用-2024年08月01日 1.创建Hadoop用户2.SSH登陆权限设置3.java的安装4.Hadoop单机安装配置5.Hadoop伪分布式安装配置 1.创建Hadoop用户 如果安装Ubuntu的时候不是用的“hadoop”用户&#xff0c;那么需要增加一个名为 hadoop的用户首先按ctrlaltt打开终端窗口&…

源代码加密防泄漏如何做?

源代码开发环境复杂&#xff0c;涉及的开发软件、文件类型庞杂多变&#xff0c;究竟有什么源代码加密防泄漏软件能够适应众多开发软件而不影响原有的工作效率&#xff1f; 相信这是很多IT管理员或者老板们都想要了解的问题&#xff0c;今天和行业内专业人士讨论&#xff0c;将…

【docker】虚拟化与docker基础

一、虚拟化 1.虚拟化概述 什么是虚拟化&#xff1f; 虚拟化&#xff1a;将应用程序和系统内核资源进行解耦&#xff0c;以操作系统级别进行隔离&#xff0c;目的是提高资源利用率 2、虚拟化的功能 将虚拟化的性能优化趋近于物理资源的性能&#xff0c;主要用于提高资源利用…

浏览器被360劫持了的解决办法

所有浏览器一打开就是360界面&#xff0c;查询资料解决 以谷歌浏览器为例&#xff1a;打开其exe的位置&#xff0c;将exe文件重命名&#xff0c;再次创建快捷方式即可

Kickstart自动安装系统

目录 一、Kickstart的介绍 1.1 为什么要使用Kickstart? 1.2 如何解决以上问题&#xff1f; 1.3 Kickstart的作用 二、实验环境 2.1 实验所需环境 2.2 测试所给的环境是否可用 三、安装Kickstart配置ks文件 3.1 安Kickstart 3.2 配置ks文件 3.2.1 使用图像配置工具配置…

日志采集格式

本实验需要两个虚拟机&#xff0c;一个用于配置&#xff0c;一个用于查看测试结果 node1主机上的配置 vim /etc/rsyslog.conf #添加配置&#xff0c;写入指定的日志格式 13 module(load"builtin:omfile" Template"HAHA") 14 $template HAHA,"%FROM…

Ceres Cuda加速

文章目录 一、简介二、准备工作三、实现代码四、实现效果参考资料一、简介 字Ceres2.2.1版本之后,作者针对于稠密矩阵的分解计算等操作进行了Cuda加速,因此这里就基于此项改动测试一下效果。 二、准备工作 1、首先是需要安装Cuda这个英伟达第三方库,https://developer.nvidi…

eclipse免安装版64位 2018版本(java开发软件)

前言 eclipse是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言&#xff0c;它只是一个框架和一组服务&#xff0c;用于通过插件组件构建开发环境。 一、下载地址 下载地址&#xff1a;分享文件&#xff1a;eclipse v2018.zip下载 二、安装步骤 1、下载解压后将…

日撸Java三百行(day13:链表)

目录 一、链表的基础知识 二、链表的代码实现 1.链表创建 2.链表遍历 3.链表定位查找 4.链表插入 5.链表删除 6.数据测试 7.完整的程序代码 总结 一、链表的基础知识 在之前顺序表的学习中&#xff0c;我们其实提到过链表。链表它是线性表在不同的物理存储方式下派生…

HarmonyOS 音视频之音频采集实战

HarmonyOS 音视频之音频采集实战 背景 应用开发过程中很多场景都有音频采集需求&#xff0c;比如聊天功能的发送语音功能&#xff0c;实时语音转文本功能&#xff0c;实时语音通话&#xff0c;实时视频通话等。在Android和iOS端&#xff0c;系统提供了两种形式&#xff1a; …

图+代码 | Bloom Filter实现及应用

什么是布隆过滤器&#xff08;Bloom Filter&#xff09;&#xff1f; 布隆过滤器是一种空间复杂度很低的概率型数据结构&#xff0c;用于判断一个元素是否在一个集合中。它有两种可能的返回结果&#xff1a; 元素可能在集合中&#xff1a;这可能是一个真阳性&#xff08;确实…

使用Variadic Templates(可变参数模板)实现printf

最近学习了C2.0版本的一些新的特性&#xff0c;利用Variadic Templates&#xff08;可变参数模板&#xff09;实现printf函数。 语言环境 Dev-C 5.11 并需要自己的环境是支持C11的&#xff0c;例如:Dev-C 5.11可以通过以下步骤进行修改&#xff1a; 源码 #include <io…

编程与AI:保持竞争力的策略

人工智能时代&#xff0c;程序员如何保持核心竞争力&#xff1f; 随着AIGC&#xff08;如chatgpt、midjourney、claude等&#xff09;大语言模型接二连三的涌现&#xff0c;AI辅助编程工具日益普及&#xff0c;程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工…

顶刊、顶会、水刊的论文读哪个,如何做一个称职的学术裁缝_来自B站水论文的程序猿

系列文章目录 文章目录 系列文章目录一、顶刊、顶会要看二、水刊&#xff1a;SCI4区&#xff0c;部分3区 看水刊&#xff0c;发现新大陆1、数据集2、性能3、复现 三、如何做一个称职的学术裁缝1、缝合2、编故事 一、顶刊、顶会要看 通过顶刊、顶会知道好的东西长什么样子即可&…

【从零开始一步步学习VSOA开发】创建VSOA的client端

创建VSOA的client端 创建工程 参考 hellovsoa 工程&#xff0c;创建 client 工程&#xff0c;工程源码修改如下&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/select.h> #include "vsoa_client.h&q…