采用深度学习进行发票查验验证码模型的训练,在我电脑上模型训练的环境如下:
显卡:RTX 2080TI
tensorflow-gpu:2.5.3

1 训练集和测试集的准备

发票查验的验证码分为4种类型,分别为黑色、红色、黄色、蓝色,经过我的测试,采用4个模型的效果最好,每个模型对应识别一种类型的验证码。
首先我们4种类型的验证码都准备10万张。
00黑色类型的验证码:
在这里插入图片描述
01红色类型的验证码:
在这里插入图片描述
02黄色类型的验证码:
在这里插入图片描述
03蓝色类型的验证码:
在这里插入图片描述
验证码图像图像准备好后,对其进行标记,也就是对验证码重命名:
在这里插入图片描述
由于中文字符的个数很多,为了达到比较好的训练效果,验证码准备的越多约好,有条件的话每种类型验证码都准备30万张。

2 深度学习训练网络搭建

验证码识别也属于OCR识别,当然采用OCR识别效果最好也是最成熟的网络结构:CRNN+CTC。
CTC网络代码如下:

    rununit=256
    model=models.Sequential()
    model.add(Conv2D(64,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',input_shape=(32,None,3)))
    model.add(MaxPooling2D(pool_size=(2,2),strides=None,padding='valid'))
    model.add(Conv2D(128,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2),strides=None,padding='valid'))
    model.add(Conv2D(256,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu'))
    model.add(Conv2D(256,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu'))
    model.add(ZeroPadding2D(padding=(0,1)))
    model.add(MaxPooling2D(pool_size=(2,2),strides=(2,1),padding='valid'))
    model.add(Conv2D(512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu'))
    model.add(BatchNormalization(axis=1))
    model.add(Conv2D(512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu'))
    model.add(BatchNormalization(axis=1))
    model.add(ZeroPadding2D(padding=(0,1)))
    model.add(MaxPooling2D(pool_size=(2,2),strides=(2,1),padding='valid'))
    model.add(Conv2D(512,kernel_size=(2,2),strides=(1,1),padding='valid',activation='relu'))
    model.add(Permute(dims=(2,1,3)))
    model.add(TimeDistributed(Flatten()))
    model.add(Bidirectional(GRU(rununit,return_sequences=True,kernel_initializer='he_normal')))
    model.add(Dense(rununit,activation='linear'))
    model.add(Bidirectional(GRU(rununit,return_sequences=True,kernel_initializer='he_normal')))
    model.add(Dropout(rate=0.25))
    model.add(Dense(n_class,activation='softmax',kernel_initializer='he_normal'))

    model.summary()
    #载入已经训练好的模型接着训练
    # model=models.load_model('./model/chinatax_gen_01.h5')

    #以上代码模型就创建完了 接下来使用ctc loss
    #多输入单输出
    #获取模型的输出 接下来使用函数式API
    x=model.output#(None, 16, 37)这个是一个Tensor
    print(x.shape)
    model_output_shape=x.get_shape()
    #n_len=model_output_shape[1]
    '''
    y_true: 张量 (samples, max_string_length), 包含真实标签。
    y_pred: 张量 (samples, time_steps, num_categories
    ), 包含预测值,或 softmax 输出。
    input_length: 张量 (samples, 1), 包含 y_pred 中每个批次样本的序列长度。
    label_length: 张量 (samples, 1), 包含 y_true 中每个批次样本的序列长度。
    '''
    y_true=Input(shape=(None,),dtype='float32',name='the_labels')#(?,20)
    y_pred=x#(None, None, 37)
    input_length=Input(shape=(1,),dtype='int64',name='input_length')#(?, 1)
    label_length=Input(shape=(1,),dtype='int64',name='label_length')#(?, 1)
    
    #ctc损失函数 #(?, 1)
    ctc_loss=Lambda(ctc_lambda_func,output_shape=(1,),name='ctc_loss')(
        [y_true,y_pred,input_length,label_length]
    )
    #生成一个多输入单输出的ctc 模型 输入从第一个模型的输入开始
    input_tensor=model.input#(?,None, 40, 3)
    ctc_model=models.Model(inputs=[input_tensor,y_true,input_length,label_length],outputs=[ctc_loss])
    #编译模型 loss里的键值名称必须是上图中ctc_loss中的name名称
    ctc_model.compile(loss={'ctc_loss':lambda y_true,y_pred:y_pred},optimizer=optimizers.RMSprop())

    ctc_model.summary()

打印出的网络结构如下:

__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
conv2d_input (InputLayer)       [(None, 32, None, 3) 0
__________________________________________________________________________________________________
conv2d (Conv2D)                 (None, 32, None, 64) 1792        conv2d_input[0][0]
__________________________________________________________________________________________________
max_pooling2d (MaxPooling2D)    (None, 16, None, 64) 0           conv2d[0][0]
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 16, None, 128 73856       max_pooling2d[0][0]
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)  (None, 8, None, 128) 0           conv2d_1[0][0]
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 8, None, 256) 295168      max_pooling2d_1[0][0]
__________________________________________________________________________________________________
conv2d_3 (Conv2D)               (None, 8, None, 256) 590080      conv2d_2[0][0]
__________________________________________________________________________________________________
zero_padding2d (ZeroPadding2D)  (None, 8, None, 256) 0           conv2d_3[0][0]
__________________________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D)  (None, 4, None, 256) 0           zero_padding2d[0][0]
__________________________________________________________________________________________________
conv2d_4 (Conv2D)               (None, 4, None, 512) 1180160     max_pooling2d_2[0][0]
__________________________________________________________________________________________________
batch_normalization (BatchNorma (None, 4, None, 512) 16          conv2d_4[0][0]
__________________________________________________________________________________________________
conv2d_5 (Conv2D)               (None, 4, None, 512) 2359808     batch_normalization[0][0]
__________________________________________________________________________________________________
batch_normalization_1 (BatchNor (None, 4, None, 512) 16          conv2d_5[0][0]
__________________________________________________________________________________________________
zero_padding2d_1 (ZeroPadding2D (None, 4, None, 512) 0           batch_normalization_1[0][0]
__________________________________________________________________________________________________
max_pooling2d_3 (MaxPooling2D)  (None, 2, None, 512) 0           zero_padding2d_1[0][0]
__________________________________________________________________________________________________
conv2d_6 (Conv2D)               (None, 1, None, 512) 1049088     max_pooling2d_3[0][0]
__________________________________________________________________________________________________
permute (Permute)               (None, None, 1, 512) 0           conv2d_6[0][0]
__________________________________________________________________________________________________
time_distributed (TimeDistribut (None, None, 512)    0           permute[0][0]
__________________________________________________________________________________________________
bidirectional (Bidirectional)   (None, None, 512)    1182720     time_distributed[0][0]
__________________________________________________________________________________________________
dense (Dense)                   (None, None, 256)    131328      bidirectional[0][0]
__________________________________________________________________________________________________
bidirectional_1 (Bidirectional) (None, None, 512)    789504      dense[0][0]
__________________________________________________________________________________________________
dropout (Dropout)               (None, None, 512)    0           bidirectional_1[0][0]
__________________________________________________________________________________________________
the_labels (InputLayer)         [(None, None)]       0
__________________________________________________________________________________________________
dense_1 (Dense)                 (None, None, 3867)   1983771     dropout[0][0]
__________________________________________________________________________________________________
input_length (InputLayer)       [(None, 1)]          0
__________________________________________________________________________________________________
label_length (InputLayer)       [(None, 1)]          0
__________________________________________________________________________________________________
ctc_loss (Lambda)               (None, 1)            0           the_labels[0][0]
                                                                 dense_1[0][0]
                                                                 input_length[0][0]
                                                                 label_length[0][0]
==================================================================================================
Total params: 9,637,307
Trainable params: 9,637,291
Non-trainable params: 16

我这里识别的中文字符集为最常见的4000个左右,对于这种场景,没必要兼容所有的中文字符。
中文字符集如下:

characters='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ一乙八卜厂刀刁丁儿二几九力了乃七人入十又才叉川寸大凡飞干个工弓广及己巾久口亏马么门女乞千刃三山上勺尸士巳土丸万亡卫夕习下乡小丫也已亿义于与丈之子巴办贝比币卞不仓长车尺仇丑从歹丹邓订斗队厄乏反方分丰风凤夫父讣冈戈公勾互户化幻火讥计见介斤今仅井巨开亢孔历六仑毛木内牛匹片仆气欠切区犬劝壬仁认仍日冗少升什氏手书双水太天厅屯瓦王韦为文乌无毋五午勿心凶牙以艺忆尹引尤友予元曰月云匀允扎支止中爪专艾凹扒叭白半包北本必边丙布册斥出处匆丛打代旦电叼叮东冬对尔发犯冯弗付甘功古瓜归汉夯号禾弘乎卉汇击饥记加甲叫节纠旧句卡刊可兰乐礼厉立辽另令龙卢矛卯们灭民皿末母目奶尼鸟宁奴皮平扑讫仟巧且丘囚去冉让扔闪申生圣失石史矢示世仕市术甩帅司丝四他它台叹讨田汀头凸外未戊务仙写兄玄穴训讯央业叶仪议印永用由右幼玉驭孕匝札轧乍占仗召正汁只主仔左安百邦毕闭冰并产场臣尘成吃池弛驰充冲虫传闯创此次存达当导灯地吊丢动多夺朵讹而耳伐帆防仿访份讽伏负妇刚各巩共关观光圭轨过亥汗好合红后华划欢灰回会讳伙圾机肌吉汲级伎纪夹价尖奸件江讲匠交阶尽臼决诀军扛考扣夸匡扩老肋吏列劣刘吕伦论妈吗买迈芒忙米名牟那氖年农乓乒朴齐祁岂企迄扦迁乔庆曲权全任纫戎肉如汝阮伞扫色杀汕伤芍舌设师式收守戍死寺似讼岁孙她汤廷同吐团托驮网妄危伟伪问污伍西吸汐戏吓先纤向协邪兴刑邢行匈休朽戌许旭血旬寻驯巡汛迅压亚讶延厌扬羊阳仰尧爷页曳伊衣夷屹亦异因阴优有迂屿宇羽芋吁约杂再在早则宅兆贞阵争芝执旨至仲众舟州朱竹庄妆壮自字阿芭吧把坝扳扮伴报狈庇别兵伯驳补步材财灿苍沧层岔肠抄吵扯彻辰忱沉陈呈迟赤初串床吹纯词囱村呆但岛低狄弟佃甸盯钉冻抖豆杜肚妒兑吨囤扼返饭泛坊芳妨纺吠芬吩纷坟汾佛否扶甫抚附改杆肝肛纲岗杠告更攻汞贡沟估谷龟邯含罕旱何亨宏吼护沪花怀坏还鸡极即技忌际妓歼坚间角劫戒芥进近劲究玖灸局拒抉均君坎抗壳克坑吭抠库块快狂旷况困来劳牢冷李里丽励利沥连良两疗邻吝伶灵陇芦庐卤陆驴卵乱抡沦纶玛麦没每闷免妙牡亩呐纳男拟你尿扭纽弄努呕沤判抛刨沛批屁评沏启弃汽呛羌抢芹沁穷邱求驱却扰忍韧妊闰沙纱杉删邵社伸身沈声时识寿抒束吮私伺宋苏诉汰坍坛体条听彤投秃吞陀妥完汪忘违围苇尾纬位纹吻我沃巫呜芜吾吴坞希系匣闲县孝肖芯辛忻形杏汹秀序轩呀芽严言杨妖冶医沂矣抑邑役译吟饮应迎佣忧邮犹酉佑余园员远运灾皂灶诈张杖帐找折这针诊证吱址纸志诌肘助住抓状坠灼孜纵邹走足诅阻佐作坐哎岸肮昂拔爸佰败板版拌绊苞饱宝抱杯卑备奔苯彼贬变表秉拨波帛泊怖采参厕侧诧拆昌畅炒衬诚承齿侈宠抽炊垂刺担单诞到的迪抵底典店钓迭顶定侗剁法矾钒范贩肪房放非肥肺废沸氛奋忿枫奉肤拂服斧府阜咐该秆疙庚供苟狗构购咕沽孤姑股固刮乖拐怪官贯规诡柜刽国果函杭呵和河轰呼忽狐弧虎画话环昏或货季剂佳驾肩艰拣饯建降郊侥杰姐届金茎京经径净咎疚拘狙居驹咀沮具炬卷咖凯炕坷苛刻肯空苦侩矿岿坤昆垃拉拦郎佬泪例隶怜帘练林拎岭咙垄拢陋炉虏录侣轮罗码卖盲氓茅茂玫枚妹孟弥觅泌苗庙抿明鸣命抹沫陌拇姆牧奈闹呢妮泥拈念狞拧泞疟欧殴爬帕怕拍庞咆泡呸佩抨朋坯披贫坪苹凭坡泼迫妻其奇歧祈泣钎浅枪侨茄怯青顷泅屈取券炔乳软若叁丧刹苫衫陕尚绍舍呻绅审肾诗虱实使驶始事势侍饰视试受枢叔述刷饲松怂肃所苔抬态贪坦屉迢帖图兔拖驼拓玩宛枉往旺委味瓮卧武物昔析矽细侠贤弦现限线详享些胁泄泻欣幸性姓学询押岩炎沿奄佯疡耶夜依宜易诣绎英拥咏泳油盂鱼雨郁育苑岳枣责择泽闸咋沾斩账胀招沼者侦枕征怔郑枝知肢织直侄帜制质炙治忠终肿周帚咒宙诛拄贮注驻转拙卓茁宗卒组哀按袄疤柏拜帮绑胞保背钡甭泵迸毖陛扁便标柄饼炳玻勃残草测茬茶查差尝钞城持炽除穿疮春茨促带殆贷待怠胆挡荡帝点垫栋恫洞陡毒独度段钝盾哆垛俄饵洱贰罚阀珐费封疯氟俘赴复钙柑竿钢缸革阁给宫拱钩垢骨故剐挂冠闺鬼癸贵哈孩骇郝阂贺很狠恨恒哄虹洪侯厚胡哗徊宦荒皇恍挥恢诲绘荤浑活迹急挤济既枷荚架茧柬俭荐贱剑姜将奖浇骄娇狡饺绞皆洁结界疥诫津荆炯韭矩举觉绝钧俊郡咯砍看拷柯科咳客垦枯垮挎奎括栏览烂姥垒类厘荔俐俩炼亮临玲柳娄律峦孪洛骆络蚂骂脉茫冒贸眉美昧迷勉面秒闽某哪钠娜耐南挠恼逆柠钮浓怒虐挪鸥趴派盼叛胖炮胚盆砒毗拼品屏柒契砌恰洽牵前俏窃钦侵亲轻氢秋酋泉染饶绕茸荣绒柔茹洒砂珊神甚牲省胜狮施拾食蚀屎柿拭是适恃室首树竖耍拴顺说烁思送诵俗虽挞胎炭逃剃恬挑贴烃亭庭挺统突退挖哇洼娃歪弯威畏胃闻挝钨诬屋侮误洗虾峡狭咸涎显险宪相香响项巷削挟卸信星型修须叙恤宣选绚勋逊鸦哑咽研衍砚彦殃洋养姚咬药要姨蚁疫茵荫音姻荧盈映哟勇幽诱俞禹语狱垣怨院钥郧陨哉咱蚤怎眨栅炸毡栈战昭赵珍挣狰拯政帧指峙盅钟种重洲轴昼柱祝拽砖追浊兹咨姿籽总奏祖昨柞啊埃挨唉爱氨俺胺案盎敖捌笆耙罢班般颁梆蚌剥豹倍被笔毙宾病钵铂捕哺部蚕舱柴豺倡郴称乘逞骋秤耻翅臭础唇瓷脆挫耽郸党档捣倒敌涤递凋调爹逗都读顿峨娥恶饿恩烦匪诽粉峰逢浮俯釜赶皋高羔哥胳格根耕埂耿恭躬顾逛桂郭海氦害捍悍航耗浩荷核哼烘候壶桓换唤涣晃悔贿烩获积姬疾脊继家贾钾监兼捡健舰涧浆桨胶轿较桔借紧晋烬浸痉竞酒疽俱剧捐娟倦绢倔峻浚骏烤课恳恐哭胯宽框捆莱狼朗浪捞烙涝狸离莉栗砾哩莲涟恋凉谅料烈赁铃凌陵留流赂旅虑挛埋莽铆秘眠娩悯莫拿难脑馁能倪匿娘捏聂涅脓诺哦畔旁袍陪配砰疲瓶破剖莆埔圃浦栖凄脐起铅钱钳悄桥峭窍秦倾卿请拳缺热容辱润弱桑涩莎晒扇晌捎烧哨射涉砷娠逝殊恕衰栓谁朔耸颂素速绥祟损笋唆索泰谈袒唐倘烫涛绦桃陶套特疼剔涕铁通桐捅透徒途涂鸵袜顽挽桅蚊紊翁涡捂悟牺息席夏陷祥哮消宵晓校笑效屑胸羞袖绣徐畜眩殉鸭蚜烟盐艳唁宴验鸯秧氧样舀胰倚益谊殷莹痈涌铀娱峪浴预鸳冤袁原圆悦阅耘晕砸栽宰载赃脏造贼斋窄债盏展站涨哲浙真砧疹振症脂值挚致秩衷皱珠株诸逐烛桩谆准捉桌酌资租钻座皑笨崩绷敝彪彬菠舶脖埠猜彩菜惭惨曹掺谗铲阐猖常偿唱巢晨匙崇绸船捶淳绰疵凑粗崔淬措袋逮掸惮淡弹蛋祷悼盗得笛第掂惦淀掉谍兜堵断堆掇舵堕鄂菲啡酚烽符涪袱辅脯副盖敢鸽铬梗龚够菇蛊馆惯硅涵焊毫菏盒涸痕鸿唬淮患焕黄凰谎晦秽婚混祸基绩祭悸寄寂假笺检剪减渐铰矫脚教接秸捷惊颈竟厩救菊据距惧眷掘菌勘康啃控寇眶盔傀啦婪琅廊勒累梨犁理粒敛脸梁辆聊猎淋菱羚领琉聋笼隆颅掳鹿铝率绿掠略萝逻麻曼猫梅萌猛梦眯谜密绵冕描敏铭谋淖捻啮您偶啪排徘盘培烹捧啤偏票萍颇婆粕菩戚畦崎骑掐乾堑清情球蛆躯渠娶圈痊雀萨啥商梢奢赊蛇赦深婶渗绳盛授售兽梳淑孰庶爽硕宿隋随梭琐酞探堂淌掏萄淘梯惕添甜眺停铜桶偷屠推脱唾烷晚惋婉望唯惟维萎谓尉梧晤硒悉惜烯袭铣掀衔舷馅厢象萧淆啸斜谐械衅虚酗绪续悬旋雪崖涯焉阉淹阎掩眼谚痒窑野掖液铱移逸翌银淫寅隐婴萤营庸恿悠淤渔隅域欲渊跃酝铡粘崭绽章睁职趾掷痔窒猪著蛀缀啄着淄渍综族做隘傲奥跋斑棒傍谤堡悲辈惫焙逼编遍斌博渤裁策插搽搀馋敞超朝掣趁程惩畴厨锄滁储揣喘窗赐葱窜搓搭答傣氮道登等堤蒂缔奠跌鼎董痘犊赌渡短缎敦遁惰鹅遏筏番焚愤粪锋幅腑赋傅富溉港搁割葛蛤隔辜雇棺辊棍锅酣韩寒喊喝黑喉猴葫湖猾滑缓痪慌惶辉蛔惠惑缉棘集颊缄硷践溅蒋椒焦搅窖揭街筋晶景敬窘揪就鹃竣喀揩慨堪棵渴裤款筐葵馈愧溃阔喇腊阑揽缆榔棱傈痢联链量晾裂琳硫搂鲁禄屡缕氯落蛮帽媒寐媚幂棉缅渺募琶牌湃跑赔喷彭棚琵脾痞骗铺葡普期欺棋谦嵌腔强翘琴禽晴氰琼趋确裙然惹揉锐散搔骚嫂森筛善赏稍甥剩湿释舒疏赎暑黍属税舜斯搜酥粟遂锁塔毯棠锑提啼替腆艇童筒痛湍椭蛙湾皖腕喂渭温窝握晰稀犀喜隙厦羡湘翔硝销谢锌猩惺雄锈絮婿喧循雅蜒堰雁焰谣椰腋壹揖遗椅硬游釉逾愉渝遇喻御寓裕援缘越粤暂葬凿曾喳渣湛掌蛰植殖智滞粥蛛煮铸筑装椎琢滋紫棕揍最尊矮碍暗靶摆稗搬雹鲍碑鄙蓖痹辟滨摈搏睬缠痴酬稠愁筹雏楚搐触椽锤椿辞慈催瘁错滇碘殿碉叠锭督睹躲跺蛾蜂缝辐福腹缚概感搞跟鼓褂瑰跪滚貉瑚槐豢煌幌毁魂畸辑嫉蓟嫁煎简鉴键酱剿睫解锦谨靳禁睛粳靖舅锯楷窟跨筷窥魁廓赖蓝滥酪雷楞漓廉粮粱零龄溜馏楼碌路滤滦锣裸满谩锚煤蒙盟锰瞄谬摸漠寞墓幕睦腻溺暖蓬硼鹏碰频聘蒲签遣勤寝鹊群蓉溶瑞腮塞嗓瑟傻煞摄慑慎嗜输署蜀鼠数睡肆嗣塑溯蒜碎蓑塌摊滩痰塘搪滔腾誊填跳酮颓腿蜕碗微嗡蜗雾锡溪媳暇锨嫌献腺想像楔歇携新腥嗅蓄靴衙腰摇遥颐肄裔意溢颖雍蛹榆虞愚愈誉猿源韵詹障照罩锗斟甄蒸置稚锥滓罪蔼熬榜膀鼻碧蔽弊箔膊蔡碴察蝉踌瞅磁雌摧粹翠磋瘩凳滴翟嫡碟镀端锻孵腐嘎膏歌箍寡管裹豪赫褐箕嘉碱槛酵截竭兢精静境聚慷颗酷蜡辣谰璃僚寥撂廖榴漏箩骡嘛馒蔓慢漫貌酶镁蜜蔑摹模膜暮慕嫩蔫酿裴漂撇魄谱漆旗歉墙蔷锹敲榷熔赛僧煽墒裳韶誓瘦墅漱摔嗽僳酸算隧缩谭碳舔褪潍蔚瘟稳斡舞熙熄辖鲜熊墟需嘘熏演漾瑶疑缨蝇踊舆辕愿遭榨摘寨辗彰漳肇遮蔗蜘赚赘鞍懊澳磅镑褒暴膘憋瘪播踩槽嘲潮撤澈撑澄幢醇聪醋撮稻德蝶懂墩额樊敷噶镐稿骸憨鹤嘿横蝴糊蝗慧稽稼箭僵蕉踞撅靠磕澜磊黎鲤撩潦凛瘤篓戮履瞒霉摩墨碾撵镊镍潘磐澎劈僻篇飘潜谴撬擒趣褥蕊撒缮蔬熟撕嘶艘踏瘫潭膛躺趟踢题豌慰嘻膝瞎箱橡霄蝎鞋颜噎毅樱影豫蕴增憎樟震镇嘱撰篆撞踪醉遵翱薄壁避辨辩濒餐操糙橙橱篡颠靛雕篙糕翰撼憾衡磺霍激冀缴鲸镜篮懒蕾擂篱燎霖窿潞醚螟磨默穆霓凝耪篷膨瓢瞥器黔橇鞘擎醛瘸燃融儒擅膳噬薯擞獭糖蹄懈薪醒薛燕邀赞澡噪赠瘴辙臻整嘴癌臂辫擦藏簇戴蹈瞪繁壕嚎簧徽豁礁藉鞠爵糠儡镣磷螺檬糜藐懦瞧龋孺鳃赡曙霜瞬穗蹋檀嚏瞳臀魏檄霞襄臆翼赢糟燥骤瞩蹦鞭躇戳藩翻覆襟镭镰藕瀑藤嚣鹰瞻瓣爆鳖簿蹭颤蹿蹬蹲幺丐兮丕叨伛仵伥伧伉伫讴讷阱阪圩芊妃纡纣纥纨旮旯牝芙芸芷芮苋苌苁囵囫帏岍岐岖岘岑岚怄忤沐沌汨杞忑忐矶町钋钊甬鸠虬卦佼诘诙诟诠诤诨泔沭弩妲姗妾驿驽骀穹竺俨俪俅俚荟荀茗荠茭娅姝姣骁骅骈绛珂珑笈笃羿莘粑菁帼帷庵庾惬悻婊婕娼婵殒殓笙笠笤笳笞谡谥弑喋'

3 模型的训练以及性能测试

网络结构搭建完成后,就可以进行模型的训练,这里需要注意的时,要训练4个模型,因为我的方法是每个模型只识别一种类型的验证码。

train_times:256
true_acc rate:0.9539473684210527
max true acc rate:0.9671052631578947
----------------------------------------------------------------------------------------------------

train_times:257
true_acc rate:0.9539473684210527
max true acc rate:0.9671052631578947
----------------------------------------------------------------------------------------------------

训练过程的日志记录如上所示,对于01类型的验证码,在训练批次达到257时,最大的准确率就已经达到96.7%,可见模型的识别效果已经达到极高的水平。
模型训练好了,就可以将其部署为服务,接下来采用我的服务对包含中文的验证码进行识别。
在这里插入图片描述
识别其中的红色字符:

import base64
import requests

if __name__=='__main__':
    #读取图片,将图片转换为base64编码
    img_str=None
    with open('./chinatax/test.png','rb') as f:
        #直接读取图片是一种Unicode字节编码 b
        img_content=f.read()
        #将Unicode字节编码转为base64字节编码 b
        img_base64=base64.b64encode(img_content)
        #将base64字节转换为字符串类型
        img_str=img_base64.decode()
    
    if img_str!=None:
        json_data={
            'img_str':img_str,
            'yzm_lx':'01'
        }

        yzm_ret=requests.post(url='http://47.107.92.103:11000/yzmDetect',json=json_data)
        print('识别结果:',end='')
        print(yzm_ret.text)

在这里插入图片描述
通过自己阿里云上的服务,可以正确识别出验证码的中文字符。

Logo

领路信创诚邀您共建高质量内容社区,投稿申请~

更多推荐