用PyTorch构建验证码识别系统:完整实战教程
验证码(CAPTCHA)是一种用于防止机器人操作的安全机制。本教程将带你一步步实现一个验证码识别系统:包括数据生成、模型构建、训练与测试,全部基于 PyTorch 完成。
📚 项目概览
我们将完成以下工作流程:
生成带标签的验证码图像数据集
自定义 PyTorch 数据集类进行加载和预处理
构建 CNN + RNN 网络结构用于识别
完整训练流程与测试函数
可视化识别结果与未来优化方向
🧱 Step 1:环境准备
安装所需的库:
pip install torch torchvision captcha pillow numpy matplotlib
🏗️ Step 2:生成验证码数据集
我们使用 captcha 库动态生成图像并保存。
from captcha.image import ImageCaptcha
import os, random, string
from PIL import Image
characters = string.digits + string.ascii_uppercase
img_width, img_height = 160, 60
code_length = 4
def generate_captcha_dataset(save_dir="captcha_data", total=8000):
os.makedirs(save_dir, exist_ok=True)
generator = ImageCaptcha(width=img_width, height=img_height)
for i in range(total):
text = ''.join(random.choices(characters, k=code_length))
img = generator.generate_image(text)
img.save(os.path.join(save_dir, f"{text}_{i}.png"))
generate_captcha_dataset()
🧼 Step 3:数据加载与预处理
创建自定义 Dataset:
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
import torch
class CaptchaDataset(Dataset):
def init(self, path, transform=None):
self.path = path
self.files = [f for f in os.listdir(path) if f.endswith('.png')]
self.char_to_idx = {c: i for i, c in enumerate(characters)}
self.transform = transform
def __len__(self):
return len(self.files)
def __getitem__(self, idx):
img_name = self.files[idx]
label = img_name.split('_')[0]
label_tensor = torch.tensor([self.char_to_idx[c] for c in label], dtype=torch.long)
img = Image.open(os.path.join(self.path, img_name)).convert("RGB")
if self.transform:
img = self.transform(img)
return img, label_tensor
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
dataset = CaptchaDataset("captcha_data", transform=transform)
loader = DataLoader(dataset, batch_size=64, shuffle=True)
🧠 Step 4:搭建 CNN + LSTM 模型
import torch.nn as nn
class CaptchaModel(nn.Module):
def init(self):
super().init()
self.conv = nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(), nn.MaxPool2d((2,1))
)
self.lstm = nn.LSTM(128*7, 128, bidirectional=True, num_layers=2, batch_first=True)
self.fc = nn.Linear(256, len(characters))
def forward(self, x):
x = self.conv(x)
x = x.permute(0, 3, 1, 2)
B, W, C, H = x.shape
x = x.reshape(B, W, C*H)
x, _ = self.lstm(x)
x = self.fc(x)
return x
🏋️ Step 5:训练模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = CaptchaModel().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
for epoch in range(10):
model.train()
total_loss = 0
for images, labels in loader:
images, labels = images.to(device), labels.to(device)
output = model(images)
loss = sum(criterion(output[:, i], labels[:, i]) for i in range(code_length))
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {total_loss:.4f}")
🔍 Step 6:预测函数
def predict(model, img_path):
model.eval()
img = Image.open(img_path).convert("RGB")
img = transform(img).unsqueeze(0).to(device)
with torch.no_grad():
out = model(img)
pred = torch.argmax(out, dim=2)[0]
return ''.join([characters[i] for i in pred])
img_path = "captcha_data/C7K2_123.png"
print("预测结果:", predict(model, img_path))
浙公网安备 33010602011771号