编辑:Happy
首发:AIWalker

paper: https://arxiv.org/abs/2105.01883
code: https://github.com/DingXiaoH/RepMLP(核心code已开源)

本文是清华大学&旷视科技在结构重参数领域继ACNet、RepVGG、DBB之后又一突破:RepMLP,它将重参数卷积与全连接层进行了巧妙地衔接,同时利用了全连接层的全局建模、位置感知特性与卷积的局部结构提取能力。在ImageNet分类、人脸识别以及语义分割等任务(无论是否具有平移不变性)上均能涨点。此外,相比标准卷积,RepMLP的一个优势:在大幅增加参数的同时不会造成推理速度的显著降低。比如,从RepMLP-Res50-g8/16到RepMLP-Res50-g4/8,参数量提升47%,但FLOPs仅提升3.6%,推理速度仅下降2.2%。

Abstract

本文提出一种多层感知器风格的神经网络构建模块RepMLP用于图像识别,它有一系列的全连接层构成。相比卷积层,全连接层更为高效,可以进行更好的长期依赖与位置模式建模,但在局部结构提取方面较差,因此通常不太适合于图像识别。

本文提出一种结构重参数技术,它为全连接层添加了局部先验信息以使其可以进行强有力的图像识别。具体来说:在训练阶段,我们在RepMLP内部构建了卷积层,而在推理阶段,我们将这些卷积层合并到全连接层内。

在CIFAR数据集上,简简单单的MLP模型即可取得与CNN非常接近的性能。通过将RepMLP插入到现有CNN中,我们在ImageNet数据集上提升ResNets模型精度达1.8%,在人脸识别任务上提升2.9%,在Cityscapes提升2.3%mIoU精度且具有更低的FLOPs。

该发现说明:全连接层的全局表达、位置感知能力与卷积的局部结构提取能力的组合能够以更快的速度在平移不变任务(比如语义分割)、图像对齐+位置模式相关任务(比如人脸识别)上的性能。

本文主要贡献包含以下几点:

  • 提出利用全连接层的全局建模、位置感知能力,并为其插上局部先验的翅膀,使其适用于图像识别任务;
  • 提出一种简单的、平台不可知的、可微分算法用于将并行卷积、BN合并到全连接层中,使其具有局部先验且不造成任何推理耗时增加;
  • 提出一种高效模块RepMLP,并在多个视觉任务上证实了其有效性。

RepMLP

训练阶段的RepMLP(见下图)由三部分构成:Global Perceptron、Partition Perceptron、Local Perceptron。接下来,我们将针对所提RepMLP进行详细介绍,同时表明如何如何将训练阶段的RepMLP转换为推理阶段的全连接层。

Formulation

我们假设特征图表示为M∈RN×C×H×WM \in R^{N \times C \times H \times W}M∈RN×C×H×W,我们采用F和W表示卷积与全连接层的核参数。为简单起见,本文采用了pytroch风格的数据排布与伪代码风格,比如K×KK \times KK×K卷积处理的数据流表示如下:
M(out)=CONV(M(in),F,p)M^{(out)} = CONV(M^{(in)}, F, p) M(out)=CONV(M(in),F,p)
其中M(out)∈RN×O×H′×W′M^{(out)} \in R^{N \times O \times H^{'} \times W^{'}}M(out)∈RN×O×H′×W′表示输出特征,O表示输出通道数,p表示pad的像素数量,F∈RO×C×K×KF \in R^{O \times C \times K \times K}F∈RO×C×K×K表示卷积核(暂时假设groups=1)。为简单起见,我们还假设H′=H,W′=W,stride=1,p=⌊K2⌋H^{'} = H, W^{'} = W, stride=1, p=\lfloor \frac{K}{2}\rfloorH′=H,W′=W,stride=1,p=⌊2K​⌋。

