ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

读BERT论文记录

2021-02-27 23:03:06  阅读:226  来源: 互联网

标签:BERT 微调 训练 记录 模型 论文 任务 句子


最近阅读了提出BERT的论文,做一个简要的阅读记录,供大家和自己阅读。

题目:

BERT:Pre-training of Deep Bidirectional Transformers for Language Understanding
通过深层双向Transformer来提高语言理解能力

摘要

我们引入了一种新的语言表示模型叫做BERT,BERT代表了:Bidirectional Encoder Representations from Transformers。与最近的语言表示模型不同的是,BERT旨在通过所有层上的左边和右边的上下文联合条件处理,从未标记的文本中训练深层双向的表示。

结果显示,预训练的BERT模型可以通过只微调一个输出层就可以在很多任务上得到最先进的模型而不需要很重要的特定任务的模型,如问答和语言推断任务。

BERT在概念上简单,在实战上很强大。他实现了新的最先进的结果在11个自然语言处理任务中。包括将GLUE的结果提高到80.5%(7.7%点的绝对提升),MultiNLI 准确率到86.7%(4.6%点的绝对提升),SQuAD v1.1 问答测试的F1到93.2(1.5的绝对提升),SQuAD v2.0测试的F1到83.1(5.1的绝对提升)

1.引言

已经证明语言模型预训练对于改善许多自然语言处理任务是有效的。这些包括句子级任务,例如自然语言推论和释义,旨在通过整体分析来预测句子之间的关系,以及token级别的任务(例如命名实体识别和问题回答),需要模型在token级别产生细粒度的输出。

现有两种将预训练的语言表示应用于下游任务的策略:基于特征和微调。基于特征的方法如ELMo,使用具体任务固定的结构,讲预训练的表示做为一个额外的特征。微调方法,如Generative Pre-trained Transformer (OpenAI GPT),引入了很少数量的具体任务的参数,通过微调所有的预训练参数在下游任务上训练。这两种方法在预训练过程中的目标是一致的:使用单向的语言模型得到一般的语言表示。

我们认为现有的方法限制了语训练表示的能力,尤其是对于微调方法来说。主要的限制是标准的语言模型是单向的,这就限制了可以在预训练过程中使用的结构的选择。如,在OpenAI GPT中,作者使用了一个从左到右的结构,每一个token在Transformer中只能看到之前的tokens。这样的限制对于句子级任务而言不是最理想的,并且在将基于微调的方法应用于token级任务(例如问题回答)时非常有害,在这种情况下,必须从两个方向合并上下文。

在本文中,我们通过提出BERT改进了基于微调的方法:Bidirectional Encoder Representations from Transformers.
BERT通过使用Cloze任务的启发而使用“屏蔽语言模型”(MLM)预训练目标,从而减轻了前面提到的单向性约束。
屏蔽语言模型从输入中随机屏蔽了某些标记,目的是仅根据其上下文来预测屏蔽词的原始词汇ID。与从左到右的语言模型预训练不同,MLM目标使表示形式能够融合左右上下文,这使我们能够预训练深层双向Transformer。除了屏蔽语言模型外,我们还使用“下一个句子预测”任务来联合预训练文本对表示。本文的贡献如下:

我们证明了双向预训练对语言表示的重要性。 与Radford等人不同,他们使用单向语言模型进行预训练,而BERT使用屏蔽语言模型来启用预训练的深度双向表示。这也与Peters等人形成对比,Peters等人使用了经过独立训练的从左到右和从右到左的LM的简单连接。

我们表明,经过预训练的表示形式减少了许多精心设计的任务特定体系结构的需求。BERT是第一个基于微调的表示模型,可在一系列句子级和token级任务上实现最先进的性能,优于许多特定于任务的体系结构。

BERT推动了11个NLP任务的发展。代码和预训练模型可以在https://github.com/google-research/bert.得到。

2.相关工作

预先训练通用语言表示形式已有很长的历史,我们将简要回顾这部分中使用最广泛的方法。

2.1 无监督的基于特征的方法

