ITPub博客

首页 > 人工智能 > 自然语言 > 周明:预训练模型在多语言、多模态任务的进展

周明:预训练模型在多语言、多模态任务的进展

自然语言 作者:AIBigbull2050 时间:2020-09-18 13:22:27 0 删除 编辑
2020-09-12 15:34:16

周明:预训练模型在多语言、多模态任务的进展

作者 | 周明

编辑 | 陈彩娴

8月29日至30日,由中国科学技术协会、中国科学院、南京市人民政府为指导单位,中国人工智能学会、南京市建邺区人民政府、江苏省科学技术协会主办的主题为“智周万物”的2020年中国人工智能大会(CCAI 2020)在江苏南京新加坡·南京生态科技岛举办。在大会上,微软亚洲研究院副院长、国际计算语言学会(ACL)前任主席周明做了主题为《预训练模型在多语言、多模态任务的进展》的特邀报告。



以下是周明老师的演讲实录:



1 预训练模型助力NLP

自然语言处理(NLP),目的是使得计算机具备人类的听、说、读、写、译、问、答、搜索、摘要、对话和聊天等能力,并可利用知识和常识进行推理和决策,并支持客服、诊断、法律、教学等场景。自然语言理解,被认为是AI皇#冠上的明珠。一旦有突破,则会大幅度推动AI在很多重要场景落地。

过去这五年,对自然语言是一个难忘的五年,它的一个标志就是神经网络全面引入到了自然语言理解。从大规模的语言数据到强有力的算力,加上深度学习,把整个自然语言带到一个新的阶段。

今天我要讲的预训练模型,它使自然语言处理由原来的手工调参、依靠ML专家的阶段,进入到可以大规模、可复制的大工业施展的阶段,令我们这个领域的人感到非常振奋。而且预训练模型从单语言、扩展到多语言、多模态任务。一路锐气正盛,所向披靡。

那么,预训练模型到底是什么,它是怎么应用在很多产品里,未来又有哪些发展机会和挑战呢。下面试图由浅入深地给大家介绍一下。



2 预训练模型

下面简要介绍预训练模型的基础技术,包括Transformer、自监督学习、微调。然后详细介绍预训练模型在语言、图像、文档和视频等任务中的进展,

预训练通过自监督学习从大规模数据中获得与具体任务无关的预训练模型。体现某一个词在一个特定上下文中的语义表征。第二个步骤是微调,针对具体的任务修正网络。训练数据可以是文本、文本-图像对、文本-视频对。预训练模型的训练方法可使用自监督学习技术(如自回归的语言模型和自编码技术)。可训练单语言、多语言和多模态的模型。此类模型可经过微调之后,用于支持分类、序列标记、结构预测和序列生成等各项技术,并构建文摘、机器翻译、图片检索、视频注释等应用。


为什么我们要做预训练模型?原因如下:

首先,预训练模型是一种迁移学习的应用,利用几乎无限的文本,学习输入句子的每一个成员的上下文相关的表示,它隐式地学习到了通用的语法语义知识。

第二,它可以将从开放领域学到的知识迁移到下游任务,以改善低资源任务,对低资源语言处理也非常有利。

第三,预训练模型在几乎所有 NLP 任务中都取得了目前最佳的成果。

最后,这个预训练模型+微调机制具备很好的可扩展性,在支持一个新任务时,只需要利用该任务的标注数据进行微调即可,一般工程师就可以实现。

下面介绍预训练模型的三个关键技术。


周明:预训练模型在多语言、多模态任务的进展


1、Transformer

它在NLP各个任务中都取得了优异的性能,它是预训练语言模型的核心网络。给定一句话或是一个段落作为输入,首先将输入序列中各个词转换为其对应的词向量,同时加上每一个词的位置向量,体现词在序列的位置。然后将这些词向量输入到多层Transformer网络中,通过自注意力(self-attention)机制来学习词与词之间的关系,编码其上下文信息;再通过一个前馈网络经过非线性变化,输出综合了上下文特征的各个词的向量表示。

每一层Transformer网络主要由Multi-head self-attention层(多头自注意力机制)和前馈网络层两个子层构成。Multi-head self-attention会并行地执行多个不同参数的self-attention,并将各个self-attention的结果拼接作为后续网络的输入,self-attention机制会在后面中做详细介绍。此后,我们得到了蕴含当前上下文信息的各个词的表示,然后网络会将其输入到前馈网络层以计算非线性层次的特征。

