python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率

python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率,第1张

概述python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率目录python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率前言摘要本文主要解决的问题一、生成真实验证码二、定义DCGAN模型生成器判别器代码三、训练DCGAN模型参数定义对抗训练过程代码四、用DCGAN模型生成 python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率

目录python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率前言摘要本文主要解决的问题一、生成真实验证码二、定义DCGAN模型生成器判别器代码三、训练DCGAN模型参数定义对抗训练过程代码四、用DCGAN模型生成验证码五、建立并训练CNN模型六、测试模型准确率七、总结写在最后

前言好久不见呀,朋友们,这篇文章已经是“蓄谋已久”的了,一直没有时间编写,今天总算挤出点时间来好好写写了。因为之前有在看深度学习的书籍,并写了python生成验证码→处理验证码→建立CNN模型训练→测试模型准确率→识别验证码这篇博客,当时对CNN和GAN两个模型特别感兴趣,一直想着要做个实际的应用出来,于是乎,这篇的主角就是GAN了。在此之前看了很多关于GAN的文章,发现其有很多的变种,而本篇主要使用的是DCGAN,即深度卷积生成对抗网络。限于本人的理解能力,只是了解了GAN的皮毛,若本文有哪些不对的地方,还请大佬们指正~摘要

本文先是自定义生成了51000张验证码图片,5w张作为训练集,1k张作为测试集,先用训练集训练DCGAN模型,之后基于DCGAN模型生成验证码,这边规定生成的验证码需满足两个要求,一个是判别器评分大于0.95,另一个是验证码的4字符不在训练集中。最后,用模型所生成的这些验证码去训练一个CNN模型,并用一开始的1k张测试集去验证模型的准确率,最终的准确率为80%左右。

本文主要解决的问题

使用GAN生成指定字符的验证码图片,即生成器不但要会生成逼真的验证码,并且还能生成指定字符的验证码,同样,判别器不但要会判别真伪,还要会识别验证码的字符。

一、生成真实验证码

这一步就省略了,因为跟我的上一篇博客基本是一样的,只是生成的验证码数量多了,即self.train_num改为50000。

