深度学习领域在近几年取得了重大突破,其中大部分研究成果都基于感知技术,计算机通过模仿人类的思维方式,感知物体、识别内容。生成对抗网络的理念由Goodfellow于2014年提出的,它的发展历程只有六年,却对人工智领域带来了极大的冲击。

GAN的博弈过程,就是使用生成器制造的数据分布来拟合真实的数据分布。设置是一个生成动漫图片的网络,接收一个随机的噪声,生成动漫图片并输出。设置为判别网络,输入一张动漫图片,判别器可以计算出该图为生成的或真实图片的概率。两者分别根据返回的结果反向更新网络,相互抗衡,动态变化最后达到纳什均衡。

基于GAN性能的优越性,该模型逐渐被运用到图像处理领域的各个方向,其中包括图片转换、图像修复、风格迁移、图像生成等。例如:2016年Phillip Isola等人设计的pix2pixGAN[4]模型,可以将语义图片转换为街景和建筑的照片、素描图转彩色图片等,在图像转换领域实现了重大突破。

原始的GAN网络虽然在2014年才首次提出,但其扩展速度迅猛,产生了大量衍生网络,如:DCGAN、SGAN、ACGAN等。2015年Mattya首次提出了chainerGAN,通过DCGAN实现动漫人物生成,但Chainer框架并未得到大范围应用。随后,Jie Lei等人在2017年发表了Animegan,该项目使用GAN框架,提出了三种新的损失函数:灰度风格loss、灰度对抗loss、色彩重构loss,将各类现实场景下的图像转化为动漫风格的图像,例如自然风景、道路街景的转换。但遗憾的是,这些项目对于非计算机领域的爱好者使用具有一定难度,产生了局限性。

2017年,复旦大学和CMU的学生共同发布了一项名为MakeGirlsMore的动漫人物生成项目,发布后在Github受到广泛关注。该项目使用 React.js作为页面基本框架,为了提高项目的实用性,开发者将Chainer模型转化为基于WebAssembly的Java 模型。用户可以在浏览器的界面上设置动漫人物的相关参数,例如:眼睛颜色、面部表情、发型等信息,实现动漫人物的自动生成。

 训练方案

首先,建立图像样本库需要大量动漫图像,可使用Python在动漫素材相关网站爬取或使用网络上已有的数据集,按照固定比例划分训练集和测试集,并对样本进行标准化处理,使图像大小保持,每一张图片拥有唯一ID。

其次,选择CNN作为DCGAN的基础网络,对CNN的池化层和全连接层进行调整。DCGAN是一种深度卷积网络,可以实现目标特征提取以及图像分类。在定义DCGAN中的生成网络和判别网络时,通过增加ReLU、Sigmoid等激活函数用于参数处理、图像分类等工作。

在训练网络之前,使用Pytorch作为框架,Python作为编程语言完成代码编写,利用Adam优化器最小化损失函数,优化程序调整超参数。训练网络时,使用Visdom实现训练过程的可视化,通过控制学习率、迭代次数、训练比例等参数,设置多组对照实验,观察实验结果并利用测试集进行多次测试。

将多组实验结果进行对比分析,可得到一组最优网络参数,利用训练好的目标网络模型,便可输出多张不同的动漫图像,技术路线如图1.3所示:

图1.3 技术路线图


神经网络及GAN相关技术介绍



 神经网络相关概念

计算机网络中的神经元是神经网络基本组成单位,它的结构参考了生物神经元。1943年McCulloch等人提出了神经元模型M-P。对于神经网络的发展有着重要的影响。M-P抽象模型如图2.1所示:

图2.1 神经元结构模型

结合图2.1来看,神经元的输入输出关系用有向箭头来表示,输入信号可以用Xi表示,输出用Y来表示, Wi表示权重。多个神经元可以通过设定的连接关系组合成为神经网络。

目前,神经网络根据工作原理可以分为人工神经网络和生物神经网络,在计算机领域中,人工神经网络的原理是利用计算机模拟大脑的工作方式。下图2.2展示了神经网络主要类别,本文的DCGAN模型就是基于多层神经网络CNN实现的。

图2.2 神经网络主要类别

单层感知器模型前馈神经网络最经典的模型,该模型与1957年由Frank Rosenblatt提出,可实现二类线性分类。将神经元节点添加在网络的输入、输出位置,作为网络的输入单元和输出单元。输入单元的功能是传输数据,输出单元实现对上一层的输入进行计算功能。下图2.3为第一代神经网络感知模型:

图2.3 第一代神经网络模型

由于第一代神经网络模型不能适用于处理异或问题,仅局限于线性可分问题。所以直至20 世纪 80 年代中期,分布式并行处理(Parallel Distributed Pro-cessing ,PDP)模型开始受到广泛关注。反向传播算法也逐渐成为 PDP 模型的主要学习算法这时,神经网络才又开始引起人们的注意,并重新成为新的研究热点[7]。第二代神经网络结构也应运而生,如图2.4所示:

图2.4 第二代神经网络结构图

2006年Geoffrey Hinton提出了深度网络,通过大量数据训练神经元间的权重,让整个网络按照最大概率来生成数据,是一种概率生成模型,能够通过学习表示高阶抽象的复杂函数,可以使用它来识别特征、分类数据、生成数据等。

 卷积神经网络

卷积神经网络(convolutional neural network,CNN)是指至少在网络的一层中使用卷积运算来代替一般的矩阵乘法运算的神经网络[18]。第一个卷积神经网络是Alexander Waibel在1987年提出的时延神经网络(TDNN),但是直到2012年ImageNet竞赛之前,CNN才重新走进人们的视野。目前常用的CNN结构是由多个卷积层、池化层、全连接层组合构成的。如图 2.5 所示

图2.5 神经网络结构图

卷积层主要通过卷积核进行图像局部特征提取,其神经元按照宽度,高度和深度的排列方式,适用于彩色图像的RGB三色通道结构,因此它的排列方式又称为三维排列。避免了传统的感知器模型纬度较低的问题,可以更好地生成于高分辨率的图像,卷积层的各个参数设置影响卷积神经网络的性能,网络的精度和卷积层数呈正相关。

激活层一般常使用ReLU激活函数,它可以缓解梯度消失问题,通过将特征图映射到新的特征空间,提高模型鲁棒性、非线性表达能力。

池化层的主要作用是进行特征选择。池化层可以通过下采样过程,对于特征图进行融合和降维,相较于卷积层降低了计算量,避免了信息冗余。常用最大池化法和平均池化法。

全连接层用于将前一层输出的局部特征,重新连接成完整的图,可以将卷积神经网络的尾部重新拟合,减少特征信息的损失。

 卷积运算

卷积(Convolution)的过程是在图像每个位置进行线性变换映射成新值的过程。本节主要讨论卷积运算在图像处中的运用。卷积运算主要是通过特征提取器(滤波器)对图片进行特征提取,例如图像的线条、结构等,降低深层网络模型的复杂度。其下列公式2.1、2.2可表示多层神经,上下层之间的关系:

上式2.1、2.2中有几个重要参数,W1:卷积前图像的宽度;W2:卷积后特征图的宽度;H1:卷积前图像的宽度;H2:卷积后特征图高度 ;S:步长(Stride),卷积核在滑动时的间隔;F:filter的宽度;P:零补充(Zero Padiding),在原始图像两端补零的圈数。

下图2.6是一张大小的原始图片,设置经过卷积操作后,得到一张大小的特征图像的部分过程,图2.6为原始输入图像,绿色部分为卷积核,蓝色图像为目标图像,为卷积后图像长度,图2.7中的值可以通过绿色部分的运算。

卷积后图像特征图的长度为:

运算后的取值为:

通过以上运算过程,可以总结出,卷积运算就是将高维数据映射到低维数据,而逆卷积运算就是卷积运算的相反操作,将低维数据映射到高维数据。


动漫图像生成网络设计



 DCGAN设计原则

DCGAN目前是GAN在实际工程实践中被采用最多的衍生网络,为了提高图像生成质量,增强其稳定性,许多研究学者尝试进行优化,并提出了四点设计原则,本课题中DCGAN的生成器和判别器的设计是基于该原则实现,下面将进一步阐述它们之间的关系。

(1)卷积层代替池化层

池化操作会使卷积核在缩小的特征图上覆盖了更大的图像视野,但是对网络性能的优化效果较小,使用卷积层代替池化层,让网络自动选择筛去不必要信息,学习上采样和下采样过程,提高计算机运算能力。

(2)去掉全连接层

全连接层一般添加在网络的末层,用于将图像特征进行连接,可以减少特征信息的损失,但是由于其参数过多,会产生过拟合、计算速度降低等问题。由于面部图像特征提取的感受野范围较小,不需要提取全图特征,所以为了避免上述问题,本项目中网络模型去掉了全连接层。