数十年来,学习广泛适用的单词表示法一直是研究的活跃领域,包括非神经方法和神经方法。预训练的单词嵌入是现代NLP系统不可或缺的一部分,与从头开始学习的嵌入相比有很大的改进 。为了预训练单词嵌入向量,使用了从左到右的语言建模目标,以及在左右上下文中区分正确单词和错误单词的目标。这些方法已推广到更粗粒度,例如句子嵌入或段落嵌入。为了训练句子的表示形式,以前的工作使用目标对候选的接下来的句子进行排名,给定前一句子的表示形式从左到右生成下一句的单词或对自动编码器得出的目标进行消噪。

ELMo及其前身将传统的词嵌入研究沿不同的维度进行了扩展。他们从左到右和从右到左的语言模型中提取上下文敏感的特征。每一个词的带有语境的表示是从左到右和从右到左的语言模型的链接。当将上下文单词嵌入与现有的特定于任务的体系结构集成时,ELMo改进了几种主要的NLP最新基准,包括问题回答,情感分析和命名实体识别。 Melamud等提出通过LSTM同时从左边和右边的上下文预测某个词的任务来学习带有上下文的表示。和ELMo相似,他们的模型是基于特征的并且不是深层双向的。Fedus等人表明,完形填空任务可以用来提高文本生成模型的鲁棒性。

2.2 无监督的微调方法

与基于特征的方法一样,这个方向的第一个工作就是从未标记的文本中预训练词嵌入的参数。

最近,产生上下文标记表示的句子或文档编码器已经从未标记的文本中进行了预训练,并针对有监督的下游任务进行了微调。这种方法的好处是只有很少的参数需要被从头学习。至少部分由于此优势,OpenAI GPT在GLUE基准测试中的许多句子级任务上获得了之前的最新结果。从左到右的语言建模和自动编码器已用于预训练此类模型。

2.3 从监督数据中转移学习

也有工作显示了从大型数据集的监督任务的有效转移,例如自然语言推理和机器翻译。计算机视觉研究还证明了从大型预训练模型进行迁移学习的重要性,其中有效的方法是微调使用ImageNet预训练的模型。

3.BERT

在本节中,我们将介绍BERT及其详细实现。 我们的框架有两个步骤:预训练和微调。 在预训练期间,通过不同的预训练任务对未标记的数据进行模型训练。为了进行微调,首先使用预训练参数初始化BERT模型,然后使用来自下游任务的标记数据对所有参数进行微调。每个下游任务都有单独的微调模型,即使它们使用相同的预训练参数进行了初始化。图1中的问答示例将作为本节的运行示例。

图片来自于论文
图1:BERT的总体预训练和微调程序。除了最后一层,在预训练和微调过程中使用的是相同的结构。形同的预训练参数被用于初始化不同的下游任务。在微调期间,所有的参数都进行微调。[CLS]是一个特殊的符号,添加在每一个输入之前。[SEP]是一个特殊的分割符(例如:分割问题和答案)

BERT的一个独特特征是其跨不同任务的统一体系结构。预训练的体系结构和最终的下游体系结构之间的差异很小。

模型结构 BERT的模型架构是多层双向Transformer编码器,基于Vaswani等人描述的原始方法实现,并在tensor2tensor库中发布。由于使用Transformers已变得很普遍,并且我们的实现几乎与原始实现相同,因此我们将省略对模型体系结构的详尽背景说明,并向读者推荐原论文及出色的指南来了解Transformer,例如“The Annotated Transformer”。

在这项工作中,我们将层(即Transformer块)的数量表示为L,将隐藏层大小表示为H,并将自注意头的数量表示为A。我们主要报告两种模型大小的结果:BERTbase(L = 12,H = 768,A = 12,总参数= 110M)和BERTlarge(L = 24,H = 1024,A = 16,总参数= 340M)。

为了进行比较,选择BERTbase具有与OpenAI GPT相同的模型大小。但是,至关重要的是,BERT Transformer使用双向自我关注,而GPT Transformer使用受限的自我关注,其中每个token只能关注其左侧的上下文。

输入输出表示 为了使BERT处理各种下游任务,我们的输入能够明确地表示在一个token序列中的单个句子和一对句子(例如h<Question,Answer >)。在整个工作中,“句子”可以是任意连续文本,而不是实际的语言句子。“序列”是指BERT的输入令牌序列,它可以是一个句子或两个句子包装在一起。

