Attention Is All You Need论文翻译

news2024/11/23 17:08:09

论文名称 注意力即是全部

论文地址 https://user.phil.hhu.de/~cwurm/wp-content/uploads/2020/01/7181-attention-is-all-you-need.pdf

摘要

主流的序列转导模型基于复杂的递归或卷积神经网络,这些网络包含编码器和解码器。性能最好的模型通过注意力机制将编码器和解码器连接起来。我们提出了一种新的简单网络架构——Transformer,仅基于注意力机制,完全摆脱了递归和卷积。对两个机器翻译任务的实验表明,这些模型在质量上优于传统模型,同时具有更高的并行性,并且训练所需时间显著减少。我们的模型在WMT 2014英德翻译任务中取得了28.4的BLEU分数,相比现有最佳结果(包括集成模型)提升了2分以上。在WMT 2014英法翻译任务中,我们的模型经过8个GPU训练3.5天后,创造了41.0的单模型最新BLEU分数,这只是文献中最佳模型训练成本的一小部分。

1 引言

     递归神经网络,尤其是长短期记忆(LSTM)[12]和门控递归神经网络(GRU)[7],在序列建模和转导问题(如语言建模和机器翻译)中已被确立为最先进的方法 [29, 2, 5]。此后,许多研究继续推动递归语言模型和编码-解码架构的边界 [31, 21, 13]。递归模型通常在输入和输出序列的符号位置上展开计算。通过将这些位置与计算时间的步骤对齐,它们生成隐藏状态序列 ht,这一过程依赖于前一个隐藏状态 ht−1 和位置 t 的输入。然而,这种固有的顺序特性阻碍了训练示例内的并行化,而在较长序列长度时,这变得尤为关键,因为内存限制限制了跨示例的批处理。最近的研究通过分解技巧 [18] 和条件计算 [26] 在计算效率上取得了显著改善,同时也提高了后者的模型性能。然而,顺序计算的根本限制仍然存在。

       注意力机制已成为各种任务中引人注目的序列建模和转导模型的重要组成部分,允许在建模依赖关系时不考虑它们在输入或输出序列中的距离 [2, 16]。然而,在所有情况下,除了少数几种情况 [22],这种注意力机制都是与递归网络结合使用的。

       在本工作中,我们提出了Transformer,这是一种完全依赖注意力机制以建立输入和输出之间全局依赖关系的模型架构,从而避免了递归。Transformer允许显著更多的并行化,并且在使用八个P100 GPU训练仅十二小时后,能够达到翻译质量的新最优水平。

2 背景

       减少顺序计算的目标也是扩展神经GPU [20]、ByteNet [15] 和 ConvS2S [8] 的基础,这些模型都使用卷积神经网络作为基本构件,为所有输入和输出位置并行计算隐藏表示。在这些模型中,关联来自两个任意输入或输出位置的信号所需的操作数量随着位置之间的距离增加而增加,对于ConvS2S是线性增长,对于ByteNet则是对数增长。这使得学习远程位置之间的依赖关系变得更加困难 [11]。在Transformer中,这一操作数量被减少到一个常数,尽管由于对注意力加权位置进行平均处理而导致有效分辨率降低,这是我们通过第3.2节中描述的多头注意力机制来弥补的。

       自注意力,有时称为内注意力,是一种将单个序列的不同位置相关联的注意力机制,用于计算该序列的表示。自注意力已成功应用于多种任务,包括阅读理解、抽象摘要、文本蕴含和学习任务无关的句子表示 [4, 22, 23, 19]。端到端记忆网络基于递归注意力机制,而不是顺序对齐的递归,并且在简单语言问答和语言建模任务上表现良好 [28]。

       然而,据我们所知,Transformer是第一个完全依赖自注意力来计算输入和输出表示的转导模型,而不使用顺序对齐的RNN或卷积。在接下来的章节中,我们将描述Transformer,阐述自注意力的动机,并讨论其相较于 [14, 15] 和 [8] 等模型的优势。

3 模型架构

       大多数竞争性的神经序列转导模型具有编码器-解码器结构 [5, 2, 29]。在这里,编码器将符号表示的输入序列 (x1, ..., xn) 映射到连续表示的序列 z = (z1, ..., zn)。给定 z,解码器然后一次生成一个元素的输出符号序列 (y1, ..., ym)。在每一步中,该模型是自回归的 [9],在生成下一个符号时,将之前生成的符号作为额外输入。

       Transformer遵循这一整体架构,使用堆叠的自注意力层和逐点全连接层分别构建编码器和解码器,如图1的左半部分和右半部分所示。

