飞桨paddlepaddle论文复现——BigGAN论文翻译解读
飞桨paddlepaddle论文复现——BigGAN论文翻译解读
- 摘要
- 介绍
- GAN回顾
- 原始GAN
- DCGAN
- WGAN
- BigGAN
- scaling
- Hierarchical latent spaces分层潜在空间
- 截断技巧
- Orthogonal Regularization正交正则化
- 分析
- 表征不稳定性:生成器
- 表征不稳定性:判别器
- 总结
- 代码
- 致谢
- 未完待续
论文地址:LARGE SCALE GAN TRAINING FOR HIGH FIDELITY NATURAL IMAGE SYNTHESIS
github地址:https://github.com/sxhxliang/BigGAN-pytorch
飞桨论文复现课程:https://aistudio.baidu.com/aistudio/education/group/info/1340
飞桨官网:https://www.paddlepaddle.org.cn/
摘要
尽管最近在生成图像建模方面取得了进展,但是从像ImageNet这样的复杂数据集中成功生成高分辨率,多样化的样本仍然是一个难以实现的目标。 为此,我们以最大规模培训了生成对抗网络,并研究了这种规模所特有的不稳定性。 我们发现将正交正则化应用于生成器使得它适用于简单的“截断技巧”,允许通过截断潜在空间来精确控制样本保真度和变化之间的权衡。我们的修改导致模型在类别条件下的图像合成中达到了新的技术水平。 当我们使用128×128分辨率在ImageNet上进行训练时,我们的模型(BigGAN)的Inception Score(IS)为166.3,Fréchet Inception Distance(FID)为9.6,相比之前的最佳IS为52.52,FID为18.65。
介绍
近年来,生成图像建模的状态发展迅速,生成对抗网络处于使用直接从数据中学习的模型生成高保真、多样化图像的最前沿架构。 GANs训练是动态的,并且几乎对其设置的每个方面都很敏感(从优化参数到模型架构),不过大量的研究已经在经验和理论上都给出了证实,表明GANs可以在各种环境中进行稳定的训练。 尽管取得了这些进展,但是在条件ImageNet下建模的现有实际技术水平只达到了52.5的IS,而真实数据的IS值则为233。
在这项工作中,我们着手缩小GAN生成的图像与ImageNet数据集中的真实图像之间的保真度和变化差距。 我们为此目标做出以下三个贡献:
- 我们证明了GAN从缩放中获益匪浅,并且与现有技术相比,训练模型的参数为2到4倍,batch大小达到8倍。 我们介绍了两种简单的通用体系结构更改,可以提高可伸缩性,并修改正则化方案不断调节,从而显著提升性能。
- 作为我们修改的副作用,我们的模型变得适合“截断技巧”,这是一种简单的采样技术,可以对样本种类和保真度之间的权衡进行明确、细粒度的控制。
- 我们发现特定于大规模GAN的不稳定性,并根据经验表征它们。 利用此分析的见解,我们证明新颖技术和现有技术的结合可以减少这些不稳定性,但完全的训练稳定性只能以极高的性能成本实现。
我们的修改大大改善了类别条件下的GAN。 当我们在128×128分辨率下对ImageNet进行训练时,我们的模型(BigGAN)将最先进的IS和FID分别从52.52和18.65提高到166.3和9.6。 我们还成功地在ImageNet上以256×256和512×512分辨率训练BigGAN,并且在256×256处实现了TS和FID 为233.0和9.3以及在512×512处的IS和FID为241.4和10.9。最后,我们在更大的数据集上训练我们的模型 - JFT-300M - 并证明我们的设计选择在ImageNet传输良好。
GAN回顾
原始GAN
GAN目标函数(损失函数)公式:
工作过程:
首先生成器产生一组数据,生成完数据之后将其固定住,将生成的数据与真实的数据一起送进判别器,训练判别器,直到判别器能将这两组数据准确区分开为止,此时固定住判别器,接下来训练生成器,生成器不断产生数据(也叫做假数据),直到判别器不能区分两组数据为止(判别器将假数据判别成真数据),如此往复,直到判别器再也不能区分由生成器生成的假数据和给定的真数据的区别为止(或者到达给定的迭代次数)。
推导过程可以参考:GAN的原理及推导 - 向前奔跑的少年 - 博客园
DCGAN
DCGAN的网络结构:
DCGAN 的判别器和生成器都使用了卷积神经网络(CNN)来替代GAN 中的多层感知机,同时为了使整个网络可微,拿掉了CNN 中的池化层,另外将全连接层以全局池化层替代以减轻计算量。
如上图,生成器G 将一个100 维的噪音向量扩展成64 * 64 * 3 的矩阵输出,整个过程采用的是微步卷积的方式。微步卷积是属于反卷积(去卷积,Deconvolution)的一种。
在DCGAN中我们需要用到卷积和反卷积:
卷积:
卷积有三种模式,分别是full、same、valid
从filter和image刚相交开始做卷积,白色部分为填0。(橙色部分为image, 蓝色部分为filter)
反卷积:
WGAN
WGAN推荐参考这篇博文:GAN的原理及推导 - 向前奔跑的少年 - 博客园
BigGAN
表1:我们提出的修改的模型下的Fréchet Inception Distance(FID,越低越好)和Inception Score(IS,越高越好)。 Batch是批量大小,Param是参数总数,Ch. 是每层中单元数的通道乘数,Shared表示是否使用共享嵌入,Hier.是否使用分层潜在空间,Ortho.是否正交正则化,Itr如果值为1000,则表示该设置对10610^6106次迭代是稳定的,否则表示在该迭代次数下它就崩溃了。 除了行1-4之外,还计算了8个不同随机初始化的结果。
我们首先增加基线模型的批量大小,并立即发现这样做的巨大好处。表1的第1-4行表明,简单地将批量大小增加8倍,使现有技术IS提高了46%。我们推测这是每批次覆盖更多模式的结果,为两个网络提供更好的梯度。这种缩放的一个值得注意的副作用是我们的模型在更少的迭代中达到更好的最终性能,但变得不稳定并且经历完全的训练崩溃。我们将在第4节中讨论其原因和后果。对于这些实验,我们在崩溃后立即停止训练,并报告之前保存的检查点的分数。
然后,我们将每层中的宽度(通道数)增加50%,大约两倍于两个模型中的参数数量。这导致IS进一步提高21%,我们认为这是由于模型的容量相对于数据集的复杂性而增加。加倍深度似乎不会对ImageNet模型产生相同的影响,反而会降低性能。
scaling
在Batch size增大到原来 8 倍的时候,生成性能上的IS提高了 46%。文章推测这可能是每批次覆盖更多模式的结果,为生成和判别两个网络提供更好的梯度。增大Batch size还会带来在更少的时间训练出更好性能的模型,但增大Batch size也会使得模型在训练上稳定性下降。
batchsize是现有方法8倍,每个batch覆盖更多的mode,为网络提供更好的梯度,卷积网络用的信道数是现有方法的2-4倍,对复杂数据增加了模型的容量,增加宽度,后面提出的biggan-depp 增加了深度,用了残差+瓶颈网络,提高了评分,更快的收敛。但是副作用是训练不稳定,容易崩,同时在网络中,还使用了一层自注意力,每层都是用SN谱归一化。
Hierarchical latent spaces分层潜在空间
不止首次输入噪声Z,在中间的每个残差块都输入Z,生成128pixel 图片为例,每个残差块对应一个Z块,初始的全连接输入也需要一个。总共需要6个,z_dim=120, 也就是每次输入的z的维度是20。
BigGAN在先验分布 z 的嵌入上做了改进,普遍的GAN都是将z作为输入直接嵌入生成网络,而 BigGAN 将噪声向量z送到G的多个层而不仅仅是初始层。
如下图,将噪声向量z通过split等分成多块,然后和条件标签c连接后一起送入到生成网络的各个层中,对于生成网络的每一个残差块又可以进一步展开为右图的结构。可以看到噪声向量z的块和条件标签c在残差块下是通过concat操作后送入BatchNorm层,其中这种嵌入是共享嵌入,线性投影到每个层的bias和weight。
还在网络中加入了class-conditional-batchnorm
截断技巧
训练的时候用Z~N(0,1)。测试采样的时候,z用截断,就是超过一定范围的时候数,不要,重新来,直到在范围内。
从图中我们可以看出来随着阈值的减小,图像的质量越来越高,但是生成图像的多样性也将降低。
Orthogonal Regularization正交正则化
对于许多模型而言,由不同采样引起的分布,相比在训练中看到的会不一样,很容易造成一些麻烦。我们的一些较大模型不适合截断,在馈送截断噪声时会产生饱和伪影(图4(b))。为了抵消这种情况,我们试图通过将G调节为平滑来强制实现截断的适应性,以便z的整个空间映射到良好的输出样本。为此,我们转向正交正则化,它直接强制正交性条件:
Rβ(W)=β∣∣WTW−I∣∣F2R_β(W) = β||W^TW - I||^2_FRβ(W)=β∣∣WTW−I∣∣F2
其中W是权重矩阵和β是超参数。 众所周知,这种正则化往往过于局限,因此我们探索了几种旨在放松约束的变体,同时为我们的模型赋予了理想的光滑度。 我们发现最好的版本从正则化中删除了对角项,并且目标是最小化滤波器之间的成对余弦相似性,但不限制它们的范数:
Rβ(W)=β∣∣WTW⨀(1−I)∣∣F2R_β(W) = β||W^TW {\bigodot} (1- I)||^2_FRβ(W)=β∣∣WTW⨀(1−I)∣∣F2
其中1表示一个矩阵,其中所有元素都设置为1。我们扫描β值并选择为10−410^{-4}10−4,从而找到足够小的额外正则化,以提高我们的模型易于截断的可能性。 在表中,我们观察到没有正交正则化时,只有16%的模型适合截断,而有正交正则化训练时则有60%。
分析
图5,光谱归一化之前G(a)和D(b)层中第一个奇异值σ0σ_0σ0的典型图。 G中的大多数层都具有良好的光谱,但是没有约束,一个小的子集在整个训练过程中会增长并在崩溃时爆炸。 D的光谱噪声较大,但表现更好。 从红色到紫色的颜色表示增加深度。
表征不稳定性:生成器
我们在训练期间监测一系列权重,梯度和损失统计数据,以寻找可能预示训练崩溃开始的指标,我们发现每个权重矩阵中的前三个奇异值σ0σ_0σ0,σ1σ_1σ1,σ2σ_2σ2是最有用的,大多数G层具有良好的光谱范式,但有些层(通常是G中的第一层,过于完整且非卷积)表现不佳,光谱范式在整个训练过程中增长,在崩溃时爆炸。
为了确定这种症状是否是塌陷造成的或者仅仅是一种症状,我们研究了对G施加额外调节以明确抵消光谱爆炸的影响。首先,我们直接使每个权重的顶部奇异值σ0σ_0σ0正则化,朝向固定值σregσ_{reg}σreg或者以某个比率r⋅sg(σ1)r{\cdot}sg(σ_1)r⋅sg(σ1)朝向第二奇异值(其中sg为停止梯度操作以防止正则化增加σ1σ_1σ1)。 或者,我们使用部分奇异值分解来代替σ0σ_0σ0。给定权重W,其第一个奇异向量μ0μ_0μ0和ν0ν_0ν0,以及σ0σ_0σ0将被值σclampσ_{clamp}σclamp钳制,我们的权重变为:
W=W−max(0,σ0−σclamp)ν0μ0TW = W - max(0,σ_0-σ_{clamp})ν_0μ_0^TW=W−max(0,σ0−σclamp)ν0μ0T
其中σclampσ_{clamp}σclamp被设置为σregσ_{reg}σreg或r⋅sg(σ1)r{\cdot}sg(σ_1)r⋅sg(σ1)。 我们观察到无论有无光谱归一化,这些技术都具有防止σ0σ_0σ0或σ0σ1\frac{σ_0}{σ_1}σ1σ0逐渐增加和爆炸的效果,但即使在某些情况下它们可以温和地提高性能,但没有任何组合可以防止训练崩溃。 这一证据表明,虽然调节G可能会改善稳定性,但它不足以确保稳定性。 因此,我们将注意力转向D。
表征不稳定性:判别器
与G一样,我们分析D的权重的光谱以深入了解其行为,然后通过施加额外的约束来寻求稳定训练。图5(b)显示了D的的典型图。与G不同,我们看到光谱是嘈杂的,σ0σ1\frac{σ_0}{σ_1}σ1σ0表现良好,并且奇异值在整个训练过程中增长,但只是在崩溃时跳跃而不是爆炸。
D光谱中的峰值可能表明它周期性地接收到非常大的梯度,但我们观察到Frobenius规范是平滑的,表明这种效应主要集中在前几个奇异方向上。我们假设这种噪声是通过对抗训练过程进行优化的结果,其中G定期产生强烈干扰D的batch。如果这种频谱噪声与不稳定性有因果关系,那么自然的反制是使用梯度惩罚,这明显地规范了D的雅可比行列式的变化。我们从(Mescheder等人,2018)那里探索R1R_1R1零中心梯度罚分:
R1=γ2EPD(x)[∣∣∇D(x)∣∣F2]R_1 = \frac{γ}{2}E_{P_{D(x)}}[||\nabla{D(x)}||^2_F]R1=2γEPD(x)[∣∣∇D(x)∣∣F2]
默认建议强度γγγ为10时,训练变得稳定并改善G和D中光谱的平滑度和有界性,但性能严重下降,导致IS减少45%。减少惩罚可以部分缓解这种恶化,但会导致频谱越来越不良;即使将惩罚力度降低到1(没有发生突然崩溃的最低强度),IS也会减少20%。使用正交正则化,DropOut和L2的各种改良重复该实验,揭示了这些正则化策略的行为效果:对D的惩罚足够高时,可以实现训练稳定性但是性能成本很高。
我们还观察到D在训练期间的损失接近于零,但在崩溃时经历了急剧的向上跳跃。这种行为的一个可能的解释是D过度拟合训练集,记忆训练样本而不是学习真实和生成图像之间的一些有意义的边界。作为D记忆的简单测试,我们在ImageNet训练和验证集上评估未折叠的鉴别器,并测量样本分类为真实或生成的百分比。虽然训练精度始终高于98%,但验证准确度仅在50-55%的范围内,并不比随机猜测更好(无论正则化策略如何)。这证实了D确实记住了训练集;我们认为这符合D的角色,这不是明确的概括,而是提炼训练数据并为G提供有用的学习信号。
总结
我们发现稳定性不仅仅来自G或D,而是来自他们通过对抗性训练过程的相互作用。 虽然他们的不良症状调节可用于追踪和识别不稳定性,但确保合理的调节是训练所必需的,但不足以防止最终的训练崩溃。 可以通过强烈约束D来强制实现稳定性,但这样做会导致性能上的巨大成本。 使用现有技术,可以通过放松这种调节并允许在训练的后期阶段发生塌陷来实现更好的最终性能,此时模型经过充分训练以获得良好的结果
代码
生成器:
class Generator(nn.Module):def __init__(self, code_dim=100, n_class=1000, chn=96, debug=False):super().__init__()self.linear = SpectralNorm(nn.Linear(n_class, 128, bias=False))if debug:chn = 8self.first_view = 16 * chnself.G_linear = SpectralNorm(nn.Linear(20, 4 * 4 * 16 * chn))self.conv = nn.ModuleList([GBlock(16*chn, 16*chn, n_class=n_class),GBlock(16*chn, 8*chn, n_class=n_class),GBlock(8*chn, 4*chn, n_class=n_class),GBlock(4*chn, 2*chn, n_class=n_class),SelfAttention(2*chn),GBlock(2*chn, 1*chn, n_class=n_class)])# TODO impl ScaledCrossReplicaBatchNorm self.ScaledCrossReplicaBN = ScaledCrossReplicaBatchNorm2d(1*chn)self.colorize = SpectralNorm(nn.Conv2d(1*chn, 3, [3, 3], padding=1))def forward(self, input, class_id):codes = torch.split(input, 20, 1)class_emb = self.linear(class_id) # 128out = self.G_linear(codes[0])# out = out.view(-1, 1536, 4, 4)out = out.view(-1, self.first_view, 4, 4)ids = 1for i, conv in enumerate(self.conv):if isinstance(conv, GBlock):conv_code = codes[ids]ids = ids+1condition = torch.cat([conv_code, class_emb], 1)# print('condition',condition.size()) #torch.Size([4, 148])out = conv(out, condition)else:out = conv(out)out = self.ScaledCrossReplicaBN(out)out = F.relu(out)out = self.colorize(out)return F.tanh(out)
判别器:
class Discriminator(nn.Module):def __init__(self, n_class=1000, chn=96, debug=False):super().__init__()def conv(in_channel, out_channel, downsample=True):return GBlock(in_channel, out_channel,bn=False,upsample=False, downsample=downsample)gain = 2 ** 0.5if debug:chn = 8self.debug = debugself.pre_conv = nn.Sequential(SpectralNorm(nn.Conv2d(3, 1*chn, 3,padding=1),),nn.ReLU(),SpectralNorm(nn.Conv2d(1*chn, 1*chn, 3,padding=1),),nn.AvgPool2d(2))self.pre_skip = SpectralNorm(nn.Conv2d(3, 1*chn, 1))self.conv = nn.Sequential(conv(1*chn, 1*chn, downsample=True),SelfAttention(1*chn),conv(1*chn, 2*chn, downsample=True), conv(2*chn, 4*chn, downsample=True),conv(4*chn, 8*chn, downsample=True),conv(8*chn, 16*chn, downsample=True),conv(16*chn, 16*chn, downsample=False))self.linear = SpectralNorm(nn.Linear(16*chn, 1))self.embed = nn.Embedding(n_class, 16*chn)self.embed.weight.data.uniform_(-0.1, 0.1)self.embed = spectral_norm(self.embed)def forward(self, input, class_id):out = self.pre_conv(input)out = out + self.pre_skip(F.avg_pool2d(input, 2))# print(out.size())out = self.conv(out)out = F.relu(out)out = out.view(out.size(0), out.size(1), -1)out = out.sum(2)out_linear = self.linear(out).squeeze(1)embed = self.embed(class_id)prod = (out * embed).sum(1)# if self.debug == debug:# print('class_id',class_id.size())# print('out_linear',out_linear.size())# print('embed', embed.size())# print('prod', prod.size())return out_linear + prod
训练:
class Trainer(object):def __init__(self, data_loader, config):# Data loaderself.data_loader = data_loader# exact model and lossself.model = config.modelself.adv_loss = config.adv_loss# Model hyper-parametersself.imsize = config.imsizeself.g_num = config.g_numself.z_dim = config.z_dimself.g_conv_dim = config.g_conv_dimself.d_conv_dim = config.d_conv_dimself.parallel = config.parallelself.gpus = config.gpusself.lambda_gp = config.lambda_gpself.total_step = config.total_stepself.d_iters = config.d_itersself.batch_size = config.batch_sizeself.num_workers = config.num_workersself.g_lr = config.g_lrself.d_lr = config.d_lrself.lr_decay = config.lr_decayself.beta1 = config.beta1self.beta2 = config.beta2self.pretrained_model = config.pretrained_modelself.dataset = config.datasetself.use_tensorboard = config.use_tensorboardself.image_path = config.image_pathself.log_path = config.log_pathself.model_save_path = config.model_save_pathself.sample_path = config.sample_pathself.log_step = config.log_stepself.sample_step = config.sample_stepself.model_save_step = config.model_save_stepself.version = config.versionself.n_class = config.n_classself.chn = config.chn# Pathself.log_path = os.path.join(config.log_path, self.version)self.sample_path = os.path.join(config.sample_path, self.version)self.model_save_path = os.path.join(config.model_save_path, self.version)self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')print('build_model...')self.build_model()if self.use_tensorboard:self.build_tensorboard()# Start with trained modelif self.pretrained_model:print('load_pretrained_model...')self.load_pretrained_model()
致谢
非常感谢百度论文复现营 AI Studio以及飞桨团队,无偿的让我们参加这次复现营,请到行业大牛带领我们读论文,进行论文复现,在群里为我们尽心尽力的答疑,并且还赠送免费算力让我们跑程序,利用这次机会我学到了很多,也非常感谢大佬G-Lab计算机视觉实验室对论文的翻译,让我在短时间内快速的理解了论文,希望我接下来的科研之路能够越来越顺利,也希望百度AI Studio和飞桨团队越来越好,共同打造好属于我们自己的框架。
未完待续
接下来会是讲解代码
参考文献:
[1]: https://aistudio.baidu.com/aistudio/education/group/info/1340
[2]: https://www.dazhuanlan.com/2019/12/12/5df1233a03c1f/
[3]: http://www.gwylab.com/index.html
飞桨paddlepaddle论文复现——BigGAN论文翻译解读相关推荐
- 使用飞桨PaddlePaddle复现用于图像光源处理的深度重照明网络(DRN)
使用飞桨PaddlePaddle复现用于图像光源处理的深度重照明网络(DRN) 一.效果展示 二.实现思路 冠军模型:Wavelet Decomposed RelightNet (WDRN) 经典模型 ...
- 飞桨PaddlePaddle(论文复现)-BigGAN解读
飞桨PaddlePaddle(论文复现)-BigGAN解读 先来看看效果(左上脚为生成的图像) 论文在现有GAN的基础上对生成样本的保真度与多样性之间的权衡进行改进 在ImageNet的128*128 ...
- 飞桨PaddlePaddle升级解读 | PaddleDetection物体检测统一框架
目标检测是机器视觉领域的核心问题之一.7 月 3 日百度 AI 开发者大会,飞桨核心框架 Paddle Fluid v1.5 宣布开源了 PaddleDetection 物体检测统一框架,用户可以非常 ...
- 飞桨PaddlePaddle深度学习实战
作者:刘祥龙,杨晴虹,胡晓光,于佃海 著 出版社:机械工业出版社 品牌:机工出版 出版时间:2020-09-01 飞桨PaddlePaddle深度学习实战
- 七夕礼物没送对?飞桨PaddlePaddle帮你读懂女朋友的小心思
本文作者:飞桨工程师 量子位 转载 | 公众号 QbitAI 七夕节,广大的钢铁直男们,你们给女朋友的礼物买对了么? "女孩儿的心思男孩你别猜,你猜来猜去也猜不明白.不知道她为什么掉眼泪,也 ...
- 基于百度飞桨PaddlePaddle模型训练的手势识别模型控制音乐播放器
基于百度飞桨paddle模型训练的手势识别模型控制音乐播放器 前言 一.什么是百度飞桨PaddlePaddle? 一.1 飞桨AI Studio 二.实际使用 1.配置虚拟环境 2.安装 三.实战 四 ...
- 工程师程序员的自我修养 Episode.4 基于百度飞桨PaddlePaddle框架的女朋友情绪分析防被打消息推荐深度学习系统
具体为什么想到这个题目呢...大概是我也想不出别的什么有趣的话题或者项目的工作了吧. 有一天,柏拉图问老师苏格拉底什么是爱情?老师就让他到理论麦田里去,摘一棵全麦田里最大最金黄的麦穗来,期间只能摘一次 ...
- 国产首款——飞桨PaddlePaddle深度学习框架介绍
现在深度学习框架不但内卷严重,而且头部效应明显.一提起深度学习框架,首先想到的肯定是Google家的TensorFlow,和Facebook家的PyTorch.究竟排名谁先谁后,还要看你是工业界还是学 ...
- 飞桨PaddlePaddle深度学习七日打卡营结营体会(小白菜只想混算力康康证书)
我是真的纯纯小白菜了,没法像大佬们一样技术心得体会了... 这是我第一次接触飞桨,第一次报飞桨的打卡营 我就 搞个 纯纯的体验版心得体会?(毕竟我就想看看证书啥样再混个算力 咋上路的 被大佬给我丢了个 ...
- 百度飞桨PaddlePaddle图像分割七日打卡营 class4 deeplab实现
百度飞桨PaddlePaddle图像分割七日打卡营 class4 deeplab实现 deeplab.py import numpy as np import paddle.fluid as flui ...
最新文章
- 燃爆,100个Python实战小项目汇总!
- 公文字体字号标准2020_零秒处理公文格式的三个要点
- Oracle处理小数点后位数、格式化数字、查找指定字符所在位置的几个函数
- python线上编辑问题_python django - static文件处理与线上部署测试
- 计划任务执行 php代码,php实现Windows任务计划定时执行的代码以及扩展(图)
- python闭包的延迟绑定_Python延迟绑定问题原理及解决方案
- java面试题1 牛客:A派生出子类B,B派生出子类C,并且在java源代码中有如下声明:
- sybase默认数据库
- simulink仿真实例_推荐几本关于制冷仿真的书籍(制冷仿真必备)
- teraterm linux环境,linux ssh telnet TeraTerm终端中文显示乱码解决方法
- android工程模式的指令,华为手机怎么进入工程模式 华为进工程模式指令
- 如何在Vue引入静态图片?
- ES数据的操作(二)
- Python肺CT图像窗位窗宽调整
- java上传加密_Java实现文件的加密与解密
- 计算机主机重装主机过程,电脑更换硬盘重装系统全过程详解
- 2021-01-22学习记录 || 通过二维数组初始化窗体并进行代码重构
- 项目管理四个核心要素
- Mongodb 查询重复数据
- 网络基础---广域网技术
热门文章
- html5 斗鱼 苹果,斗鱼ios端——手游直播开播指导
- 【论文解读】VDN( Variational Denoising Network )变分去噪网络
- Vue开发环境搭建 VsCode
- 威纶和s7200通讯线_威纶触摸屏与西门子S7200通讯实例
- java 获取url图片_java io流根据url读取图片
- python bin文件读写_Python读写文件
- 雅可比矩阵(Jacobian)、海森矩阵(Hessian)
- linux查看网口位置命令,Linux下查看网卡信息及确定网卡位置
- html media设置自适应屏幕用法,css使用@media响应式适配各种屏幕的方法示例
- linux下mysql定时备份