(3)批量归一化

本课题中的生成器和判别器都是五层神经网络,每一层输入的数据的复杂度都会逐层递增,使输出数据的分布发生变化,对网络参数的初始化和BP算法的性能产生影响。将数据进行批量归一化(Bach Normalization,BN),可以使输出的数据服从某个固定数据的分布,把数据特征转换为相同尺度,从而加速神经网络的收敛速度。

(4)激活函数

激活函数(Activation Function)具有连续可导的特性,可以使神经网络进行非线性变化,通过对数值优化来学习网络参数,提升网络的扩展性。本课题的生成器和判别器均为五层网络模型,计算量较大,每一层的激活函数选择需要满足高计算效率和训练稳定两点,其导函数的值域分布合理。

基于以上原则,在DCGAN的生成器添加了ReLu函数、Tanh函数,判别器中添加了LeakyReLu函数和Sigmoid函数,如下内容将对这四个激活函数进行的简单介绍。

Sigmoid函数是一种两端饱和型函数,取值范围在0∼1之间,Sigmoid函数定义如公式3.1所示:

下图3.1是Sigmoid的函数图像,它以坐标轴原点0为分界,输入值变大,输出结果接近于1,输入值减小,输出结果接近0,所以一般用它做输出端,解决二分类问题。这种特性也存在一定弊端,例如,神经网络训练结果输出恒大于零,并且当输入数据为极大,极小值时,Sigmoid函数梯度无限趋近于0,不利于神经网络的反向传播。

图3.1 Sigmoid函数图像

Tanh函数的图像也是S型,一般情况下Tanh的收敛速度都优于Sigmoid函数,它可以避免出现均值不为零的情况,公式如3.2所示:

由函数图像3.2可得,它的值域为(0,1),DCGAN网络在生成器的输出层添加Tanh函数,有利于图像色彩覆盖。

图3.2 Tanh函数图像

Relu激活函数是一种左饱和的激活函数。它的计算效率较高,一般常用于隐层神经元输出,在近几年被广泛用于训练多层神经网络模型,其函数公式3.3所示:

由ReLU函数图3.3可知,导数在x>0时为1,x<0时为0,可以提高神经网络的收敛速度。但是ReLU也存在一些问题,例如“死亡ReLU”,在训练时,如果有一个数据较大的梯度流通过ReLu神经元,导致参数更新出现问题,数据分布被打乱,这个神经元的梯度保持为0,且无法对任一数据进行激活操作。

![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8zM1AyRmRBbmp1OWtCNTJTeDV1eEtzVVVlWEd 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 VbHBDNmtITGliemw4c21Sek5UWUkzSGxxdUoxYjlnUlJpY1dpYWRQQnBnVXNQZlMyaWJuenl1TFA3UlN1VVEvNjQw?x-oss-process=image/format,png)

图3.3 ReLU函数图像

LeakyReLU函数可以解决“死亡ReLU”现象,是基于ReLU函数的基础上提出的,函数公式如3.4所示:

如图3.4所示,当小于0时,给增加一个斜率,取值一般较小,避免了ReLU在负半轴训练时停滞的问题。

图3.4 LeakyReLU函数图像

 DCGAN网络结构

DCGAN模型由生成网络G与判别网络D组成,网络结构均为五层,生成网络的接受一个随机输入的噪声,通过该噪声生成一张目标图像;判别网络接受一张图像,对该图像做出判断后,计算出一个概率值,若该图像来源为生成网络,则输出0,若该图像来自真实的数据分布,则输出为1。两者根据反馈的结果,不断更新自己的参数,直至达到纳什均衡。

 生成网络和判别网络详细设计

生成器网络结构

生成模型的网络结构一共有五层,通过上采样方法生成大小的图像,它的主要结构如图3.6所示:

图3.6 DCGAN的生成器网络结构图

生成器整个网络结构没有池化层,输入一个服从均匀分布的nz维度的噪声,神经网络根据输入的向量信息,分步获取输入图像的特征信息,例如:线条、风格等,随后根据网络的深度,不断优化图片的细节。

输入一张的图片,根据需要的特征图大小设置相应的卷积核,卷积核的大小影响了生成网络的可学习空间特征值的大小。在代码中使用nn.Sequential()函数可以根据传入的次序,将卷积、激活、池化等按照顺序加入该模块中,在构建完网络层后,自动调用forward方法。在除了输出层之外的每一层,加上批归一化(BN)处理,缓解模型崩溃问题。根据每层网络结构的需求,使用对应的激活函数,最后,输出一个像素的3通道RGB图像。具体的层次结构如下表3.1所示:

表3.1 DCGAN生成模型层次结构

**Layer1是输入层,**输入随机噪声,将Stride设置为1,将Padding设置为0。接下来,通过ConvTranspose2d()函数求逆卷积,并在BN层对数据进行批量归一化处理,使用ReLU激活函数加速收敛,输出对应的特征映射图;

**Layer2:**将Stride设置为2,将Padding设置为1,添加BN层将数据批量归一化处理,使用ReLU激活函数加速收敛,输出对应的特征映射图;

**Layer3:**将Stride设置为2,将Padding设置为1,添加BN层将数据批量归一化处理,使用ReLU激活函数加速收敛,输出对应的特征映射图;

**Layer4:**将Stride设置为2,将Padding设置为1,添加BN层将数据批量归一化处理,使用ReLU激活函数加速收敛,输出对应的特征映射图;

**Layer5:****输出层,**将Stride设置为3,将Padding设置为1,使用Tanh作为激活函数,输出对应的图像。

生成器代码结构图如图像3.7所示:

图3.7生成器代码结构图

判别器网络结构

判别模型的网络结构一共有五层,采用下采样方法。整个网络结构没有池化层,采用LeakyReLU作为激活函数,最后,通过一个全连接层输出判别结果,范围为0∼1,表示输入图像属于真实样本还是由生成器所生成的图像,它的结构如图3.8所示:

图3.8 DCGAN的判别器网络结构图

判别器中也添加了BN层,并且每一层都使用激活函数进行非线性处理,具体的层次结构如下表3.2所示:

表3.2 DCGAN判别模型层次结构

**Layer1:输入层,**首先输入图片,Stride设置为1,将Padding设置为0。通过Conv2d()函数求卷积,接下来使用LeakyReLU()激活函数,优化网络收敛速度;

**Layer2:**输入图像,Stride设置为2,将Padding设置为1,添加BN层将数据批量归一化处理,使用LeakyReLU()激活函数加速收敛;

**Layer3:**输入图像,Stride设置为2,将Padding设置为1,添加BN层将数据批量归一化处理,使用LeakyReLU()激活函数加速收敛;

**Layer4:**输入图像,Stride设置为2,将Padding设置为1,添加BN层将数据批量归一化处理,使用LeakyReLU()激活函数加速收敛;

**Layer5:输出层,**Stride设置为3,将Padding设置为1,使用sigmoid()函数输出概率,表示图像的真实性。

综上,可以看出这两个网络模型的Padding、Stride等设置几乎相同,整体的网络结构是对称,只是各层使用的激活函数有差异。

 损失函数

损失函数是一种非负实数函数,可以评估模型的预测值与真实值不一致的程度。两者差距减少,概率分布越接近,差距增加,概率差异越高,在Pytorch中可以通过导入torch.nn包来使用。Pytorch中提供许多损失函数,每一种函数都有其特性,例如:MSELoss是一种均方误差损失函数,使用梯度下降算法,一般常用于解决股票预测、房价预测等回归类问题;SmoothL1Loss是一种稳定的损失函数,也被用于解决回归问题,它的函数曲线光滑可以避免梯度爆炸的问题;BCELoss是CrossEntropyLoss的一个特例,常用于解决分类问题。在本课题中我们需要,判断样本的输出是真实图片还是生成图片,所以本课题选择BCELoss作为损失函数,它在 PyTorch 中的定义如公式2.1所示:

由于生成网络和判别网络的输出层的激活函数分别为Than函数和Sigmoid函数,两者都是S型函数,其函数特性会导致反向传播算法收敛速度降低,使用BCELoss函数后,解决了因sigmoid函数导致的梯度消失问题。

 Adam优化器

在DCGAN的训练过程中,可以通过优化器最小化损失函数,一般分为一阶优化算法和二阶优化算法。本课题选用Adam优化程序调整超参数,它结合了 AdaGrad 和 RMSProp 算法最优的性能,不仅可以计算每个参数的自适应学习率,还可以通过训练数据的不断迭代使网络权重自动更新,相较于其他几种算法而言Adam算法实现简单、对计算机资源占用率较低,收敛速度也更快。