对于全连接层,假设P和Q为输入与输出维度,V(in)∈RN×P,V(out)∈RN×QV^{(in)} \in R^{N \times P}, V^{(out)} \in R^{N \times Q}V(in)∈RN×P,V(out)∈RN×Q分别表示输入与输出,W∈RQ×PW \in R^{Q \times P}W∈RQ×P表示全连接层核,计算公式如下:
V(out)=MMUL(V(in),W)=V(in)⋅WTV^{(out)} = MMUL(V^{(in)}, W) = V^{(in)} \cdot W^T V(out)=MMUL(V(in),W)=V(in)⋅WT
接下来我们聚焦于全连接层,假设FC不会改变输入输出分辨率,即H′=H,W′=WH^{'} = H, W^{'} = WH′=H,W′=W。我们采用RS(reshape)表示仅仅改变张量形变而不会改变内存数据顺序的操作,它是一种cost-free操作。输入首先会被平整为N个长度为CHWCHWCHW的向量,即V(in)=RS(M(in),(N,CHW))V^{(in)} = RS(M^{(in)}, (N,CHW))V(in)=RS(M(in),(N,CHW)),然后乘以核W(OHW,CHW)W(OHW, CHW)W(OHW,CHW)得到输出V(out)(N,OHW)V^{(out)}(N,OHW)V(out)(N,OHW),最后再RS为M(out)(N.O,H,W)M^{(out)(N.O,H,W)}M(out)(N.O,H,W)。为更好的阅读,在歧义的情况下我们忽略RS而简写为:
M(out)=MMUL(M(in),W)M^{(out)} = MMUL(M^{(in)}, W) M(out)=MMUL(M(in),W)
这种形式的全连接层无法充分利用图像的局部信息(因其忽视了位置信息)。

Components of RepMLP

我们并未采用上述形式的全连接层,因为它不仅缺乏局部先验,而且会导致巨量参数:COH2H2COH^2H^2COH2H2。以通用配置为例,H=W=128,C=O=128H=W=128,C=O=128H=W=128,C=O=128,此时FC的参数量高达10G,这是完全不可接受的。为降低参数量,我们提出了Global PerceptronPartition Peceptron分别进行分区间与分区内依赖性建模。

Global Perceptron 它将进行特征拆分且不同分区特征进行参数共享。比如,(N,C,14,14)(N,C,14,14)(N,C,14,14)将被拆分为(4N,C,7,7)(4N,C,7,7)(4N,C,7,7),我们将每个7×77\times 77×7视作一个分区。假设h,wh,wh,w表示期望分区的高和宽,输入M∈RN×C×H×WM\in R^{N\times C \times H \times W}M∈RN×C×H×W首先reshape为(N,C,Hh,h,Ww,w)(N,C,\frac{H}{h},h,\frac{W}{w},w)(N,C,hH​,h,wW​,w),然后对坐标轴顺序进行调整N,Hh,Ww,C,h,wN, \frac{H}{h}, \frac{W}{w}, C, h, wN,hH​,wW​,C,h,w,最后再reshape为(NHWhw,C,h,w)(\frac{NHW}{hw}, C, h,w)(hwNHW​,C,h,w)。通过这种方式,参数量可以从COH2W2COH^2W^2COH2W2下降到COh2w2COh^2w^2COh2w2。

然而,拆分将会打破相同通道不同分区之间的相关性。也就是说,每个分区将会进行独立建模,而忽视了位置上的相关性。为对每个分区添加相关性,Global Perceptron采用了以下几个操作:

  • 对每个分区采用均值池化得到一个像素;
  • 将上述所得送入到BN、两层MLP;
  • 将上述所得进行reshape并与分区特征相加。

完成Global Perceptron操作后,将所得特征送入到后续的Partition PerceptronLocal Perceptron

Partition Perceptron 它包含FC与BN层,并以分区特征作为输入。前述输出(NHWhw,C,h,w)(\frac{NHW}{hw}, C, h,w)(hwNHW​,C,h,w)将通过reshape、re-arrange、reshape等操作变为N,O,H,WN,O,H,WN,O,H,W。我们进一步采用组卷及降低FC3的参数量,定义如下:
M(out)=gCONV(M(in),F,g,p),F∈RO×Cg×K×KM^{(out)} = gCONV(M^{(in)}, F, g, p), F\in R^{O \times \frac{C}{g}\times K \times K} M(out)=gCONV(M(in),F,g,p),F∈RO×gC​×K×K
类似的,组形式的FC核W∈RQ×PgW \in R^{Q\times \frac{P}{g}}W∈RQ×gP​,此时参数量可以减少g倍。尽管这种形式的FC不被某些框架(如Pytorch)支持,但我们可以采用1×11\times 11×1卷积代替实现。它的实现包含三个步骤:

  • 将V(in)V^{(in)}V(in)reshape为空域尺寸为1×11\times 11×1的特征;
  • 采用groups=g的1×11\times 11×1卷积;
  • 将上述所得特征reshape为V(out)V^{(out)}V(out)。

