位置: IT常识 - 正文

PyTorch 深度学习实战 | 基于生成式对抗网络生成动漫人物

编辑:rootadmin
原力计划PyTorch 深度学习实战 | 基于生成式对抗网络生成动漫人物

推荐整理分享PyTorch 深度学习实战 | 基于生成式对抗网络生成动漫人物,希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

生成式对抗网络(Generative Adversarial Network, GAN)是近些年计算机视觉领域非常常见的一类方法,其强大的从已有数据集中生成新数据的能力令人惊叹,甚至连人眼都无法进行分辨。本文将会介绍基于最原始的DCGAN的动漫人物生成任务,通过定义生成器和判别器,并让这两个网络在参数优化过程中不断“打架”,最终得到较好的生成结果。

01、生成动漫人物任务概述

日本动漫中会出现很多的卡通人物,这些卡通人物都是漫画家花费大量的时间设计绘制出来的,那么,假设已经有了一个卡通人物的集合,那么深度学习技术可否帮助漫画家们根据已有的动漫人物形象,设计出新的动漫人物形象呢?

本文使用的数据集包含已经裁减完成的头像如图1所示,每张图像的大小为96*96*3像素,总数为51000张。

图 1 动漫人物数据集

这项任务与之前的有监督任务不同之处在于,监督任务是有明确的输入和输出来对模型进行优化调整,而这一项任务是基于已有的数据集生成新的与原有数据集相似的新的数据。这是一个典型生成式任务,即假设原始数据集中所有的动漫图像都服从于某一分布,数据集中的图片是从这个分布随机采样得到的,倘若可以获得这个分布是什么,那么就可以获得与数据集中图片分布相同但完全不同的新的动漫形象。因此,生成式任务最重要核心任务就在于如何去获得这个分布。现有的基于图像的生成式框架有VAE和GAN两大分支,GAN的大名想必很多人都有所耳闻,其实验效果也是要由于VAE分支,本文将介绍基于GAN的动漫人物生成任务。

02、反卷积网络

反卷积层是GAN网络的非常重要的一个部件。大多数卷积层会使特征图的尺寸不断变小,但反卷积层是为了使得特征图逐渐变大,甚至与最初的输入图片一致。反卷积层最开始用于分割任务,后来也被广泛应用于生成式任务中,如图2所示,为一个反卷积层的正向传播时的计算过程,下层蓝色色块的为输入,白色虚线色块为padding的部分,上层绿色的为反卷积层的输出,原本3×3大小的特征图经过反卷积可以得到5×5的输出。本文的网络结构中也使用了反卷积层作为重要的一环。

图2 反卷积示意图

在分类或者分割等计算机视觉的任务当中,最终损失函数都需要对网络的输出与标签的差异进行量化,比如常见的L1、L2、交叉熵等损失函数,那么在生成式任务当中,当网络输出一张新的图片,如何去评判这张图片与原始数据集的分布是否一致?这是非常困难的一项事情,而GAN用很巧妙的思路规避了直接去判断分布是否一致,通过引入另一个网络(判别器)实现了判断两张图片是否一致这一任务。

具体来说,假设原始的分布为Pdata(X) ,PG(X;θ) 指参数值为θ的卷积网络,其以随机数x作为初入,输出一张图像,该卷积网络称为生成器,根据最大似然定理,希望每个样例出现的概率的乘积最大,即最大化:

对 θ 进行求解,可得:

即GAN的生成器目标是找到PG(X;θ)的一组参数,使其接近Pdata(X)分布,从而最小化生成器G生成结果与原始数据之间的差异

为了解决这个问题,GAN引入了判别器的概念,使用判别器D(X),来判断PG(X;θ)生成的结果与Pdata(X)分布是否一致,判别器的目标是给真样本奖励,假样本惩罚,判别器的目的在于尽可能的区分生成器生成的样本与数据集的样本,当输入为数据集的样本时,判别器输出为真,当输入为生成器生成的样本时,判别器输出为假,GAN的结构如图 3所示。

图3 GAN模型结构

判别器希望最大化的目标函数,就是

这一优化目标与交叉熵函数的形式非常相似,需要注意的是,在优化判别器时,生成器中的参数是不变的。生成器与判别器的目标不同,由于没有像监督学习那样的标签用于生成器,因此,生成器的目标为尽可能的骗过判别器,使判别器认为生成器生成的样本与原始数据集分布一致,即生成器的目标函数为

