Transformer解析
Transformer解析(Attention Is All You Need)
【超详细】【原理篇&实战篇】一文读懂Transformer-CSDN博客
Transformer论文逐段精读【论文精读】_哔哩哔哩_bilibili
【超详细】【原理篇&实战篇】一文读懂Transformer-CSDN博客
大模型面试准备(十二):深入剖析Transformer - 残差连接和层归一化_残差层和归一化层-CSDN博客
Transformer通俗笔记:从Word2Vec、Seq2Seq逐步理解到GPT、BERT-CSDN博客
“Attention Is All You Need” 是一篇由 Ashish Vaswani 等人撰写的论文,发表于 2017 年的 NeurIPS 会议上。这篇论文提出了 Transformer 模型,Transformer是一种用于自然语言处理(NLP)和其他序列到序列(sequence-to-sequence)任务的深度学习模型架构。Transformer架构引入了自注意力机制(self-attention mechanism),这是一个关键的创新,使其在处理序列数据时表现出色。
Transformer 模型的主要特点:
自注意力机制(Self-Attention):Transformer 模型的核心是自注意力机制,它允许模型在序列的每个位置都计算与其他位置的注意力,从而捕捉序列内部的长距离依赖关系。这种机制使得模型能够更好地理解文本中的上下文信息。
并行化处理:与循环神经网络(RNN)和长短期记忆网络(LSTM)不同,Transformer 模型可以并行处理序列中的所有元素,这大大提高了模型的训练速度。
编码器-解码器架构:Transformer 模型通常由编码器和解码器两部分组成。编码器将输入序列转换为中间表示,解码器则根据这个表示生成输出序列。这种架构特别适用于机器翻译等任务。
位置编码:由于自注意力机制本身不包含序列中的位置信息,Transformer 引入了位置编码来为模型提供序列中单词的位置信息。
多头注意力(Multi-Head Attention):Transformer 模型使用多头注意力机制来从不同的表示子空间中捕捉信息,这增强了模型的表达能力。
层标准化(Layer Normalization)和残差连接(Residual Connections):这些技术有助于提高模型的训练稳定性和性能。
Transformer重点
编码器(Encoder):
编码器:(多头注意力+MLP+残差连接)*N(N=6)
2 sub layer:
- Multi-Head Attention(多头注意力)
- position-wise fully connected feed-forward network(一个MLP)
在每一个sub layer中,有一个residual connection(残差连接)和一个Layer Norm(层归一化)。
残差连接(Residual Connection)-CSDN博客
【深度学习 | ResNet核心思想】残差连接 & 跳跃连接:让信息自由流动的神奇之道-CSDN博客
Layer Norm(x+sub layer(x))
[BatchNorm和LayerNorm——通俗易懂的理解_layernorm和batchnorm-CSDN博客](https://blog.csdn.net/Little_White_9/article/details/123345062?ops_request_misc=%7B%22request%5Fid%22%3A%225650B123-9D57-41CE-A28B-51467C660DDF%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=5650B123-9D57-41CE-A28B-51467C660DDF&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-123345062-null-null.142^v100^pc_search_result_base8&utm_term=Layer Norm&spm=1018.2226.3001.4187)
batchNorm和layerNorm:
在上面的立方体中,可以理解为batch(有多少个句子),seq(句子里有多少词),feature(一个词的向量表示,在论文中是长度为512)。均值变为0方差变为1(减去均值再除以标准差)。
batchNorm(批归一化)是关注的不同样本和序列的同一feature的切面(蓝色)。
而layerNorm(层归一化)关注的是一个样本下的东西(黄色)。
编码器的输出作为解码器的输入。
解码器(Decoder):
解码器:(带掩码的多头注意力+多头注意力+MLP+残差连接)*N(N=6)
- 3 sub layer:
- Masked Multi-Head Attention(带掩码多头注意力)
- Multi-Head Attention(多头注意力)
- position-wise fully connected feed-forward network(一个MLP)
在 Transformer 模型中,带掩码的多头注意力机制(Masked Multi-Head Attention)主要用于解码器(Decoder)部分,其作用是确保解码器在生成输出序列时,每一步只能使用之前的时间步的信息,而不能“看到”未来的信息。这种机制对于保持生成序列的自回归特性至关重要,以下是其具体作用和重要性:
- 自回归特性:在序列生成任务(如语言模型、机器翻译)中,模型在生成当前词的同时,只能依赖于之前已经生成的词,而不能利用未来的词。带掩码的多头注意力机制通过掩码(Masking)操作实现这一点,确保在计算当前位置的注意力权重时,只考虑当前和之前位置的信息。
- 避免未来信息泄露:在训练过程中,模型应该只根据给定的输入序列生成输出,而不应该利用未来的信息。如果不使用掩码,模型可能会“作弊”,利用未来的信息来生成当前的输出,这会影响模型的泛化能力和实用性。
- 提高模型的鲁棒性:通过限制模型只能使用过去的信息,带掩码的多头注意力机制迫使模型学习如何更好地从已有的信息中提取和利用有用的特征,从而提高了模型的鲁棒性。
- 实现并行解码:在解码过程中,由于每个时间步的输出只依赖于之前的输出,这允许模型并行生成整个序列,而不是必须等待前一个词生成完毕。这在某些场景下可以提高解码的效率。
- 保持序列生成的连贯性:在生成文本或其他类型的序列数据时,保持序列的连贯性和逻辑性是非常重要的。带掩码的多头注意力机制通过确保每一步生成都只依赖于之前的信息,有助于生成更加连贯和合理的序列。
在 Transformer 模型中,这种掩码通常是通过一个上三角矩阵实现的,其中未来位置的权重被设置为一个非常大的负数(例如负无穷大),这样在应用 softmax 函数时,这些位置的注意力权重会接近于零,从而被忽略。这种掩码也被称为因果掩码(Causal Mask),因为它确保了解码过程中的因果关系。
编码器和解码器之间的联系作用的几个关键点:
- 信息传递:编码器将输入序列(如源语言文本)转换为一系列连续的表示,解码器则利用这些表示来生成输出序列(如目标语言文本)。编码器-解码器注意力机制使得解码器能够在每一步生成输出时,都能够参考编码器提供的上下文信息。
- 对齐关系:在机器翻译等任务中,编码器-解码器注意力机制有助于识别输入序列和输出序列之间的对齐关系。例如,它可以帮助模型确定在翻译过程中,源语言中的某个词对应于目标语言中的哪个词。
- 上下文建模:解码器在生成每个输出词时,不仅要考虑已经生成的输出序列的部分,还要考虑整个输入序列的上下文。编码器-解码器注意力机制使得解码器能够在生成过程中充分利用输入序列的全局上下文信息。
- 灵活性:编码器-解码器架构提供了灵活性,使得模型可以处理各种序列到序列的任务,如文本摘要、问答系统、对话系统等,而不仅仅是机器翻译。
- 并行处理:在训练阶段,编码器可以并行处理整个输入序列,而解码器则可以并行生成整个输出序列,这大大提高了模型的训练效率。
- 自回归特性:尽管解码器可以并行接收编码器的输出,但在生成输出序列时,它仍然保持自回归特性,即在生成当前词时,只能使用之前的时间步信息,而不能使用未来的信息。
在 Transformer 模型的具体实现中,编码器-解码器注意力层通常位于解码器的每个层中。在这一层次上,查询(Queries)来自于解码器的上一层输出,键(Keys)和值(Values)来自于编码器的输出。通过这种方式,解码器可以有效地利用编码器处理过的输入序列信息来生成输出序列。
Attention:
Q、K、V(都是矩阵):
对于每一个key,有一个value和它对应。
query(黄色部分)将进行查询,搜索到与query相似度最大的若干key,并进行权重的分配(相似度越高的权重也就越高),综合value返回结果。
不同注意力->不同权重,结果也不同
Scaled Dot-Product Attention
Transformer自己的注意力机制叫做:Scaled Dot-Product Attention。
$$
Attention(Q,K,V)=softmax(QK^T/\sqrt{dk})V
$$
这里的query和key的维度是一样的(都是dk),而value的维度是(dv)。
注意到softmax中的公式,Q乘以K的转置(做一个内积,余弦相似度),再除以根号dk,再softmax(对每一行做softmax)得到n个非负的且加起来和等于1的权重。
这里其实是一个点乘注意力(dot-product attention)+除以根号dk
为什么除以根号dk?
Scaled dot-product attention 中的缩放因子
$$
\sqrt{dk}
$$
是为了调整点积注意力的缩放,以防止在计算注意力分数时出现过大的数值,这可能会导致梯度消失或者梯度爆炸的问题。这里的
$$
\sqrt{dk}
$$
是查询(queries)、键(keys)向量的维度。
当我们计算两个向量的点积时,如果向量的维度
$$
\sqrt{dk}
$$
较大,那么点积的结果可能会变得非常大。由于 softmax 函数的输入值如果过大,会导致输出值接近于 0 或 1,这会使得梯度非常小,从而在反向传播过程中难以有效地更新权重。通过除以
$$
\sqrt{dk}
$$
,我们可以将点积的结果缩放到一个更合理的范围内,这样 softmax 函数的输出分布会更加平滑,梯度也会更加稳定。
具体来说,缩放点积注意力的计算步骤如下:
计算查询 Q和所有键 K之间的点积。
将点积结果除以
$$
\sqrt{dk}
$$
,这样做可以防止点积结果过大。应用 softmax 函数来获取注意力权重,这些权重表示每个值 V在计算加权和时的重要性。
使用注意力权重对值 V进行加权求和,得到最终的注意力输出。
数学上,Scaled dot-product attention 可以表示为:
$$
Attention(Q,K,V)=softmax(QK^T/\sqrt{dk})V
$$
其中 Q是查询矩阵,K 是键矩阵,V是值矩阵,
$$
\sqrt{dk}
$$
是缩放因子。
这种缩放操作是 Transformer 模型中的一个关键设计,它有助于模型在处理长序列时保持稳定性,并且使得模型能够更有效地学习序列中的长距离依赖关系。
掩码机制
掩码机制:
在 Transformer 模型中,掩码机制(Masking Mechanism)的作用主要是在解码器(Decoder)的自注意力层中防止未来信息的泄露,确保模型在生成当前输出时只能使用之前的时间步信息。这种机制对于保证序列生成任务的正确性和因果关系至关重要。以下是掩码机制的几个主要作用:
- 因果关系维护:在序列生成任务中,如语言模型或机器翻译,每个输出应该是基于之前输出的因果序列。掩码机制确保解码器在生成当前词时,不会利用到未来词的信息,从而维护了序列的因果性。
- 训练稳定性:通过限制自注意力层的计算范围,掩码机制可以防止在训练过程中出现错误的信息流,这有助于提高模型训练的稳定性和效率。
- 并行解码:在解码过程中,掩码机制允许模型并行生成整个序列,因为每个输出词的生成只依赖于它之前的词,而不是整个序列。这大大提高了解码速度。
- 避免无效计算:在自注意力计算中,掩码机制通过忽略无关的位置(例如填充位置或未来的词),减少了不必要的计算,从而提高了计算效率。
- 处理变长序列:在处理不同长度的序列时,掩码机制可以动态地适应序列的实际长度,忽略填充部分,确保模型只关注有效的序列部分。
在 Transformer 模型的解码器中,通常使用两种类型的掩码:
- 因果掩码(Causal Mask):这种掩码确保在生成序列的每个时间步时,模型只能看到当前和之前的词,而不能“看到”未来的词。这通常通过一个上三角矩阵实现,其中未来位置的权重被设置为一个非常大的负数(例如负无穷大),使得在应用 softmax 函数时,这些位置的注意力权重接近于零。
- 填充掩码(Padding Mask):在处理包含不同长度序列的批次时,通常会使用填充(Padding)来对齐序列长度。填充掩码用于告诉模型忽略这些填充的位置,因为它们不包含有效信息。
例如,在机器翻译任务中,当模型正在生成英文翻译的第 i 个词时,它只能使用到已经翻译好的前 i-1 个词,而不能使用第 i 个词之后的信息。这样可以确保翻译的连贯性和正确性,因为翻译的每个步骤都是基于当前可用的最完整的上下文信息。
多头注意力
其实在Scaled Dot-Product Attention中没有什么要去学的参数,这里直接QKV线性变化低维投影,然后重复h次最后concat再做一次线性投影。
在 Transformer 模型中的多头注意力机制(Multi-Head Attention)中,进行线性变换(Linear Transformation)和拼接(Concatenation)的步骤是为了增加模型的表达能力,允许它在不同的表示子空间中并行地学习信息。以下是这些步骤的具体作用和原因:
线性变换:
- 增加非线性:通过线性变换,模型可以学习到输入数据的不同线性组合,这有助于引入非线性特性,使得模型能够捕捉更复杂的特征和模式。
- 特征提取:每个“头”(Head)中的线性变换可以看作是一种特征提取过程,它允许模型在不同的表示子空间中捕捉不同的信息。
- 减少维度:在拼接之前,通常需要对每个头的输出进行线性变换,以减少维度,使得不同头的输出可以被拼接在一起而不会超过原始的维度限制。
拼接:
- 整合信息:拼接操作将多个头的输出合并成一个单一的表示,这样模型就可以同时考虑到所有头学习到的信息。
- 增加宽度:拼接增加了模型的宽度,类似于在卷积神经网络中增加滤波器的数量,这有助于提高模型的容量和学习能力。
- 保留多样性:每个头可以学习到不同的特征,拼接这些特征可以保留这种多样性,使得模型能够从多个角度理解数据。
多头注意力的优势:
- 并行处理:多头注意力允许模型并行地在不同的子空间中学习信息,这提高了计算效率。
- 捕捉不同尺度的特征:不同的头可以捕捉到不同尺度的特征,例如,一些头可能关注局部细节,而另一些头可能关注更广泛的上下文信息。
- 提高鲁棒性:多头机制增加了模型的鲁棒性,即使某些头没有学习到有用的特征,其他头仍然可以提供有用的信息。
在实际操作中,多头注意力的计算过程通常如下:
- 将输入 ( X ) 通过三个不同的线性变换得到查询 ( Q )、键 ( K ) 和值 ( V )。
- 将 ( Q )、( K ) 和 ( V ) 分别分割成多个头,每个头对应一个子空间。
- 对每个头,计算 ( Q ) 和 ( K ) 的点积注意力,然后应用 softmax 函数得到注意力权重,最后用这些权重对 ( V ) 进行加权求和。
- 将所有头的输出拼接在一起,并通过另一个线性变换来整合信息,得到最终的多头注意力输出。
这种设计使得 Transformer 模型在处理序列数据时非常有效,尤其是在自然语言处理任务中。
多头注意力的公式理解_multihead attention公式-CSDN博客
Application of Attention in Our Model
Transformer中的三个attention是在干什么事情?
在Transformer架构中,有3种不同的注意力层:
解码器中的交叉注意力层(Cross attention layer)(右上角)
在 Transformer 中,交叉注意力层位于字面上的中心位置;它连接了编码器和解码器,是在模型中使用注意力最直接的方式。
要实现这一点,需要将目标序列作为查询,将上下文序列作为键/值传递。
- Q = 解码器中因果注意力层的输出向量
- K = 编码器输出的注意力向量
- V = 编码器输出的注意力向量
编码器中的全局自注意力层(Global self attention layer)(左下角)
全局自注意力是Transformer编码器的一部分,它的作用是负责处理整个输入序列。
它允许每个序列元素直接访问其他所有序列元素,只需将整个序列作为Q,K,V即可,所有输出可以并行计算。
Q = 输入序列中的当前位置词向量
K = 输入序列中的所有位置词向量
V = 输入序列中的所有位置词向量
解码器中的因果自注意力层(Casual attention layer)(右下角)
因果注意力层对解码器中输出序列执行类似于全局自注意力层的工作;但与编码器的全局自注意力层有不同的处理方式。
Transformer是一个“自回归”模型,它逐个标记地生成文本,并将输出反馈到输入中;为了使这个过程高效,这些模型确保每个序列元素的输出只依赖于前面的序列元素;这些模型是“因果”的。
要构建一个因果自注意力层,在计算注意力分数和求和注意力值时需要使用适当的掩码,因为输出序列也是一次性输入的,但在计算前面分词的时候是不希望它后面的分词也参与计算的。
Position-wise Feed-Forward Networks
$$
\text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2
$$
一个单隐藏层的MLP,做语义的转换。
如上图所示:
- 最下面蓝色的是输入,上面红色的长块就是注意力
- 注意力能够提取到有用的序列信息
- 这些有用的信息再经过一次MLP
在Transformer模型中,Position-wise Feed-Forward Network(FFN)是编码器和解码器内部的一个关键组件。它的作用主要体现在以下几个方面:
增加模型的表达能力:FFN通过引入非线性变换,使得模型能够捕捉到输入数据中更复杂的特征和模式。这对于处理序列数据尤其重要,因为序列数据往往包含丰富的上下文信息和复杂的依赖关系。
参数效率:尽管Transformer模型的自注意力机制能够处理长距离依赖,但它的参数数量随着输入序列长度的增加而线性增长。FFN通过在每个位置独立地应用相同的权重,使得模型能够在保持参数数量相对固定的同时,处理不同长度的输入序列。
位置不变性:FFN的设计使得它对输入序列中的位置信息不敏感,这有助于模型更好地泛化到不同的输入序列。在自注意力机制中,位置信息是通过位置编码(Positional Encoding)来引入的,而FFN则专注于处理序列中的局部特征。
并行化处理:由于FFN在每个位置独立地应用相同的权重,这使得它可以很容易地在不同的位置上并行处理,从而提高模型的训练效率。
减少过拟合:FFN通过引入额外的参数和非线性变换,增加了模型的复杂度,这有助于模型在面对复杂数据时减少过拟合的风险。
FFN通常由两个线性变换和一个非线性激活函数(如ReLU)组成,其结构可以表示为:
$$
\text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2
$$
其中,( x ) 是输入向量,( W_1 ) 和 ( W_2 ) 是权重矩阵,( b_1 ) 和 ( b_2 ) 是偏置向量。
FFN的结构如下所示:
- 第一个线性变换:输入数据首先通过一个线性变换,这个变换由权重矩阵 W1 和偏置向量 b1 组成。
- ReLU激活函数:经过第一个线性变换后,数据会通过ReLU激活函数,ReLU函数的公式是 max(0,x)max(0,x),它将所有负值置为0,保留所有正值。这一步的目的是增加模型的非线性,使得模型能够学习到更复杂的函数。
- 第二个线性变换:经过ReLU激活后的数据再通过另一个线性变换,这个变换由权重矩阵 W2 和偏置向量 b2 组成。
在Transformer模型中,FFN通常在自注意力层之后应用,它的作用是对自注意力层的输出进行进一步的变换和特征提取。通过这种方式,FFN与自注意力机制协同工作,共同提高了模型的性能和泛化能力。
RNN:
如何从RNN起步,一步一步通俗理解LSTM_rnn lstm-CSDN博客
Embeddings and Softmax
在RNN中,自然是包含时序信息的:将之前的输出自然的作为输出。
但注意力机制而言,如果将一个句子顺序打乱,其得到的权重是不变的->这显然是不符合常理的,因为打乱顺序就意味着语义变化。为了弥补这种缺陷,加入了 位置编码。
input->词嵌入,得到一个向量->位置编码(正余弦,值在-1到1)->将向量和位置编码相加。
在Transformer模型中,”Embedding” 和 “Softmax” 是两个重要的概念,它们在模型的不同部分发挥着关键作用。
Embedding
定义:
- Embedding 是一种将离散数据(如单词、字符或其他符号)映射到连续的向量空间的技术。在自然语言处理(NLP)中,embedding 通常用于将词汇表中的单词转换为固定长度的向量。
在Transformer中的应用:
- 词嵌入(Word Embedding):在Transformer模型的输入阶段,每个单词首先被转换为一个词嵌入向量。这些向量捕捉了单词的语义信息,并且可以通过训练进一步优化。
- 位置编码(Positional Encoding):由于Transformer模型本身不具备捕捉序列中位置信息的能力,因此需要添加位置编码到词嵌入中。位置编码是一种将位置信息编码到向量中的方法,它与词嵌入向量相加,以确保模型能够理解单词在序列中的位置。
Softmax
定义:
- Softmax 是一种将实数向量转换为概率分布的函数。对于向量中的每个元素,Softmax 函数计算其相对于其他元素的指数,并将其归一化,使得所有输出值的和为1。
在Transformer中的应用:
- 自注意力机制中的输出:在自注意力层中,每个单词的嵌入向量会通过一个线性变换,然后应用Softmax函数。Softmax函数的输出表示每个单词对其他所有单词的关注程度,即注意力权重。
- 解码器中的输出:在解码器的最后阶段,模型会预测下一个单词的概率分布。这里也会使用Softmax函数,将最后一个隐藏层的输出转换为词汇表上的概率分布,以便选择下一个最可能的单词。
具体应用示例
词嵌入:
- 假设词汇表大小为10000,每个单词被映射到一个维度为512的向量空间。词嵌入层会将输入的单词索引转换为相应的512维向量。
位置编码:
- 位置编码通常是与词嵌入向量相同维度的向量,它通过正弦和余弦函数生成,以确保模型能够区分不同位置的单词。
自注意力层中的Softmax:
- 在自注意力层中,每个单词的嵌入向量会通过一个线性变换,得到一个未归一化的注意力分数。然后,Softmax函数将这些分数转换为概率分布,即每个单词对其他单词的关注权重。
解码器的输出Softmax:
- 在解码器的最后,模型会将最后一个隐藏层的输出通过一个线性变换,然后应用Softmax函数,得到词汇表上每个单词的概率分布。这个分布用于选择下一个最可能的单词。
通过这些机制,Transformer模型能够有效地处理序列数据,捕捉单词之间的依赖关系,并在各种NLP任务中取得优异的性能。
Why Self-Attention
没有说的太清楚
Complexity per Layer(每层的复杂度)
Sequential Operations(序列操作):
- O(1):这意味着在处理序列时,每个层的操作可以并行化,不需要等待前一个操作完成。
- **O(n)**:并行化程度较差
Maximum Path Length(最大路径长度)
CNN/RNN/Transformer对比 - 知乎 (zhihu.com)
Transformer 的应用:
Transformer 模型自提出以来,已经在自然语言处理领域取得了巨大的成功,尤其是在机器翻译、文本摘要、问答系统和文本生成等任务中。此外,它也被用于语音识别和计算机视觉等领域。
“Attention Is All You Need” 论文的提出标志着 NLP 领域的一个重要转折点,它不仅推动了模型架构的发展,也为后续的研究和应用奠定了基础。
Transformer和CNN:
Transformer 和 CNN 是两种在深度学习领域广泛使用的模型架构,它们各自有着独特的优势和适用场景。
Transformer:
- 并行处理能力:Transformer 模型由于不依赖于序列的循环结构,可以并行处理序列中的所有元素,这使得它在训练时能够充分利用现代硬件的并行计算能力,从而加快训练速度。
- 自注意力机制:Transformer 通过自注意力机制能够捕捉序列中的长距离依赖关系,这在处理长序列数据时特别有用,如机器翻译和文本生成等任务。
- 多头注意力:Transformer 模型中的多头注意力机制可以同时从不同的表示子空间中学习信息,增强了模型的表达能力。
- 位置编码:由于 Transformer 本身不包含序列中的位置信息,因此需要引入位置编码来为模型提供序列中单词的位置信息。
CNN:
- 局部特征提取:CNN 通过卷积层可以有效地提取图像中的局部特征,如边缘、纹理等,这使得它在图像识别和分类任务中表现出色。
- 参数共享:CNN 的卷积层通过权重共享减少了模型的参数数量,这不仅减少了计算成本,也使得模型更加高效。
- 多层结构:CNN 通常包含多个卷积层和池化层,这有助于模型学习从低级到高级的特征表示。
- 平移不变性:CNN 的卷积操作具有平移不变性,这意味着模型对图像中物体的位置变化具有一定的鲁棒性。
在计算机视觉领域,CNN 长期以来一直是主流的模型架构,但近年来 Transformer 也开始在这一领域取得突破。例如,Vision Transformer(ViT)通过将图像分割成多个小块,然后将这些小块作为序列输入到 Transformer 模型中,已经在多个视觉任务中取得了优异的性能。
在自然语言处理领域,Transformer 已经成为许多任务的首选模型,如机器翻译、文本摘要和问答系统等。它的并行化处理能力和长距离依赖关系的捕捉能力使其在这些任务中超越了传统的 RNN 和 LSTM 模型。
总的来说,Transformer 和 CNN 各有优势,选择哪种模型取决于具体的任务需求、数据类型和计算资源。在某些情况下,甚至可以将两者结合起来,以利用它们各自的优势。