深度学习:FNN,CNN,RNN,LSTM
在生物神经网络中,每个神经元与其他神经元相连,当它兴奋时,就会向相连的神经元发送化学物质,从而改变这些神经元内的电位;如果某神经元的电位超过了一个阈值,那么它就会激活,即兴奋起来并向其他神经元发送化学物质。
在深度学习中也借鉴了这样的结构,每一个神经元接受输入
,通过带权重
的连接进行传递,将总输入信号与神经元的阈值进行比较,最后通过激活函数处理确定是否激活,并将激活后的计算结果y输出,而我们所说的训练,所训练的就是这里面的权重w。
可以将神经元拼接起来,两层神经元,即输入层+输出层(M-P神经元),构成感知机。 而多层功能神经元相连构成神经网络,输入层与输出层之间的所有层神经元,称为隐藏层:隐层(Hidden Layer)是位于输入层和输出层之间的一层或多层神经元的集合。
【逼近定理】在激活函数满足一定条件的前提下,任意给定输入空间中的一个连续函数和近似精度
,存在自然数
和一个隐含节点数为
单隐层全连接神经网络,对着连续函数的
逼近精度小于
。
【万能近似定理】如果前馈神经网络具有至少一个非线性输出层,那么只要有足够数量的隐层单元,它就可以以任意精度来近似任何一个有限维空间到另一个有限维空间的函数,换句话说就是只含一层隐藏层的有限神经元网络可以逼近在实数集上紧子空间的连续函数。
1,FNN(MLP)
BP神经网络的原理:BP神经网络各层神经元之间互相连接。BP神经网络从外界接到输入向量后,经由隐藏层的非线性变换,最终产生一个输出。在训练过程中,主要采用的反向传播的方式,即在训练时的正向传播,通过模型的输出和真实值之间的误差建立误差函数,然后从输出端反向沿着损失函数的梯度下降方向,并通过求偏导的方式调整权重参数、偏置量等,使得经过训练的模型的输出和期望值相比达到最优。
BP神经网络算法的核心是反向传播算法。主要方法过程是通过对连接权值不断调整,使输出结果逐步逼近期望值,其过程包括信号的正向传播过程和误差的反向传播过程。反向传播是在求解损失函数对参数求到时候用到的方法,目的是通过链式法则对参数进行一层一层的求导。需要注意的是要对参数进行随机初始化而不是全部置为0,否则所有隐藏层的数值都会与输入相关,这种情况称为对称失效。
在信号向前传播的过程中,输入样本从输入层进入网络,经隐含层逐层传递至输出层,如果输出层的实际输出与期望输出不同,则转至误差反向传播过程;如果如果输出层的实际输出与期望输出相同或网络不再收敛,结束学习算法。
在误差反向传播的过程中,输出误差(期望输出与实际输出之差)将按原路反传计算,通过隐含层反向传播至输入层。在该过程中,误差将会被分配给各层神经元,获得各层神经元的误差信号,并将其作为修正各单元权值的根据。整个过程基于梯度下降法实现,不停地调整各层神经元的权值和阈值,是误差信号降低最低。
1.1,BP&MLP
BP神经网络是指采用反向传播算法训练的神经网络。反向传播算法是一种用于计算神经网络梯度的有效方法,主要步骤包括前向传播和反向传播。BP神经网络强调的是训练方法,因此几乎任何神经网络结构(如MLP、CNN、RNN等)都可以使用BP算法进行训练。
MLP神经网络是一种前馈神经网络,由至少三层节点组成:输入层、一个或多个隐藏层、输出层,专注于网络结构。MLP神经网络通常使用反向传播算法(BP)来训练,因此MLP神经网络训练时常被称为BP神经网络。但需要注意的是,BP不局限于MLP,它也可以训练其他类型的神经网络。
BP神经网络的优点:
- 能够自适应、自主学习。BP可以根据预设参数更新规则,通过不断调整神经网络中的参数,已达到最符合期望的输出。
- 拥有很强的非线性映射能力。
- 误差的反向传播采用的是成熟的链式法则,推导过程严谨且科学。
- 算法泛化能力很强。
传统神经网络的训练方式为不能用在深度神经网络:BP算法作为传统训练多层网络的典型算法,网络稍微一深,训练结果就会很不理想,主要问题有梯度越来越稀疏:从顶层越往下,误差校正信号越小;容易收敛到局部最小值,深度结构非凸目标代价函数中普遍存在的局部最小会导致利用BP神经网络训练非常困难。
1.2,梯度消失&爆炸
【梯度消失】当网络层数很多或者激活函数的导数在大部分输入上很小(例如 Sigmoid 的导数最大也只有 0.25)时,反向传播时梯度会在链式法则下不断相乘,导致靠近输入层的梯度趋近于 0。结果是前面层的权重几乎不更新,模型学习停滞,训练困难。典型表现是训练早期损失下降缓慢,前几层特征无法有效学习。
【案例】假设激活函数为:sigmoid函数
求导可得:
二阶导:
可以看出导数越求越小,最后接近于0,梯度消失。
【案例】深度神经网络中,梯度是通过链式法则进行反向传播的。每一层的梯度都需要与前一层的梯度相乘,然后再传递到前一层,依此类推,直到传递到网络的输入层。如果网络层数较多,那么在反向传播过程中会经过多次连续的乘法操作,从而可能导致梯度的值指数级地减小,最终趋近于零,即梯度消失)。
【解决方案】
- 更换激活函数:ReLU、Leaky ReLU、ELU 等。
- 批量归一化:通过将每一层神经元的输入拉回到均值为 0、方差为 1 的标准正态分布,使输入值落在激活函数梯度较大的非饱和区。
- 残差:传统的层是
,而残差层是
。
【梯度爆炸】当权重初始化过大或者网络权重在训练过程中不断累积导致梯度在反向传播中指数级增长,梯度会变得非常大。结果是权重更新过度,模型参数可能变得不稳定,损失可能出现 NaN,训练完全失控。RNN 和深层全连接网络尤其容易出现这种情况。
【案例】考虑一个深层全连接网络,每层只有一个神经元,权重初始化为
,使用线性激活。假设输入
,目标输出
,使用均方误差
。网络输出经过
层:
。
梯度
当
时:
1.3,正向传播
图中:绿色方框表示偏执,黄色表示概率,红色表示参数,黑色表示权重。用下面的记号来描述这样网络:
:表示表示
层的神经元总数。
:表示
层第
个神经元的参数。
:表示
层第
个神经元的偏执。
:表示第
层的神经元
与
层神经元
之间的连线权重。
:表示激活函数。
前馈神经网络通过下面公式进行信息传播:
...
拆解后归并,可得:
+
令:
![]()
则:
这样,前馈神经网络可以通过逐层的信息传递,得到网络最后的输出。
1.4,反向传播
反向传播(Backpropagation)用于计算神经网络中各层权重和偏置的梯度,从而实现模型参数的更新。它是前向传播的逆过程,通过计算损失函数对神经网络输出的梯度,逐层向后传播,从输出层到输入层,计算每一层的梯度,并用于更新模型参数。反向传播是前向传播的逆过程,通过计算损失函数对神经网络输出的梯度,逐层的传播,通过这样的方法可以计算出一个神经网络的损失函数梯度,并调参实现梯度下降。
例如,求解
上面的数字表示数值,下面的数字表示梯度。从 f 开始计算,梯度为 1,
,同理
,
,
,类似这样一步一步求出结果。
给定一组样本
,用前馈神经网络的输出为
,待优化目标函数为;
其中
为损失函数,
和
包含了每一层的权重矩阵和偏置向量:
,
的作用使得
取最小值,避免误差放大或使得分类更加精确(正则化学习)。
学习的目标是最小化
。如果采用梯度下降方法,可以用如下方法更新参数:
其中,
是参数的更新(学习)率。
计算
,根据链式法则:
对于第
层,定义一个误差项
为目标函数关于第
层的神经元
的偏导数,表示第
层神经元对最终误差的影响。
因为
因此:
(单独一项)
(整体)
同理:
计算第
层的误差项
其中 ⨀︀ 是向量的点积运算符,表示每个元素相乘。
从上式可以看出,第
层的误差项可以通过第
层的误差项计算得到。这就是误差的反向传播(Backpropagation,BP)。
反向传播算法的含义:第
层每个神经元的误差项是所有与该神经元相连的第
层的神经元的误差项的权重之和,再乘上该神经元激活函数的梯度。
在计算出每一层的误差项之后,就可以得到每一层参数的梯度。因此,前馈神经网络的训练过程可以分为以下三步:
- 先前馈计算每一层的状态和激活值,直到最后一层。
- 反向传播计算每一层的误差。
- 计算每一层参数的偏导数,并更新参数。该训练过程被称为反向传播算法。
1.5,实际案例
残差(表示误差的偏导数):
- 输出层→隐藏层:残差 = -(输出值-样本值) * 激活函数的导数。
- 隐藏层→隐藏层:残差 = (右层每个节点的残差加权求和)* 激活函数的导数。
- 输出层→隐藏层:残差 = -(输出值-样本值) * Sigmoid*(1-Sigmoid) = -(输出值-样本值)输出值(1-输出值)。
- 隐藏层→隐藏层:残差 = (右层每个节点的残差加权求和)* 当前节点的Sigmoid*(1-当前节点的Sigmoid)。
更新权重:
输入层:权重增加 = 输入值* 右层对应节点的残差 * 学习率
隐藏层:权重增加 = 当前节点的Sigmoid* 右层对应节点的残差 * 学习率
偏移值的权重增加 = 右层对应节点的残差 * 学习率
2,循环神经网络(RNN)
2.1,基本概述
大脑区别于机器的一个最大的特征就是有记忆,并且能够根据自己的记忆对未知的事务进行推导,思想拥有持久性的。由于传统的神经网络没有设计记忆结构,因此在处理序列数据上无所适从(即便经过特殊的处理),这不仅导致工作量变大,预测的结果也会收到很大的影响。例如,如果要翻译“这个知名作家的书都非常精彩”:
The books of the famous writer [are] all wonderful.当生成到 writer 时,这里下一个生成的词应该是 are,而不是 is。这涉及到对前文文本books 的依赖。传统的 MLP 或者 CNN 是无法做到这种连接的,因为他们会先输出the,而后输出books,而后输出 of。每次输出,都不会留下记忆,所以输出【are】这个位置的单词的时候,自然不知道前面的 books 这个信息。
循环神经网络(RNN)针对 BP 神经网络的缺点,增加了信息跨时传递的结构。传统的神经网络模型面对许多问题显得无能为力,因为同层节点之间无连接,网络传播也是顺序的。
RNN的本质:拥有记忆能力的神经网络,并且会根据这些记忆的内容来进行推断。
RNN的优势:RNN背后的想法是利用顺序的信息。 在传统的神经网络中,假设所有输入(和输出)彼此独立。如果预测句子中的下一个单词,就要知道它前面有哪些单词,甚至要看到后面的单词才能够给出正确的答案。RNN 之所以称为循环,就是因为它们对序列的每个元素都会执行相同的任务,所有的输出都取决于先前的计算。 从另一个角度讲RNN的它是有“记忆”的,可以捕获到目前为止计算的信息。
2.2,网络结构及原理
对于RNN而言,每个时刻的隐藏层除了连接本期的输入层和输出层,还连接着上一时刻和下一时刻的隐藏单元,这也就是历史信息的传递方式。过去的信息正是通过这样的结构影响当期的输出。此外,RNN虽然也是采用反向传播的方式,但跟BP模型不一样的是,它还包含了最后一个时间将积累的残差传递回来的过程。这种方式被称为基于时间的反向传播(BPTT)。
【基本结构】将网络的输出保存在一个记忆单元中,这个记忆单元和下一次的输入一起进入神经网络中。可以看到网络在输入的时候会联合记忆单元一起作为输入,网络不仅输出结果,还会将结果保存到记忆单元中。
RNN 可以被看做是同一神经网络的多次赋值,每个神经网络模块会把消息传递给下一个,将这个图的结构展开
循环神经网络具有特别好的记忆特性,能够将记忆内容应用到当前情景下,但是网络的记忆能力并没有想象的那么有效。记忆最大的问题在于它有遗忘性,总是更加清楚地记得最近发生的事情而遗忘很久之前发生的事情,循环神经网络同样有这样的问题。
- 以词序列 {长颈鹿, 脖子, 长} 为例,在给定“脖子”来预测下一个词是什么的 时候,FFN 将仅仅考虑“脖子”来进行预测,可能预测出的下一词包含“短”,“疼” 等等;
- 而 RNN 将同时考虑“长颈鹿”和“脖子”,其预测出下一词是“长”的概率 将更高,历史信息“长颈鹿”的引入,可以有效提升预测性能。
2.3,过程拆解
RNN 其实也是一个普通的神经网络,只不过多了一个 hidden_state 来保存历史信息。这个hidden_state 的作用就是为了保存以前的状态,RNN 中保存的记忆状态信息,就是这个 hidden_state 。
设输入序列为
,隐状态为
,对应的输出为
,输入层、隐藏层、输出层对应的网络参数分别为:
。
为激活函数,
为输出函数。将输入序列一个元素接着一个元素地串行输入时:
- FNN:
- RNN:
省略的偏执
,
是当前状态的输入值,
就是上一个状态的 hidden_state,也就是记忆部分。
【问题】RNN不同时间步为啥采用相同的参数
?在RNN中,不同时间步之间共享参数的原因主要是为了捕捉序列数据的时序关系,减少参数数量,防止模型过拟合。假设要用 RNN 来预测一句话中的下一个单词。在这种任务中,句子是一个序列,每个单词的预测需要依赖前面的单词。RNN 通过在每个时间步共享相同的参数(即权重矩阵),可以在不增加模型复杂度的情况下让每个时间步学习和传递序列的上下文信息。
- 减少参数数量:共享参数让我们在处理一个序列时不必为每个时间步都设定独立的参数,参数总量大大减少,模型更轻量。
- 加强时序依赖:共享参数让模型可以将序列信息从前面传递到后面。比如,通过共享参数,RNN可以理解“enjoy”通常和“reading”有关系,从而提高对下一个单词的预测准确性。
2.4,遗忘机制,梯度爆炸&消失
【问题一】记忆力过强(遗忘机制):在传统的 RNN 中,每个时间步的隐藏状态都是通过当前的输入和上一时间步的隐藏状态计算得到的,每个时间步的隐藏状态都包含了全部历史时刻的信息,因此随着时间步的增加,隐藏状态中的信息会越来越多,其中有价值的信息含量的比率会越来越少。
【问题二】处理长序列时存在梯度消失和梯度爆炸的问题(梯度裁剪、调整学习率、LSTM、GRU):模型的记忆力过强不仅会降低信息的价值,还会导致处理长序列时的梯度消失和梯度爆炸等问题,从而导致模型难以捕捉到序列中较远的依赖关系。
【梯度爆炸】核心问题就是RNN在不同时间步使用共享参数
,导致
时刻的损失对
时刻的参数的偏导数存在
的指数形式,一旦
很小或很大就会导致梯度消失或梯度爆炸的问题。如图,梯度不断反传,梯度不断变小(箭头不断变小)。
设 RNN 语言模型的训练损失:
其中
为损失函数,
为标签
损失
关于参数
的梯度为:
其中
其中
进而:
从上式中可以看出,求解
的梯度时涉及大量的矩阵级联相乘。这会导致其数值被级联放大或缩小。当
的最大特征值小于 1 时,会发生梯度消失;当
的最大特征值大于 1 时,会发生梯度爆炸。梯度消失和爆炸导致训练上述 RNN 非常困难。为了解决梯度消失和爆炸问题,GRU和 LSTM引入门控结构,取得了良好效果,成为主流的 RNN 网络架构。
【梯度消失】参数更新更多的受到临近词的影响,那些和当前时刻
较远的词对当前的参数更新影响很小。假设需要预测句子The writer of the books下一个单词,由于梯度消失,books对下一个词的影响比writer对下一个词的影响更大,导致模型错误的预测成了are,但这显然是不对的。
3,长短期记忆网络(LSTM)
3.1,基本原理
普通RNN虽然具备一定的记忆功能,但是却不能很好地处理长期记忆问题。循环神经网络包含非常复杂的参数动态变化,这导致它非常难训练。RNN 也是采用后向传播算法对权重和阀值进行优化,虽然可以将之前的隐藏层状态存储在记忆单元中,但对于处理相隔距离较远的信息却无能为力。当误差的权重大于 1 时,权重经过多次相乘会导致梯度爆炸的问题;而当误差的权重小于 1 时,经过多次传播,又会出现梯度消失的情况。RNN训练难度的本质在于参数在时间结构的传递中不断使用,即在不同的时间点反复使用,因此只要权重有微小的变化就有可能造成“蝴蝶效应”。
所以需要设计一个模型结构,让模型可以去选择记住什么信息、忘掉什么信息,提高信息的价值,并解决梯度问题。LSTM 虽然只解决了短期依赖的问题,并且它通过刻意的设计来避免长期依赖问题,这样的做法在实际应用中被证明是十分有效的。
【LSTM架构】如果把LSTM视为一个黑盒而先不去考虑其内部结构,就有下面的LSTM模型:
相比RNN只有一个传递状态
,LSTM有两个传输状态,一个
(cell state),和一个
(hidden state)。其中对于传递下去的
改变得很慢,通常输出的
是上一个状态传过来的
加上一些数值。
控制哪些信息会被遗忘,哪些信息会被留下,
则在不同节点下往往会有很大的区别。
3.2,LSTM中的门结构
- 对于第一个时间步,隐状态
和细胞状态
可以是初始化为零向量,也可以使用一些预训练的权重或者其他先验知识来初始化
和
,来更好的训练模型。
- 对于第t个时间步,LSTM有三个输入:
,
和
。直接把
,
拼接到一起,成为一个新的更长的向量。
- 有4个权重矩阵:
。每个权重矩阵都对应了自己的偏置,不过这里先忽略偏置。用
,
拼接到一起的向量分别与这四个权重矩阵相乘,再用一个激活函数去激活,就得到了四个向量:
。其中,只有
是以tanh函数激活的,它后续会被作为一个输入向量;而其他三个向量后续都是作为门控向量之用,所以是以sigmoid函数激活(所以每个门控信号都是一个元素取值在 [0,1] 的向量,元素值离 1 越近,代表记忆下来的数据越多!!)。
【中门控制机制】
为了根据
,
和
得到当前的
和
,LSTM内部主要有三个阶段:
- 遗忘阶段:这个阶段主要是对上一个节点传进来的输入进行选择性忘记。具体来说是通过计算得到的
来作为忘记门控,来让上一个状态的
遗忘一些不重要的东西(不用去纠结什么是重要的、什么是不重要的,把它当成一个黑盒子。这个能力通过学习权重矩阵
的参数来实现!)。
- 选择记忆阶段:这个阶段将这个阶段的输入有选择性地进行“记忆”。主要是会对输入进行选择记忆:希望模型做到把重要的着重记录下来,不重要的就敷衍一点(这个能力通过学习权重矩阵
的参数来实现)。记忆门包含两个部分:一个sigmoid网络和一个tanh网络。
- sigmoid网络:门控信号
(i for information)来算出向量
,其意义在于决定哪些信息要更新。
- tanh网络:用一个权重矩阵
来创建向量
(或者状态候选向量
),代表了这一步的输入信息。
- 将上面两步得到的结果相加,即可得到传输给下一个状态的
。
- 输出阶段:这个阶段将决定哪些将会被当成当前状态的输出。计算出的
,通过了tanh,把每个元素都投射到了(-1,1),而后和向量
做元素相乘,得到了这一个时间步的隐状态
。算完当前时间步的隐状态
后,再将其乘一个权重矩阵,得到的就是当前时间步的output
。与普通RNN类似,输出的
往往最终也是通过
变化得到。
4,卷积神经网络
4.1,卷积、池化、感受野
卷积:用一个固定大小的矩形区去席卷原始数据,将原始数据分成一个个和卷积核大小相同的小块,然后将这些小块和卷积核相乘输出一个卷积值。这种局部计算的方式使得卷积能够捕捉到输入图像的局部特征,例如边缘、纹理和形状等。
工作原理:通过卷积手段,使得上层神经元都只和它下一层神经元一个局部窗口内的神经元相连,构成一个局部连接网络,显著地减少了神经网络中的连接个数。对于每一个卷积层,都包含若干个特征平面,每个特征平面由一些矩阵排列的神经元组成,同一个特征平面实现神经元的权值共享,即卷积核。
卷积计算:一个权重矩阵,也就是
(卷积的核 kernel),这个权重矩阵的大小一般为
或者
,但是在 LeNet 里面还用到了比较大的
。 在输入矩阵上使用权重矩阵进行滑动,每滑动一步,将所覆盖的值与矩阵对应的值相乘,并将结果求和并作为输出矩阵的一项,依次类推直到全部计算完成。卷积核一般都为 3*3,5*5,而并不是更大的原因:
- 相对于用较大的卷积核,使用多个较小的卷积核可以获得相同的感受野和能获得更多的特征信息,同时使用小的卷积核参数更小,计算量更小。
- 用户可以使用更多的激活函数,有更多的非线性,使得在用户的CNN模型中的判决函数有更有判决性。
感受野:某一层神经元能够“看到”的输入数据的范围。它表示从网络的某一层输出的神经元,所感知到的输入图像的区域。随着层数增加,感受野会越来越大。
- 小:聚焦局部信息,计算效率高,适合处理图像中细微纹理;无法捕捉长上下文信息。
- 大:更好地捕捉长程信息,计算开销大,注意力机制的计算复杂度是
,其中
是序列的长度。
感受野计算:从最后一层往下计算的方法,即先计算最深层在前一层上的感受野,然后逐层传递到第一层,使用的公式可以表示如下:
其中,
是第
层卷积层的感受野,
是卷积的步长,
是
层卷积核的大小。 假设输入图像为 7×7,使用 3×3 的卷积核,步幅为 1,填充为 0:
第一层卷积: 输入 7×7,步幅 1,输出 5×5。感受野为 3×3。
第二层卷积: 输入 5×5,步幅 1,输出 3×3。感受野为 5×5。
第三层卷积: 输入 3×3,步幅 1,输出 1×1。感受野为 7×7。
池化(子采样):池化是将相临的多个特征用一个特征来代替,压缩数据和参数的数量,减小过拟合,同时提高模型的容错性。上图中,每一层就相当于一次降采样,这就是池化。
工作原理:池化也叫子采样,通过包括均值子采样和最大值子采样两种形式。通过子采样,取一定区域内最大值或均值取代该区域内所有神经元的特征,降低各层输入维度,即能够保留神经元的基本特征,又可以避免输入维度过高而导致过拟合。池化常用方法有:最大值和平均值。
最大值:
平均值:
dropout层:dropout是2014年 Hinton 提出防止过拟合而采用的trick,增强了模型的泛化能力 Dropout(随机失活)是指在深度学习网络的训练过程中,按照一定的概率将一部分神经网络单元暂时从网络中丢弃,相当于从原始的网络中找到一个更瘦的网络,说的通俗一点,就是随机将一部分网络的传播掐断,听起来好像不靠谱,但是通过实际测试效果非常好。
全连接层:全链接层一般是作为最后的输出层使用,卷积的作用是提取图像的特征,最后的全连接层就是要通过这些特征来进行计算,输出所要的结果了,无论是分类,还是回归。特征都是使用矩阵表示的,所以再传入全连接层之前还需要对特征进行压扁,将他这些特征变成一维的向量,如果要进行分类的话,就是用sofmax作为输出,如果要是回归的话就直接使用linear即可。
4.2,卷积神经网络的优点
为什不使用全连接神经网络,而使用卷积神经网络:28*28像素的黑白手写数字,就让我们有13002个参数要去学习。
- 假设全连接网络包括:输入层(28*28)、隐藏层(16)* 2、输出层(10)
- 输入层 ➡ 隐藏层1:784*16(权重)+16(偏执)=12560
- 隐藏层1 ➡ 隐藏层2:16*16(权重)+16(偏执)=272
- 隐藏层2 ➡ 输出层:16*10(权重)+10(偏执)=170
如果用苹果手机随便拍一张1200万像素、彩色的照片呢(彩色就无法用0~1的灰度来表示,而需要把一张图片分为三层,分别代表R、G、B)。
首先是学习原理上的改进,卷积神经网络不再是有监督学习,不需要从图像中提取特征,而是直接从原始图像数据进行学习,这样可以最大程度防止信息在还没有进入网络之前就丢失。
另一方面是学习方式改进。全连接神经网络一层的结果与上一层的结点全部连接。局部感知就是感受野,实际上就是卷积核和图像卷积的时候,每次卷积核所覆盖的像素只是一小部分,是局部特征,所以说是局部感知。CNN是一个从局部到整体的过程,而传统的神经网络是整体的过程。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



















所有评论(0)