在每一层Transformer网络中,会将残差连接(residual connection)把自注意力机制前或者前馈神经网络之前的向量引入进来,以增强自注意力机制或者前馈网络的输出结果向量。并且还做一个layer normalization,也就是通过归一化把同层的各个节点的多维向量映射到一个区间里面,这样各层节点的向量在一个区间里面。这两个操作加入在每个子层后,可更加平滑地训练深层次网络。

Transformer可以用于编码,也可以用于解码。所谓解码就是根据一个句子的输入得到一个预想的结果,比如机器翻译(输入源语言句子,输出目标语言句子),或者阅读理解(输入文档和问题,输出答案)。解码时,已经解码出来的词要做一个自注意力机制,之后和编码得到的隐状态的序列再做一个注意力机制。这样可以做N层。然后通过一个线性层映射到词表的大小的一个向量。每个向量代表一个词表词的输出可能性,经过一个Softmax层得到每个词的输出概率。

接下来详细介绍self-attention机制,以一个head作为示例。假定当前输入包含三个词,给定其输入词向量或是其上一层Transformer网络的输出,将其通过三组线性变换,转换得到三组queries、keys 和 values向量。query和key向量用来计算两两词之间的得分,也就是其依赖关系,这个得分会同其对应的value向量做加权和,以得到每个词综合上下文信息的表示。

给定当前第一个词的query向量,其首先同各个词的key向量通过点积操作得到这两个词的得分,这些得分用来表示这两个词的依赖或是相关程度。这些得分之后会根据query等向量的维度做一定比例的缩放,并将这些得分通过softmax操作做归一化。

之后,各个得分会同其相对应的value向量相乘得到针对第一个词加权的各个value向量,这些加权的value向量最终相加以得到当前第一个词的上下文表示。

在得到第一个词的上下文表示后,给定第二个词的query向量,我们会重复之前的操作,计算当前query向量同各个词key向量的得分,对这些得分做Softmax归一化处理,并将这些得分同其对应的value向量做加权和,以得到其编码上下文信息的表示。

下面是一个最简化的例子以便简单说明自注意力机制。为了简单起见,这里假设Q、K和V的变化都不起作用,也就是不变。


周明:预训练模型在多语言、多模态任务的进展

输入是The weather is nice today。利用自注意力机制调整每个词的表示。比如The。我们认为它要受到其他所有词的影响。但是影响力可大可小。那么每个词的影响力是通过计算the 与每个词的关联度,然后通过一个softmax归一化得到一个权值。每个词一个权值。这样the的最后表示就是和每个词计算关联度的结果之和。

多头注意力机制就是对一个节点,可以设置几组K、Q和V,分别计算关联度(通过Q和K计算点积)和加权调整的值(通过V和关联度计算)。几组结果可以拼在一起,通过一个线性变换,体现多角度的特征抽取。多头可以是16个头、12个头等。



2、自监督学习

在预训练的模型中,AR(自回归)LM 和 AE(自动编码器)是最常用的自监督学习方法,其中,自回归LM 旨在利用前面的词序列预测下个词的出现概率(语言模型)。自动编码器旨在对损坏的输入句子,比如遮掩了句子某个词、或者打乱了词序等,重建原始数据。通过这些自监督学习手段来学习单词的上下文相关表示。



3、微调

在做具体任务时,微调旨在利用其标注样本对预训练网络的参数进行调整。以我们使用基于BERT(一种流行的预训练模型)为例来判断两个句子是否语义相同。输入是两个句子,经过BERT得到每个句子的对应编码表示,我们可以简单地用预训练模型的第一个隐节点预测分类标记判断两个句子是同义句子的概率,同时需要额外加一个线性层和softmax计算得到分类标签的分布。

预测损失可以反传给 BERT再对网络进行微调。当然也可以针对具体任务设计一个新网络,把预训练的结果作为其输入。

下面介绍预训练模型的历史沿革。