整个过程定义如下:
M′=RS(V(in),(N,P,1,1))R′=RS(W,(Q,Pg,1,1))gMMUL(V(in),W,g)=RS(gCONV(M′,F′,g,0),(N,Q))M^{'} = RS(V^{(in)}, (N, P, 1, 1)) \\ R^{'} = RS(W, (Q, \frac{P}{g}, 1, 1)) \\ gMMUL(V^{(in)}, W, g) = RS(gCONV(M^{'}, F^{'},g, 0), (N,Q)) M′=RS(V(in),(N,P,1,1))R′=RS(W,(Q,gP​,1,1))gMMUL(V(in),W,g)=RS(gCONV(M′,F′,g,0),(N,Q))
Local Perceptron 它将分区特征经由几个卷积进行处理。前面的图示Fig1给出了h,w>7,K=1,3,5,7h,w>7, K=1,3,5,7h,w>7,K=1,3,5,7的示意图。理论上,仅有的约束为:核尺寸K≤h,wK \le h, wK≤h,w(因为采用比分辨率更大的核没有意义),但是我们参考ConvNet的常规操作仅采用了奇数核。为简单起见,我们采用K×KK\times KK×K这种方框形式,其他1×3,3×51\times3, 3\times51×3,3×5同样有效。所有卷积分支的输出与Partition perceptron的输出相加作为最终的输出。

A Simple, Platform-agnostic, Differentiable Algorithm for Merging Conv into FC