我们将WordPiece嵌入与30,000个token词汇表结合使用。每个序列的第一个标记始终是特殊分类标记([CLS])。与此令牌相对应的最终隐藏状态用作分类任务的合计序列表示形式。句子对打包在一起形成单个序列。我们通过两种方式区分句子。 首先,我们使用特殊令牌([SEP])将它们分开。 其次,我们向每个标记添加学习的嵌入,以指示它是属于句子A还是句子B。如图1所示,我们将输入嵌入表示为E,将特殊[CLS]令牌的最终隐藏向量表示为C∈RH,将第i个输入token的最终隐藏向量表示为Ti∈RH。

对于给定的token,其输入表示是通过将相应的token,段和位置嵌入求和而构造的。 这种结构的可视化效果如图2所示。

在这里插入图片描述
图2

3.1 预训练BERT

与Peters等和Radford等不同。我们不使用传统的从左到右或从右到左的语言模型来预训练BERT。相反,我们使用本节中描述的两个无监督任务对BERT进行预训练。 此步骤显示在图1的左侧。

TASK #1:Masked LM 从直觉上讲,有理由相信,深层双向模型比从左至右模型或左至右模型和右至左模型的浅层连接严格上说更强大。不幸的是,标准的条件语言模型只能从左到右或从右到左进行训练,因为双向条件将允许每个单词间接“看到自己”,并且该模型可以在多层结构中轻松预测目标单词的语境。

为了训练深度双向表示,我们简单地随机屏蔽一定百分比的输入,然后预测这些屏蔽的token。 我们将此步骤称为“Masked LM”(MLM),尽管在文献中通常将其称为Cloze任务。在这种情况下,如在标准LM中一样,将词汇表上与被屏蔽的token相对应的最终隐藏向量送到的输出softmax中。 在所有实验中,我们随机屏蔽每个序列中所有WordPiece tokens的15%。 与去噪音频编码器相比,我们仅预测被屏蔽的单词,而不重构整个输入。

尽管这可以使我们获得双向的预训练模型,但缺点是我们在预训练和微调之间造成了不匹配,因为[MASK]令牌在微调过程中不会出现。为了减轻这种情况,我们并不总是用实际的[MASK] token替换“被屏蔽”的单词。训练数据生成器随机选择token位置的15%进行预测。如果选择了第i个token,我们将替换第i个token,其中(1)80%的可能性是[MASK];(2)10%的可能性是随机token;(3)10%的可能是未更改的第i个token。 然后,Ti将用于预测具有交叉熵损失的原始token。 我们在附录C.2中比较了此过程的变体。

**Task #2::Next Sentence Prediction (NSP)
**
许多重要的下游任务,例如问答(QA)和自然语言推论(NLI),都是基于对两个句子之间关系的理解,而这不是语言模型直接捕获的。 为了训练能够理解句子关系的模型,我们预训练了可以从任何单语语料库生成的二值化的下一个句子预测任务。具体而言,当为每个预训练选择示例句子A和B时,B的50%时间是跟随在A之后的实际下一个句子(标记为IsNext),而50%是来自语料库的随机句子(标记为NotNext)。如图1所示,C用于下一句预测(NSP)。 尽管它很简单,但我们在5.1节中证明了完成此任务的预培训对QA和NLI都非常有益。

NSP任务与Jernite等人以及Logeswaran和Lee使用的表示学习目标密切相关。 但是,在先前的工作中,只有句子嵌入被传输到下游任务,而BERT传输所有参数以初始化最终任务模型参数。

预训练数据 预训练过程很大程度上遵循了有关语言模型预训练的现有文献。 对于预训练语料库,我们使用BooksCorpus(800M个单词)和English Wikipedia(2500万个单词)。 对于Wikipedia,我们仅提取文本段落,而忽略列表,表格和标题。 为了提取长的连续序列,使用文档级语料库而不是诸如“十亿字基准”之类的经过改组的句子级语料库是至关重要的。

3.2 微调BERT