至此,GAN的损失函数可写为

03、DCGAN

本文中使用DCGAN作为网络模型,其核心思想与GAN一致,只是将原始GAN的多层感知器替换为了卷积神经网络,从而更符合图像的性质。下面介绍DCGAN的结构。

图4 DCGAN生成器网络结构

如图4可知,DCGAN的生成器从一个100维的随机变量开始,不断叠加使用反卷积层,最终得到的64*64*3的输出层。

其判别器为一个5层的卷积结构,以64*64*3大小作为输入,单独一个值作为输出,为输入判别器的图像与数据集图像同分布的概率。

训练步骤与损失函数与上文中GAN的一致,通过交替更新参数的方式,使生成器和判别器逐渐收敛。在下文中将具体介绍如何构建DCGAN并实现动漫人物生成。

04、基于DCGAN的动漫人物生成

新建GanModel.py文件,并在这个脚本中构建DCGAN的生成器和判别器模型,首先是生成器模型,由于本数据集的图片大小为96*96,因此对原始DCGAN的参数做了一些调整,使得最终经过生成器得到的图片大小也是96*96。

如代码清单1所示为经过调整后的生成器网络,同样包含有5层,出去最后一层,每层中都有一个卷积层、一个归一化层以及一个激活函数。

代码清单1 调整后的生成器网络

1.import torch.nn as nn2.# 定义生成器网络G3.class Generator(nn.Module):4. def __init__(self, nz=100):5. super(Generator, self).__init__()6. # layer1输入的是一个100x1x1的随机噪声, 输出尺寸1024x4x47. self.layer1 = nn.Sequential(8. nn.ConvTranspose2d(nz, 1024, kernel_size=4, stride=1, padding=0, bias=False),9. nn.BatchNorm2d(1024),10. nn.ReLU(inplace=True)11. )12. # layer2输出尺寸512x8x813. self.layer2 = nn.Sequential(14. nn.ConvTranspose2d(1024, 512, 4, 2, 1, bias=False),15. nn.BatchNorm2d(512),16. nn.ReLU(inplace=True)17. )18. # layer3输出尺寸256x16x1619. self.layer3 = nn.Sequential(20. nn.ConvTranspose2d(512, 256, 4, 2, 1, bias=False),21. nn.BatchNorm2d(256),22. nn.ReLU(inplace=True)23. )24. # layer4输出尺寸128x32x3225. self.layer4 = nn.Sequential(26. nn.ConvTranspose2d(256, 128, 4, 2, 1, bias=False),27. nn.BatchNorm2d(128),28. nn.ReLU(inplace=True)29. )30. # layer5输出尺寸 3x96x9631. self.layer5 = nn.Sequential(32. nn.ConvTranspose2d(128, 3, 5, 3, 1, bias=False),33. nn.Tanh()34. )35.36. # 定义Generator的前向传播37. def forward(self, x):38. out = self.layer1(x)39. out = self.layer2(out)40. out = self.layer3(out)41. out = self.layer4(out)42. out = self.layer5(out)43. return out

定义判别器模型及前向传播过程如代码清单2所示。

PyTorch 深度学习实战 | 基于生成式对抗网络生成动漫人物

代码清单2 判别器模型的定义与前向传播过程

1.# 定义鉴别器网络D2.class Discriminator(nn.Module):3. def __init__(self):4. super(Discriminator, self).__init__()5. # layer1 输入 3 x 96 x 96, 输出 64 x 32 x 326. self.layer1 = nn.Sequential(7. nn.Conv2d(3, 64, kernel_size=5, stride=3, padding=1, bias=False),8. nn.BatchNorm2d(64),9. nn.LeakyReLU(0.2, inplace=True)10. )11. # layer2 输出 128 x 16 x 1612. self.layer2 = nn.Sequential(13. nn.Conv2d(64, 128, 4, 2, 1, bias=False),14. nn.BatchNorm2d(128),15. nn.LeakyReLU(0.2, inplace=True)16. )17. # layer3 输出 256 x 8 x 818. self.layer3 = nn.Sequential(19. nn.Conv2d(128, 256, 4, 2, 1, bias=False),20. nn.BatchNorm2d(256),21. nn.LeakyReLU(0.2, inplace=True)22. )23. # layer4 输出 512 x 4 x 424. self.layer4 = nn.Sequential(25. nn.Conv2d(256, 512, 4, 2, 1, bias=False),26. nn.BatchNorm2d(512),27. nn.LeakyReLU(0.2, inplace=True)28. )29. # layer5 输出预测结果概率30. self.layer5 = nn.Sequential(31. nn.Conv2d(512, 1, 4, 1, 0, bias=False),32. nn.Sigmoid()33. )34.35. # 前向传播36. def forward(self, x):37. out = self.layer1(x)38. out = self.layer2(out)39. out = self.layer3(out)40. out = self.layer4(out)41. out = self.layer5(out)42. return out