在将RePMLP转换为三个FC之前,我们首先看一下如何将卷积合并到FC。假设FC核W(i)(Ohw,Chw)W^{(i)} (Ohw, Chw)W(i)(Ohw,Chw),卷积核F(O,C,K,K)(K≤h,w)F(O,C,K,K)(K \le h, w)F(O,C,K,K)(K≤h,w),我们期望构建W′W^{'}W′满足:
MMUL(M(in),W′)=MMUL(M(in),W(1))+CONV(M(in),F,p)MMUL(M^{(in)}, W^{'}) = MMUL(M^{(in)}, W^{(1)}) + CONV(M^{(in)}, F, p) MMUL(M(in),W′)=MMUL(M(in),W(1))+CONV(M(in),F,p)
我们注意到:对任意与W(1)W^{(1)}W(1)同形状的核W(2)W^{(2)}W(2),MMUL的加法特征满足:
MMUL(M(in),W(1))+MMUL(M(in),W(2))=MMUL(M(in),W(1)+W(2))MMUL(M^{(in)}, W^{(1)}) + MMUL(M^{(in)}, W^{(2)}) = MMUL(M^{(in)}, W^{(1)} + W^{(2)}) MMUL(M(in),W(1))+MMUL(M(in),W(2))=MMUL(M(in),W(1)+W(2))
因此,只要可以构建与W(1)W^{(1)}W(1)同形状的WF,pW^{F,p}WF,p,我们就可以将F合并到W(1)W^{(1)}W(1)并满足:
MMUL(M(in),WF,p)=CONV(M(in),F,p)MMUL(M^{(in)}, W^{F,p}) = CONV(M^{(in)}, F, p) MMUL(M(in),WF,p)=CONV(M(in),F,p)
很明显,W(F,p)W^{(F,p)}W(F,p)一定存在(因为卷积可视作稀疏版FC)。考虑到不同平台对于卷积的加速策略、内存排布等方式的不同,A平台的矩阵构建可能并不适合于B平台。我们提出了一种简单的、平台无关解决方案

正如前面所说,对于任意输入M(in)M^{(in)}M(in),卷积核F,存在一个FC核W(F,p)W^{(F,p)}W(F,p)满足:
M(out)=CONV(M(in),F,p)=MMUL(M(in),W(F,p))M^{(out)} = CONV(M^{(in)}, F, p) = MMUL(M^{(in)}, W^{(F,p)}) M(out)=CONV(M(in),F,p)=MMUL(M(in),W(F,p))
采用矩阵乘形式,此时有:
V(out)=V(in)⋅W(F,p)TV^{(out)} = V^{(in)} \cdot W^{(F,p)_T} V(out)=V(in)⋅W(F,p)T​
我们对齐插入恒等矩阵I(Chw,Chw)I(Chw, Chw)I(Chw,Chw),并采用如下定律:
V(out)=V(in)⋅(I⋅W(F,p)T)V^{(out)} = V^{(in)} \cdot (I \cdot W^{(F,p)_T}) V(out)=V(in)⋅(I⋅W(F,p)T​)
注意:W(F,p)W^{(F,p)}W(F,p)是由F构建得到,I⋅W(F,p)TI\cdot W^{(F,p)_T}I⋅W(F,p)T​表示对特征MIM^{I}MI进行卷积。通过显示RS,此时有:
M(I)=RS(I,(Chw,C,h,w))I⋅W(F,p)T=CONV(M(I),F,p)V(out)=Vin⋅RS(I⋅W(F,p)T,(Chw,Ohw))M^{(I)} = RS(I, (Chw, C, h, w)) \\ I \cdot W^{(F, p)_T} = CONV(M^{(I)}, F, p) \\ V^{(out)} = V^{in} \cdot RS(I \cdot W^{(F, p)_T}, (Chw, Ohw)) M(I)=RS(I,(Chw,C,h,w))I⋅W(F,p)T​=CONV(M(I),F,p)V(out)=Vin⋅RS(I⋅W(F,p)T​,(Chw,Ohw))
通过比较上述公式,我们可以得到:
W(F,p)=RS(CONV(M(I),F,p),(Chw,Ohw))TW^{(F, p)} = RS(CONV(M^{(I)}, F, p), (Chw, Ohw))^T W(F,p)=RS(CONV(M(I),F,p),(Chw,Ohw))T
该公式精确的展示了如何通过F,p构建W(F,p)W^{(F,p)}W(F,p)。简而言之,卷积核的等效FC核可以通过对恒等矩阵进行卷积并添加合适reshape得到

Converting RepMLP into Three FC Layers

为采用上述理论,我们首先需要通过等价融合方式消除BN层。假设F∈RO×Cg×K×KF \in R^{O \times \frac{C}{g}\times K \times K}F∈RO×gC​×K×K表示卷积核,μ,σ,β,γ\mu, \sigma, \beta, \gammaμ,σ,β,γ表示BN中的参数。那么两者的融合方式如下:
Fi,:,:,:′=γiσiFi,:,:,:bI′=−μiγiσi+βiF^{'}_{i,:,:,:} = \frac{\gamma_i}{\sigma_i}F_{i,:,:,:} \\ b_I^{'} = - \frac{\mu_i \gamma_i}{\sigma_i} + \beta_i Fi,:,:,:′​=σi​γi​​Fi,:,:,:​bI′​=−σi​μi​γi​​+βi​
1D形式BN于FC3的融合采用类似形式可得:W^∈ROhw×Chwg,b^∈ROhw\hat{W} \in R^{Ohw \times \frac{Chw}{g}}, \hat{b} \in R^{Ohw}W^∈ROhw×gChw​,b^∈ROhw。通过上述一系列的表换,我们就可以得到一个FC核于一个偏置向量,即为推理时的FC的参数。

Experiments

Pure MLP and Ablation Studies

我们首先在CIFAR10上验证RepMLP的有效性,测试的网络结构见下图。

在训练阶段,我们采用了标准数据增广(padding、RandomCrop、RandomFlip),batch=128,cosine学习率衰减机制,训练了100epoch。结果见下表。

从上表可以看到:

  • 纯MLP模型能够以52.8M FLPs达到91.11%的精度,不过该结果弱于Wide ConvNet;
  • 转换前的计算量优于包含卷积与BN,其计算量非常大,这说明了结构重参数的重要性;
  • 移除Local Perceptron,模型精度下降8.5%,说明了局部先验的重要性;
  • 移除Gloabl Perceptron,模型精度下降1.5%,说明了全局建模的重要性;
  • 替换FC3为卷积,尽管其感受野更大,但仍造成精度下降3.5.%,说明了FC要比卷积更有力;
  • 采用RepMLP替换F实验的卷积,优于没有全局感知,精度仍出现了下降。

RepMLP-ResNet for ImageNet Classification

我们采用ResNet作为基线模型并用于评估RepMLP作为传统ConvNet构建模型的性能。模块定义见上图。

上面两个表给出了不同阶段替换时的性能对比,从中可以看到:

  • 当仅仅对c4进行替换时,r=8时RepMLP-Res50具有比ResNet50更少的参数量,更快的推理速度(快10%);
  • Table2的前两行说明:当前深度学习框架对于组形式1×11\times11×1卷积支持程度并不够好,参数量提升59%,但推理速度仅下降了0.7%;更进一步的组形式1×11\times 11×1优化有可能使得RepMLP更高效。
  • 采用RepMLP模块替换ResNet中的模块会导致轻微的速度下降,但精度出现了显著提升。比如,仅仅采用RepMLP替换c4即可带来0.94%精度提升,参数量仅增加5M;c3+c4的替换可以取得最佳的均衡。

上表对比了更高输入分辨率下的性能对比。从中可以看到:

  • 相比同参数量的传统ConvNet,RepMLP-Res50的计算量更低、推理速度更快。比如,相比224×224224\times 224224×224输入的ResNet101,RepMLP-Res50仅需50%FLOPs,更少的参数量,推理速度快50%,即可取得同等精度;当输入分辨率为320×320320\times 320320×320时,RepMLP-Res50在精度、速度以及FLOPs方面的优势更大。
  • 提升RepMLP的参数量会导致非常轻微的速度下下降。比如,从RepMLP-Res50-g8/16到RepMLP-Res50-g4/8,参数量提升47%,但FLOPs仅提升3.6%,推理速度仅下降2.2%。这对于大型服务器的高吞吐量推理极为有用。
  • 相比Nonlocal与GC,RepMLP-Res50的推理速度几乎相同,但精度高1%;
  • 相比于GPU端低效的EfficientNet,RepMLP-Res50在速度于精度方面表现更优。

除了前述模块改进外,作者还提供了一种高速版本,其结果见上图右,性能见下表。

从上表可以看到:轻量版RepMLP取得了与原始ResNet50相当的进度,但FLOPs降低30%,推理速度快55%

Face Recognition

不同于卷积,FC不具备平移不变性性,这使得RepMLP非常适合于具有位置先验的图像(比如人脸)。因此,我们采用RepMLP在人脸识别任务上进行了有效性验证,结果见下表。

从上表可以看到:

  • 相比MobileFaceNet,FaceResNet具有更高的精度,但推理速度更慢;
  • 相比MobileFaceNet,RepMLP-FaceRes取得了4.91%的精度提升,同时推理速度快8%(尽管具有更高的FLOPs)。

Semantic Segmentation

语义分割是一种极具代表性的平移不变任务,我们在Cityscapes数据上验证RepMLP-Res50的有效性。结果见下表。

从中可以看到:

  • 相比Res-50,PSPNet+RepMLP-Res50-g4/8取得了2.31%的mIoU指标提升;
  • 尽管RepMLP方案具有更多的参数量,但其FLOPs更低,推理速度更快。

推荐阅读

  1. RepVGG|让你的ConVNet一卷到底,plain网络首次超过80%top1精度
  2. CVPR2021|“无痛涨点”的ACNet再进化,清华大学&旷视科技提出Inception类型的DBB
  3. 新坑!谷歌提出MLP-Mixer:一种无卷积、无注意力,纯MLP构成的视觉架构
  4. CVPR2021 | 动态滤波器卷积新高度!DDF:同时解决内容不可知与计算量两大缺陷
  5. 动态卷积超进化!通道融合替换注意力,减少75%参数量且性能显著提升 ICLR 2021
  6. 比CNN更强有力,港中文贾佳亚团队提出两类新型自注意力网络|CVPR2020
  7. TNT|为充分利用局部与全局结构信息,华为诺亚提出全新Transformer:TNT
  8. 金字塔Transformer,更适合稠密预测任务的Transformer骨干架构
  9. ResNet被全面超越了,是Transformer干的:依图科技开源“可大可小”T2T-ViT,轻量版优于MobileNet
  10. CNN与Transformer的强强联合!谷歌最新开源BoTNet,ImageNet达84.7%准确率

“重参数宇宙”再添新成员:RepMLP,清华大学旷视科技提出将重参数卷积嵌入到全连接层相关推荐

  1. CVPR2021|ACNet再进化,清华大学旷视科技提出Inception类型的DBB

    编辑:Happy 首发:AIWalker 原创文章,未经授权,禁止二次转载 paper: https://arxiv.org/pdf/2103.13425.pdf code: https://gith ...

  2. 阿里云ECS家族再添新成员,推出密集计算型实例规格族ic5

    去年,阿里云正式发布云服务器ECS企业级产品家族,推出面向173种企业应用场景的19款实例.适合在复杂的企业计算环境下,满足对于高性能.高可靠的计算需求. 时隔近一年,回看ECS企业级产品家族已经发展 ...

  3. CW32超低功耗家族再添新成员:32位M0+内核MCU CW32L052系列产品

    2023年2月,武汉芯源半导体超低功耗家族再添新成员--32位M0+内核MCU CW32L052系列芯片. CW32L052 是基于 eFlash 的单芯片低功耗微控制器,集成了主频高达 48MHz ...

  4. 微软高价收购动视暴雪,元宇宙乱战再添新成员

    本文概述:微软宣布以687亿美元收购动视暴雪,并根据微软官网公告显示:此次收购将加速微软游戏业务在移动.PC.游戏机和云领域的增长,并将为搭建元宇宙提供基础. 1.为什么说暴雪是一具空壳? 2.微软如 ...

  5. 湖南阿波罗智行L4级低速自动驾驶小车亮相 湖南自动驾驶“朋友圈”再添新成员

    10月16日,长沙国际会展中心,湖南阿波罗智行科技有限公司举行BOBO·GO低速自动驾驶产品推介会,由湖南湘江新区本土企业自主设计研发的首款L4级低速自动驾驶售卖小车BOBO·GO(波波购)正式亮相. ...

  6. SPECTRUM数字化仪M2p系列再添新成员--5Ms/s采样率

    近日,spectrum发布了M2p系列新成员,采样率为5MS/s的数字化仪,依然是支持1.2.4或8通道采集模式,采样精度为16bit.同时,与之对应的NETBOX系列也同时发布,支持4.8.16.2 ...

  7. 华为海思家族再添新成员:麒麟980规格亮相!!!

    上星期麒麟 710 处理器与华为 nova 3i 一起宣告,近来,海思新一代旗舰处理器麒麟 980 又有新曝光.麒麟 980 处理器依据 7 纳米制程,选用 4 个 A77 大核+4 个 A55 小核 ...

  8. 阿里云数据库再添新成员,企业级MariaDB正式开卖!

    摘要: 就在上周,刚刚结束的2018杭州云栖大会上,阿里云与MariaDB共同宣布,企业级MariaDB在阿里云正式上线. 据了解, MariaDB企业版由阿里云数据库团队与MariaDB团队联合研发 ...

  9. 腾讯混合云存储 TStor 系列再添新成员,并行存储一体机正式发布​

    ​最近国内某大型互联网公司依靠其数据优势成功上市,可见数据的重要性,而数据和存储密不可分,您真的知道自己需要更高性能存储吗? 在当今数据爆发式增长的时代,数据已经成为很多行业最重要的资源,没有之一. ...

最新文章

  1. Python-列表和元组
  2. java 导入导出txt文件_Java读取和写入txt文件
  3. 前端学习(1124):思考题
  4. 排序算法总结(四)快速排序【QUICK SORT】
  5. Mysql源码编译安装主从复制
  6. sqlserver2000下载地址
  7. 优秀实践采购团队的8个要点
  8. gvim 安装pathogen
  9. 正则表达式JS-1212
  10. em算法 图像模糊检测_基于EM算法的眼底OCT图像反卷积去模糊技术
  11. csdn竟然还有这种神器!后悔没有早点知道!超好用的csdn插件,别再犹豫了,赶快入手吧!
  12. linux CST与EDT时区互转
  13. js 防抖是什么 JavaScript防抖怎么用
  14. Jmeter分布式压力测试全过程(阿里云ECS)
  15. ROS发布静态tf变换
  16. git学习之:如何将远程代码强制拉取同步(覆盖)到本地文件夹
  17. Circos了解一下?~
  18. 淘宝滑块验证码的解决方法 和 接口
  19. 数字货币正确的交易理念——第四章:操作形态的重要意义
  20. Web开发者十大必备网站资源任你挑

热门文章

  1. back track 5 / BT5 默认用户名密码
  2. 微信小程序-实现删除指定列表项
  3. 关于二维码生成工具类简介
  4. java之TimeUnit.SECONDS.sleep()详细分析(全)
  5. 基于SpringBoot+MyBatis实现的私人影院系统
  6. Java 编译与反编译
  7. javac的命令(-Xbootclasspath、-classpath与-sourcepath等)
  8. [附源码]计算机毕业设计Python+uniapp基于Android的自来水收费系统3e359(程序+源码+LW+远程部署)
  9. Matlab修改字体方法,解决中文乱码问题
  10. 在台式电脑上完美安装Mac OS X操作系统的解决方案