微调很简单,因为Transformer中的自我关注机制允许BERT通过交换适当的输入和输出来建模许多下游任务(无论它们涉及单个文本还是文本对)。对于涉及文本对的应用程序,常见的模式是在应用双向交叉注意之前对文本对进行独立编码,例如Parikh等。BERT而是使用自我注意机制来统一这两个阶段,因为使用自我注意对连接的文本对进行编码实际上包括了两个句子之间的双向交叉注意。对于每个任务,我们只需将特定于任务的输入和输出插入BERT,并端到端微调所有参数。 在输入时,来自预训练的句子A和句子B类似于(1)释义中的句子对,(2)附带假设和前提对,(3)问题回答中的疑问和回答,以及(4)在文本分类或序列标记中退化text-∅对。在输出中,token表示被馈送到token层级任务(例如序列标记或问题回答)的输出层,[CLS]表示被馈送到输出层以进行分类(例如需求或情感分析) 。

与预训练相比,微调相对来说不那么费力。 从完全相同的预训练模型开始,复制论文中的所有结果在单个Cloud TPU最多需要1个小时,或者在GPU上需要几个小时。 我们将在第4节的相应小节中描述特定于任务的详细信息,更多详细信息可以在附录A.5中找到。

4.实验

在本节中,我们展示了BERT在11个NLP任务上的微调结果。

4.1 GLUE

通用语言理解评估(GLUE)基准是各种自然语言理解任务的集合。 GLUE数据集的详细说明包含在附录B.1中。

