Dynamic Slicing for Deep Neural Networks

  • 一.Introduction
  • 二.Motivation And Goal
    • 2.1.Motivation
    • 2.2.Problem Formulation
    • 2.3.Challenges
  • 三.NNSlicer
    • 3.1.Approach Overview
    • 3.2.Profiling and Forward Analysis
    • 3.3.Backward Analysis and Slice Extraction
  • 四.Applications
    • 4.1.Adversarial Defense
    • 4.2.Network Simplification and Pruning
    • 4.3.Model Protection
  • 五.Limitations And Discussion
  • 六.参考文献

一.Introduction

程序切片(program slice)技术已经广泛引用到程序调试,测试,验证等任务上,意在求得能够影响感兴趣的程序点(points of interest)的值的语句集合(set of statements)。

但是现有的程序切片主要是应用于传统由人工定义函数和指令的软件(程序员手写),而不能适用于基于深度学习的软件,这些软件的核心是深度神经网络(Deep Neural Networks),由一个个神经元(neuron)和突触(synapses )构成。神经元是一个数学运算(加减乘除),突触是神经元之间的连接,通常附带权值。

如下图所示,图中所有的圈代表神经元,连接线代表突触,神经元负责进行加法运算(例子),而2个神经元之间的突触会让前一个神经元的输出乘上自身的权值输入到下一个神经元。这些权值就是深度神经网络需要学习的参数。

但是,这些突触的权值通常难以让人理解,这里作者希望能用程序切片技术理解深度神经网络(DNN)的行为。

这里,作者定义DNN slicing为DNN网络中神经元和突触的一个子集,这一小部分的神经元和突触能够明显地影响部分感兴趣的神经元的值(感兴趣的通常是输出部分的神经元,不是中间部分),对DNN进行slice有以下好处:

  • DNN的决策结果通常难以解释也难以debug,切片可以用来提取对决策影响最大的算术运算,使得模型可解释性更好。
  • DNN的大小越来越大(现在CV领域的state-of-art有180MB了,NLP领域的340MB),所以如何提高模型的效率成为了研究热点。切片有助于减小模型大小。
  • 模型切片对保护模型也是有好处的,通常大的模型难以保护而切片可以让模型最重要的一部分凸显出来,保护切片比保护整个模型要节省资源。

同时,DNN切片也面临许多挑战:

  • 与传统程序中的指令和变量是由程序员自己定义好的并且有明确含义的不同,DNN通常由各种算术运算组成,这些算术运算直观上没有意义,DNN的行为通常由学习到的突触权重定义。所以,如何根据连接关系理解每一个神经元的行为是一个问题。
  • DNN的每一个输出基本上所有的神经元都参与了,所以必须根据神经元对切片标准(slice criterion)的贡献来区分和描述神经元。
  • 传统程序中的数据流图通常是稀疏的,小规模的。但是DNN中的数据流通常是成千上万个神经元的连接,这对系统效率提出了很大挑战。

所以这里,作者提出NNSlicer,一个针对DNN的基于DNN数据流分析的动态切片技术(说动态是因为它需要在运行时,根据相应的输入样本来切片,而不是传统的静态切片),切片标准定义为带有特殊意义的神经元(比如分类网络的最后一层神经元,这些神经元每一个输出的是样本属于相应类别的概率)。NNSlicer专注动态切片,每一次的切片都是针对相应输入样本的,而不像传统的静态切片,是输入无关的。

NNslicer包含3个阶段:profiling phase,forward analysis phase,backward analysis phase。

  • 在profiling阶段作者把所有训练样本输入到模型,并计算每个神经元在所有样本上的平均值作为该神经元的baseline,之后根据这个baseline来理解该神经元针对给定样本的反应(reaction)。
  • 在forward analysis阶段作者只输入需要计算slice的样本,并记录这些每个神经元针对样本的输出值,神经元在这一阶段的输出和profiling阶段求的平均值的差作为神经元对相应样本的反应(reaction)。差值的绝对值作为神经元针对给定样本的敏感度。
  • 但是高敏感度的神经元并不一定对切片标准重要,因为该神经元的输入可能被之后的神经元重定向或抵消,因此作者实现了backward analysis来从输出神经元反向追踪数据流来理解每个神经元的贡献,slice初始化值输出部分满足切片标准的神经元,然后通过计算前置神经元的贡献迭代分析slice中的每个神经元。前置神经元中贡献度高的会被添加到slice中并之后也会进行backward analysis。

