利用深度学习实现验证码识别-3-ResNet18

在当今数字化时代,验证码作为一种重要的安全验证手段,广泛应用于各种网络场景。然而,传统的验证码识别方法往往效率低下,准确率不高。今天,我们将介绍一种基于 ResNet18 的验证码识别方法,它能够高效、准确地识别验证码,为网络安全提供有力保障。
在这里插入图片描述

一、技术背景

深度学习技术在图像识别领域取得了巨大的成功,ResNet18 作为一种经典的深度神经网络架构,具有强大的特征提取能力和良好的泛化性能。我们利用 ResNet18 的这些优势,将其应用于验证码识别任务中,通过迁移学习的方法,快速训练出一个高效的验证码识别模型。

以下是实现 ResNet18 验证码识别的代码:

import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset, random_split
from torchvision import transforms, models
import random
import string
from PIL import Image, ImageDraw, ImageFont
import os
import matplotlib.pyplot as plt# 检查 CUDA 是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f'Using device: {device}')# 数据生成器,支持自定义字符集和验证码长度
class CaptchaDataset(Dataset):def __init__(self, length=1000, charset=None, captcha_length=5, transform=None):self.length = lengthself.transform = transformself.charset = charset if charset is not None else string.ascii_letters + string.digitsself.captcha_length = captcha_lengthself.num_classes = len(self.charset)self.font = ImageFont.truetype("arial.ttf", 40)self.image_size = (100, 40)def __len__(self):return self.lengthdef __getitem__(self, idx):text = ''.join(random.choices(self.charset, k=self.captcha_length))image = Image.new('L', self.image_size, color=255)draw = ImageDraw.Draw(image)draw.text((10, 5), text, font=self.font, fill=0)if self.transform:image = self.transform(image)label = [self.charset.index(c) for c in text]return image, torch.tensor(label, dtype=torch.long)# 数据增强和预处理
transform = transforms.Compose([transforms.Resize((40, 100)),transforms.RandomRotation(10),transforms.ColorJitter(brightness=0.5, contrast=0.5),transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,))
])# 设置字符集和验证码长度
charset = string.digits  # 仅支持数字
captcha_length = 4  # 验证码长度设置为 6 位
dataset = CaptchaDataset(length=2000, charset=charset, captcha_length=captcha_length, transform=transform)
train_size = int(0.8 * len(dataset))
val_size = len(dataset) - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False)# 使用预训练 ResNet 模型,迁移学习
class CaptchaModel(nn.Module):def __init__(self, num_classes, captcha_length):super(CaptchaModel, self).__init__()self.captcha_length = captcha_lengthself.resnet = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)self.resnet.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)num_ftrs = self.resnet.fc.in_featuresself.resnet.fc = nn.Linear(num_ftrs, num_classes * self.captcha_length)  # 动态调整输出层大小def forward(self, x):x = self.resnet(x)return x.view(-1, self.captcha_length, num_classes)# 初始化模型,损失函数和优化器
num_classes = len(charset)
model = CaptchaModel(num_classes=num_classes, captcha_length=captcha_length).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 加载或保存训练检查点
def save_checkpoint(state, filename="captcha_model_checkpoint.pth.tar"):print("=> Saving checkpoint")torch.save(state, filename)def load_checkpoint(filename="captcha_model_checkpoint.pth.tar"):print("=> Loading checkpoint")return torch.load(filename)# 支持多次训练,从检查点恢复训练
def train_model(epochs, resume=False):start_epoch = 0if resume and os.path.isfile("captcha_model_checkpoint.pth.tar"):checkpoint = load_checkpoint()model.load_state_dict(checkpoint['state_dict'])optimizer.load_state_dict(checkpoint['optimizer'])start_epoch = checkpoint['epoch']scaler = torch.cuda.amp.GradScaler()for epoch in range(start_epoch, epochs):model.train()running_loss = 0.0for images, labels in train_loader:images, labels = images.to(device), labels.to(device)optimizer.zero_grad()with torch.cuda.amp.autocast():outputs = model(images)loss = sum(criterion(outputs[:, i, :], labels[:, i]) for i in range(captcha_length))scaler.scale(loss).backward()scaler.step(optimizer)scaler.update()running_loss += loss.item()# 计算验证集准确率val_accuracy = evaluate_accuracy(val_loader)print(f'Epoch [{epoch+1}/{epochs}], Loss: {running_loss/len(train_loader):.4f}, Val Accuracy: {val_accuracy:.4f}')# 保存检查点save_checkpoint({'epoch': epoch + 1,'state_dict': model.state_dict(),'optimizer': optimizer.state_dict(),})# 计算准确率
def evaluate_accuracy(data_loader):model.eval()correct = 0total = 0with torch.no_grad():for images, labels in data_loader:images, labels = images.to(device), labels.to(device)outputs = model(images)predicted = torch.argmax(outputs, dim=2)total += labels.size(0) * captcha_lengthcorrect += (predicted == labels).sum().item()return correct / total# 可视化模型预测结果
def visualize_predictions(num_samples=16):model.eval()samples, labels = next(iter(DataLoader(val_dataset, batch_size=num_samples, shuffle=True)))samples, labels = samples.to(device), labels.to(device)with torch.no_grad():outputs = model(samples)predicted = torch.argmax(outputs, dim=2)samples = samples.cpu()predicted = predicted.cpu()labels = labels.cpu()fig, axes = plt.subplots(4, 4, figsize=(10, 10))for i in range(16):ax = axes[i // 4, i % 4]ax.imshow(samples[i].squeeze(), cmap='gray')true_text = ''.join([dataset.charset[l] for l in labels[i]])pred_text = ''.join([dataset.charset[p] for p in predicted[i]])ax.set_title(f'True: {true_text}\nPred: {pred_text}')ax.axis('off')plt.show()# 训练模型
train_model(epochs=20, resume=False)# 可视化模型预测结果
visualize_predictions()

在这里插入图片描述

在这里插入图片描述

四、模型评估与可视化

  1. 准确率计算:我们使用准确率作为模型的评估指标,计算方法是将模型预测正确的验证码数量除以总验证码数量。在验证集上的准确率可以反映模型的泛化能力。
  2. 可视化预测结果:为了更好地理解模型的预测结果,我们使用可视化方法展示了模型在验证集上的预测结果。具体来说,我们随机选择了一些验证码图像,并将其输入到模型中进行预测。然后,我们将模型的预测结果与真实结果进行比较,并以图像的形式展示出来。

五、总结与展望

通过使用 ResNet18 进行验证码识别,我们取得了较好的效果。在未来的工作中,我们可以进一步优化模型架构和训练方法,提高模型的准确率和效率。同时,我们还可以将该方法应用于其他类型的验证码识别任务中,为网络安全提供更加全面的保障。

总之,ResNet18 为验证码识别提供了一种新的思路和方法,它具有强大的特征提取能力和良好的泛化性能,能够高效、准确地识别验证码。相信在未来的发展中,深度学习技术将在验证码识别领域发挥更加重要的作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/878563.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Canvas绘制线条时断断续续的

解决线条断断续续的关键代码如下: 我们可以使用quadraticCurveTo来实现贝塞尔曲线使其变成光滑的曲线 注意: ctx.value.lineCap "round"; ctx.value.lineJoin "round"; 这两个属性是必须设置的 lastX,…

域名是什么

在这个数字世界中,域名无疑是连接用户与网站的关键纽带。域名,是由一串字符组成的地址,用于在互联网上唯一标识和定位一个特定的资源。本文将深入探讨域名的概念、作用以及对互联网发展的重要性。 一、域名的定义与结构 域名可以看作是互联网…

MySQL第10讲--约束的介绍

文章目录 前言约束约束的演示 外键约束删除外键外键删除/更新行为 前言 在第9讲MySQL第9讲–函数的介绍中我们主要介绍了几种mysql的内置函数:字符串函数、数值函数、流程函数、日期函数,并对这些函数中常用的几种函数做了总结,如下图所示&am…

大跨度工业仓储气膜:零排放与消防安全的理想选择—轻空间

在现代工业仓储领域,气膜结构建筑因其独特的优势逐渐受到企业的青睐。它不仅能够提供大跨度的无柱空间,还具备零排放、环保、快速建造、灵活应用等诸多优点,同时满足严格的消防安全要求,是实现高效仓储管理和可持续发展的理想选择…

为什么bootloader跳转地址要加4?

问题 “我看你验证程序从ROM跳Flash地址要加4,为啥?” 又被问到了,这次记一下,以后谁再问我就直接发链接,必须点赞关注,哈哈 答案 上电流程 ARM内核上电以后会从启动地址开始执行,就是vecto…

某宝上买盗版wordpress的危害和要承担的法律后果

购买和使用盗版WordPress模板存在以下危害和法律后果要点提示: 侵权行为:使用盗版WordPress模板在法律上属于侵犯知识产权,构成侵权行为。 法律责任:可能会面临法律诉讼、罚款甚至刑事责任,如拘留或罚款等。 安全隐…

密钥分发与公钥认证:保障网络通信的安全

在网络通信中,密钥的安全分发和公钥的有效认证是确保系统安全的关键。本文将为基础小白介绍密钥分发与公钥认证的基本概念和实际应用,帮助大家更好地理解这些技术如何保障我们的网络通信安全。 1. 密钥分发与公钥认证的背景 由于密码算法是公开的&…

CF848A From Y to Y

题目概要 对于给定的一个长度为 n n n 的字符串,初始时,我们将它视作 n n n 个长度为 1 1 1 的字符串的可重集,然后重复下列操作 n − 1 n-1 n−1 次: 从这些字符串中任取两个字符串 s , t s,t s,t,将它们删除&…

每天分享一个FPGA开源代码(2)- spi 读写Flash

Flash的用途主要是用于存储主控制器的程序,SPI -Flash芯片就是支持SPI通讯协议的flash芯片。 在FPGA开发中,一般有这两种方式下载程序到板子上: (1)通过 JTAG下载程序到FPGA中直接运行,下载速度快&#xff…

k8s-pod 实战四 什么是 Kubernetes Pod?如何在生产环境中使用它?(学习专场,实战就看这一篇就够了)

一、pod概念 Kubernetes Pod 是 Kubernetes 中最小的部署单元。每个 Pod 包含一个或多个容器,这些容器共享相同的网络命名空间和存储卷。以下是 Pod 的详细介绍和一个生产实例的使用示例。 Pod 概述 定义:Pod 是 Kubernetes 中可以创建、调度和管理的最小单元,通常包含一个…

新手c语言讲解及题目分享(十四)--函数专项练习(二)

新手c语言讲解及题目分享(十四)--函数专项练习(一)-CSDN博客 目录 前言 一.函数调用中的参数传递 1.普通变量作为函数的参数 2.数组元素作为参数 3.数组名作为函数的参数 4.指…

从误删到重生:2024年数据恢复软件市场新趋势与精选工具

现在科技发展越来越先进,大部分的办公内容也都是通过电脑来进行操作的。但是总免不了偶尔会遇到电脑蓝屏或者其他原因导致数据丢失的情况。那辛辛苦苦做好的材料不见了一定很恼火。这次我分享几个电脑数据恢复工具来解决这个问题。 1.福晰数据恢复 连接直达&#…

江苏省地图大屏展示

Html部分绘制echarts图 <div id"chart3" style"width: 100%;height: 100%;"></div>Js部分引入地图数据data.js <script th:src"{/js/geoJson/data.js}"></script> <script type"text/javascript">var…

Nginx负载均衡中的变量使用:动态配置与实践

Nginx是一款功能丰富的Web服务器和反向代理&#xff0c;其负载均衡能力尤为突出。在Nginx的配置中&#xff0c;变量的使用允许实现更灵活和动态的负载均衡策略。本文将详细介绍如何在Nginx负载均衡中使用变量&#xff0c;包括变量的基本概念、使用方法、以及如何通过变量实现高…

docker实战基础五(Dockerfile)

编写高效的 Dockerfile 是确保容器化应用成功的关键步骤。以下是关于如何在 Dockerfile 中创建用户、添加环境变量、使用 ENTRYPOINT、理解 CMD 和 ENTRYPOINT 的区别,以及 ADD 和 COPY 指令的区别的详细说明。 一、创建用户 在Docker容器中运行应用程序时,为了安全性,通常…

C++ | Leetcode C++题解之第392题判断子序列

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isSubsequence(string s, string t) {int n s.size(), m t.size();vector<vector<int> > f(m 1, vector<int>(26, 0));for (int i 0; i < 26; i) {f[m][i] m;}for (int i m - 1; …

操作系统面试真题总结(五)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 线程切换要保存哪些上下文&#xff1f; 当发生线程切换时&#xf…

【论文阅读】Stealing Image-to-Image Translation Models With a Single Query(2024)

摘要 Training deep neural networks(训练深度神经网络) requires(需要) significant computational resources(大量计算资源) and large datasets(大型数据集) that are often confidential(机密的) or expensive(昂贵的) to collect. As a result(因此), owne…

sed awk 第二版学习(二)—— 正则表达式语法

目录 一、表达式 二、成行的字符 1. 反斜杠 2. 通配符 3. 编写正则表达式 4. 字符类 &#xff08;1&#xff09;字符的范围 &#xff08;2&#xff09;排除字符类 &#xff08;3&#xff09;POSIX 字符类补充 5. 重复出现的字符 6. 匹配单词 7. gres 替换脚本 8. …

使用 Rust 和 Bevy 创建你的第一个三维渲染应用程序

为什么选择 Rust 进行三维开发&#xff1f; Rust 的特点使其非常适合用于三维开发&#xff1a; 内存安全性&#xff1a;Rust 的所有权系统和严格的编译器检查可以防止常见的内存错误&#xff0c;如空指针和数据竞争。高性能&#xff1a;Rust 是一门系统编程语言&#xff0c;能…