基于 PyTorch 和 CNN 的验证码识别模型实现
在本篇文章中,我们将使用 PyTorch 来实现一个基于 卷积神经网络(CNN) 的验证码识别系统。验证码(CAPTCHA)用于防止自动化程序滥用服务,通常包含一系列混合的字母、数字或符号。由于验证码的多样性和复杂性,本文将通过一个深度学习模型来自动识别其中的字符。
通过本教程,你将学习如何使用 PyTorch 和 卷积神经网络(CNN) 处理和识别验证码图像。
- 环境准备
首先,确保你已经安装了 PyTorch 和一些图像处理相关的库。可以通过以下命令安装:
bash
pip install torch torchvision numpy matplotlib opencv-python pillow
PyTorch:主要用于构建和训练深度学习模型。
Torchvision:提供了许多用于图像处理的工具和模型。
NumPy:用于数据操作和数值计算。
OpenCV:用于加载和处理图像。
Pillow:用于图像处理。
2. 数据准备与预处理
验证码图像通常包含多个字符,这些字符组成了一个验证码字符串。为了让我们的模型能够识别这些字符,我们需要对图像进行一些常见的预处理操作:
图像灰度化:转换为灰度图像,简化数据的复杂性。
调整图像大小:确保所有图像具有相同的尺寸。
归一化处理:将像素值归一化到[0, 1]范围。
标签编码:将验证码中的字符转换为数字表示。
(1) 数据加载与预处理
我们将通过自定义数据集类来加载图像,并进行必要的预处理操作。
python
import os
import cv2
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
class CaptchaDataset(Dataset):
def init(self, image_dir, char_set, image_size=(64, 128)):
self.image_dir = image_dir
self.image_paths = [os.path.join(image_dir, fname) for fname in os.listdir(image_dir)]
self.char_set = char_set
self.image_size = image_size
def __len__(self):
return len(self.image_paths)
def __getitem__(self, idx):
img_path = self.image_paths[idx]
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, self.image_size)
img = img.astype('float32') / 255.0 # 归一化处理
img = torch.tensor(img).unsqueeze(0) # 将图像转换为Tensor并增加通道维度
# 标签处理:将字符转换为数字索引
label = os.path.basename(img_path).split('.')[0]
label_encoded = [self.char_set.index(c) for c in label]
return img, torch.tensor(label_encoded)
字符集定义
char_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" # 可识别的大写字母和数字
数据集初始化
train_dataset = CaptchaDataset(image_dir="captcha_images", char_set=char_set)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
(2) 标签编码
在这个任务中,验证码的标签是一个字符串,我们将它们转换为字符集中的索引。例如,"A" 映射为 0,"B" 映射为 1,依此类推。
- 构建卷积神经网络(CNN)
验证码识别的关键是提取图像中的字符特征。卷积神经网络(CNN)擅长这一任务,能够从图像中自动提取空间特征。我们将构建一个包含多个卷积层、池化层和全连接层的模型。
(1) 定义CNN模型架构
我们将使用多个卷积层来提取图像中的特征,并通过全连接层进行最终的字符分类。
python
import torch.nn as nn
import torch.optim as optim
class CaptchaCNN(nn.Module):
def init(self, num_classes=36, sequence_length=4):
super(CaptchaCNN, self).init()
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(128 * 8 * 16, 1024)
self.fc2 = nn.Linear(1024, num_classes * sequence_length)
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = self.pool(torch.relu(self.conv3(x)))
x = x.view(-1, 128 * 8 * 16) # 扁平化
x = torch.relu(self.fc1(x))
x = self.fc2(x)
# 输出每个字符的概率分布
x = x.view(-1, 4, 36) # 假设验证码长度为4
return self.softmax(x)
构建模型
model = CaptchaCNN(num_classes=len(char_set), sequence_length=4)
(2) 网络结构解释
卷积层(Conv2d):用于从输入图像中提取特征。
池化层(MaxPool2d):用于减小特征图的尺寸,从而减少计算量。
全连接层(Linear):用于将卷积层提取的特征映射到输出空间。
Softmax激活函数:用于对每个字符进行分类,输出每个字符的概率分布。
4. 模型训练
我们将使用 交叉熵损失 函数来训练模型,目标是最小化字符分类的损失。训练过程中,我们将使用 Adam优化器 来优化模型参数。
(1) 训练模型
python
更多内容访问ttocr.com或联系1436423940
定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
训练模型
epochs = 10
for epoch in range(epochs):
model.train()
running_loss = 0.0
for i, (images, labels) in enumerate(train_loader):
images = images.unsqueeze(1) # 添加通道维度
labels = labels.view(-1) # 展平成一维
# 清空梯度
optimizer.zero_grad()
# 前向传播
outputs = model(images)
# 计算损失
loss = criterion(outputs.view(-1, len(char_set)), labels)
# 反向传播
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f"Epoch {epoch+1}/{epochs}, Loss: {running_loss/len(train_loader)}")
(2) 训练过程
输入图像:图像通过卷积层提取特征。
输出预测:网络输出每个字符的概率分布。
损失函数:使用 交叉熵损失 来衡量预测和实际标签之间的差距。
优化:通过 Adam优化器 更新网络权重。
5. 模型评估与预测
在训练完毕后,我们可以评估模型在测试集上的表现,并使用模型进行验证码的预测。
(1) 模型评估
python
在测试集上评估模型
test_dataset = CaptchaDataset(image_dir="test_captcha_images", char_set=char_set)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images = images.unsqueeze(1)
labels = labels.view(-1)
outputs = model(images)
_, predicted = torch.max(outputs, 2)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"Accuracy: {correct / total * 100:.2f}%")
(2) 模型预测
使用训练好的模型对新的验证码进行预测:
python
def predict_captcha(model, img_path, char_set):
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, (128, 64))
img = img.astype('float32') / 255.0
img = torch.tensor(img).unsqueeze(0).unsqueeze(0) # 转为[1,1,64,128]的形状
model.eval()
with torch.no_grad():
output = model(img)
_, predicted = torch.max(output, 2)
predicted_label = ''.join([char_set[i] for i in predicted[0].cpu().numpy()])
return predicted_label
测试预测
test_image_path = "captcha_images/test1.png"
predicted_label = predict_captcha(model, test_image_path, char_set)
print(f"Predicted CAPTCHA label: {predicted_label}")
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异