图1:Transformer模型架构。

3.1 编码器和解码器堆栈

编码器:编码器由 N = 6 个相同层的堆叠组成。每层有两个子层。第一个是多头自注意力机制,第二个是简单的逐位置全连接前馈网络。我们在每个子层周围采用残差连接 [10],然后进行层归一化 [1]。即,每个子层的输出为 LayerNorm(x + Sublayer(x)),其中 Sublayer(x) 是该子层自身实现的函数。为了便于这些残差连接,模型中的所有子层以及嵌入层的输出维度均为 d_model = 512。

解码器:解码器同样由 N = 6 个相同层的堆叠组成。除了每个编码器层中的两个子层,解码器还插入了第三个子层,该子层对编码器堆栈的输出执行多头注意力。类似于编码器,我们在每个子层周围采用残差连接,然后进行层归一化。我们还修改了解码器堆栈中的自注意力子层,以防止位置关注后续位置。这种掩蔽结合输出嵌入偏移一个位置的事实,确保位置 i 的预测仅能依赖于位置小于 i 的已知输出。

3.2 注意力

       注意力函数可以被描述为将查询和一组键值对映射到输出,其中查询、键、值和输出都是向量。输出作为值的加权和进行计算,其中分配给每个值的权重由查询与相应键的兼容性函数计算得出。

3.2.1 缩放点积注意力

       我们将特定的注意力机制称为“缩放点积注意力”(见图2)。输入包括维度为 d_k 的查询和键,以及维度为 d_v 的值。我们计算查询与所有键的点积,将每个结果除以 √d_k,然后应用 softmax 函数以获得对值的权重。

       实际上,我们在一组查询上同时计算注意力函数,这些查询被打包成一个矩阵 Q。键和值同样被打包成矩阵 K 和 V。我们计算输出矩阵如下:

图2:(左)缩放点积注意力。(右)多头注意力由几个部分组成注意力层并行运行。

     两种最常用的注意力函数是加性注意力 [2] 和点积(乘法)注意力。点积注意力与我们的算法相同,唯一不同的是缩放因子 √(1/d_k)。加性注意力通过具有单隐藏层的前馈网络计算兼容性函数。虽然两者在理论复杂度上相似,但实际上,点积注意力要快得多,并且更节省空间,因为它可以使用高度优化的矩阵乘法代码实现。

       对于较小的 d_k 值,这两种机制的性能相似,但对于较大的 d_k 值,加性注意力的表现优于未缩放的点积注意力 [3]。我们推测,对于较大的 d_k 值,点积的数值会变得很大,从而将 softmax 函数推入梯度极小的区域 [4]。为了抵消这一影响,我们将点积缩放为 √(1/d_k)。

3.2.2 多头注意力

       我们发现,将查询、键和值线性投影 h 次至 d_k、d_k 和 d_v 维度比仅执行一个具有 d_model 维度的键、值和查询的单一注意力函数更加有效。在这些投影版本的查询、键和值上,我们并行执行注意力函数,从而得到 d_v 维度的输出值。这些输出值被连接起来,再次进行投影,形成最终值,如图 2 所示。

       多头注意力使模型能够在不同位置共同关注来自不同表示子空间的信息。使用单个注意力头时,平均化会抑制这种效果。

       投影是参数矩阵 W_Q^i ∈ R^(d_model × d_k),W_K^i ∈ R^(d_model × d_k),W_V^i ∈ R^(d_model × d_v) 和 W_O ∈ R^(hd_v × d_model)。在本工作中,我们采用 h = 8 个并行注意力层,或称为注意力头。对于每个头,我们使用 d_k = d_v = d_model/h = 64。由于每个头的维度降低,总体计算成本与具有完整维度的单头注意力相似。

3.2.3 注意力在我们模型中的应用

Transformer 在三种不同的方式中使用多头注意力:

  • 在“编码器-解码器注意力”层中,查询来自前一解码器层,而内存的键和值来自编码器的输出。这使得解码器中的每个位置可以关注输入序列中的所有位置。这模拟了序列到序列模型中典型的编码器-解码器注意力机制,如 [31, 2, 8] 所示。

  • 编码器包含自注意力层。在自注意力层中,所有的键、值和查询来自同一个地方,在这种情况下,是编码器中前一层的输出。编码器中的每个位置都可以关注编码器前一层的所有位置。

  • 同样,解码器中的自注意力层允许解码器中的每个位置关注包括该位置在内的所有解码器位置。我们需要防止解码器中的左向信息流,以保持自回归特性。我们通过在缩放点积注意力内部掩蔽(设置为 −∞)与非法连接对应的 softmax 输入中的所有值来实现这一点。见图 2。