定义完模型的基本结构后,新建另一个python脚本DCGAN.py,并将数据集放在同一目录下。如代码清单3所示,首先是引入会用到的各种包以及超参数,将超参数写在最前面方便后续需要修改的时候进行调整。其中超参数主要包含,一次迭代的batchsize大小,这个参数视GPU的性能而定,一般建议8以上,如果显存足够大,可以增大batchsize,batchsize越大,训练的速度也会越快。ImageSize为输入的图片大小,Epoch为训练要在数据集上训练几个轮次,Lr是优化器最开始的学习率的大小,Beta1为Adam优化器的一阶矩估计的指数衰减率,以及DataPath为数据集存放位置,OutPath为最终结果存放位置。

代码清单3 DCGAN超参数定义

1.import torch2.import torchvision3.import torchvision.utils as vutils4.import torch.nn as nn5.from GanModel import Generator, Discriminator6.7.# 设置超参数8.BatchSize = 89.ImageSize = 9610.Epoch = 2511.Lr = 0.000212.Beta1 = 0.513.DataPath = './faces/'14.OutPath = './imgs/'15.# 定义是否使用GPU16.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

接下来定义train函数,如代码清单4所示。以数据集、生成器、鉴别器作为函数输入,首先设置优化器以及损失函数。

代码清单4 train函数定义

1.def train(netG, netD, dataloader):2. criterion = nn.BCELoss()3. optimizerG = torch.optim.Adam(netG.parameters(), lr=Lr, betas=(Beta1, 0.999))4. optimizerD = torch.optim.Adam(netD.parameters(), lr=Lr, betas=(Beta1, 0.999))5.6. label = torch.FloatTensor(BatchSize)7. real_label = 18. fake_label = 0

再开始一轮一轮的迭代训练并输出中间结果,方便debug。

代码清单5 鉴别器训练

1.for epoch in range(1, Epoch + 1):2. for i, (imgs, _) in enumerate(dataloader):3. # 固定生成器G,训练鉴别器D4. optimizerD.zero_grad()5. # 让D尽可能的把真图片判别为16. imgs = imgs.to(device)7. output = netD(imgs)8. label.data.fill_(real_label)9. label = label.to(device)10. errD_real = criterion(output, label)11. errD_real.backward()12. # 让D尽可能把假图片判别为013. label.data.fill_(fake_label)14. noise = torch.randn(BatchSize, 100, 1, 1)15. noise = noise.to(device)16. fake = netG(noise)17. # 避免梯度传到G,因为G不用更新18. output = netD(fake.detach())19. errD_fake = criterion(output, label)20. errD_fake.backward()21. errD = errD_fake + errD_real22. optimizerD.step()

如代码清单5所示,首先固定生成器的参数,并随机一组随机数送入生成器得到一组假图片,同时从数据集中抽取同样数目的真图片,假图片对应标签为0,真图片对应标签为1,将这组数据送入判别器进行参数更新。

代码清单 6 生成器训练

1. # 固定鉴别器D,训练生成器G2. optimizerG.zero_grad()3. # 让D尽可能把G生成的假图判别为14. label.data.fill_(real_label)5. label = label.to(device)6. output = netD(fake)7. errG = criterion(output, label)8. errG.backward()9. optimizerG.step()10. if i % 50 == 0:11. print('[%d/%d][%d/%d] Loss_D: %.3f Loss_G %.3f'12. % (epoch, Epoch, i, len(dataloader), errD.item(), errG.item()))13.14.vutils.save_image(fake.data,15. '%s/fake_samples_epoch_%03d.png' % (OutPath, epoch),16. normalize=True)17.torch.save(netG.state_dict(), '%s/netG_%03d.pth' % (OutPath, epoch))18.torch.save(netD.state_dict(), '%s/netD_%03d.pth' % (OutPath, epoch))