预训练模型的发展虽然这几年才大热,但是我觉得源于早期的词嵌入(word embedding)的工作。比如Word2Vec。它的训练的结果是词的嵌入,是一个静态的表示;此后ULMFiT 是第一个使用RNN基于LM训练的上下文相关的预训练模型;CoVe利用翻译任务来训练编码器-解码器,并使用编码器作为预训练模型;ELMo 使用双向 LSTM合并两个方向的隐状态获得上下文相关表示;GPT采用LM进行训练,它是基于Transformer的单向预训练模型;BERT是基于Transformer的基于掩码的预训练模型;MT-DNN基于BERT增加了一些任务进行多任务训练;MASS使用编码-解码器来训练预训练模型;UNILM尝试同时支持语言理解和生成任务。


把预训练模型用于多语言任务:XLM是一种支持多语言的BERT模型;Unicoder引入若干新的任务改进了 XLM;T5把多种自然语言任务(比如机器翻译、问答),用了更大的数据,在一个网络训练,同时支持这些任务;BART是一种编码-解码器模型,通过还原损坏的句子训练;mBART将 BART理念扩展到多语言。另外还有最新的很多模型恕我这里没有全部列出。此外也扩展到多模态。


周明:预训练模型在多语言、多模态任务的进展

这是一个更加详细的总结。名称、用途、架构、特点,这里就不详细说明了。


总体来讲,预训练模型发展趋势:

第一,模型越来越大。比如Transformer的层数变化,从12层的Base模型到24层的Large模型。导致模型的参数越来越大,比如GPT 110 M,到GPT-2是1.5 Billion,图灵是17 Billion,而GPT-3达到了惊人的175 Billion。一般而言模型大了,其能力也会越来越强。但是训练代价确实非常大。

第二,预训练方法也在不断增加,从自回归LM,到自动编码的各种方法,以及各种多任务训练等。

第三,还有从语言、多语言到多模态不断演进。

最后就是模型压缩,使之能在实际应用中经济的使用,比如在手机端。这就涉及到知识蒸馏和teacher-student models,把大模型作为teacher,让一个小模型作为student来学习,接近大模型的能力,但是模型的参数减少很多。



预训练模型举例说明:

BERT

这里用BERT举例说明预训练模型训练方法。基于Transformer。其基本模型为 12 层模型,还有一个大型模型为 24 层模型。这里说明几个关键地方。

1. tokenizer,简单地理解为词的切分,比如工具BPE。针对一个数据集合,BPE工具自动获得该数据集的token的集合,取频率最高的前N个token作为词表,其他的token都看作是UNK(unknown word)。

2. 对数据集合的每个数据,通过BPE做tokenize,形成token的序列。

3. 训练时,每个token有一个多维向量表示,比如1 024维。随机初始化。

4. 计算预测的损失。该损失反向传播来调整各层的网络参数。也包括每个token的多维向量表示。

5. 最后训练的结果,包括每个token的多维向量表示、每层的网络参数,以及各个attention model的参数等。

6. 在用预训练模型时,把输入序列tokenize之后,对每个token,从词典中得到多维向量表示。然后根据每层的网络参数,计算输出。

训练任务:BERT使用了掩码语言模型(就是盖住一个单词或者多个单词,然后让模型预测)。损失用来调整网络。

BERT还使用NSP(下一句预测),旨在预测第二句是否是第一句的下一句。

周明:预训练模型在多语言、多模态任务的进展

UniLM

UniLM由微软研究院自然语言计算组开发,是一种最先进的预训练的模型,用于语言理解和生成任务。首先它是一个transformer机制。用了三个任务训练:第一个任务就是掩码语言模型(就是自编码)类似于BERT,利用左右词汇预测被盖住的词;第二个任务就是自回归语言模型,类似GPT,利用前面的词序列预测下一个词;第三个任务就是编码-解码模型,利用输入句子和已经输出的词来预测接下来的词。

这三个任务进行多任务训练。通过一个掩码矩阵控制哪些词可以用来attention。训练得到的模型具备了理解和生成两种能力。在GLUE任务集合、文摘生成和答案抽取等任务上都取得了当时最好的水平。

预训练模型已广泛应用于产品,比如提高搜索的相关性等。上图显示必应搜索使用了我们预训练模型的问答系统,给定一个NL问题,系统提取包含答案的文本并确定答案部分。它也可以用于问题生成。给定一个文本,生成关于这个文本的若干问题。可以用于语言教育等领域。



3 预训练模型在多语言任务的应用

周明:预训练模型在多语言、多模态任务的进展