作者采用Tensorflow实现NNSlicer,能够支持CNN(包括ResNet)。针对ResNet10的一个样本,NNSlicer大概40秒,针对ResNet18的一个样本,大概550秒。针对batch就更快了。

为了证明NNSlicer的有效性,作者将NNSlicer应用到3个任务上:对抗防御(adversial defense),模型修剪(model pruning),模型保护(protection)。

  • 作者展示了针对一个样本计算的slice能够反映模型针对该样本的决策过程,在对抗样本计算出的slice与正常样本有明显的不同。基于NNSlicer实现的对抗输入检测器达到0.83的检出率和1.0的召回率。
  • 作者展示了NNslicer可以用来针对特定的类别定制模型,给定模型输出的一个子集。NNSlicer计算输出子集的一个slice并生成由slice中的神经元和突触组成的更小的模型,slice模型的性能显著优于其它模型修剪方法。在没有fine-tuning的情况下模型的准确率高于80%。
  • NNslicer同样可以用来进行模型保护,为了节省模型保护的开销,作者只选择模型的重要slice进行保护。通过隐藏NNSlicer选取的50%的模型参数,暴露的部分几乎能对模型提取攻击免疫。

作者的贡献如下:

  • 第一篇研究动态DNN切片的工作。
  • 实现了NNSlicer并应用到流行的神经网络架构,该工具高效可扩展。
  • 作者将NNSlicer应用到3个任务上并论证其有效性。

二.Motivation And Goal

2.1.Motivation

与传统的程序切片类似,对DNN模型进行切片也是有意义的并且能应用到许多软件工程任务上:

  • DNN模型是黑盒的,通常不易让人理解它是如何做出决策的,更别说去理解为什么DNN会预测出错了。在传统软件中,程序执行时出现与正常程序不同的控制流或者数据流可能会出现错误。所以,如果能够应用一些技巧来分析DNN的决策逻辑对软件工程是非常有帮助的。(对抗防御任务)
  • 近年来,DNN的大小及其所需的计算能力迅速增长,因此工程师,研究者们非常希望在不牺牲太多精度的情况下减小DNN的大小以提高效率。模型修剪(去除一些神经元和突触)是应用最广泛的技术之一。然而,如何删减模型(即删除哪些神经元和突触)是一个关键问题,因为谁都不想删除可能导致严重性能下降的关键结构。决定修剪哪些神经元和突触与计算程序切片(slice)非常相似。
  • 随着模型在不同组织间交易和共享,模型保护(即防止模型被盗)的需求日益增加。各种技术,如同态加密和硬件enclave可用于保护模型,但保护通常会导致性能下降。 一个实用的解决方案是保护模型的一部分,而不是整个模型。因此,将DNN划分为重要和不重要的slice可能是有益的,因为可以将有限的保护资源分配给更重要的slice。

这些任务之间的相似之处在于需要找到在DNN决策过程中更重要的神经元和突触子集,这是作者的目标。

2.2.Problem Formulation

这里定义了一些符号和概念并形式化描述了DNN slice的目标