3.3 逐位置前馈网络

       除了注意力子层外,我们的编码器和解码器中的每个层还包含一个全连接的前馈网络,该网络对每个位置分别并且一致地应用。这由两个线性变换组成,中间夹着一个 ReLU 激活函数。

       虽然线性变换在不同的位置上是相同的,但它们在层与层之间使用不同的参数。另一种描述方式是将其视为两个卷积,卷积核大小为1。输入和输出的维度为 d_model = 512,而内层的维度为 d_f_f = 2048。

3.4 嵌入与 Softmax

       与其他序列转导模型类似,我们使用学习到的嵌入将输入标记和输出标记转换为维度为 d_model 的向量。我们还使用通常的学习线性变换和 softmax 函数将解码器的输出转换为预测的下一个标记概率。在我们的模型中,我们在两个嵌入层和预 softmax 的线性变换之间共享相同的权重矩阵,类似于 [24]。在嵌入层中,我们将这些权重乘以 √d_model。

3.5 位置编码

       由于我们的模型不包含递归和卷积,为了使模型能够利用序列的顺序,我们必须注入一些关于序列中标记的相对或绝对位置的信息。为此,我们在编码器和解码器堆栈底部的输入嵌入中添加“位置编码”。位置编码的维度与嵌入相同,即 d_model,以便这两者可以相加。位置编码有许多选择,既可以是学习得到的,也可以是固定的 [8]。

       在本工作中,我们使用不同频率的正弦和余弦函数:

表1:最大路径长度、每层复杂度和最小顺序操作数用于不同的层类型。N是序列长度,d是表示维度,k是核卷积的大小和r限制自注意力中的邻域大小。

       其中 pos 是位置,i 是维度。也就是说,位置编码的每个维度对应于一个正弦波。波长从 2π 以几何级数增长到 10000 · 2π。我们选择这个函数是因为我们假设它能够让模型更容易地学习基于相对位置的关注,因为对于任何固定的偏移量 k,P_E^(pos+k) 可以表示为 P_E^(pos) 的线性函数。

       我们还尝试使用学习位置嵌入 [8],但发现这两种版本的结果几乎相同(见表 3,第 (E) 行)。我们选择正弦版本,因为它可能使模型能够推断训练过程中未遇到的更长序列长度。

4 为什么自注意力

       在本节中,我们将自注意力层与常用于将一种变长符号表示序列 (x1, ..., xn) 映射到另一种相等长度序列 (z1, ..., zn) 的递归和卷积层进行比较,其中 xi 和 zi ∈ R^d,例如典型序列转导编码器或解码器中的隐藏层。为了激励我们使用自注意力机制,我们考虑了三个设计目标。

       一是每层的总计算复杂度。另一个是可以并行化的计算量,以所需的最小顺序操作的数量来衡量。第三是网络中长程依赖的路径长度。学习长程依赖关系是许多序列转导任务中的关键挑战。影响学习这种依赖关系能力的一个关键因素是前向和后向信号在网络中需要遍历的路径长度。输入和输出序列中任意位置组合之间的路径越短,学习长程依赖关系就越容易 [11]。因此,我们还比较不同层类型的网络中任意两个输入和输出位置之间的最大路径长度。

       如表 1 所示,自注意力层用恒定数量的顺序执行操作连接所有位置,而递归层则需要 O(n) 的顺序操作。在计算复杂度方面,当序列长度 n 小于表示维度 d 时,自注意力层比递归层快,这在状态最先进的机器翻译模型中通常是句子表示的情况,如 word-piece [31] 和 byte-pair [25] 表示。为了提高涉及非常长序列的任务的计算性能,自注意力可以限制仅考虑围绕相应输出位置的 r 大小的输入序列邻域。这将使最大路径长度增加到 O(n/r)。我们计划在未来的工作中进一步研究这一方法。

       单个卷积层的核宽 k < n 不会连接所有输入和输出位置的对。要做到这一点,在连续核的情况下,需要堆叠 O(n/k) 个卷积层,或者在扩张卷积的情况下需要 O(log_k(n)) [15],这增加了网络中任意两个位置之间最长路径的长度。相较于递归层,卷积层通常更昂贵,计算因子为 k。然而,可分离卷积 [6] 会显著降低复杂度至 O(k · n · d + n · d^2)。即使 k = n,然而,可分离卷积的复杂度仍然等于自注意力层与逐位置前馈层之和,这是我们在模型中采用的方法。

       自注意力还有一个附加好处,即可以产生更具可解释性的模型。我们检查模型的注意力分布,并在附录中呈现和讨论示例。单个注意力头不仅清楚地学习执行不同的任务,而且许多头似乎表现出与句子的句法和语义结构相关的行为。