如代码清单6所示,接下来固定判别器参数,训练生成器,生成器的目标是根据随机数生成得到的图片能够骗过判别器,使之认为这些图片为真,因此将生成得到的假图经过判别器得到判别结果,并设置标签全部为1,计算损失函数并反向传播对生成器参数进行更新。

在训练过程中,不断打印生成器和判别器Loss的变化情况,从而方便进行观察并调整参数。每训练完一个Epoch,则将该Epoch中生成器得到的假图保存下来,同时存储生成器和判别器的参数,防止训练过程突然被终止,可以使用存储的参数进行恢复,不需要再从头进行训练。

最后完成mian函数主程序入口代码的编写,其包含了加载数据集、定义模型、训练等步骤,如代码清单 7所示。

Transforms定义了对数据集中输入图片进行预处理的步骤,主要包含scale对输入图片大小进行调整,ToTensor转化为PyTorch的Tensor类型以及Normalize中使用均值和标准差来进行图片的归一化。

代码清单7 主程序

1.if __name__ == "__main__":2. # 图像格式转化与归一化3. transforms = torchvision.transforms.Compose([4. torchvision.transforms.Scale(ImageSize),5. torchvision.transforms.ToTensor(),6. torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])7. dataset = torchvision.datasets.ImageFolder(DataPath, transform=transforms)8.9. dataloader = torch.utils.data.DataLoader(10. dataset=dataset,11. batch_size=BatchSize,12. shuffle=True,13. drop_last=True,14. )15.16. netG = Generator().to(device)17. netD = Discriminator().to(device)18. train(netG, netD, dataloader)

开始训练后,在命令行可得类似于如图5的输出。

图5 训练过程命令行输出

与手写数字识别不同在于,可以发现生成器和判别器的Loss值都在一会高一会低的状态,这种状态是我们想要的结果吗?如果大家注意观察,会发现很多情况下当判别器的Loss值下降时,生成器的Loss值会上升,而判别器的Loss出现了上升,生成器Loss会出现下降。这是由于判别器和生成器一直处于一种互相“打架”的状态,生成器想要骗过判别器,而判别器则努力不去被生成器骗过,才会有Loss值出现如此状况。两个网络在循环打架过程中不断增强,最终就可以得到一个甚至能骗过人眼的生成器。

让我们来看一下经过一个Epoch迭代后的生成器得到的结果如图6所示。

图6 Epoch1测试结果可视化

好像已经有了那么一些轮廓,但又像戴了近视镜一样看不清,颇有些印象派作家的画风,继续训练网络,如图7所示,等到第5,第10个Epoch,会发现生成器生成的质量越来越高。

图7 Epoch15测试结果可视化

一直到第25个Epoch,得到的结果如图 8所示,尽管生成的图片中还是存在一些结构性问题,但也有一些图片逐渐开始接近于我们的期待。当然,本文迭代次数较少,仅有25次,若进一步升高迭代次数,最终可获得更加真实的动漫头像。

图8 Epoch25测试结果可视化

05、文末送书

今天给大家送出的是由冀俊峰著【作者简介】北京大学出版社出版的《数字身份与元宇宙信任治理》!

解析元宇宙框架及其信任治理底层逻辑,讨论数字身份模式的发展趋势,分解元宇宙数字身份的技术要素,建设元宇宙信任环境,助力未来元宇宙数字身份构建、管理、应用赋能及零信任安全管理。

内容简介

本书是一本介绍数字身份和元宇宙的普及型书籍,力求专业性与通俗性相平衡。全书共八章,其中前四章主要介绍数字身份管理及应用,包括数字身份的相关概念及特性;身份认证管理、应用赋能及零信任安全管理;各国的数字身份实施;讨论数字身份在公共治理、商业服务等领域的应用价值。后面四章主要探究元宇宙框架及其信任治理,从Web技术架构的演变,介绍元宇宙的网络技术基础Web 3.0,以及相关的数字身份模式的发展趋势;讨论元宇宙中的数字身份技术要素及形态特征,以及数字身份、数字分身等关键特征要素;探讨利用数字身份对元宇宙的信任环境进行治理的方法和技术;探讨如何构建元宇宙的信任治理规则。