这里2个核心概念:

  • 神经元(neuron):一个神经元 nnn 表示一个算术运算符,它接收一个或多个数值输入进行算术运算产生一个数值输出。只要对应的算术运算执行了,就称 nnn 被激活了, 输出 yyy 被称为激活值。一个神经元连接有多个突触 s1,...,sks_1, ..., s_ks1​,...,sk​,对应权重为 w1,...,wkw_1, ..., w_kw1​,...,wk​。
  • 突触(synapse):每一个突触 sis_isi​ 会对它的前置神经元 xix_ixi​ 的激活值用其权重 wiw_iwi​ 进行缩放( vxi⋅wiv_{x_i} \cdot w_ivxi​​⋅wi​)并输入到下一个神经元 nnn 中。相应的, nnn 的激活值会通过相应突触的缩放输入到后置神经元。

最后一层的神经元没有后置神经元,其输出激活值就是整个DNN的输出。现代的DNN模型都可被视为神经元和突触的集合:

  • 一个将长度20的输入映射为10输出的全连接层可视为10个神经元,每一个神经元连接20个突触并对20个输入进行相加操作
  • 一个卷积层中 16×3×3×3216 \times 3 \times 3 \times 3216×3×3×32 的滤波器,可以被视为32个神经元,每个神经元连接144个突触并进行相加运算。
  • 一个ReLU可以视为只连接一个突触的神经元。

在一个样本的决策过程中,一个神经元可能会被不同的输入激活多次,比如卷积层中,一个卷积神经元要不停的在输入样本不同的地方进行卷积操作,这样这一个神经元就进行了多次运算。

基于神经元和突触,作者定义了以下符号:

符号 含义
M=(N,S)M = (N, S)M=(N,S) 由神经元集合 NNN 和突触集合 SSS 组成的模型 MMM
n,yn, yn,y 神经元 nnn 和其激活值 yyy
s,x,ws, x, ws,x,w 突触 sss 和其输入值 xxx 和权重 www
I,ξI, \xiI,ξ 输入数据集 III,以及样本 ξ∈I\xi \in Iξ∈I
O,oO, oO,o 输出神经元集合 OOO 以及输出神经元 o∈Oo \in Oo∈O
C,MCC, M^CC,MC 切片标准 CCC 和对应的模型切片 MC=(NC,SC)M^C= (N^C,S^C)MC=(NC,SC), NC⊂NN^C \subset NNC⊂N, SC⊂SS^C \subset SSC⊂S
CONTRIBCONTRIBCONTRIB 某一个神经元或突触的累积贡献——对切片标准的贡献
contribcontribcontrib 某一个神经元或突触的局部贡献——在一次运算中产生的贡献
θ\thetaθ 控制切片指质量的超参数

2.3.Challenges

DNN模型切片面临3大挑战

  • 理解每个神经元的行为:与传统软件由程序员定义指令,函数不同。模型突触的权重是通过学习获得的,每一个神经元只是一小个building block,它的功能很难衡量。但是,为了计算slice,必须区分每个神经元的行为。
  • 量化每个神经元的贡献:传统软件中,每个指令对切片标准的贡献都是二值问题,影响了或者没有影响切片标准对应的指令。而DNN模型中所有的神经元对切片标准对应的输出神经元或多或少产生影响,很难量化每个神经元的贡献程度。
  • 处理大模型:现在的模型通常包括数以万计的神经元,分析这种规模的模型通常需要高效率算法,如何利用现有计算资源加速分析是一个挑战性问题。

三.NNSlicer

作者提出NNSlicer来解决上述问题,前面提到NNSlicer包括3阶段:profiling , forward analysis, backward analysis。

3.1.Approach Overview

流程大概如下图所示:

左上部分对应模型初始部分,边的值代表突触的权重。在profiling阶段,作者将训练集中所有样本输入到模型中,每个样本都会在模型每个神经元留下激活值,作者针对每个神经元记录下所有样本对应该神经元的激活值,并求平均作为神经元的行为标准(behavioral standard ),在下图右上部分,每个神经元平均值为0(为了从简)。在forward analysis 阶段,作者针对每个感兴趣的样本开始求该样本对应的slice,首先将某一个感兴趣的样本输入模型,将该样本在每个神经元留下的激活值与profiling阶段计算的神经元行为标准的差值作为神经元对样本的反应(the neuron reaction to the input sample)。在backward analysis阶段,作者从切片标准定义的输出神经元出发,迭代地计算前置神经元和突触的贡献,红色突出部分就是最后求得的slice。