为了对GLUE进行微调,我们按照第3节中的描述表示输入序列(针对单个句子或句子对),并使用与第一个输入标记([CLS])相对应的最终隐藏向量C∈RH作为合计表示 。唯一的在微调阶段引入的新参数是分类层的权重W∈Rk*H,k是标签的数量。我们使用C和W计算一个标准的分类损失,也就是log(softmax(CW).

对于所有GLUE任务,我们使用32的批处理大小并进行了3轮的学习。 对于每个任务,我们在开发集上选择了最佳的微调学习率(在5e-5、4e-5、3e-5和2e-5中)。
此外,对于BERTlarge,我们发现微调有时在小型数据集上不稳定,因此我们进行了几次随机重启,并在开发集上选择了最佳模型。对于随机重启,我们使用相同的预训练检查点,但执行不同的微调数据打乱和分类层初始化。

结果列于表1。BERTbase和BERTlarge与现有技术相比,在所有任务上的性能均优于所有系统,平均精度分别提高了4.5%和7.0%。请注意,除了attention masking之外,BERTbase和OpenAI GPT在模型架构方面几乎相同。对于最大且报告最广的GLUE任务MNLI,BERT获得4.6%的绝对准确度改进。 在官方GLUE排行榜上,BERTlarge的得分为80.5,而OpenAI GPT的得分为72.8。

我们发现,在所有任务中,BERTlarge的性能都大大优于BERTbase,尤其是那些训练数据很少的任务。 模型大小的影响将在5.2节中更全面地探讨。

在这里插入图片描述
表1:GLUE测试结果。每个任务下方的数字表示培训示例的数量。 “平均”列与官方GLUE得分略有不同,因为我们排除了有问题的WNLI集。BERT和OpenAI GPT是单模型,单任务。 报告QQP和MRPC的F1得分,报告STS-B的Spearman相关性,报告其他任务的准确性得分。 我们排除使用BERT作为其组件之一的条目。

4.2 SQuAD v1.1

斯坦福问题解答数据集(SQuAD v1.1)是10万个众包问题/答案对的集合。 给定一个问题以及Wikipedia中包含答案的段落,任务是预测段落中答案的文本范围。如图1所示,在问题解答任务中,我们将输入的问题和段落表示为单个的打包序列,其中问题使用A嵌入,而段落使用B嵌入。在微调期间,我们仅引入起始向量S∈RH和终止向量E∈RH。 单词i作为答案范围的开始的概率计算为Ti和S之间的点积,之后是softmax层:
在这里插入图片描述
相似的公式也在答案的结尾运用。从位置i到位置j的候选跨度的得分定义为S·Ti + E·Tj,并且将j≥i的最大得分跨度用作预测。训练目标是正确的起点和终点位置的对数似然率的总和。 我们以3e-5的学习率和32批量大小微调了3轮。

表2显示了排行榜中排名靠前的条目以及排名靠前的发布系统的结果。SQuAD排行榜的最高结果没有可用的最新公共系统描述,并且可以在训练他们的系统时使用任何公共数据。 因此,我们首先在TriviaQA上进行微调,然后再在SQuAD上进行微调,从而在系统中使用适度的数据增强。

我们的系统在整体表现上领先最佳系统性能+1.5 F1,而在单个系统方面则优于+1.3 F1。 实际上,就F1分数而言,我们的单个BERT模型优于最好的集成系统。如果没有TriviaQA的微调数据,我们只会损失0.1-0.4 F1,仍然远远领先于所有现有系统。

在这里插入图片描述
Table 2

4.3 SQuAD v2.0

SQuAD 2.0任务通过在提供的段落中不存在简短答案的可能性扩展了SQuAD 1.1问题定义,从而使问题更加实际。我们使用一种简单的方法来扩展SQuAD v1.1 BERT模型以完成此任务。 我们将没有答案的问题视为答案范围以[CLS]token开头和结尾。 答案起始和终止的跨度位置的概率空间扩展为包括[CLS]令牌的位置。为了进行预测,我们将无应答跨度的分数进行比较:snull = S·C + E·C与最佳非零跨度的分数:
在这里插入图片描述
当s ˆ i,j> snull +τ时,我们预测了一个非空答案,在开发集上选择了阈值τ以最大化F1。我们没有在该模型中使用TriviaQA数据。 我们对进行了2轮微调,学习率为5e-5,批量大小为48。

表3中显示了与之前的排行榜条目和排名靠前的作品进行比较的结果,其中不包括使用BERT作为其组件之一的系统。 与先前的最佳系统相比,我们观察到+5.1 F1的改进。

在这里插入图片描述

4.4 SWAG

The Situations With Adversarial Generations
(SWAG)数据集包含113k句子对完成示例,这些示例评估了基于常识的推理。给定一个句子,任务是在四个选择中选择最合理的延续。在SWAG数据集上进行微调时,我们构造了四个输入序列,每个输入序列都包含给定句子(句子A)和可能的延续词(句子B)的串联。 引入的唯一特定于任务的参数是一个向量,其向量量与[CLS]token的表示C的点积表示每个选择的得分,并使用softmax层对其进行归一化。

我们对模型进行了3轮的微调,学习率为2e-5,批处理大小为16。结果显示在表4中 。BERTlarge优于作者的ESIM + ELMo系统27.1%,OpenAI GPT优于8.3 %。

在这里插入图片描述
表四

5 Ablation Studies

在本节中,我们将对BERT的多个方面进行消融实验,以更好地了解它们的相对重要性。其他消融研究可在附录C中找到。

5.1 预训练任务的作用

我们通过使用与BERTbase完全相同的预训练数据,微调方案和超参数来评估两个预训练目标,从而证明BERT的深度双向表示的重要性:

No NSP: 使用了“Masked LM”(MLM)但没有使用“next sentence prediction” (NSP)任务训练的模型。

LTR & No NSP: 使用标准的从左到右(LTR)LM(而不是MLM)训练的仅左上下文模型。 左约束也应用于微调,因为删除它会引入预训练/微调不匹配,从而降低下游性能。此外,该模型在没有NSP任务的情况下进行了预训练。 这可以与OpenAI GPT相提并论,但要使用我们的更大的训练数据集,输入表示形式和微调方案。

我们首先研究NSP任务带来的影响。 在表5中,我们表明删除NSP会对QNLI,MNLI和SQuAD 1.1的性能产生重大影响。 接下来,我们通过比较“无NSP”与“ LTR和无NSP”来评估训练双向表示的影响。 在所有任务上,LTR模型的性能都比MLM模型差,而MRPC和SQuAD的性能下降很大。

对于SQuAD,直观上很清楚,因为令牌级别的隐藏状态没有右侧上下文,所以LTR模型在令牌预测时的性能会很差。 为了真诚地尝试加强LTR系统,我们在顶部添加了一个随机初始化的BiLSTM。这确实可以显着改善SQuAD上的结果,但结果仍然比预训练的双向模型的结果差很多。BiLSTM损害了GLUE任务的性能。

我们认识到,像ELMo一样,也有可能训练单独的LTR和RTL模型并将每个令牌表示为两个模型的串联。 但是:(a)这是单个双向模型的两倍花费; (b)对于QA这样的任务,这是不直观的,因为RTL模型中不会出现问题的答案; (c)这绝对不像深度双向模型那么强大,因为它可以在每一层使用左右上下文。

在这里插入图片描述

5.2 模型大小的影响

在本节中,我们探索模型大小对微调任务准确性的影响。 我们训练了许多具有不同层数,隐藏单元和注意头的BERT模型,而其他方面则使用了与上述相同的超参数和训练过程。

表6中显示了选定的GLUE任务的结果。在此表中,我们报告了5次随机微调重新启动后的平均开发集的准确性。
我们可以看到较大的模型也会导致所有四个数据集的准确性提高,即使对于只有3,600个带标签的训练示例的MRPC,它与所有预训练任务也大不相同。

在这里插入图片描述

我们有能力在相对于现有文献而言已经相当大的模型的基础上实现如此显着的改进,这也许也令人感到惊讶。例如,在Vaswani等人中探索的最大的变压器是(L = 6,H = 1024,A = 16),编码器的参数为100M,而我们在文献中发现的最大的变压器是(L = 64,H = 512,A = 2),参数为235M。相比之下,BERTbase包含110M参数,而BERTlarge包含340M参数。

众所周知,增加模型大小将导致对机器翻译和语言建模等大规模任务的持续改进,这已得到表6LM困惑度所提供的训练数据所示证明。但是,我们相信这是第一个有说服力的证明,证明只要模型已经有过充分的预训练,将模型缩放到极端的模型大小也可以在非常小的规模的任务上带来很大的改进。

Peters等人对将预训练的Bi-LM大小从两层增加到四层对下游任务的影响提出了不同的结果,Melamud等人提到将隐藏维度的大小从200增加到600有帮助,但进一步增加到了1000却没有带来进一步的改善。这两个先前的工作都使用基于特征的方法-我们假设当直接在下游任务上微调模型并且仅使用很少数量的随机初始化的附加参数时,特定于任务的模型可以从更大,更多的模型中受益。 即使下游任务数据非常小,也可以进行富有表现力的预训练表示形式。

5.3 带有BERT的基于特征的方法

到目前为止,所有提出的BERT结果都使用了微调方法,在预训练模型中添加了一个简单的分类层,并且在下游任务上共同对所有参数进行了微调。但是,从预训练模型中提取固定特征的基于特征的方法具有某些优势。首先,并非所有任务都可以由Transformer编码器体系结构轻松表示,因此需要添加特定于任务的模型体系结构。第二,预先训练出需要昂贵花费的数据表示形式,然后在该表示形式之上进行更便宜的模型运行许多实验,这具有很大的计算优势。

在本节中,我们通过将BERT应用于CoNLL-2003命名实体识别(NER)任务来比较这两种方法。在BERT的输入中,我们使用了一个区分大小写的WordPiece模型,并且包括了数据提供的最大文档上下文。按照标准惯例,我们将其公式化为标记任务,但在输出中不使用CRF层。我们使用第一个子token的表示形式作为NER标签集上token级别分类器的输入。

为了消除微调方法,我们通过从一个或多个层使用激活函数来应用基于特征的方法,而无需微调BERT的任何参数。 这些上下文嵌入的词向量用作分类层之前随机初始化的两层768维BiLSTM的输入。

结果列于表7。BERTlarge与最先进的方法具有竞争力。 最佳性能的方法是将来自预训练的Transformer的前四个隐藏层的token表示连接起来,这仅比微调整个模型低0.3 F1。 这表明BERT对于微调和基于特征的方法都是有效的。

6 结论

最近使用语言模型进行迁移学习的经验改进已证明,丰富的,无监督的预培训是许多语言理解系统不可或缺的一部分。 尤其是,这些结果使即使是资源匮乏的任务也可以从深度的单向体系结构中受益。 我们的主要贡献是将这些发现进一步推广到深层次的双向体系结构,从而使相同的经过预训练的模型能够成功解决各种各样的NLP任务。

标签:BERT,微调,训练,记录,模型,论文,任务,句子
来源: https://blog.csdn.net/qq_40729302/article/details/114024838

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有