二、定义DCGAN模型生成器输入:batchsize×100×1×1维的噪声+batchsize×随机4字符的onehot编码向量中间处理:使用反卷积将噪声和label进行上采样,生成同维度的矩阵向量,然后将它们合并到一起,最后喂入生成器输出:batchsize×对应于输入的随机4字符的132×40的验证码图片判别器输入:batchsize×真实的或生成器生成的132×40的验证码图片+batchsize×该验证码字符onehot编码向量中间处理:使用卷积将图片的矩阵向量和label进行下采样,生成同维度的矩阵向量,然后将它们合并到一起,最后喂入判别器输出:batchsize×属于真实验证码图片的概率(0~1),也即score,score越接近1,表示越真实代码
import stringimport torchimport torch.nn as nnword2num = {v:k for k,v in enumerate(List(string.digits+string.ascii_uppercase))}captcha_number = 4nc = 3image_size = 64latent_space_size = 100ngf = 128ndf = 128class Generator(nn.Module):    '''生成器'''    def __init__(self):        super(Generator,self).__init__()        self.deconv_x = nn.Sequential(nn.ConvTranspose2d(latent_space_size, ngf//2, 4, 1, 0),nn.ReLU(True))        self.deconv_y = nn.Sequential(nn.ConvTranspose2d(captcha_number*len(word2num), ngf//2, 4, 1, 0),nn.ReLU(True))        self.model = nn.Sequential(            nn.ConvTranspose2d(ngf,ngf*8,4,1,0,bias=False),            nn.Batchnorm2d(ngf*8),            nn.ReLU(True),            nn.ConvTranspose2d(ngf*8,ngf*4,4,1,1,bias=False),            nn.Batchnorm2d(ngf*4),            nn.ReLU(True),            nn.ConvTranspose2d(ngf*4,ngf*2,4,2,1,bias=False),            nn.Batchnorm2d(ngf*2),            nn.ReLU(True),            nn.ConvTranspose2d(ngf*2,ngf,4,2,1,bias=False),            nn.Batchnorm2d(ngf),            nn.ReLU(True),            nn.ConvTranspose2d(ngf,nc,4,2,1,bias=False),            nn.Tanh())    def forward(self,x,y):        x = self.deconv_x(x)        y = self.deconv_y(y.unsqueeze(2).unsqueeze(3))        out = torch.cat([x,y],1)        output = self.model(out)        return output    class discriminator(nn.Module):    '''判别器'''    def __init__(self):        super(discriminator,self).__init__()        self.conv1_x = nn.Sequential(nn.Conv2d(nc, ndf//2, 4, 2, 1),nn.LeakyReLU(0.2,inplace=True))        self.conv1_y = nn.Sequential(nn.Conv2d(captcha_number*len(word2num), ndf//2, 4, 2, 1),nn.LeakyReLU(0.2,inplace=True))        self.model = nn.Sequential(            nn.Conv2d(ndf,ndf,4,2,1,bias=False),            nn.LeakyReLU(0.2,inplace=True),            nn.Conv2d(ndf,ndf*2,4,2,1,bias=False),            nn.Batchnorm2d(ndf*2),            nn.LeakyReLU(0.2,inplace=True),            nn.Conv2d(ndf*2,ndf*4,4,2,1,bias=False),            nn.Batchnorm2d(ndf*4),            nn.LeakyReLU(0.2,inplace=True),            nn.Conv2d(ndf*4,ndf*8,4,2,1,bias=False),            nn.Batchnorm2d(ndf*8),            nn.LeakyReLU(0.2,inplace=True),            nn.Conv2d(ndf*8,1,2,1,0,bias=False),            nn.SigmoID())            def forward(self,x,y):        x = self.conv1_x(x)        y = self.conv1_y(y.vIEw(x.size(0), captcha_number*len(word2num), 1, 1).expand(-1,-1,image_size,image_size))        out = torch.cat([x,y],1)        output = self.model(out)        return output
三、训练DCGAN模型参数定义生成器和判别器均使用Adam优化器,学习率learning_rate均设为1e-05,beta1系数均设为0.5使用bceloss作为损失函数训练周期epoch:100batch_size:64对抗训练过程判别器discriminator接收真实验证码图片+对应4字符,损失函数的y_true全为1,执行反向传播,优化器更新;生成器接收随机噪声z+随机4字符,计算得到的伪图片需要执行detach截断反向传播的梯度流;接收生成器生成的伪验证码图片+对应4字符,损失函数的y_true全为0,执行反向传播,优化器更新。生成器Generator接收随机噪声z+随机4字符,损失函数的y_true全为1,执行反向传播,优化器更新。代码
import numpy as npimport stringimport osfrom PIL import Imageimport torchimport torch.nn as nnfrom torch.optim import Adamfrom torch.autograd import Variablefrom torch.utils.data import Datasetfrom torch.utils.data import DataLoaderfrom torchvision import transformsfrom torchvision.utils import save_image, make_grIDimport matplotlib.pyplot as plt%matplotlib inlinedevice = 'cuda' if torch.cuda.is_available() else 'cpu'image_path = 'images/train/'latent_space_size = 100nc = 3 # chanel of img batch_size = 64epochs = 100learning_rate = 0.00001beta1 = 0.5workers = 2def one_hot_encode(value):    order = []    shape = captcha_number * len(word2num)    vector = np.zeros(shape, dtype=float)    for k, v in enumerate(value):        index = k * len(word2num) + word2num.get(v)        vector[index] = 1.0        order.append(index)    return vector, orderdef one_hot_decode(value):    res = []    for ik, iv in enumerate(value):        val = iv - ik * len(word2num) if ik else iv        for k, v in word2num.items():            if val == int(v):                res.append(k)                break    return "".join(res)class ImageDataSet(Dataset):    def __init__(self, folder):        self.transform=transforms.Compose([                transforms.Resize((image_size,image_size)),                transforms.ToTensor(),                transforms.normalize([0.5]*nc,[0.5]*nc)                ])        self.images = [os.path.join(folder,i) for i in os.Listdir(folder)]    def __len__(self):        return len(self.images)    def __getitem__(self, IDx):        image_path = self.images[IDx]        captcha_str=image_path[-8:-4]        vector,order = one_hot_encode(captcha_str)        vector=torch.floatTensor(vector)        image = self.transform(Image.open(image_path))        return image,vector,orderdef loader(image_path,batch_size):    imgdataset=ImageDataSet(image_path)    return DataLoader(imgdataset,batch_size=batch_size,shuffle=True,num_workers=workers)if __name__ == '__main__':    netd=discriminator().to(device=device)  # 生成器    netg=Generator().to(device=device)      # 判别器    # Adam优化器    optimizerD = Adam(netd.parameters(),lr=learning_rate,betas=(beta1,0.999))    optimizerG = Adam(netg.parameters(),lr=learning_rate,betas=(beta1,0.999))    # bceloss损失函数    criterion = nn.bceloss().to(device=device)    # 生成一批固定的噪声z和字符标签,用于观看模型拟合的效果    fix_z = Variable(torch.floatTensor(10,latent_space_size,1,1).normal_(0,1)).to(device=device)    fix_y=[]    random_strs=[np.random.choice(os.Listdir(image_path))[:4] for _ in range(10)]    print(random_strs)    print()    for i in random_strs:        fix_y.append(one_hot_encode(i)[0])    fix_y=Variable(torch.floatTensor(fix_y)).to(device=device)    G_LOSS=[]    D_LOSS=[]    DataLoader=loader(image_path,batch_size)    for epoch in range(epochs):        mean_G=[]        mean_D=[]        for ii,(img,vector,order) in enumerate(DataLoader):            img=Variable(img).to(device=device)            vector=Variable(vector).to(device=device)            is_real = Variable(torch.ones(img.size(0))).to(device=device) # 1 for real            is_fake = Variable(torch.zeros(img.size(0))).to(device=device) # 0 for fake            # 训练判别器            netd.zero_grad()            output=netd(img,vector)            errD_real = criterion(output.vIEw(-1), is_real)            errD_real.backward()            z = Variable(torch.randn(img.size(0),latent_space_size,1,1).normal_(0,1)).to(device=device)            fake_pic=netg(z,vector).detach()            output=netd(fake_pic,vector)            errD_fake = criterion(output.vIEw(-1), is_fake)            errD_fake.backward()            optimizerD.step()            # 训练生成器            netg.zero_grad()            fake_pic=netg(z,vector)            output=netd(fake_pic,vector)            errG = criterion(output.vIEw(-1), is_real)            errG.backward()            optimizerG.step()            mean_G.append(errG.item())            mean_D.append(errD_real.item()+errD_fake.item())        print(f'epoch:{epoch}         D_LOSS:{np.mean(mean_D)}           G_LOSS:{np.mean(mean_G)}')        G_LOSS.append(np.mean(mean_G))        D_LOSS.append(np.mean(mean_D))        if epoch%20==0:            fake_u=netg(fix_z,fix_y)            imgs = make_grID(fake_u.data*0.5+0.5,nrow=5).cpu()            plt.imshow(imgs)            plt.show()    plt.plot(List(range(len(G_LOSS))),G_LOSS)    plt.plot(List(range(len(G_LOSS))),D_LOSS)    plt.show()     # 保存模型    torch.save(netd.state_dict(),'DCGAN_netd.pth')    torch.save(netg.state_dict(),'DCGAN_netg.pth')

大约三个小时左右,模型训练完成,来看看效果咋样,DCGAN模型生成的与真实的验证码图片比较如下:

DCGAN生成的验证码真实的验证码

效果其实还算不错,不过跟真实的相比还是有点差距的。

四、用DCGAN模型生成验证码

生成的验证码将满足两个条件:

输入到判别器中的得到结果评分大于0.95生成的4字符验证码不在训练集中,即全新的验证码图片
import torchfrom torch.autograd import Variablefrom torchvision.utils import save_image, make_grIDfrom PIL import Imagefrom tqdm import tqdmimport osimport stringword2num={v:k for k,v in enumerate(List(string.digits+string.ascii_uppercase))}image_path='images/train/'device = 'cuda' if torch.cuda.is_available() else 'cpu'latent_space_size = 100image_height=40image_wIDth=132if not os.path.exists('生成的图片/')	os.makedirs('生成的图片/')temp=List(word2num.keys())all_a=[] # 储存所有可能的4字符验证码for i in temp:    for j in temp:        for k in temp:            for l in temp:                what=i+j+k+l                all_a.append(what)netd=discriminator().to(device=device)netg=Generator().to(device=device)netd.load_state_dict(torch.load('DCGAN_netd.pth'))netg.load_state_dict(torch.load('DCGAN_netg.pth'))all_aa=[i[:4] for i in os.Listdir(image_path)]for a in tqdm(all_a):    z = Variable(torch.randn(1,latent_space_size,1,1).normal_(0,1)).to(device=device)    fake_pic=netg(z,Variable(torch.floatTensor([one_hot_encode(a)[0]])).to(device=device))    score=netd(fake_pic,Variable(torch.floatTensor([one_hot_encode(a)[0]])).to(device=device)).vIEw(-1).data.cpu().numpy()[0]    if (score>0.95)&(a not in all_aa):        imgs = make_grID(fake_pic.data*0.5+0.5).cpu() # CHW        save_image(imgs,f'生成的图片/{a}.png')        imgs=Image.open(f'生成的图片/{a}.png')        imgs=transforms.Resize((image_height,image_wIDth))(imgs)        imgs.save(f'生成的图片/{a}.png')

运行以上代码,三个小时左右便完成了验证码图片的生成,无意外的话生成的验证码有1w+以上

五、建立并训练CNN模型

限于边幅这一步的代码就省略了吧,因为跟我的上一篇博客是基本一样的,只是训练集需要改用DCGAN生成的验证码,process_img函数做二值化时的阈值改为120,epochs改为10,以及batch_size改为32。

以下为训练过程打印输出:

Train startIteration is 383epoch:1, step:100, loss:0.11870528757572174epoch:1, step:200, loss:0.09803573042154312epoch:1, step:300, loss:0.07167644798755646epoch:2, step:100, loss:0.060339584946632385epoch:2, step:200, loss:0.0454578697681427epoch:2, step:300, loss:0.045735735446214676epoch:3, step:100, loss:0.03509911149740219epoch:3, step:200, loss:0.03168116882443428epoch:3, step:300, loss:0.03217519074678421epoch:4, step:100, loss:0.029901988804340363epoch:4, step:200, loss:0.032566048204898834epoch:4, step:300, loss:0.028481818735599518epoch:5, step:100, loss:0.022674065083265305epoch:5, step:200, loss:0.019393315538764epoch:5, step:300, loss:0.023355185985565186epoch:6, step:100, loss:0.027277015149593353epoch:6, step:200, loss:0.018431685864925385epoch:6, step:300, loss:0.01690380461513996epoch:7, step:100, loss:0.022878311574459076epoch:7, step:200, loss:0.02011089399456978epoch:7, step:300, loss:0.020655091851949692epoch:8, step:100, loss:0.013621113263070583epoch:8, step:200, loss:0.015619204379618168epoch:8, step:300, loss:0.024786094203591347epoch:9, step:100, loss:0.016219446435570717epoch:9, step:200, loss:0.015738267451524734epoch:9, step:300, loss:0.016928061842918396epoch:10, step:100, loss:0.01601400598883629epoch:10, step:200, loss:0.015124175697565079epoch:10, step:300, loss:0.01665317639708519Train done
六、测试模型准确率

这一步也就省略了吧,因为跟我的上一篇博客测试模型准确率时的代码完全一样的

以下为测试打印输出:

load cnn modelFail, captcha:NTJI->NTJ1Fail, captcha:E57N->E5Z6Fail, captcha:BKI6->BKT6Fail, captcha:U0IQ->UCIQFail, captcha:GEQI->GEQ1Fail, captcha:KIC4->K1C4Fail, captcha:PCSO->PCS0Fail, captcha:XW4O->XW40Fail, captcha:TQXU->TQYUFail, captcha:4KCY->4K0YFail, captcha:COG1->CCG1Fail, captcha:CZX7->CZY7Fail, captcha:Q508->Q5D8Fail, captcha:79GR->798RFail, captcha:DNBT->DNBI......Fail, captcha:V043->VO43Fail, captcha:G1XF->G1YF完成。总预测图片数为1000张,准确率为81%

可以看到准确率为81%

七、总结在没有使用任何真实图片的情况下,只用DCGAN生成的伪图片去训练CNN模型,然后用真实的图片去验证模型的准确率,效果还是不错的,只是需要的用于训练DCGAN的验证码数量多了一点。在一开始用500张到用50000张去训练DCGAN模型,最终CNN模型的准确率是逐步上升的,这点无可厚非,因为量上去了。并且在这个过程中,还需要不断地改变超参数,以适应量的递增。期间,有试过用DCGAN模型生成的伪验证码图片跟一些真实的验证码图片,去训练CNN模型,得到的准确率确实会比只用真实的那部分验证码图片去训练要好一点点。想要在极少的真实验证码图片上去训练GAN,并且还要得到很不错的效果的,我想只能改变当前的DCGAN模型,或者使用其他深度学习模型才能完成了。

以上即本篇的全部内容,主要核心代码全都在上面了,若想要完整的源代码,那就关注一下《Python王者之路》公众号,回复关键词:20210601,即可获取源代码。


本文所参考的链接

https://github.com/chenyuntc/pytorch-GANhttps://github.com/TeeyoHuang/conditional-GAN
写在最后

时隔半年,我又重新捡起了我的CSDN,半年了,你知道我这半年是怎么过的吗。。。

一个原因是上班太忙了,根本没时间静下心来写写东西,虽然目前是双休,而且总是幻想着周末一定要好好学习一番,可真正到了周末才发现,还是床比较舒服一点~

另一个原因是有个卡点一直过不去,做不到完美,一开始我想的是只用500张真实的验证码图片,就能训练出一个能够输出逼真验证码图片的GAN模型,这样的话就可以完美地解决了所有字符型验证码了,然而想象很美好,现实却很骨感。。

不过呢,现在总算是完成了半年前就想写的这篇博客了,其实把这个探究的过程记录下来,成就感也是满满的,悬挂着的心也可以放松一下了,然后,继续奔着下一个目标前进!!

刚好,今天正好是六一,那就在这祝各位小朋友&大朋友们,节日快乐啦~

总结

以上是内存溢出为你收集整理的python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率全部内容,希望文章能够帮你解决python+DCGAN模型生成验证码+训练CNN模型+测试模型准确率所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1185432.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存