3.2.Profiling and Forward Analysis

给定样本 ξ\xiξ,通过模型 MMM 时对神经元 nnn 的激活值记为 yn(ξ)y^n(\xi)yn(ξ)。如果 nnn 被激活了 mmm 次(CNN的卷积运算需要很多次)那么 yn(ξ)=1m∑i=1myin(ξ)y^n(\xi) = \frac{1}{m} \sum\limits_{i = 1}^m y^n_i(\xi)yn(ξ)=m1​i=1∑m​yin​(ξ) 。

在profiling阶段,数据集 DDD 针对神经元 nnn 的平均激活值 yn(D)‾=∑ξ∈Dyn(ξ)∣D∣\overline{y^n(D)} = \frac{\sum_{\xi \in D} y^n(\xi)}{|D|}yn(D)​=∣D∣∑ξ∈D​yn(ξ)​。 yn(D)‾\overline{y^n(D)}yn(D)​ 则会作为 nnn 的行为标准, 它不依赖于特定输入,所以计算一次就够了。

在forward analysis阶段,神经元 nnn 针对样本 ξ\xiξ 的反应(reaction)Δyn(ξ)\Delta y^n(\xi)Δyn(ξ) 计算为 Δyn(ξ)=yn(ξ)−yn(D)‾\Delta y^n(\xi) = y^n(\xi) - \overline{y^n(D)}Δyn(ξ)=yn(ξ)−yn(D)​。Δyn(ξ)\Delta y^n(\xi)Δyn(ξ) 为正值则表示 nnn 对 ξ\xiξ 的反应比较积极,反之亦然。绝对值 ∣Δyn(ξ)∣|\Delta y^n(\xi)|∣Δyn(ξ)∣ 越大表示 nnn 对 ξ\xiξ 更敏感。比如,在图片分类任务中,输出神经元中检测猫的神经元对猫的图片相比卡车图片会更敏感和积极。

3.3.Backward Analysis and Slice Extraction

backward analysis 阶段就是要计算每个神经元和突触针对符合切片标准的输出部分的贡献。forward analysis阶段计算的神经元反应还不能够与贡献等价。比如,对猫反应更敏感的神经元对卡车输出部分贡献度更小。为了计算贡献,作者引入了反向数据流分析。

这里每个神经元 nnn 的贡献值用 CONTRIBnCONTRIB_nCONTRIBn​ 表示,计算算法如下所示,算法输出包括感兴趣的神经元集合 OOO.


假设一个神经元 nnn 有 kkk 个突触 {s1,...,sk}\{s_1, ..., s_k\}{s1​,...,sk​} 连接到 kkk 个前置神经元 {n1,...,nk}\{n_1, ..., n_k\}{n1​,...,nk​}。yn=∑i=1kwi.yniy^n = \sum\limits_{i = 1}^k w_i.y^{n_i}yn=i=1∑k​wi​.yni​,nin_ini​ 和 sis_isi​ 的局部贡献(local contribution)contribi=CONRTIBn.Δyn.wi.Δynicontrib_i = CONRTIB_n . \Delta y^n . w_i . \Delta y^{n_i}contribi​=CONRTIBn​.Δyn.wi​.Δyni​。

之后,nin_ini​ 和 sis_isi​ 的累计贡献更新为:
CONTRIBni+=sign(contribi)CONTRIB_{n_i} += sign(contrib_i) CONTRIBni​​+=sign(contribi​)

CONTRIBsi+=sign(contribi)CONTRIB_{s_i} += sign(contrib_i) CONTRIBsi​​+=sign(contribi​)

可以看到,整个网络的 CONTRIBCONTRIBCONTRIB 计算是从后向前计算的。

作者考虑到的神经元运算符如下:

但是,为所有神经元计算更新贡献是非常耗时的,作者在计算每个前置神经元的局部贡献 contribcontribcontrib 之后按绝对值大小排序,对神经元 nnn 的影响小于 θ\thetaθ 的神经元被排除, θ\thetaθ 是可调参数。

经过backward analysis后可以得到 MC=(NC,SC)M^C= (N^C,S^C)MC=(NC,SC),其中 NCN^CNC 和 SCS^CSC 由非零贡献的突触和神经元组成。

四.Applications

应用到的任务包括对抗防御,模型修剪和模型保护,对比的state-of-art方法是EffectivePath。

4.1.Adversarial Defense

对抗样本是精心构造的能导致模型预测出错的样本,它们通常是对正常样本添加一个小的扰动获得,人类通常察觉不到。所以,对抗防御在AI和SE(软工)领域成为了讨论热点,为了解决这个问题,有的人试图通过训练或者添加最新架构让模型更鲁棒,有的人另辟蹊径:对抗输入检测,一旦检测到可疑输入,模型停止服务。作者则讨论了NNSlicer在对抗输入检测中的应用。

NNSlicer针对一个样本计算出的slice可以视为该样本决策过程的一个抽象,通常情况上来说,对抗样本和正常样本的slice会有明显不同。所以,通过对大量正常样本的slice的学习,人们可以理解DNN对样本的决策过程。所以,当一个新样本的slice和正常样本明显不同,那么它很有可能是对抗样本。

假定:

  • MMM 是给定DNN模型。
  • ξ\xiξ 是输入样本。
  • M(ξ)M(\xi)M(ξ) 是 MMM 预测的标签。
  • C=(ξ,M(ξ))C = (\xi, M(\xi))C=(ξ,M(ξ)) 是切片标准,意思是针对 ξ\xiξ 计算输出神经元对应标签 M(ξ)M(\xi)M(ξ) 部分的slice。
  • MξM_\xiMξ​ 为 CCC 对应的slice。

作者训练一个slice分类器 FFF,用来对样本 ξ\xiξ 对应的slice进行分类。FFF 在正常样本进行训练,目的是捕获slice与其类别的对应关系。如果 F(Mξ)≠M(ξ)F(M_\xi) \neq M(\xi)F(Mξ​)​=M(ξ),那么 ξ\xiξ 很有可能是对抗样本。这里 FFF 用到的是决策树模型。

应用NNSlicer到对抗防御的好处如下:

  • NNSlicer不需要修改或者重新训练原始模型。
  • NNSlicer可以扩展以支持大型的DNN模型,很多现有的方法只能支持小模型。
  • NNSlicer只需要正常的样本数据就可以防御,很多现有方法需要正常和对抗样本来进行防御。因为对抗样本总能推成出新,所以NNSlicer是一个更加现实的选项。

在实验评估阶段作者对比的是EffectivePath和FeatureMap。应用到ResNet10模型和CIFAR-10数据集上(32×3232 \times 3232×32 size)。所有的分类器用10000个正常样本训练。

作者在17种攻击上测试NNSlicer和2个baseline方法。包括gradient-based attacks, score-based attacks, and decision-based attacks。具体来说包括FGSM,Deepfool,JSMA,PGD等等。对每一种攻击方法,作者随机选择500个正常样本生成对抗样本,这些对抗样本成功误导了模型,作者将这些对抗样本和对应正常样本输入到对抗样本检测器中,并用 precision, recall 和 F1来衡量。

4.2.Network Simplification and Pruning

作者这里通过修剪无关紧要的神经元来获得更轻量级的模型,假定 MMM 是一个多分类模型。这里设定 C=(I,O)C = (I, O)C=(I,O),其中 OOO 是感兴趣的目标类别,之后修剪得到的模型在目标类别依旧有好的效果。

