自动编码(AE,DAE,CAE,SAE)器的方法介绍与简单实现(附代码)

一.目录

  • 自动编码(AE)器的简单实现

    • 一.目录
    • 二.自动编码器的发展简述
      • 2.1 自动编码器(Auto-Encoders,AE)
      • 2.2 降噪自编码(Denoising Auto-Encoders, DAE)(2008)
      • 2.3 堆叠降燥自动编码器 (Stacked Denoising Auto-Encoders, SAE)(2008)
      • 2.4 卷积自动编码器(Convolution Auto-Encoders, CAE)(2011)
      • 2.5 变分自动编码器(Variational Auto-Encoders, VAE)(Kingma, 2014)
      • 2.5 几种算法的改进点表格
    • 三. 实验
      • 3.1 传统的自动编码器实验结果

        • 模型结构与实现代码
        • 训练过程
        • 编码器输出的可视化结果
        • 说明与讨论
      • 3.2 堆叠降噪自编码器
        • 模型结构与实现代码
        • 训练过程
        • 编码器输出的可视化结果
        • 说明与讨论
      • 3.3 卷积自编码器
        • 模型结构与实现代码
        • 训练过程
        • 编码器输出的可视化结果
      • 3.4 变分自编码器
        • 模型结构与实现代码
        • 训练过程
        • 自编码器输出的可视化结果
    • 四.讨论
    • 参考文献

二.自动编码器的发展简述

2.1 自动编码器(Auto-Encoders,AE)

传统的自动编码器是一种数据的压缩算法,其算法包括编码阶段和解码阶段,且拥有对称的结构。
目前自编码器的应用主要有两个方面,第一是数据去噪,第二是为进行可视化而降维。配合适当的维度和稀疏约束,自编码器可以学习到比PCA等技术更有意思的数据投影。

传统编码器的编解码过程描述如图:

自动编码器的训练过程使用传统的基于梯度的方式进行训练。

评价:

学界评价:传统自编码器的目的是使输出与输入尽量相同,这完全可以通过学习两个恒等函数来完成,但是这样的变换没有任何意义,因为我们真正关心的是隐层表达,而不是实际输出。因此,针对自编码器的很多改进方法都是对隐层表达增加一定的约束,迫使隐层表达与输入不同。

2.2 降噪自编码(Denoising Auto-Encoders, DAE)(2008)

自编码器真正关心的是隐藏层的特征表达,一个好的表达能够捕获输入信号的稳定结构,以该目的为出发出现了降噪自动编码器。降噪自动编码器,首先对干净的输入信号加入噪声产生一个受损的信号。然后将受损信号送入传统的自动编码器中,使其重建回原来的无损信号。

降噪自编码器的编解码过程描述如图:

其中过程可以使用如下公式描述:

降噪自编码器与传统的自动编码器的主要区别在于:

  1. 降噪自编码器通过人为的增加噪声使模型获得鲁棒性的特征表达
  2. 避免使隐层单元学习一个传统自编码器中没有意义的恒等函数

评价:

学界评价:降噪自编码器通过对输入信号人为地进行损坏,主要是为了达到两个目的,首先是为了避免使隐层单元学习一个传统自编码器中没有实际意义的恒等函数,其次就是为了使隐层单元可以学习到一个更加具有鲁棒性的特征表达。
降噪自编码器最大的优点在于,重建信号对输入中的噪声具有一定的鲁棒性,而最大的缺陷在于每次进行网络训练之前,都需要对干净输入信号人为地添加噪声,以获得它的损坏信号,这无形中就增加了该模型的处理时间。

2.3 堆叠降燥自动编码器 (Stacked Denoising Auto-Encoders, SAE)(2008)

参考深度置信网络的方法,将降噪自编码器进行堆叠可以构造成堆叠降噪自编码器。与自编码器和降噪自编码器不同,堆叠降噪自编码器的提出是为了解决。

降噪自编码器的编解码过程描述如图:

每个子问题的训练过程与降噪自编码器自编码器相同.

整个堆叠降噪自编码器的训练过程如下:

为解码的权重和偏置。