有许多语言中,它们都有大量的单一语言数据,并且某些语言对之间存在一些对照数据。我们可以学习一个跨语言的预训练模型,其中来自两种不同语言的单词,如果具有相似的含义,将联系在一起。然后,基于预训练的模型要建立某个具体任务的系统。对某些语言,如果有带标注的数据,利用之经微调可以得到一个系统。所得到的模型应用于其他语言的同一个任务,即使该语言没有标注数据,也有一定效果。该语言如有标注数据也可进一部微调。这样实现了跨语言之间的迁移学习。


下面介绍一个典型多语言预训练模型XLM。它将BERT扩展到多语言理解任务。


XLM中使用了两个任务。第一个是掩码(屏蔽)语言模型,它与BERT中类似,输入是一个句子,可以是A语言、也可以是B语言。通过共享所有语言的模型参数和词汇,XLM可以获得跨语言功能。第二个任务是TLM(翻译语言模型),它叫做翻译,其实并没有考虑对译关系。输入是双语对照句对,看作一个语言,去训练掩码语言模型。


我们开发的Unicoder-1进一步增加了跨语言训练新任务。除了在单语句子上进行单词和短语层面的“掩码LM”,以及对双语句子进行掩码LM(称作翻译LM)之外,我们增加一个新的训练任务:在利用了Giza+做了单词对齐之后,通过预测两个单词的对译关系是否存在。这个任务可以在单词级别做、短语级别做,也可以在句子级别做。不仅用正例,也引入了反例,通过对比式学习,加强学习效果。


我们还将 Unicoder 扩展到跨语言生成任务。这个预训练模型UNICODER-2做了如下任务训练:给定来自多语言语料库的输入句子,首先打乱其句子,对文本加噪音,然后通过解码器尝试恢复。解码时可以传统方法每次仅预测一个token,也可通过我们最近的Prophet(先知)网络一起预测两个token或者多个token,然后取第一个词输出,再预测下一位置的token。这样做预测能力有新的提高。

周明:预训练模型在多语言、多模态任务的进展


我们建立了多语言任务的评测数据集XGLUE。XLGUE中的 11 个下游任务,其中包括NER(命名实体识别)、POS(词性标注)等。现在XGLUE已经发布。这些任务现在涵盖 19 种语言。


我们在XGLUE上评测了多个跨语言预训练模型(包括 MBERT、XLM、XLM-R 和 Unicoder),并在上表中列出比较结果。可以看到,我们的Unicoder 在许多理解和生成任务上实现了最佳的平均性能。


周明:预训练模型在多语言、多模态任务的进展

多语言预训练模型可以把英语的模型应用到其他语言。英语的标注数据比较多,而其他语言往往缺少标注数据。因此,利用多语言预训练模型可以对新的语言,做zero-shot或者few-shot的学习。比如这里展示了问答系统。英文问答数据finetune训练的QA在法语、德语上也有很好的效果。也可以产生新闻的标题。同样也是在英语标注集合finetune训练之后的系统,也可以生成其他语言的标题。


这里总结一下多语言预训练模型。它缓解了多种语言的资源短缺问题。多语言预训练模型帮助多语言搜索、QA、广告、新闻、文本摘要、低资源神经机器翻译等取得新的提升。


多语言预训练模型仍然面临许多挑战,首先最有效的预训练任务仍然是掩码LM(在多语种或双语语料库上),我们要拓展新的任务以便充分利用多语言/双语的特点。


第二,词汇表比单语言的预训练模型(例如BERT / RoBERTa)大得多,单语3万,多语25万。这样导致要学的模型参数就会增加很多,训练的开销更大。

第三,有的语言对有词汇、语法的同源关系,迁移学习效果好,比如英语的finetune结果对法语、意大利语、西班牙语比较好,而对汉语的效果不太明显。


下一步可以考虑在语系内部进行多语言模型训练。


4 预训练模型在多模态任务中的应用


1、图像-语言的预训练模型

图像-语言的预训练模型的目的,可以是用于理解或者生成。这里仅介绍理解用的预训练模型。做法如下:给定一个包含一幅图片和对应的caption(就是文字描述)的数据库。比如这个例子包括图片和对应的文字描述。首先对这个数据库进行预处理,用FASTER-RCNN 得到图片每个对象label的分布,以及对象的输出向量表示(softmax之前的输出向量表示)。一个图片的所有对象按照从左到右、从上到下的顺序排列,可以形成一个序列。和文本序列排列在一起。我们可以用BERT方式训练一个预训练模型,比如掩码的方式,盖住文字段的某个token来预测这个token。或者盖住对象序列的某一个对象来预测这个对象的输出向量表示,或者直接预测这个对象的label。另外预测对象序列和text是否是相互描述。