这里 , OTO^TOT 是感兴趣的类别。 ITI^TIT 是这些类别对应的样本集合,rrr 是修剪率。CONTRIBsTCONTRIB^T_sCONTRIBsT​ 是突触 sss 对应的贡献值,对每一层网络,作者对突触按贡献值升序排序,前面比重 rrr 的突触会被修剪,如果一个神经元对应的突触都被修剪了,那么该神经元也被修剪。

下表中NNSlicer all表示 OTO^TOT 设置为10个类别,测试的时候只包含目标类别。Weight是基于突触绝对值的修剪办法,绝对值小的突触会被修剪。Channel是基于平均相连权重的修剪方法。


在修剪率变大之后,作者开始对修剪后的模型进行fine-tuning,即在10000个样本上进行1个epoch的训练。下标展现的是模型在2个目标类别集合上fine-tuning之后的性能。

NNSlicer以牺牲模型在非目标类别上的性能为代价保存了模型在目标类别上的性能,对比实验中,作者发现模型slice在非目标类别上性能大打折扣。它意味这模型基于类别分解模型(10分类变4分类)。

4.3.Model Protection

现有的模型保护措施通常是同态加密或者在可信环境下执行模型。所有的计算在加密模式下进行,然而,保护的计算通常量非常大。CryptoNets通常花了300秒在MNIST上执行一个模型。为了减少模型防护的开销,作者选择只防护重要部分。

在评估时,作者假定模型攻击者有完整训练数据集,攻击者数据集大小叫做budget。作者只保护模型针对指定类别的部分。下图中acc越低说明模型保护措施越到位。

五.Limitations And Discussion

  • DNN结构:作者只考虑了CNN模型中常用的五种操作,而其他体系结构中使用的一些操作不包括在内,如递归神经网络(RNN)和图卷积网络(GCN)。
  • 规模:由于时间有限,作者没有在非常大的模型和数据集上进行实验。对于具有数百万权重的大型DNN模型,NNSlicer大约需要10分钟来计算输入样本的切片。在一台机器上为如此大型的模型构建对抗性防御可能需要几天的时间。尽管这个过程很慢,特别是在实验室实验中,但考虑到公司通常会在大型集群上训练一个模型几个星期,作者认为这在实践中是可以接受的。
  • 切片标准:作者主要讨论仅涉及输出神经元的切片标准,但对中间神经元的切片也可能是有意义的(类似于在传统程序中检查中间变量)。这种灵活的标准定义可以实现新的应用,例如,以更精细的粒度解释或调试神经网络。
  • 更多应用:除了文中提到的3种应用,其它应用也是有意思的。比如,将不同的slice组成一个新的模型是否有可能,这样的话,DNN模型的训练方式可能发生改变。还有,NNSlicer可以如何应用到模型诊断和调试。
  • 其它切片技术:NNSlicer依赖输入计算slice,其它slice技术也值得探索,比如静态slice,条件slice也能帮助开发者理解DNN模型在什么情况下是脆弱的。

六.参考文献

[1] Zhang Z , Li Y , Guo Y , et al. Dynamic Slicing for Deep Neural Networks[J]. ACM, 2020.