堆叠降噪自编码器与降噪自编码器的区别在于:

  1. 堆叠降噪自编码器采用了降噪编码器的编码器作为基础单元,并且使用其训练方法进行预训练
  2. 降噪自动编码器是无监督学习(自监督)的一种方法,而降噪自编码器是一种有监督方法.

评价:

学界评价:堆叠降噪自编码器是降噪自编码器的一个应用方法.

2.4 卷积自动编码器(Convolution Auto-Encoders, CAE)(2011)

全卷积网络是一种面向特定应用(图像语义分割)的卷积神经网络,其结构图如下图所示:

与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。

与全卷积网络类似的一种无监督方法称为卷机自动编码器.

由于卷积神经网络所取得的各种优异表现,直接推动了卷积自编码器的产生.卷积自编码器属于传统自编码器的一个特例.它使用卷积层和池化层替代了原来的全连接层.卷积
自编码器能很好的保留二维信号的空间信息.

学界评价:其主要差别在于卷积自编码器采用卷积方式对输入信号进行线性变换,并且其权重是共享的,这点与卷积神经网络一样。因此,重建过程就是基于隐藏编码的基本图像块的线性组合。

我实现后的感受:

2.5 变分自动编码器(Variational Auto-Encoders, VAE)(Kingma, 2014)

变分自编码器是一种主要用于数据生成的自编码器的变体.当作为生成模型时,首先利用数据训练变分自编码器,然后只使用变分自编码器的解码部分,自动生成与训练数据类似的输出.

其结构图如图所示:

整个结构可以分成三个部分,分别是编码部分,解码部分和生成部分.编码部分和解码部分同时进行训练,目标函数是从KL散度的概念中推倒得到的.

该公式正好是变分自编码器的目标函数.目标函数可以分成两个部分,分别约束了中间的隐变量受到一个标准分布的约束和输出图像尽量与原图相同.

2.5 几种算法的改进点表格

编码器名称提出时间改进点目的传统自编码器1986无无降噪自编码器2008将带有噪声的损坏信息作为输入信号使重建信号鲁棒性更强堆叠自编码器2008将多层结构和栈式训练引入自编码器使自编码器可以训练更高层数卷积自编码器2011将卷积层引入自编码器更好的处理图片数据,得到更好的效果变分自编码器2014相当于在传统自编码器的隐层表达上增加一个对隐变量的约束,提出了一种将概率模型和神经网络结构的方法使编码器产生的隐层表达满足正态分布,能够更好的生成图像模型

三. 实验

3.1 传统的自动编码器实验结果

模型结构与实现代码

传统的自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:

模型分为三个子模块,由上至下分别为输入层,编码器层和解码器层,编码器将输入维度为784(28 28)的mnint灰度值转化为一个维度为2的值.编码器将维度为2的值解码回维度为784(28 28)的mnint灰度值.

使用python-keras代码实现关键代码如下.

def __init__(self, ENCODING_DIM_INPUT=784, ENCODING_DIM_OUTPUT=2, Name = "ae"):input_image = Input(shape=(ENCODING_DIM_INPUT, ))# encoding layerhidden_layer = Dense(ENCODING_DIM_OUTPUT, activation='relu')(input_image)# decoding layerdecode_output = Dense(ENCODING_DIM_INPUT, activation='relu')(hidden_layer)# build autoencoder, encoder, decoderautoencoder = Model(inputs=input_image, outputs=decode_output)encoder = Model(inputs=input_image, outputs=hidden_layer)# compile autoencoderautoencoder.compile(optimizer='adam', loss='mse', metrics=['accuracy'])self.autoencoder = autoencoderself.encoder = encoder复制代码

训练过程

本实验讨论使用relu和tanh两种激活函数的自监督训练的情况.训练的loss函数选择为方均根误差.
训练过程的loss变化图像如下.

使用tanh作为激活函数时,loss变化情况如下.

可以观察到,loss收敛到0.0685,效果较好.使用relu作为激活函数同样能够有效收敛,不过误差数值相对较大.由于篇幅原因不将图片在此进行展示.误差数值相对较大的原因将在下一节进行讨论.

编码器输出的可视化结果

本节将从重建图像和编码器输出层的二维可视化图像两部分进行展示,分别展示使用tanh和relu两种损失函数的训练结果.

训练好的自动编码器重建图像(使用relu激活函数)如下图:

训练好的自动编码器重建图像(使用tanh激活函数)如下图:

两者对比可以发现relu函数训练出的模型存在一些像素颗粒,这也验证了上一节loss函数较大的实验结果.为了解释该问题,展示编码器输出层的二维可视化图片.

训练好的编码器输出图像(使用relu激活函数)如下图:

训练好的编码器输出图像(使用tanh激活函数)如下图:

以上两张图片是 编码器-解码器 结构中编码器部分的输出绘制成的二维可视化图片,不同的颜色代表了不同的数字,对应的数字在右边的图例中进行了显示.从以上两张图片中可以得到:

  1. 由于relu函数对负数的截断性质,使用relu激活函数训练的模型中有一部分点被限制在x=0,y=0两条边缘线上,这也是上文中提到的训练误差较大和出现像素颗粒的原因.
  2. 自动编码器虽然能够对mnist数据集进行编码和解码,但是效果并没有其改进的其他方法理想,这一观点可以从解码图片较为模糊和编码器可视化后各个类别的分类相重合得到验证.

说明与讨论

传统自编码器有很大的改进空间,改进空间的可以从几个方面阐述:

  1. 解码器输出较为模糊
  2. 编码器可视化的类别间的界限不明显

3.2 堆叠降噪自编码器

模型结构与实现代码

传统的自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:

模型分为三个子模块,由上至下分别为输入层,多层编码器层和多层解码器层,编码器将输入维度为784(28 28)的mnint灰度值转化为一个维度为2的值.编码器将维度为2的值解码回维度为784(2828)的mnint灰度值

使用python-keras代码实现关键代码如下.

class DAE(ae.AE):def __init__(self, ENCODING_DIM_INPUT=784, ENCODING_DIM_LAYER1=128,ENCODING_DIM_LAYER2=64, ENCODING_DIM_LAYER3=10,ENCODING_DIM_OUTPUT=2,Name="dae" ):# input placeholderinput_image = Input(shape=(ENCODING_DIM_INPUT, ))# encoding layerencode_layer1 = Dense(ENCODING_DIM_LAYER1,activation='relu')(input_image)encode_layer2 = Dense(ENCODING_DIM_LAYER2,activation='relu')(encode_layer1)encode_layer3 = Dense(ENCODING_DIM_LAYER3,activation='relu')(encode_layer2)encode_output = Dense(ENCODING_DIM_OUTPUT)(encode_layer3)# decoding layerdecode_layer1 = Dense(ENCODING_DIM_LAYER3,activation='relu')(encode_output)decode_layer2 = Dense(ENCODING_DIM_LAYER2,activation='relu')(decode_layer1)decode_layer3 = Dense(ENCODING_DIM_LAYER1,activation='relu')(decode_layer2)decode_output = Dense(ENCODING_DIM_INPUT,activation='tanh')(decode_layer3)# build surprised learning modelSL_output = Dense(10, activation='softmax')(encode_output)# build autoencoder, encoderautoencoder = Model(inputs=input_image, outputs=decode_output)encoder = Model(inputs=input_image, outputs=encode_output)SL_model = Model(inputs=input_image, outputs=SL_output)# compile autoencoderautoencoder.compile(optimizer='adam', loss='mse', metrics=['accuracy'])SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])复制代码

代码定义了三个模型,分别是用于自监督训练的 autoencoder, 用于二维化的编码器 encoder 和用于进行有监督训练的 SL_model.

训练过程

堆叠降噪自动编码器分为无监督的预训练过程和有监督的训练过程两部分.
本部分分别进行说明.

自监督的预训练过程loss变化情况如下.

无监督的训练过程正确率acc变化情况如下.

可以看到,在两个训练阶段,方法可以有效的达到收敛.

以下几点需要指出:

  1. 多层编码器的训练没有使用栈式编码器的训练方式.
  2. 预训练次数20epoch,并不足够模型充分收敛,但是作为预训练部分,已经充分.
  3. 预训练部分的误差与传统自编码器相比较大,是因为在初始层加入了噪声的原因.
  4. 训练时间与传统编码器相比更长,是其3倍左右.
  5. 在有监督学习的开始阶段,分类的正确率并不高,这也印证了上一部分二位可视化的结果,很多点的界限不清晰.