现有工作基于大致相似的网络结构。我们是最早发表的工作之一。我们增加了一个新的训练任务,即对象的输出向量还原为对象的FASTER-RCNN的原始向量,取得了改进效果。

在Flickr30K(image retrieval和captioning的数据集),image2text和text2image两个任务。Text2image任务是给定text,从1 K的图片(给定)排序,得到最优的匹配。MSCOCO(微软提供的数据集)任务完全与Flick30K一样。Pre-training dataset是三百万image-caption pairs 的谷歌提供的 Conceptual Captions。

目前最好的系统:ViLBERT来自facebook,UNITER来自微软产品组。UNICODER-VL由于增加了新的训练任务(如前述),预训练模型对图片和文本的编码能力有所提升,得到了较好效果。


2、文档-语言的预训练模型

我们开发的多模态的预训练模型LayoutLM,通过对扫描的文档,利用OCR识别之后的文字片段和文字对照的图像同时进行预训练。基于该预训练模型,抽取表格里的重要信息,包括语义类别和值。获得了目前在相关任务评测集的最高的水平(发表在KDD2020)。

这是目前可用的训练数据集合,含有11 Million扫描文档和识别的结果。NIST发表的,最主要的16类数据(信件、表格、收据等),包含了扫描文档及其对应的OCR结果。我们重新用OCR(开源工具) ,以便得到识别对象的坐标信息。


我这里解释一下我们做的LayoutLM预训练模型。


首先一个扫描的文档(digital burned doc),进入OCR引擎可以得到识别的结果,就是一个个的字符(以BPE分词之后表示)串,以及在文档中的起始位置坐标。字符串的序列和位置坐标(四个数字)作为预训练输入。然后通过类似BERT的掩码方式(就是盖住其中某些token)通过12层(或者24层)的Transformer来预测被盖住的token。预测的损失回传调整网络的全部参数。当然可以增加其他的训练任务,比如判断文档的分类。


通过对大规模的OCR识别的数据进行训练,可以得到一个预训练模型。这个预训练模型在进行下游任务时要微调。微调时,可以直接用预训练模型作为输入进行微调,也可以把文档中的对应token的图像编码也作为输入,增强预训练的信号。


周明:预训练模型在多语言、多模态任务的进展


训练任务1:掩码训练类似于BERT。预测被盖住的token,其损失回传,调整网络。

预训练任务2:判断图像的分类。按照原来数据集的分类标注,进行训练。

下游任务之一是表单理解。给一个文档,识别出文档中包含key-value,就是实体语义类型(比如时间、地点、数目)和实体的值。通过标记BIO风格的序列,就可以得到识别结果。

我们的LayoutLM对几个重要的下游任务都取得了最佳的结果。比如表单理解、收据信息抽取等等。这里不再赘述。



3、视频-语言的预训练模型


下面介绍Video-NL预训练模型。


对每个Video片段和对应的NL描述(语音识别的结果)建立这样的网络结构,左边NL的token序列,右边是视频按照时间序列均匀切分(1.5 秒)的video clip的序列,可以用S3D等工具,每个video clip对应一个输出向量表示。进入Video encoder。文本序列和video clip序列拼接起来进入Transformer。多层(比如三层、四层),后面跟着一个解码,利用一个encoder-decoder结果来做预训练。使用了如下四个任务进行预训练。

• Video-text alignment任务用来判断输入的video clip和text是否相互描述。

• Masked language model任务用来预测transcript里被mask掉的单词。

• Transcript generation任务基于输入的video clip,生成对应的video transcript,这时还有NL段置空了。

• Masked frame model任务用来预测被mask掉的video clip对应的video feature vector。

UNICODER-VL扩展到video。与其他工作相比,我们把理解和生成集成在一个预训练模型,既可以理解,也有生成能力。预训练的语料是,HowTo100M作为pre-train语料。它是从Youtube上抓下来的1.2 M视频,切分成136 M视频片段,根据时间轴配上文字说明(youtube自带的)。下游任务finetune目前我们使用YouCook2的菜谱视频,以及MSR-VTT微软发布的(视频-caption)对的数据集合。