5 训练

       本节描述了我们模型的训练方案。

5.1 训练数据和批处理

       我们在标准的 WMT 2014 英德数据集上进行了训练,该数据集包含约 450 万对句子。句子使用字节对编码(byte-pair encoding)[3] 进行编码,具有约 37000 个标记的共享源目标词汇。对于英法翻译,我们使用了规模更大的 WMT 2014 英法数据集,包含 3600 万句子,并将标记分割成一个 32000 单词片段的词汇 [31]。句子对按照近似序列长度进行批处理。每个训练批次包含一组句子对,大约包含 25000 个源标记和 25000 个目标标记。

5.2 硬件和时间安排

       我们在一台配有 8 个 NVIDIA P100 GPU 的机器上训练模型。对于本文中描述的超参数设置,每个训练步骤大约需要 0.4 秒。我们将基础模型训练总共 100,000 步,约 12 小时。对于我们的“大模型”(在表 3 最底行描述),每步时间为 1.0 秒。大模型训练 300,000 步(3.5 天)。

5.3 优化器

       我们使用 Adam 优化器 [17],设置 β_1 = 0.9,β_2 = 0.98 和 ε = 10^(-9)。我们在训练过程中根据公式调整学习率:

       这意味着在前 warmup_steps 个训练步骤中,学习率线性增加,然后根据步骤编号的平方根的倒数成比例地降低。我们使用 warmup_steps = 4000。

5.4 正则化

       在训练期间,我们应用三种类型的正则化:

  • 残差 Dropout:我们对每个子层的输出应用 dropout [27],在将其添加到子层输入并进行归一化之前。此外,我们还对编码器和解码器堆栈中嵌入与位置编码的总和应用 dropout。在基础模型中,我们使用的 dropout 率为 P_drop = 0.1。

  • 标签平滑:在训练过程中,我们应用了标签平滑,值为 ε_ls = 0.1 [30]。这会降低困惑度,因为模型学习变得更加不确定,但能提高准确性和 BLEU 分数。

6 结果

6.1 机器翻译

       在 WMT 2014 英德翻译任务上,较大的 Transformer 模型(表 2 中的 Transformer (big))比之前报告的最佳模型(包括集成模型)高出超过 2.0 BLEU,建立了新的最先进的 BLEU 分数 28.4。该模型的配置列在表 3 的底部。训练在 8 个 P100 GPU 上进行了 3.5 天。即使是我们的基础模型也超越了所有之前发布的模型和集成模型,且训练成本仅为任何竞争模型的一小部分。

       在 WMT 2014 英法翻译任务上,我们的大模型达到了 41.0 的 BLEU 分数,超越了所有之前发布的单模型,且训练成本不到之前最先进模型的四分之一。用于英法翻译的 Transformer (big) 模型使用了 dropout 率 P_drop = 0.1,而不是 0.3。

       对于基础模型,我们使用通过平均最后 5 个检查点获得的单一模型,这些检查点以 10 分钟的间隔写入。对于大模型,我们平均了最后 20 个检查点。我们使用 beam search,束大小为 4,长度惩罚 α = 0.6 [31]。这些超参数是在开发集上实验后选择的。我们在推理期间将最大输出长度设置为输入长度 + 50,但在可能的情况下尽早终止 [31]。

       表 2 总结了我们的结果,并将我们的翻译质量和训练成本与文献中的其他模型架构进行了比较。我们通过乘以训练时间、使用的 GPU 数量以及每个 GPU 的持续单精度浮点运算能力的估算值来估计训练模型所需的浮点运算次数。

表2:Transformer在数据集上取得了比之前最先进模型更好的BLEU分数英语-德语和英语-法语newstest2014考试费用仅为培训费用的一小部分。