程序分析-Slice,深度神经网络动态slice相关推荐

  1. 一步一步分析讲解深度神经网络基础-Convolutional Neural Network

    Convolutional Neural Network 参考http://cs231n.github.io/convolutional-networks/ history Convolutional ...

  2. 什么是代理模式?代理模式有什么用?通过一个小程序分析静态代理和动态代理。自己简单实现动态代理。JDK动态代理和CGLIB动态代理的区别。

    1. 代理模式有什么用 ①功能增强,在实现目标功能的基础上,又增加了额外功能.就像生活中的中介一样,他跟两边客户会有私下的交流. ②控制访问,代理不让用户直接和目标接触.就像中间商一样,他们不会让我们 ...

  3. 深度神经网络压缩与加速总结

    深度神经网络压缩与加速综述 1. 深度神经网络压缩与加速的任务 2. 模型压缩与加速方法 (1) 参数剪枝 (2) 参数共享 (3) 低秩分解 (4) 紧性滤波设计 (5) 知识蒸馏 3. 深度神经网 ...

  4. 程序崩溃 分析工具_程序分析工具| 软件工程

    程序崩溃 分析工具 A program analysis tool implies an automatic tool that takes the source code or the execut ...

  5. 2021-IEEE论文-深度神经网络在文档图像表格识别中的应用现状及性能分析

    2021年5月12日收到, 2021年6月4日接受, 出版日期2021年6月9日, 当前版本日期2021年6月24日. 原论文下载地址 摘要 - Abstract   表格识别的第一阶段是检测文档中的 ...

  6. 深度神经网络对人工智能推动的发展评述与应用分析

    大数据人工智能培训? 大数据人工智能培训推荐选择[达内教育].大数据人工智能需要学习的东西如下:1.数学基础.数学基础知识蕴含着处理智能问题的基本思想与方法,也是理解复杂算法的必备要素. 这一模块覆盖 ...

  7. 专题:深度神经网络基本问题的原理详细分析和推导

    文章目录 **写在最前面** **1 神经网络算法的直观了解** **1.1 神经网络过程描述**: **1.2 神经网络相关的几个问题** **1.2.1 表征假设和激活函数** **1.2.2 结 ...

  8. 普林斯顿大学英伟达Facebook提出基于深度神经网络的全动态推理,助力轻量级网络!...

    关注公众号,发现CV技术之美 ▊ 写在前面 深层神经网络是一种功能强大.应用广泛的模型,能够多级抽象提取任务相关信息.然而,这种成功通常是以计算成本.高内存带宽和长推理延迟为代价的,这使得它们无法部署 ...

  9. 【MATLAB深度学习工具箱】学习笔记--体脂估计算例再分析:拟合神经网络fitnet里面的函数】

    介绍 上一篇 [MATLAB深度学习工具箱]学习笔记--体脂估计算例再分析:拟合神经网络fitnet里面的数据结构]_bear_miao的博客-CSDN博客原文链接如下[MATLAB深度学习工具箱]学 ...

最新文章

  1. python全局变量有缩进吗_Python全局变量和局部变量的问题 400 请求报错 -问答-阿里云开发者社区-阿里云...
  2. SAP QM中阶之Reference Operation Set 的使用
  3. 多元分布和狄利克雷分布
  4. 【体验干货】产品经理必知:产品体验报告如何写的全而精
  5. docker 虚悬镜像 ( 悬空镜像 ) :镜像没有仓库名或没有标签
  6. 白领体检异常率连年走高,这5本书教你怎样科学养生
  7. VC6.0创建文件夹
  8. 差别对待!双一流高校只给2020级博士涨“工资”,不顾其他年级引争议
  9. 使用vue-pdf-signature实现pdf预览
  10. 第三方支付接口开发原理
  11. 实现数据结构中的栈---后进先出LIFO
  12. html5光线传感器,光线传感器是什么 光线传感器分类
  13. Amcharts4使用笔记
  14. 海豚湾--纪录日本人如何杀戮海豚的
  15. linux系统fasta程序,快速计算fasta序列长度的方法
  16. 数据结构与算法-二叉树
  17. 怎么做SEO——页面权重计算公式
  18. excel日期怎么间隔填充_系列或相同日期的自动填充Excel日期
  19. 咖说 | 「延展与重构」数字艺术的新可能
  20. 【狂神说】CSS学习笔记

热门文章

  1. 一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
  2. 2019年 CCPC-Wannafly Winter Camp 总结及感悟
  3. Linux文件目录层级结构
  4. snmp trap安装配置
  5. MySQL的下载与安装(超详细)
  6. Java length() 方法、length 属性和 size() 方法有什么区别?
  7. 云图说丨初识云速建站服务
  8. 各种后门攻击以及防御复现
  9. 红米note4出厂系统版本_红米 Note 4 开始接收 MIUI 10 国际稳定版系统更新
  10. easyui 复选框 onClickRow事件与onSelect事件与onCheck事件