编码器输出的可视化结果

本节将从重建图像和编码器输出层的二维可视化图像两部分进行展示

预训练部分

重建图像

下图展示了添加噪声的效果(第一行原图,第二行增加噪声的图).

下图展示了,对添加噪声的图片进行重构的结果(第一行增加噪声的图,第二行重构图)

编码器输出层的二维可视化图像

下图展示了添加噪声的效果(第一行原图,第二行增加噪声的图).

以下几点需要指出:

  1. 本方法可以有效的对随机噪声进行去除
  2. 恢复图与原图相比虽然能够识别但是效果更模糊
  3. 与传统自动编码器相比,本方法得到的二维图的界限更加清晰

有监督训练部分
经过有监督的训练

重建图像(因为不是目标,所以必然走样)
下图展示了,对添加噪声的图片进行重构的结果(第一行增加噪声的图,第二行重构图)

编码器输出层的二维可视化图像

经过有监督学习,二维可视化图中各个组的界限更加清晰.

说明与讨论

堆叠降噪自编码器的改进有以下启发:

  1. 使用自监督预训练与有监督训练方式相结合的形式获得更加优秀的效果
  2. 使用增加噪声的形式迫使模型学习更加有效的特征
  3. 将深度玻尔兹曼姬的思想迁移到自动编码器中

3.3 卷积自编码器

模型结构与实现代码

卷积自编码器自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:

使用python-keras代码实现关键代码如下.

def __init__(self,CHANNEL_1 = 16,CHANNEL_2 = 8,CHANNEL_OUTPUT = 1,   Name="cae"):# input placeholderinput_image = Input(shape=(28, 28, 1))# encoding layerx = Conv2D(CHANNEL_1, (3, 3), activation='relu', padding="same")(input_image)x = MaxPool2D((2, 2), padding='same')(x)x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(x)encode_output = MaxPool2D((2, 2), padding='same')(x)# decoding layerx = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(encode_output)x = UpSampling2D((2, 2))(x)x = Conv2D(CHANNEL_1, (3, 3),activation='relu', padding='same')(x)x = UpSampling2D((2, 2))(x)decode_output = Conv2D(CHANNEL_OUTPUT, (3, 3), activation='sigmoid', padding='same')(x)# build surprised learning modelencode_output_flatten = Flatten()(decode_output)SL_output = Dense(10, activation='softmax')(encode_output_flatten)# build autoencoder, encoderautoencoder = Model(inputs=input_image, outputs=decode_output)encoder = Model(inputs=input_image, outputs=encode_output)SL_model = Model(inputs=input_image, outputs=SL_output)# compile autoencoderautoencoder.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])复制代码

训练过程

堆叠降噪自动编码器分为无监督的预训练过程和有监督的训练过程两部分.
本部分分别进行说明.

在自监督的预训练过程loss变化情况如下.

图像显示,自监督的训练loss收敛于0.07左右,该误差比降噪自编码器的0.09要小.与传统自编码器的训练误差相差不多.但是从下文可知其训练效果明显优于传统自动编码器.

在有监督的训练过程正确率acc变化情况如下.

图像显示,有监督训练过程的正确率上升到0.99,比降噪自动编码器的正确(0.95)率更高.
因此在mnist数据集中的重建任务和分类任务中,卷积自动编码器有一定优势.

不过以下几点需要指出:

  1. 与sDAE相比,CAE有更高的准确率和更低的损失
  2. 更好的效果除了卷积单元能够更好的处理图像数据外,可能与CAE方法的复杂度更高和其瓶颈处通道更宽有关

编码器输出的可视化结果

可以看到和stacked AE的主要区别在于局部卷积连接,而不所有层都是全连接。对图像和某些其他数据影响在空间局部的问题,比全连接更合适.因此效果更加优秀.

于降噪自动编码器相同,首先对图片增加噪声:

然后对增加噪声的图片进行去噪:

去噪结果比较优秀,与上文中所有的结果相比是最优秀的.

3.4 变分自编码器

模型结构与实现代码

变分自动编码器的结构最为复杂,并且在模型中引入了隐变量,和KL散度等概率论概念.对模型的实现造成了一定的影响.
自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:

上图中并没有展开编码器和解码器的结构,编码器(encoder) 与 解码器(decoder)的形式分别如下:

encoder:

decoder:

使用python-keras代码实现关键代码如下.

class VAE(ae.AE):def __init__(self,ENCODING_DIM_INPUT = 784, intermediate_dim = 512,batch_size = 128,latent_dim = 2,mse_loss = True,Name="vae"):self.name = Name# input placeholderinput_image = Input(shape=(ENCODING_DIM_INPUT,), name='encoder_input')# VAE model = encoder + decoder# encoding layerx = Dense(intermediate_dim, activation='relu')(input_image)z_mean = Dense(latent_dim, name='z_mean')(x)z_log_var = Dense(latent_dim, name='z_log_var')(x)z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])# build decoder modellatent_inputs = Input(shape=(latent_dim,), name='z_sampling')x = Dense(intermediate_dim, activation='relu')(latent_inputs)outputs = Dense(ENCODING_DIM_INPUT, activation='sigmoid')(x)# # build surprised learning model# SL_output = Dense(10, activation='softmax')()# build autoencoder, encoderencoder = Model(input_image, [z_mean, z_log_var, z], name='encoder')decoder = Model(latent_inputs, outputs, name='decoder')# SL_model = Model(inputs=input_image, outputs=SL_output)outputs = decoder(encoder(input_image)[2])autoencoder = Model(input_image, outputs, name='vae_mlp')# compile autoencoder# VAE loss = mse_loss or xent_loss + kl_lossif mse_loss:reconstruction_loss = mse(input_image, outputs)else:reconstruction_loss = binary_crossentropy(input_image,outputs)reconstruction_loss *= ENCODING_DIM_INPUTkl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)kl_loss = K.sum(kl_loss, axis=-1)kl_loss *= -0.5vae_loss = K.mean(reconstruction_loss + kl_loss)autoencoder.add_loss(vae_loss)autoencoder.compile(optimizer='adam')autoencoder.summary()# SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])           self.autoencoder = autoencoderself.encoder = encoderself.decoder = decoder复制代码

训练过程

由于,变分自动编码器主要应用于图像生成,而并非是提取与分类,因此变分降噪自动编码器只有自监督的训练过程..

在自监督的训练过程,使用 KL散度+交叉熵 作为loss函数,loss变化情况如下.

可以看散度可以收敛到145的情况,能够有效进行收敛.

在自监督的训练过程,使用 KL散度+方均根 作为loss函数,loss变化情况如下.

对于两种损失函数效果的讨论在下文中进行.

自编码器输出的可视化结果

使用 KL散度+交叉熵 作为损失函数

基于kl散度的loss训练结果二维可视化如下

使用生成器对图像进行生成可以得到如下结果.

使用 KL散度+方均根 作为损失函数

基于kl散度的loss训练结果二维可视化如下

使用生成器对图像进行生成可以得到如下结果.

由于方均根与交叉熵的区别在于 解码器重现误差上面的区别,在编码器部分同样使用kl散度作为loss,因此两者的可视化结果类似.

以下几点需要指出:

  1. 二维可视化的结果中各个类别的界限较为明显,且其分布十分集中方便生成模型的图像生成.
  2. KL散度作为一种新的损失函数无法与其他方法的误差进行对比.

四.讨论

  1. 自动编码器可能的应用有特征提取,图像分类,图像去燥,图像生成等
  2. 在特征提取领域和图像分类领域使用sae有较优秀的效果
  3. 在图像去噪领域可以使用cae方法,cae方法对二维图片的去燥效果十分优秀,但是由于中间部分是比较复杂的卷机核结构,无法进行有效的可视化
  4. vae方法在图像生成领域有出色的表现,将中间的隐变量约束为正太分布的形式,十分方便的通过生成器完成图像生成.
  5. 在研究角度,vae方法将概率方法引入神经网络的计算体系中,通过网络完成对概率分布的映射,使用散度的概念构造损失函数,对其他研究有些启发.

原文链接

本文为云栖社区原创内容,未经允许不得转载。

转载于:https://juejin.im/post/5d0894d7f265da1b916395a8

