Transformer架构的局限已凸显,被取代还有多久?
江山代有才人出,各领风骚数百年。这句话无论是放在古往今来的人类身上,还是放在当今人工智能领域的大模型之上,都是最贴切不过的。无论是一个时代的伟人,还是统治一个领域的技术,最终都会有新的挑战者将其替代。Transformer作为大模型的统治者,自从出现之后,就以其强大的语言理解能力击败了RNN模型,迅速占据了NLP领域的榜首,之后又是抢占了CNN主导的图像领域,成为了整个领域的王者,在之后很长一段时间内地位都稳固如初。
不过随着终端应用领域的细分,对大模型各方面的要求也越来越具体化,比如对于开发成本的考虑,和对终端响应效率的需求等。这些都倒逼着底层模型的革新必要,随着各领域的研究深入,逐渐发现Transformer模型本身的问题已经成为技术进一步发展的阻拦,想要提高应用层面的体验,就必须解决这些问题,而底层架构是首当其冲的。
一、Transformer的封神之路
自2017年Transformer模型被提出来之前,语言模型领域还在被以RNN为主的LSTM、GRU、SRU等模型统治,注意力机制也是以普通的交叉注意力为主。而Transformer的出现,彻底打破了这个局面,首先以RNN为主的循环神经网络被替换成了传统的前馈神经网络-FNN(也称为多层感知机-MLP),也就是模型中的全连接层,这种稠密的网络连接能够为网络提供更多的参数,可以有效的学习自然语言文本中的信息。
在此之前,前馈神经网络没有被应用在语言模型的任务中,其主要原因之一就是普通的前馈神经网络在处理自然语言信息时无法为输入的词向量提供准确的位置信息,我们都知道,自然语言文本信息的处理是一个具有先后顺序的序列任务,也就是说语言是有先手顺序的,RNN天生就具备“记忆”功能,本身就是为处理序列任务而设计的模型,而FNN(前馈神经网络)对于输入的数据,不会记住具体的位置信息。
在Transformer模型中,对这一问题的处理方法是通过加入额外的位置向量来确定位置,具体操作是在处理输入数据的时候对每一个输入的数据向量都加入一个位置向量即可,这样就可以让模型“记住”每一个输入数据的具体位置了,模型也就具备了处理序列问题的能力。后面无论每个输入向量学习到了什么信息,都能够通过位置向量回溯到模型中的具体位置,也就为后面的输出提供了可参考的依据。
使用FNN替代RNN有个好处就是可以避免参数稀疏化,我们都知道CNN和RNN都是具备参数共享功能的,这种参数共享在处理简单任务的时候,可能具备一定的好处,但是在处理复杂任务的时候,参数的共享可能不会带来优势,反而是稠密连接的FNN有更大的优势,稠密连接意味着参数量的增加,而参数量的增加,至少可以让模型可承载的信息量变大。
虽然RNN的模型设计更符合人类大脑的思考机制,但是对于普通的RNN来说,FNN的稠密参数设计和并行计算优势更符合硬件的计算机制,对于GPU的利用率也会更高,这一切优势都使得FNN在之前大模型的发展中有着更好的应用性。对比CNN模型提供的稀疏矩阵计算形式,FNN的稠密矩阵计算形式则具有更高的精度和更低的延迟性。
想要把一个简单的FNN改造成合格的序列任务处理模型,最主要的还是要让输入模型的所有数据之间都能够根据具体任务需求而产生强关联,简单来说,就是让输入的每个数据之间都能够表示某种关系,比如输入一段话,让模型能够处理这段话的每个字或者每个词之间的关系,也就是让模型处理这段话之间的稠密向量连接。
当然,这种字词之间的稠密连接还需要有一定的放矢,并不是说每个字词之间直接稠密连接就能解决问题,有的字词之间的关系更加紧密,有的字词之间的关系没有那么重要。这个时候就需要根据实际任务情况对字词之间进行注意力的学习,比如前一个字和后一个字之间的注意力分配,前一个字和后两个字之间的注意力分配等。注意力越强就说明字词之间的关系更紧密,反之亦然。
这种在整个输入数据中做注意力的方法被称作为自注意力机制,和普通交叉注意力的区别就是普通交叉注意力的Q(Query)、K(Key)、V(Value)来由编码器和解码器共同的数据而产生,而自注意力的Q(Query)、K(Key)、V(Value)要么仅来自于编码器的输入,要么仅来自于解码器的输入。
可见,交叉注意力主要用于处理两个不同序列之间的关系,而自注意力主要用于处理单个序列内的元素之间的关系。在自注意力机制中,序列中的每个元素都可以与序列中的其他元素建立关联,包括与自身的关联。自注意力机制通过模型在输入序列中的不同位置之间建立动态的关联,能够使模型更好地捕捉序列中的重要信息。
Transformer是如何让模型获得更大的容量,装载更多的文本语义信息的呢?它的方法简单粗暴,那就是通过堆叠模型的层数来加大模型可学习的参数量,让更多的参数来承载文本中深层次的信息。如果要处理的文本内容太多,注意力的能力有限,还可以将注意力增加成多头的形式来加强文本向量之间的注意力关系。除此之外,Transformer模型中还应用了LayerNormalization和残差连接等设计方法来提高模型的整体表示能力。
随着大模型的发展,Transformer也在不断地攻城略地,从语言模型到视觉模型,再到语音模型、多模态应用,几乎在各个领域都能看到它的身影。究其原因就是因为Transformer具备良好的信息理解能力,这种理解能力离不开模型本身的架构设计、大规模的数据提供的信息、以及工业化大算力的支持。
l稠密矩阵注意力:Transformer模型通过FNN+Attention的方式进行残差堆叠和模块堆叠来增加模型的容量,这种带有自注意力的稠密矩阵设计方式为模型带来了巨量的参数,同时也为模型带来了更强大的理解能力。
l信息化红利机遇:信息化时代,人类产生数据的速度超乎想象。根据著名咨询机构国际公司(internationaldatacorporation,IDC)做出的估测,人类社会产生的数据一直都是以每年50%的速度增长,也就是说,大约每两年就增加一倍,这被称为大数据的摩尔定律。数据的增加为Transformer架构的发展提供了可学习的资料。
l新工业下的助力:新工业时代下的硬件设备的变化,在摩尔定律的支撑下,已经发展到了一定的量级,尤其是以GPU、DPU、NPU等为主的并行计算设备,由于社会生产的需求,其换代频率更高,近几年来,不管是挖矿淘币,还是搞深度学习都离不开强大算力的支持。
Transformer的发展在巨量参数模型、大规模可学习的数据、强大算力设备的支持下,几乎横扫了一切大模型领域。
二、Transformer的白璧微瑕
Transformer确实很好,想要更好的效果,可以说只管堆叠编解码模块来加大参数即可。Transformer几乎就是为大模型而生,但成也萧何败也萧何。在一些实际应用开发中,Transformer模型的大参数在带来更好的表现的同时,也带来了一些不得不面对的问题,那就是在训练和使用大模型的时候,随着参数的增加,需要付出更多的成本来维持。
1、更高的设备要求:
Transformer模型中巨量的参数首先带来的问题就是算力资源的消耗,一个大型Transformer模型的参数能达到成百上千亿。训练这样的模型需要大量的计算资源,包括高性能的GPU和大量的存储空间。这可能会限制一些没有足够计算资源的研究者或开发者。
大规模的参数对存储设备的要求也更高,模型中的每个参数都需要存储其值,因此参数越多,所需的存储空间就越大。例如,如果一个模型有1000亿个参数,每个参数是32位浮点数(即4字节),那么仅存储这些参数就需要400GB的空间。
Transformer模型的计算复杂度会随着输入序列长度(token数量)的增加呈二次方增长。在Transformer模型中,自注意力机制需要计算输入序列中所有token之间的关系。具体来说,对于每一个token,我们需要计算它与序列中其他所有token的注意力得分。因此,如果我们有n个token,那么我们需要进行n^2次计算。这就是为什么Transformer模型的计算复杂度随着输入序列长度(token数量)的增加呈二次方增长的原因。
在训练过程中,每个参数都需要进行前向传播和反向传播的计算。参数越多,所需的计算就越多。这不仅会增加训练时间,还会增加能源消耗。另外在训练过程中还需要在内存中存储参数的当前值、梯度以及其他优化器状态(如动量)。因此,参数越多,所需的内存就越大。在分布式训练中,还需要在不同的设备之间同步参数的更新。参数越多,所需的通信就越多,这会增加训练时间,并可能成为训练速度的瓶颈。
2、更多的数据资源:
我们都知道人工智能的三要素为算力、算法、数据,大模型也一样需具备这三个要素。大型人工智能算法模型在训练过程中,除了需要强大的算力设备作为支撑,还需要更大规模的数据作为学习资料,大量的数据获取渠道也很复杂,不仅需要更多的费用成本,还需要花费大量的人力对采集到的数进行清洗处理等,以此来达到网络模型输入的要求,提高模型最终的输出效果。
大模型对训练数据的数量和质量的要求主要是取决于最终的输出结果要求,如果参与训练的数据的数量达不到一定的要求,模型可能无法学习到数据的真实分布,导致模型的泛化能力可能会比较差,很难在实际场景中得到应用。即模型在训练数据上表现良好,但在未见过的测试数据上表现较差。而数据的质量更是直接影响着模型学习的内容是否正确。
在大模型的训练中,不仅要求数据量要大,数据的多样性也很重要。如果数据缺乏多样性,模型可能会偏向于某些特定的模式,而忽视了其他重要的信息。此外,数据的整体质量也非常重要。如果数据中包含大量的噪声或错误标签,那么模型可能会学习到错误的模式。
3、更长的训练时间:
以Transformer为基础的大模型通常比Transformer本身更复杂,有更多的层,更复杂的结构。这种复杂性增加了训练时间,因为需要更多的计算来进行前向和后向传播。
由于大模型的参数量巨大,这意味着在训练过程中需要优化的变量更多,训练这样的模型需要很长的时间。模型中的每个参数都需要在训练过程中进行更新,这就增加了计算的复杂性和时间。
大模型通常需要大量的数据来训练,以避免过拟合。处理这些大数据集需要更多的时间。即使在高性能的硬件上,由于内存和计算能力的限制,处理大量参数和复杂的模型结构也需要更长的时间。尽管大型模型在处理复杂任务时可能表现优异,但它们的训练成本(包括时间和计算资源)也相应地增加。
4、更大的电力消耗:
训练和运行大型模型需要高性能的硬件设备,如GPU或TPU。这些设备在运行时会消耗大量的电力。例如,一块NVIDIAA100GPU在满载运行时的功耗可以达到400瓦特。如果我们使用多块GPU来并行训练一个大型模型,那么电力消耗将会非常大。
以OpenAI的GPT-3模型的训练为例,GPT3有1750亿个参数,训练它需要大量的计算资源,据报道,训练GPT-3的电力消耗相当于一架飞机环绕地球500次的能量。这是因为在训练过程中,需要对大量的参数进行反复的更新和优化,这需要大量的计算能力,从而导致大量的电力消耗。
除此之外,大模型在应用阶段的电力消耗也是一个不容忽视的成本。例如,当我们使用一个大型的深度学习模型来处理复杂的任务(如图像识别或自然语言处理)时,模型需要在每个输入上进行大量的计算。这些计算需要大量的电力,尤其是当我们需要在实时或近实时的情况下处理大量的输入时。
5、参数阈值的牢笼:
大模型由于参数量大,往往存在大量的冗余参数,这些参数在训练过程中可能并没有学习到有效的信息,反而增加了模型的复杂性和训练的难度。大量的参数还会导致模型发生过拟合问题,参数过多的模型往往更容易出现过拟合现象,即模型在训练数据上表现良好,但在测试数据上表现较差。这是因为模型可能会过度学习训练数据中的噪声,而无法泛化到未见过的数据。
参数过多的另一个副作用就是模型无法学习到更高层级的有效特征:由于存在大量的冗余参数,模型可能无法有效地学习到更高层级的特征。这可能会限制模型的性能,尤其是在处理复杂任务时。大型模型的巨量参数还会导致模型的优化过程更为困难,梯度下降等优化算法在大型模型上可能会遇到局部最优、梯度消失或梯度爆炸等问题。
虽然使用一些正则化方法能够有效减缓模型的过拟合问题,但是想要从根源上解决这些问题,可能需要研究探索更有效的模型结构,以减少冗余参数,提高模型的学习效率。这是深度学习领域的一个重要研究方向。
6、特征坍塌的问题:
与参数阈值限制问题相比,模型的特征坍塌问题对模型的影响更大,大量研究表明,大模型的特征坍塌问题影响着这些精心设计的Transformer架构的表达能力。以LLaMA为例,在Transformer更深层中,特征的秩显著降低,导致所有token之间的相似性增加,这极大地降低了LLM的生成质量和多样性。
Transformer架构中的非线性特征对Transformer模型的能力有重大影响。增强非线性可以有效地缓解特征坍塌的问题,并提高Transformer模型的表达能力。从非线性的角度出发,应该构建更强大的LLM架构。
正因为Transformer存在的各种问题,研究者们正在寻找各种方法来减少Transformer模型的参数量,以降低计算资源的消耗,提高训练效率,并提高模型的泛化能力和解释性。例如,一些研究者正在探索知识蒸馏、模型剪枝、参数共享等技术来减少模型的参数量。这些方法都有一定的效果,但也有各自的挑战和限制。
三、后起之秀开始崭露头角
随着大模型规模化应用的发展,Transformer所存在的一些问题已经逐渐影响到了应用层面,也面临这不可不变的局面,其中一种方式就是继续按照老路子,增加知识理解、继续堆叠模型、提出更细致化的微调方法,以及我们在之前的文章《大模型的研究新方向:混合专家模型(MoE)》中提到的使用一些MoE的设计方法来增加模型的理解能力。
另一个研究方向就是对大模型的底层架构Transformer直接动手,有的是对Transformer架构进行外科手术改造,有的是基于以往的CNN、RNN提出新的架构,也有将多种基础模型结合常用的技巧融合而成的新架构,无论是对Transformer架构的手术性改造,还是直接踢翻Transformer的架构,基于RNN或CNN从头设计一种新的底层架构模型,其目的都是为了避免Transformer存在的问题,都是属于对底层架构的改动。下面是一些会对Transformer架构造成影响的一些新的基础架构模型。
1、RetNet:RetNet是微软研究院提出的自回归基础架构,灵感来自Transformer但采用全新的多尺度保留(MSR)机制替代多头注意力。实验证明,在scaling曲线和上下文学习方面,RetNet优异,推理成本与序列长度无关,解码速度是带键值缓存的Transformer的8.4倍,内存利用率提高70%。
在训练中,RetNet相比标准Transformer节省25-50%内存,实现了7倍加速,且在FlashAttention方面具有优势。推理延迟对批大小不敏感,实现了巨大吞吐量。RetNet由L个相同的保留层组成,每个层包含MSR模块和前馈神经网络(FFN)模块,使其在训练可并行、推理成本低和性能方面具有优势。
MSR模块通过计算元素关系并以衰减方式保留这些关系,引入位置相关的指数衰减项简化计算,同时以衰减形式保留前步信息。保持机制使用多尺度的衰减率,增强了模型表达能力。
RetNet设计为大型语言模型基础,主要优势在于同时实现训练并行、低成本推理和良好性能。它提出了"retention"机制替代"attention",支持并行、循环和分块循环计算范式。并行训练提高效率,循环推理实现低成本推断。
2、RWKV:RWKV模型是基于Transformer结构的模型,主要用于自然语言处理任务。其名称源自四个关键概念:Receptance(接受过去信息的向量)、Weight(位置权重衰减向量)、Key(类似传统自注意力中K的向量)、Value(类似传统自注意力中V的向量)。
模型由多个RWKV block组成,每个block包含Time-Mixing和Channel-Mixing两部分。Time-Mixing通过线性插值体现了recurrence特性,而Channel-Mixing在特征维度上做融合,实现了信息更新。
RWKV设计上结合了Transformer的可并行训练和RNN的高效推理。采用线性注意力机制,使训练期间可并行化计算,而在推理期间保持恒定计算和内存复杂度,成为首个非Transformer架构扩展到数十亿参数的模型。
该模型在训练时类似Transformer,但处理长上下文时计算开销较低。在推理期间,存储开销更小,能够隐式处理“无限”上下文长度。实验证明RWKV在解决Transformer的内存瓶颈和二次方扩展问题方面更为有效,性能与同规模Transformer相当,为进一步优化模型性能提供了潜在路径。这项工作在序列处理任务中平衡计算效率和模型性能方面迈出了重要一步。
3、Mamba:Mamba是一基于选择性状态空间模型的序列处理模型,源自S4架构的简单泛化。其名字体现了速度快、致命吸引力、核心机制SSSS等特征。选择性SSM层是Mamba的关键创新,能有选择地关注或忽略输入,解决了先前模型的难题,如无限期推断。
Mamba与Transformer相比,参数增长线性,可实现线性扩展,性能在百万token长度序列中提高5倍推理吞吐量。相较于Transformer,Mamba的状态空间稳定,推理和训练时间恒定线性,解决了Transformer的二次方扩展和存储问题。
Mamba通过让SSM参数成为输入函数,提高了模型的稳定性,快速推理(5倍于Transformer)和序列长度线性缩放。在语言建模任务中,Mamba-3B模型优于同规模Transformer,同时在音频、DNA序列建模等领域也达到了先进性能。这为序列处理任务中的计算效率和模型性能平衡迈出了重要一步。
4、UniRepLKNet:UniRepLKNet是腾讯和香港中文大学联合发布的基于大核卷积神经网络(CNN)的大模型基础架构,适用于多模态数据处理。其四项设计原则涉及感受野、特征抽象、深度表示,采用硬件感知的并行算法,在时序预测任务中表现出色。
大核卷积的独特优势在于无需深度堆叠即可获得大感受野,避免深度增加导致的递减问题。?UniRepLKNet通过深刻理解感受野与层数关系,设计了大核CNN架构,提高了感受野,更全面地捕捉空间信息。有效感受野的概念成为UniRepLKNet设计的基石,与卷积核大小和层数平方根成正比。
UniRepLKNet深入研究特征抽象层次,关注空间范围和高低抽象层次的平衡。架构设计不仅提高感受野,还逐层提取空间模式实现高层次特征抽象,更好地理解和表达视觉信息。对深度模型的一般表示能力也是UniRepLKNet成功的关键因素,通过增加可训练参数和引入非线性激活函数,提高表征能力。
设计上的灵活性是UniRepLKNet的优势,巧妙地将大卷积核融入设计,解耦了感受野、特征抽象和模型深度。遵循原则,选择合适的kernel size和结构,UniRepLKNet在保持效率的同时提高性能,成为强大而高效的大核CNN架构。
5、StripedHyena:ogetherAI发布的StripedHyena是一种新型人工智能模型,采用独特混合结构将门控卷积和注意力结合成Hyena运算符。其设计优化了计算效率,提高了处理效率、速度和内存效率。在OpenLLM排行榜任务等短序列任务中,StripedHyena超越了Llama-27B、Yi7B和Transformer替代品,尤其在处理长提示的基准测试中表现出色。
StripedHyena克服了Transformer核心构建块注意算子的二次代价问题,提出了Hyena,一个亚二次型注意力替代方法。在回忆和推理任务中,Hyena在序列长度上准确性提高了50多个点,超越了基于注意力的模型。在语言建模任务上,当序列长度为2K时,训练计算减少了20%,性能达到了Transformer的水平。而在序列长度为8K和64K时,Hyena分别是高度优化注意力的两倍和100倍的速度。
这一研究的关键创新点在于提出Hyena作为亚二次型注意力替代方法,通过交错隐式参数化构建,克服了传统方法的差距。StripedHyena在各方面表现出色,成为处理长序列、提高计算效率的重要模型。
6、PanGu-Π:盘古?π 是一种全新的LLM架构,旨在解决模型特征坍塌问题。通过在FFN和MSA模块中引入更多非线性,作者成功增强了整体网络的非线性,而不显著增加复杂性。在FFN中,采用基于级数的激活函数,它包含多个可学习的仿射变换,既有效增强非线性,又计算量较小。同时,对每个MSA模块的主分支和增强型短路进行并行处理,以防止特征秩的坍塌。作者还优化了增强型短路操作,保持了模型的高效性。
基于这两个新模块,盘古?π 架构在相同参数规模下实现了显著的效率提升。有两个版本的盘古 π 大模型,分别是盘古 π-7B 和盘古 π-1B。通过在大规模语料库上进行训练,这些模型展现出在各种NLP任务上的通用语言能力。实验证明,在相似规模下,盘古 π 模型在准确性和效率方面都胜过以前的大模型。
盘古?π-7B 在金融和法律领域得到应用,构建了专门的LLM,即云山大模型,在实际商业应用中取得成功。在金融和法律基准测试中,云山大模型超越了其他相似规模的先进大模型。为了增强传统Transformer架构的非线性能力,盘古 π 提出了对注意力模块和FFN模块的两项改进,进一步为Transformer引入更多非线性。
四、替代之路曲折光明
目前大模型的开发都是以Transformer为基座,而且已经有很多应用已经上市,想要替换不是一朝一夕的事情,硬件行业喊了多少年的国产化替代,到目前也没有特别明显的进展,就算是在推进最快的政府和高校之中,也只是在逐步过度而已,这不仅仅是费用的问题,还包括了一系列的环境依赖问题,比如软硬件之间的兼容、技术人员的开发知识、使用者的个人习惯等。
在当前情况下,除非是这些新的基础架构模型中有比Transformer优秀太多的模型胜出,否则,只凭借微弱的优势很难快速取代Transformer在业内的地位。就目前来说,Transformer可以通过不断地扩充参数,似乎依然可以在行业中稳住阵脚,目前的Transformer已经可以很容易扩展到万亿级别的参数,比如2021年Google就发布了拥有1.6万亿参数的Switch Transformer模型。
退一步来说,就是这些新的架构模型确实在工业界已经被证明了非常优秀,替代仍然是一个漫长的过程,因为这个替代过程不仅从学术界进行替代,更重要的是要从工业界完全替代。这需要一个长期的过程,表面上看替代的是一个基础模型框架,实际上替代的是整个开发生态。
实际上业内依然还有公司在使用TensorFlow1.x版本进行AI项目的维护和开发。众所周知,TensorFlow1.x在TensorFlow2.0发布之后就停止了更新,而TensorFlow2.x版本与TensorFlow1.x版本是完全不同的两个版本,没有任何兼容性之说,变化之大可以用两个不同的框架来形容它们。最主要的是TensorFlow1.x的问题很多,当然TensorFlow2.x也不怎么行,谷歌深度学习框架这块被Meta(原Facebook)的pytorch越甩越远了。
自从谷歌停止对TensorFlow1.x的更新后,以前使用TensorFlow1.x开发的项目在维护过程中的成本就变高了,业内很多新的算法模型都需要开发者自己去写,甚至一些适配算子也需要自己去写,即便如此,很多公司依然在使用TensorFlow1.x来维护和开发项目,这其中缘由主要就是因为项目的开发是需要一个完整的周期进行的,前期所有的开发框架都是TensorFlow1.x版本进行的,如果要更换到TensorFlow2.x版本,或者更换到pytorch框架上,都需要对所有之前的项目重写一遍。
当然问题可不止这些,除了使用新的架构重写代码,所有的软硬件配套依赖,以及上下游合作伙伴的支持方式可能都会发生变化,比如该公司计划更换开发框架,首先需要和甲方沟通获得批准同意,然后需要整个产品链上的各家开发者可能都要更换开发框架。这些才是最麻烦的,不仅要花费一笔不小的资金,还要花费大量的时间去翻新更换,不是每个公司都有做这个决策的勇气的。一般来说就是等整个项目的开发完毕之后,新项目可以选择使用新的框架来开发的。而旧项目的维护和运营还是要使用旧的框架进行,直到服务周期结束。
当然,对于新旧框架的替代过程虽然艰难,但是并不代表就不能替代。无论是任何项目的开发对于开发者而言都是需要盈利的,那么就需要对整个项目的开发成本估算,如果维护旧框架下的项目开发成本确实很高,那么对整个项目的代码使用新架构模型进行重写也不失为一种从根源上解决问题的方法,毕竟长痛不如短痛。
另外从项目的开发周期上来说,项目开发的周期越短,越有利于更换新的开发架构,而对于早期使用旧架构开发的项目,可以从未来的维护和开发周期以及成本方面全面估算是否要替代新的架构。当然对于新的项目和新的企业来说,这些都不是问题。
整体对于Transformer的挑战者而言,取代之路是不可避免的,几乎可以确定,在未来Transformer架构一定会被取代,因为Transformer的缺点几乎和其优点一样强大,但是至于被取代的时间到底还有多久,取代它的模型是哪一个?或者是多个模型平分秋色,目前还没有很明确的证据能够证明这些,不过相信随着学界不断的研究和业界的应用,这些问题逐渐会显现出明确的答案。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!