6.2 模型变体

       为了评估 Transformer 中不同组件的重要性,我们以不同方式改变基础模型,并测量在开发集 newstest2013 上的英德翻译性能变化。我们使用了前一节中描述的束搜索,但没有进行检查点平均。我们将这些结果呈现在表 3 中。

       在表 3 的第 (A) 行中,我们改变了注意力头的数量以及注意力键和值的维度,同时保持计算量恒定,如第 3.2.2 节所述。虽然单头注意力比最佳设置低 0.9 BLEU,但如果头数太多,质量也会下降。在表 3 的第 (B) 行中,我们观察到减小注意力键大小 d_k 会降低模型质量。这表明确定兼容性并不容易,而比点积更复杂的兼容性函数可能会是有益的。我们进一步在第 (C) 和 (D) 行中观察到,正如预期的那样,更大的模型效果更好,并且 dropout 对避免过拟合非常有帮助。在第 (E) 行中,我们用学习位置嵌入 [8] 替换了我们的正弦位置编码,发现与基础模型的结果几乎相同。

表3:Transformer架构的变体。未列出的值与基数的值相同模型。所有指标都在英语-德语翻译开发集newstest2013上。上市根据我们的字节对编码,困惑度是按单词计算的,不应该进行比较
每个字的困惑。

7 结论

       在本工作中,我们介绍了 Transformer,这是一种完全基于注意力机制的序列转导模型,用多头自注意力替代了编码器-解码器架构中最常用的递归层。

       对于翻译任务,Transformer 的训练速度显著快于基于递归或卷积层的架构。在 WMT 2014 英德和 WMT 2014 英法翻译任务中,我们取得了新的最先进水平。在前者任务中,我们的最佳模型甚至超越了所有之前报告的集成模型。

       我们对基于注意力的模型的未来感到兴奋,并计划将其应用于其他任务。我们计划将 Transformer 扩展到涉及文本以外的输入和输出模态的问题,并研究局部限制注意力机制,以有效处理如图像、音频和视频等大输入和输出。使生成过程减少顺序性是我们的另一个研究目标。

我们用于训练和评估模型的代码可在以下链接获取:TensorFlow GitHub Repository。

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

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

相关文章

快速学习一个算法,Transformer模型架构

今天给大家分享一个超强的算法模型&#xff0c;Transformer Transformer 模型是目前自然语言处理&#xff08;NLP&#xff09;以及计算机视觉等领域中应用非常广泛的深度学习模型架构。 它由 Vaswani 等人在 2017 年的论文《Attention is All You Need》中提出&#xff0c;并…

【智能大数据分析 | 实验三】Storm实验:实时WordCountTopology

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘&#xff0c;以提取有价值的信息和洞察。它结合了大数据技术、人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&a…

并查集的实现(朴素版)

这是C算法基础-数据结构专栏的第二十九篇文章&#xff0c;专栏详情请见此处。 由于作者即将参加CSP&#xff0c;所以到比赛结束前将不再发表文章&#xff01; 引入 并查集是一种可以快速合并查找集合的一种数据结构&#xff0c;这次我们将通过三道题来详细讲解并查集&#xff…

迈普pnsr2900x DOWNLOAD_FILE 任意文件读取漏洞

0x01 产品描述&#xff1a; ‌ 迈普NSR2900X系列是一款专为军队、政府、金融、中小型企业分支机构和中小型企业总部设计的信创接入路由器。‌ 该路由器采用国产核心元器件&#xff0c;基于国产操作系统运行迈普自主研发的网络操作系统及应用软件。它全面支持IPv4、IPv6、OS…

insert into values 语句优化

insert into values插入单行数据 SQL语句&#xff0c;insert into values插入单行数据&#xff0c;执行10万次&#xff0c;执行时间1279秒&#xff0c;优化总体执行耗时。 SQL文本&#xff0c;单行insert values&#xff0c;没有select部分。需要进一步分析执行过程消耗。 ins…

软考《信息系统运行管理员》- 5.1 信息系统数据资源维护体系

5.1 信息系统数据资源维护体系 文章目录 5.1 信息系统数据资源维护体系数据资源维护的管理对象数据资源维护的管理类型运行监控故障响应数据备份归档检索数据优化 数据资源维护的管理内容维护方案例行管理应急响应数据资源的开发与利用 数据是信息系统管理的对象与结果&#xf…

7-基于国产化FT-M6678+JFM7K325T的6U CPCI信号处理卡

一、板卡概述 本板卡系我公司自主研发&#xff0c;基于6U CPCI的通用高性能信号处理平台。板卡采用一片国产8核DSP FT-C6678和一片国产FPGA JFM7K325T-2FFG900作为主处理器。为您提供了丰富的运算资源。如下图所示&#xff1a; 二、设计参考标准 ● PCIMG 2.0 R3.0 CompactP…