Adam算法有一些重要参数,其中params表示用于优化的可以迭代参数或定义参数组;lr表示学习率,可以调节权重的更新比例,影响网络的收敛速度,在Pytorch源码中定义如下:

torch.optim.Adam(params,lr=a,betas=(b,c),eps=d, weight_decay=e)

本文基于Adam优化器的默认参数做出改进,采用一种动态调整学习率的方法,改善训练过程中产生的图像模糊,模式崩塌,损失函数震荡明显等问题,详细步骤在网络训练部分阐述。



动漫图像生成实战



本章首先将几种常用的开源框架进行对比分析,选择了最适用于本实验需要的开源框架Pytorch,并对可视化工具Visdom的功能进行说明。接下来,详细描述了网络训练流程,对各组实验生成的图像和Loss函数进行了分析,对传统的DCGAN网络训练参数提出了改进,针对相关问题提出优化方案。

 实验环境搭建

深度学习框架Pytorch

随着各类开源深度学习框架的不断更新迭代,大规模的深度学习模型得到了极大的简化,促进了图像处理、NLP、语音识别等技术的发展。本课题的核心功能是自动生成动漫图像,近几年大火的TensorFlow、Pytorch等框架都可用于处理图像类问题。

TensorFlow框架属于静态计算图,生成图像后无法改变,在初始化时需要考虑到所有的可能性,对计算机配置要求高。在代码中,静态图不支持基本的python语法,缺乏灵活性,不适用于研究性学习。

由于Pytorch框架的设计思想基于动态计算图,它的 API的设计具有极高的通用性,源码直观简洁,易于理解,支持python的条件判断、循环等基本语法,可以动态执行并且调试方便。基于它的高效性、易用性,本课题选Pytorch作为深度学习框架。

可视化工具Visdom

可视化工具可以为我们实时提供程序运行过程中各类数据变化情况和训练效果。Visdom是一款轻量级的可视化工具。适用于Pytorch框架下的图像展示,支持Python语言,可绘制多种图形,例如:热力图、地理图、自定义图像。

Visdom的UI可视化框架主要由环境和窗格组成。一般默认使用main环境,不同环境之间相互独立。窗格相当于一个容器,支持多种图像类型,一个环境中可以创建多个窗格。用户通过创建一个自己的绘图环境,启动浏览器窗口,便可以实时查看图像数据,这些图像可以缩放、保存、动态更新。

基于Visdom具有轻量、实用性、灵活性的特点,本课题选择它作为可视化工具,绘制Loss函数和生成图形变化过程,便于分析数据,调整优化器和网络训练参数。下图4.1展示了在Visdom中网络训练过程和Loss函数。

图4.1 Visdom可视化展示

综上,选用第三方框架为Pytorch,使用Python完成代码编写,通过Visdom实现图像生成过程的可视化,使用样本库对网络进行训练,实验所需的环境和软件的详细信息在下表4.1所示:

表4.1 实验环境

 训练过程

建立图像样本库

图像样本库内容为动漫人物面部特征图片,可通过爬虫获取大量原始动漫人物形象素材后,使用opencv工具将图片进行剪裁,仅留出动漫人物面部图像,本项目使用知乎用户何之源提供的已处理好的动漫图像样本库,按照1:1随机划分为训练集和测试集。

  • 训练集包含20000张动漫人物图像,图像格式为JPEG,分辨率为3✖️96✖️96,每张图像的文件名是一个唯一的id;

  • 测试集包含20000张动漫人物图像,图像格式为JPEG,分辨率为3✖️96✖️96,每张图像的文件名是一个唯一的id,样本参数图4.1:

如何通过DCGAN实现动漫人物图像的自动生成?相关推荐

  1. 基础 | 如何通过DCGAN实现动漫人物图像的自动生成?

    点击上方"机器学习与生成对抗网络",关注"星标" 获取有趣.好玩的前沿干货! 文章来源:淘系技术 背景 基于生成对抗网络(GAN)的动漫人物生成近年来兴起的动漫 ...

  2. 深度学习之基于DCGAN实现动漫人物的生成

    注:因为硬件原因,这次的实验并没有生成图片,但是代码应该是没有问题的,可以参考学习一下. 本次基于DCGAN实现动漫人物的生成.最终的效果可以参考大神**K同学啊**的博客.与上篇文章基于DCGAN生 ...

  3. Pytorch 使用DCGAN生成动漫人物头像 入门级实战教程

    有关DCGAN实战的小例子之前已经更新过一篇,感兴趣的朋友可以点击查看 Pytorch 使用DCGAN生成MNIST手写数字 入门级教程 有关DCGAN的相关原理:DCGAN论文解读-----DCGA ...

  4. pytorch实现DCGAN生成动漫人物头像

    pytorch实现DCGAN生成动漫人物头像 DCGAN原理 参考这一系列文章 数据集 21551张64*64动漫人物头像 生成效果 训练1个epoch(emm-) 训练10个epoch(起码有颜色了 ...

  5. 使用DCGAN生成动漫人物头像

    使 用 D C G A N 生 成 动 漫 人 物 头 像 使用DCGAN生成动漫人物头像 使用DCGAN生成动漫人物头像 import tensorflow as tf from tensorflo ...

  6. 如何画动漫人物的耳朵?动漫人物耳朵的画法

    如何画动漫人物的耳朵?动漫人物耳朵的画法,教程比较详细,但要画的好,还是需要绘画基础,作者从参考到构图,最后出线稿和上色都讲解了一下,最后做一下光源细化细节即可. 最终效果 一.勾勒耳部草图 1.首先 ...

  7. 使用Labelme和PaddleSeg实现动漫人物实例分割

    文章目录 前言 一.使用Labelme进行数据标注 二.使用PaddleSeg训练 1.数据集划分 2.PaddleSeg/train.py训练 3.结果可视化 4.对动漫视频进行分割 总结 前言 众 ...

  8. 怎么画动漫人物的五官:耳鼻眼嘴

    今天给大家带来的是动漫人物五官教程,动漫人物五官怎么画呢?下面就是动漫人物五官的详细绘画步骤,不知道怎么画动漫人物五官的童鞋,赶紧学习吧! 动漫人物五官的画法你学会了吗?学会动漫人物五官是很重要的哦

  9. 动漫人物脸型怎么画?如何画好动漫人物脸型?

    人物脸型怎么画?对于一些新手来说,可能画人物的脸非常的困难,那是因为没有掌握一定技巧的缘故,其实,我们画动漫人物的脸部,也并不是非常困难的,当然,会者不难,难者不会,为了让大家能够更好的掌握这些画动漫 ...

最新文章

  1. 机器学习算法库scikit-learn的安装
  2. 孙钟秀--《操作系统教程》注释(陈怀临)-- 读书笔记
  3. NOIP信息奥赛--1995“同创杯”初中复赛题题解(五)
  4. python观察日志(part12)--基于类的深拷贝与浅拷贝
  5. python duplicated函数_Python DataFrame使用drop_duplicates()函数去重(保留重复值,取重复值)...
  6. java 日期 解析_Java日期解析(Java DATE Parsing)
  7. 阿里千万实例可观测采集器-iLogtail正式开源
  8. osgi框架 android,基于OSGi的Android应用模块动态加载框架设计与实现
  9. Unity3D与JSP TomCatserver传递数据和文件( 二 ) Unity3D向java传输表单
  10. 免费人脸识别工具可以跟踪社交媒体网站上的人
  11. EXCHANGE服务器灾难恢复
  12. java 时区处理_如何使用Java处理日历时区?
  13. 深大计算机专业进腾讯,国内中游985和深圳大学计算机专业怎么选?640报考深圳大学吃亏吗...
  14. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_2-5.开源工具的优缺点选择和抽象方法的建议...
  15. Android Studio单元测试入门
  16. VSCode 花式玩法(摸鱼)了解一下
  17. 软件工程期末考试试题及答案(详细、经典)
  18. 使用vue开源项目vue-framework-wz遇到的问题以及解决方案
  19. 留美学子安全手册,这个可以有
  20. 《C语言详解》_by_Hanly.学习笔记(1)

热门文章

  1. 风口上的低代码:诱人的故事,危险的豪赌
  2. 约瑟夫·寇德卡:成为一个吉普赛人
  3. Couldnt load module input, no modules loaded
  4. 用Nero刻录ISO镜像制作启动光盘
  5. php jq实现抽奖,php 实现抽奖功能
  6. python计算圆柱体积_如何用PYTHON计算体积公式
  7. 由于幸存者偏差,导致强变量在后续迭代中逐渐削弱甚至相反怎么办|文末有福利
  8. python数字推盘游戏怎么显示步数_Python游戏开发:《最强大脑》同款游戏【数字华容道】...
  9. [0520更新]雷达原理【部分]答案 陈伯孝
  10. 根据用户IP地址来判断用户所在城市