自动编码(AE)器的简单实现相关推荐

  1. python简单装饰器_python装饰器的简单示例

    这篇文章主要为大家详细介绍了python装饰器的简单示例,具有一定的参考价值,可以用来参考一下. 对python这个高级语言感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧! 装饰器的语法以 ...

  2. java播放器使用教程_java 实现音乐播放器的简单实例

    java 实现音乐播放器的简单实例 实现效果图: 代码如下 package cn.hncu.games; import java.applet.Applet; import java.applet.A ...

  3. php阅读器开发,微信小程序阅读器的简单实例开发

    这篇文章主要介绍微信小程序阅读器的简单实例开发的相关资料,需要的朋友可以参考下 今天和朋友聊天说到小程序,然后看在看书,然后我们就弄了个小读书的demo,然后现在分享一下. 一.先来上图: 首先先说下 ...

  4. 图片播放器 简单使用

    (1)前台_客户端:     var focus_width=800;//图片宽     var focus_height=600;//图片高     var text_height=20;//字高 ...

  5. 文本语音阅读器——Python简单实现

    文本阅读器--Python简单实现 一.功能描述 实现txt文本的自动阅读功能 二.实现流程 1)txt文本准备 将所需要进行语音播放的文本转换为txt文本格式(自行准备或爬取) 2)语音文件生成 利 ...

  6. java音乐播放器视频_java 实现音乐播放器的简单实例

    java 实现音乐播放器的简单实例 实现效果图: 代码如下 package cn.hncu.games; import java.applet.Applet; import java.applet.A ...

  7. es6 迭代器(遍历器)Iterator 自定义遍历器 lterator/简单模拟values方法 for of运行机制 Array/Set/Map默认迭代器接口 对象设置迭代器

    文章目录 迭代器 Iterator 用处 (需要自定义遍历数据的时候) 自定义 遍历器 lterator 简单模拟values方法 Array Set Map 默认迭代器接口 entries valu ...

  8. python装饰器–原来如此简单

    python装饰器–原来如此简单 今天整理装饰器,内嵌的装饰器.让装饰器带参数等多种形式,非常复杂,让人头疼不已.但是突然间发现了装饰器的奥秘,原来如此简单.... # -*- coding:gbk ...

  9. Go :垃圾收集器的简单测试(附完整源码)

    Go :垃圾收集器的简单测试 package mainimport "runtime"func mk2() {b := new([10000]byte)_ = b// printl ...

最新文章

  1. 猎豹MFC--列表控件ListControl
  2. html弹窗赋值给查询框,bootstrap模态框动态赋值, ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS)...
  3. android自动填充包名,debug/release 修改包名,取不同包名下的agconnect-services.json 文件...
  4. VTK:等值面采样用法实战
  5. C语言高级编程:i++与++i区别
  6. Opserver配置Redis、SqlServer监控
  7. 现代软件工程第一次结对编程(黄金点游戏)总结
  8. msp430的常量可以这样定义
  9. CC2540和CC2541蓝牙芯片将升级为蓝牙5.0
  10. gcf,gca,gco的区别
  11. [每日一氵] TensorRT中 GA和EA的不同
  12. OpenCV:图片文字分割
  13. 软件工程如何选择方向
  14. 官场直升机 鸿蒙笔著,担当:老衲笔尖无墨水,要从空处想鸿蒙
  15. php1.6t发动机机油选择,1.6t用什么机油选择啊!?
  16. C# Windows桌面应用 ---- 实例:文件读写
  17. NETWORK笔记7:思科命令实验
  18. 认知学派用计算机来比拟人,心理学基础习题答案
  19. matlab提取图形形心
  20. 局域网内Linux服务器使用本地Windows代理上网

热门文章

  1. Fabric实战(四)-多机部署fabric网络-solo
  2. 【小记】steam 神奇软件
  3. mariadb-server
  4. TUF Notary
  5. 你为什么要学习这门专栏?
  6. c语言本地函数声明非法,C++本地函数定义是非法的
  7. 基于虚拟筛选,从头设计的方法对蛋白酪氨酸酶1B,4-噻唑啉酮类抑制剂的研究
  8. 中国移动支付行业投资机会分析与发展战略建议报告2022-2028年
  9. lqc_远程日志管理
  10. easyuefi只能在基于uefi启动的_PE启动盘的制作