下游任务包括视频搜索和视频caption生成两个任务。首先是检索任务——给定NL的query,从一个固定视频片段中搜索最匹配的视频片段。然后是caption任务——给定一段视频,加上transcript,生成对应的caption。我们的提交系统目前取得了最好的评测结果。

这样的预训练模型有很多应用。这里用Video chaptering来说明。它分为两个任务,一个是video segmentation,用于对输入video进行clip切分;一个是video captioning,用于对每个video clip生成一个总结性的内容。

我总结一下多模态预训练模型。目前它尚处于初期阶段。遵循大多数NLP预训练模型,用Transformer机制,从有限的图像/视频-语言数据集中学习联合表示,可以计算图像/视频片段和文字描述的距离,并实现图像/视频-文字之间的转换。多模态预训练模型虽然刚刚开始还不成熟,但是已经在图像/视频的搜索,以及生成文字描述当任务中显示出不错的前景。



当然,多模态预训练模型仍然面临许多挑战:

首先,图像/视频-语言对的数据的大小仍然比自然语言语料库小得多。

第二,CV仅仅用于特征提取,目前并没有将CV模型和NLP模型共同训练。当然目前没有好的算法,而且训练的cost非常大。

第三,与之有关,就是CV的对象识别,目前的类别仅限于1 000类左右,对真实场景的覆盖不够,而且识别的精度也不够,导致预训练的输入信号天然带有误差。

第四,对于多模态预训练模型,目前都是用Transformer机制,但是它的代价比较大,而且是否最合适对图像/视频-文字建立关联,还需要进一步探索。

第五,图片和视频的预训练模型也不一样,由于视频有时序,因此视频的分割按照固定时长分割,缺乏逻辑意义。而且视频的token会比NL多很多,导致训练的代价比图片和文字的预训练大很多。



5 结语


NLP经历了第一代的基于规则的NLP;第二代的基于统计的NLP;五年前进入到基于神经网络的第三代NLP(NN-NLP),在大数据、大模型、神经网络框架下取得了很好的进展,形成了一整套的技术。而现在更进一步,预训练+微调形成了工业化可扩展的解决方案。

预训练模型把迁移学习很好地用起来了,让我们感到眼前一亮。这和小孩子读书一样,一开始语文、数学、化学都学,读书、网上游戏等,在脑子里积攒了很多。当他学习计算机时,实际上把他以前学到的所有知识都带进去了。如果他以前没上过中学,没上过小学,突然学计算机就不懂这里有什么道理。这和我们预训练模型一样,预训练模型就意味着把人类的语言知识,先学了一个东西,然后再代入到某个具体任务,就顺手了,就是这么一个简单的道理。这要感谢杨强老师做的迁移学习,真的是有效。

预训练体现出所有的自监督的训练。如果为了做预训练要标数据则失去意义,因为标不了太大数据,很多知识体现不出来。恰好自然语言有几乎无限的语料,用语言模型或者用自编码方法自监督学习。一个预训练模型,只要训出来以后,后续所有任务,都可以得到很好的处理。对一个任务,只要数据足够大的任务,预训练加微调机制基本可以搞定了。当然还需要研究zero-shot,few-shot等问题,这些还有研究空间。

预训练模型在多语言任务中,rich-resource 的模型会迁移到low-resource语言任务中,减轻了数据不足的问题。预训练模型在文本中表现出色,基本可以实用。而在多模态任务中,则方兴未艾,还有巨大探索空间。比如图片/视频的预处理、训练任务的设计都将有很多有趣的研究。

要想迈向下一个阶段也有很多问题,比如现有的预训练模型是不是最优的?有没有更好的训练任务、更好的神经网络架构?训练是否可以更快?模型是否可以更小?现在疯狂追求大模型,耗尽计算资源,同时也污染了环境,是不是我们可以接受的?还有现有的模型在利用知识、尝试、进行推理,并且提供解释等方面仍然没有看到任何清晰的解决前景。这些都是难题。我希望大家一起继续努力,把这些问题好好想想,努力把NLP推向一个新的高度。



https://blog.csdn.net/weixin_42137700/article/details/108662991




来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69946223/viewspace-2722203/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
一个精通SAP供应链咨询却又对AI感兴趣的大叔

注册时间:2019-08-22

  • 博文量
    1335
  • 访问量
    722358