Python酷库之旅-第三方库Pandas(147)

目录 一、用法精讲 666、pandas.Timestamp.astimezone方法 666-1、语法 666-2、参数 666-3、功能 666-4、返回值 666-5、说明 666-6、用法 666-6-1、数据准备 666-6-2、代码示例 666-6-3、结果输出 667、pandas.Timestamp.ceil方法 667-1、语法 667-2、参数 667…

基础篇:带你打开Vue的大门(一)

学习目标&#xff1a; 理解Vue的基本概念&#xff1a;掌握Vue.js是什么&#xff0c;它的设计理念&#xff0c;以及它在现代Web开发中的应用。掌握Vue的基本语法&#xff1a;学习Vue的基础指令和语法&#xff0c;能够使用Vue构建简单的交互式界面。熟悉Vue组件化开发&#xff1…

DBA | 如何将 .bak 的数据库备份文件导入到SQL Server 数据库中?

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ] 原文链接&#xff1a;DBA | 如何将 .bak 的数据库备份文件导入到SQL Server 数据库中? 如何将&#xff08;.bak&#xff09;的SQL Server 数据库备份文件导入到当前数据库中? Step 1.登录到 Sql…

Centos7安装RocketMQ[图文教程]

文章目录 RocketMQ介绍基于Linux服务部署RocketMQ&#xff08;单机&#xff09;配置JDK环境下载RocketMQ部署RocketMQ1、解压2、修改VM参数3、配置环境变量4、编写Service文件5、启动服务 基于Docker方式部署RocketMQ安装Docker编写docker-compose文件启动RocketMQ服务 部署Roc…

前端学习-css的背景(十六)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 背景颜色 语法格式 背景图片 语法格式 背景平铺 语法格式 背景图片位置 语法格式 参数代表的意思 参数是方位名词 参数是精确单位 参数是混合单位 背…

架构设计笔记-11-未来信息综合技术

知识要点 云原生架构原则包括&#xff1a;服务化原则、弹性原则、可观测原则、韧性原则、所有过程自动化原则、零信任原则和架构持续演进原则。 区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构&#xff0c;并以密码学方式保证的不可篡改和不可…

【项目案例】-音乐播放器-Android前端实现-Java后端实现

精品专题&#xff1a; 01.C语言从不挂科到高绩点 https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482 02. SpringBoot详细教程 https://blog.csdn.ne…

项目管理系统如何助力新药研发?药物研发企业康诺亚上线瑞杰项目管理系统

在新药研发过程中&#xff0c;其特点是&#xff1a;周期长、风险高、投入大&#xff0c;同时还要与其他科学相结合&#xff0c;相互渗透、更加需要多部门的共同参与&#xff0c;因此面临的问题相对复杂&#xff0c;而且要求也比较高。所以在这一过程中&#xff0c;必须对新药研…

软考系统分析师知识点十一:系统规划

前言 今年报考了11月份的软考高级&#xff1a;系统分析师。 考试时间为&#xff1a;11月9日。 倒计时&#xff1a;26天。 目标&#xff1a;优先应试&#xff0c;其次学习&#xff0c;再次实践。 复习计划第一阶段&#xff1a;扫平基础知识点&#xff0c;仅抽取有用信息&am…

49 | 桥接模式:如何实现支持不同类型和渠道的消息推送系统?

上一篇文章我们学习了第一种结构型模式&#xff1a;代理模式。它在不改变原始类&#xff08;或者叫被代理类&#xff09;代码的情况下&#xff0c;通过引入代理类来给原始类附加功能。代理模式在平时的开发经常被用到&#xff0c;常用在业务系统中开发一些非功能性需求&#xf…

嵌入式~CAN-专辑2

我自己的原文哦~ 只发CAN相关2 随时更新~~ 一、CAN总线错误分析与解决 从实际工作中碰到的具体问题来分析一些常见的CAN总线错误和解决办法。 CAN节点数据收发过程 我们知道&#xff0c;CAN总线上的每个节点往总线上发送数据的同时&#xff0c;会读取总线上的数据&#x…

stm32单片机个人学习笔记10(TIM编码器接口)

前言 本篇文章属于stm32单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 STM32入门教程-2023版 细…

简单实现手机投屏到电脑代码

1、从手机截图到sdcard 2、将图片导出到PC 3、从PC加载图片 4、开启定时器 1、 private static void takeScreenshot(String path) {long t1 System.currentTimeMillis();String command "adb devices"; // 替换为你需要执行的shell命令String command1 "…