作者简介

冀俊峰,中科院软件所博士,高级工程师,论文曾获得国际计算机图形学会议CGI'2005 最佳论文。自2005 年以来,作者一直在国家信息中心及国家电子政务外网管理中心从事网络规划及数字经济等方面的发展研究工作,撰写论文曾多次获得国家发改委中青年经济论坛优秀论文。主要做图形学VR\AR\区块链等。

参与方式:点击文章置顶评论红包,手气王自动获得北京大学出版社《数字身份与元宇宙信任治理》1本。

本文链接地址:https://www.jiuchutong.com/zhishi/299945.html 转载请保留说明!

上一篇:【前端】实际开发案例(前端实际开发)

下一篇:如何使用OpenAI fine-tuning(微调)训练属于自己专有的ChatGPT模型?(如何使用openAI总结小说内容)

  • keep里参加的活动怎么退出(keep里参加的活动怎么删除)

    keep里参加的活动怎么退出(keep里参加的活动怎么删除)

  • 小米返回键在哪里设置(小米返回键怎么弄)

    小米返回键在哪里设置(小米返回键怎么弄)

  • 剪映怎么合并分割的视频(剪映怎么合并分割开的两段音乐)

    剪映怎么合并分割的视频(剪映怎么合并分割开的两段音乐)

  • vivo手机分辨率怎么设置(vivo手机分辨率在哪)

    vivo手机分辨率怎么设置(vivo手机分辨率在哪)

  • 美图秀秀拼图视频没有声音(美图秀秀拼图视频怎么没有原声音)

    美图秀秀拼图视频没有声音(美图秀秀拼图视频怎么没有原声音)

  • pagedown键作用(pagedown快捷键)

    pagedown键作用(pagedown快捷键)

  • 手机日历怎么显示全月(手机日历怎么显示节假日)

    手机日历怎么显示全月(手机日历怎么显示节假日)

  • iwatch5屏幕什么材质(watch5的屏幕)

    iwatch5屏幕什么材质(watch5的屏幕)

  • 钉钉浮窗看抖音算时间吗(钉钉悬浮窗看抖音会不会计入时长)

    钉钉浮窗看抖音算时间吗(钉钉悬浮窗看抖音会不会计入时长)

  • 苹果6重启按什么键(苹果重启按什么键屏幕失灵)

    苹果6重启按什么键(苹果重启按什么键屏幕失灵)

  • 头条号和西瓜号一样吗(头条号和西瓜视频是什么关系)

    头条号和西瓜号一样吗(头条号和西瓜视频是什么关系)

  • 手机的勿扰模式有什么作用(手机的勿扰模式在哪里设置)

    手机的勿扰模式有什么作用(手机的勿扰模式在哪里设置)

  • 3gp是什么格式文件(3gp格式用什么播放器打开)

    3gp是什么格式文件(3gp格式用什么播放器打开)

  • iphone11手机铃声越来越小(iphone11铃声不响)

    iphone11手机铃声越来越小(iphone11铃声不响)

  • 找靓机几天可以到货(找靓机几天可以发货)

    找靓机几天可以到货(找靓机几天可以发货)

  • 互联网和因特网的区别与联系(互联网和因特网的关系)

    互联网和因特网的区别与联系(互联网和因特网的关系)

  • 苹果屏幕绿线会扩散吗(苹果手机屏有绿线继续用有什么影响)

    苹果屏幕绿线会扩散吗(苹果手机屏有绿线继续用有什么影响)

  • 恢复十年前qq聊天记录(恢复很多年前的qq聊天记录)

    恢复十年前qq聊天记录(恢复很多年前的qq聊天记录)

  • 关闭超线程可以提升单核性能吗(关闭超线程可以提升降低功耗吗)

    关闭超线程可以提升单核性能吗(关闭超线程可以提升降低功耗吗)

  • 支付宝怎么订ktv步骤(支付宝怎么订飞机票)

    支付宝怎么订ktv步骤(支付宝怎么订飞机票)

  • 把十进制数215转换成二进制数是(十进制数215转换成八进制数是)

    把十进制数215转换成二进制数是(十进制数215转换成八进制数是)

  • word页码全是1怎么连续(word2016页码都是1)

    word页码全是1怎么连续(word2016页码都是1)

  • 手机来电图片怎么设置(手机来电图片怎么变大)

    手机来电图片怎么设置(手机来电图片怎么变大)

  • 微信上的横屏模式啥意思(微信的横屏模式怎么关闭)

    微信上的横屏模式啥意思(微信的横屏模式怎么关闭)

  • 苹果xr防水等级(苹果xr防水等级是多少)

    苹果xr防水等级(苹果xr防水等级是多少)

  • 魅族16如何开启快充(魅族16thapn怎么设置)

    魅族16如何开启快充(魅族16thapn怎么设置)

  • 小米9怎么设置开机动画(小米9怎么设置返回键)

    小米9怎么设置开机动画(小米9怎么设置返回键)

  • 你肯定不知道的Win11五个隐藏功能(你肯定不知道的11个狗狗冷知识)

    你肯定不知道的Win11五个隐藏功能(你肯定不知道的11个狗狗冷知识)

  • GPT-4,大增长时代的序幕(增长gdp是什么意思)

    GPT-4,大增长时代的序幕(增长gdp是什么意思)

  • 所得税退税会计账务怎么处理
  • 更正申报后可以作废吗
  • 小规模纳税人是季报还是月报
  • 现金流量怎么影响股票价值
  • 公司购买的电脑怎么做账
  • 迟延履行利息记什么科目?
  • 信用卡产生滞纳金
  • 钉钉报销费用明细怎么写
  • 调财务报表怎样调整
  • 房屋购买安装电梯可以抵扣吗?
  • 工程结算与工程施工
  • 小规模开专票不超过45万要交税吗
  • 什么情况下企业不能辞退员工
  • 发票过期作废不了怎么办
  • 公司预付的货款怎么做账
  • 银行支票怎么用
  • 合同资产对应的成本
  • win10开机内存占用60% 8g占用过高
  • 取得土地所有权范围内的树如何处理
  • 怎么隐藏单元
  • 给子公司开票 总公司付款
  • 进项税少入账如何处理
  • vue中使用echars
  • Pycharm安装库失败
  • Java8 Stream流Collectors.toMap当key重复时报异常(IllegalStateException)
  • 巧克力山介绍
  • 小规模与一般纳税人做账区别
  • 纳税人性质是什么
  • 超图的应用举例
  • react js 教程
  • vue中$route
  • nodejs c扩展
  • Vue项目打包
  • typescriptlang
  • Laravel5.1自定义500错误页面示例
  • 哪些税金不需要通过应交税费科目核算
  • 财务f/p是什么意思的缩写
  • css代码基础
  • 唐山发生5.1级地震
  • sql数据库移动
  • Yii 连接、修改 MySQL 数据库及phpunit 测试连接
  • 织梦联动筛选教程
  • 公司签发银行承兑汇票的行为属于什么行为
  • 什么是增值?
  • 小型生产加工企业税率
  • 财务费用 科目
  • 怎么做掉公司账面库存100万
  • 进项税额转出在电子税务局怎么操作
  • 老板买私人飞机可以避税吗
  • 月度资金预算怎么填
  • 出口转内销补交进口增值税时间
  • 费用报销单如何粘贴票据
  • 销项税额减去进项税额就是该交的税吗
  • 小微企业增值税起征点是多少
  • 接受慈善捐款结尾怎么写
  • 远程连接局域网电脑
  • mysql_error
  • ubuntu安装软件没反应
  • 怎么删除文件的隐藏属性
  • microsoft window vista
  • windows 08
  • debian更新软件
  • backupnotify.exe是什么文件的进程 backupnotify进程安全吗
  • win8怎么关闭实时保护
  • win+p怎么用
  • win10wifi总是掉线
  • 红石id
  • linux怎么挂载文件夹
  • 创建表格在哪里找
  • 怎样用在js中使用css的内容
  • ecmascript6 官方文档
  • 对于javascript理解
  • javascript教程完整版
  • 你知道什么是布
  • java dom解析
  • 申请电子发票需要盖章吗
  • 北京市房山区限行范围
  • 收到unknown发来的短信
  • 慧付钱包app官网下载
  • 财税方面的问题有什么
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设