人脸真假检测:SVM 与 ResNet18 的实战对比

  在人工智能蓬勃发展的当下,人脸相关技术广泛应用于安防、金融、娱乐等诸多领域。然而,随着人脸合成技术的日益成熟,人脸真假检测成为保障这些应用安全的关键环节。本文将深入探讨基于支持向量机(SVM)结合局部二值模式(LBP)特征,以及基于 ResNet18 神经网络的人脸真假检测方法,并通过 Python 代码实战进行详细分析与对比。

一、技术原理

(一)SVM 与 LBP 特征

  LBP 特征提取:LBP 是一种用于描述图像局部纹理特征的算子。其基本原理是对图像每个像素点,以其为中心,设定邻域像素点个数(如本文中的 8 个邻域点)和半径(本文为 1)。将邻域像素点的灰度值与中心像素点灰度值进行比较,大于等于中心像素点灰度值的邻域点记为 1,小于则记为 0,这些二进制值按顺时针或逆时针顺序排列形成一个二进制码,该码就是中心像素点的 LBP 值。对整幅图像计算 LBP 值后,通过统计不同 LBP 值出现的频率(即直方图),得到图像的 LBP 特征。这种特征对光照变化具有一定的鲁棒性,能有效捕捉图像的纹理细节 。

  SVM 模型:支持向量机是一种二分类模型,旨在寻找一个最优分类超平面,使得不同类别的样本点尽可能地远离该超平面。在本文中,采用径向基函数(RBF)作为核函数,它能够将低维空间中的数据映射到高维空间,从而更好地处理非线性分类问题。利用提取的 LBP 特征训练 SVM 模型,实现对人脸真假的分类预测。

(二)ResNet18 神经网络

  ResNet18 架构:ResNet(残差网络)是深度学习领域的经典网络结构,通过引入残差块解决了深度神经网络训练过程中的梯度消失和梯度爆炸问题,使得网络可以训练得更深。ResNet18 包含 18 层卷积层和全连接层,能够自动学习图像的高级特征。

  模型修改与训练:在本文中,对预训练的 ResNet18 模型进行了修改,将最后一层全连接层的输出特征数量调整为 1,并添加了 Sigmoid 激活函数,使其输出为 0 到 1 之间的概率值,用于二分类任务(判断人脸真假)。训练过程中,使用交叉熵损失函数(BCELoss)衡量预测结果与真实标签之间的差异,通过 Adam 优化器调整模型参数,逐步降低损失,提高模型的准确性。

二、代码实现

(一)环境设置与库导入

  首先,需要导入一系列必要的库,包括用于图像处理的 OpenCV、NumPy、scikit - image,用于深度学习的 PyTorch 及其相关工具,以及用于数据处理和评估的 scikit - learn 等:

import os
import cv2
import numpy as np
from skimage.feature import local_binary_pattern
import torch
from torch import nn
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, models
from PIL import Image
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, classification_report
import matplotlib.pyplot as plt
import random

 

(二)SVM 模型实现 

  LBP 特征提取函数extract_lbp_features函数负责读取图像并提取其 LBP 特征。首先将图像转换为灰度图,调整大小为指定尺寸,计算 LBP 值并生成直方图,最后对直方图进行归一化处理:

def extract_lbp_features(image_path, target_size=(64, 64)):try:image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)if image is None:return Noneimage = cv2.resize(image, target_size)lbp = local_binary_pattern(image, 8, 1, method='uniform')(hist, _) = np.histogram(lbp.ravel(), bins=np.arange(0, 10), range=(0, 10))hist = hist.astype("float")hist /= (hist.sum() + 1e-7)return histexcept:return None

 

  数据加载函数load_svm_data函数从指定的真假人脸图像文件夹中读取图像,提取 LBP 特征,并为每个样本标记对应的标签(0 表示假脸,1 表示真脸):

def load_svm_data(fake_dir, real_dir):X, y = [], []for img_name in os.listdir(fake_dir):img_path = os.path.join(fake_dir, img_name)features = extract_lbp_features(img_path)if features is not None:X.append(features)y.append(0)for img_name in os.listdir(real_dir):img_path = os.path.join(real_dir, img_name)features = extract_lbp_features(img_path)if features is not None:X.append(features)y.append(1)return np.array(X), np.array(y)

 

  模型训练与评估函数train_svm函数加载训练数据和测试数据,训练 SVM 模型,并对模型进行评估,输出准确率和分类报告:

def train_svm():X_train, y_train = load_svm_data("training_fake", "training_real")X_test, y_test = load_svm_data("testing_fake", "testing_real")svm = SVC(kernel='rbf', random_state=42)svm.fit(X_train, y_train)y_pred = svm.predict(X_test)accuracy = accuracy_score(y_test, y_pred)print("\n支持向量机模型评估结果:")print("准确率:", accuracy)print(classification_report(y_test, y_pred))return accuracy

 

(三)ResNet18 模型实现 

  自定义数据集类FaceDataset类继承自Dataset,用于加载真假人脸图像数据。在初始化时,将图像路径和对应的标签存储起来,并支持数据增强操作(如随机水平翻转):

class FaceDataset(Dataset):def __init__(self, fake_dir, real_dir, transform=None):self.image_paths = []self.labels = []for img_name in os.listdir(fake_dir):self.image_paths.append(os.path.join(fake_dir, img_name))self.labels.append(0)for img_name in os.listdir(real_dir):self.image_paths.append(os.path.join(real_dir, img_name))self.labels.append(1)self.transform = transformdef __len__(self):return len(self.image_paths)def __getitem__(self, idx):try:image = Image.open(self.image_paths[idx]).convert("RGB")label = self.labels[idx]if self.transform:image = self.transform(image)return image, labelexcept:return None

 

  ResNet18 模型定义与修改get_resnet18函数获取预训练的 ResNet18 模型,并修改其最后一层全连接层和添加 Sigmoid 激活函数:

def get_resnet18():model = models.resnet18(pretrained=True)num_ftrs = model.fc.in_featuresmodel.fc = nn.Linear(num_ftrs, 1)model = nn.Sequential(model, nn.Sigmoid())return model

 

  训练与评估函数train_resnet18函数对数据进行预处理,创建数据集和数据加载器,初始化模型、损失函数和优化器,进行模型训练和测试评估,并绘制训练过程中的损失和准确率曲线:

def train_resnet18():transform = transforms.Compose([transforms.Resize((224, 224)),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])def create_dataset(fake_dir, real_dir, transform):dataset = FaceDataset(fake_dir, real_dir, transform)valid_indices = [i for i in range(len(dataset)) if dataset[i] is not None]return torch.utils.data.Subset(dataset, valid_indices)train_dataset = create_dataset("training_fake", "training_real", transform)test_dataset = create_dataset("testing_fake", "testing_real", transform)train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = get_resnet18().to(device)criterion = nn.BCELoss()optimizer = torch.optim.Adam(model.parameters(), lr=0.001)losses = []accuracies = []model.train()for epoch in range(10):running_loss = 0.0for images, labels in train_loader:images, labels = images.to(device), labels.float().to(device).unsqueeze(1)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()epoch_loss = running_loss / len(train_loader)losses.append(epoch_loss)print(f"Epoch {epoch + 1}/10, Loss: {epoch_loss:.4f}")model.eval()correct, total = 0, 0test_images = []test_labels = []test_predictions = []with torch.no_grad():for images, labels in test_loader:test_images.extend(images.cpu().numpy())test_labels.extend(labels.cpu().numpy())images, labels = images.to(device), labels.float().to(device).unsqueeze(1)outputs = model(images)predicted = (outputs > 0.5).float()total += labels.size(0)correct += (predicted == labels).sum().item()test_predictions.extend(predicted.cpu().numpy())accuracy = correct / totalprint("\nResNet18模型评估结果:")print(f"准确率: {accuracy:.4f}")plt.figure(figsize=(12, 5))plt.subplot(1, 2, 1)plt.plot(losses, label='Training Loss')plt.xlabel('Epoch')plt.ylabel('Loss')plt.legend()plt.subplot(1, 2, 2)plt.plot(accuracies, label='Training Accuracy')plt.xlabel('Epoch')plt.ylabel('Accuracy')plt.legend()plt.show()return accuracy, test_images, test_labels, test_predictions

 

  可视化随机五张识别结果visualize_random_five函数从测试数据中随机选取五张图像,展示其真实标签和预测结果:

def visualize_random_five(test_images, test_labels, test_predictions):indices = random.sample(range(len(test_images)), 5)plt.figure(figsize=(15, 7))for i, idx in enumerate(indices):img = np.transpose(test_images[idx], (1, 2, 0))img = (img - np.min(img)) / (np.max(img) - np.min(img))label = 'Real' if test_labels[idx] == 1 else 'Fake'prediction = 'Real' if test_predictions[idx] == 1 else 'Fake'plt.subplot(1, 5, i + 1)plt.imshow(img)plt.title(f'Label: {label}\nPred: {prediction}')plt.axis('off')plt.show()

 

(四)主程序入口 

  在主程序中,依次训练 SVM 模型和 ResNet18 模型,比较两个模型的准确率并进行可视化,同时可视化 ResNet18 模型随机五张测试图像的识别结果:

if __name__ == "__main__":print("正在训练支持向量机模型...")svm_accuracy = train_svm()print("\n正在训练ResNet18模型...")resnet_accuracy, test_images, test_labels, test_predictions = train_resnet18()models = ['SVM', 'ResNet18']accuracies = [svm_accuracy, resnet_accuracy]plt.bar(models, accuracies)plt.xlabel('Models')plt.ylabel('Accuracy')plt.title('Model Accuracy Comparison')for i, v in enumerate(accuracies):plt.text(i, v, str(round(v, 4)), ha='center')plt.show()visualize_random_five(test_images, test_labels, test_predictions)

 

三、实验结果与分析 

 

 

 

 

 

  从训练过程输出的日志来看,ResNet18 模型在 10 个训练轮次(Epoch)中,损失(Loss)不断下降,从 Epoch 1 的 0.7298 逐步降低到 Epoch 10 的 0.2930 ,这表明模型在训练过程中不断学习,对训练数据的拟合能力逐渐增强。最终在测试集上得到的准确率为 0.6176 。

  对比 SVM 模型与 ResNet18 模型的准确率柱状图,SVM 模型的准确率为 0.5392,而 ResNet18 模型的准确率为 0.6176,ResNet18 模型的准确率相对更高。这是因为 ResNet18 作为深度神经网络,具备强大的自动特征提取能力,能够从大量图像数据中学习到更复杂、更具区分性的特征表示,从而在分类任务中表现更优。而 SVM 虽然在处理一些简单特征和小规模数据时表现良好,但在面对人脸真假检测这种复杂的图像分类任务时,其特征表示能力相对有限,导致准确率略低。

  观察 ResNet18 模型训练损失曲线,其呈现出持续下降的趋势,说明模型在训练过程中能够有效优化,不断调整参数以降低损失。但从下降的速率和幅度来看,在前期下降较快,后期下降逐渐变缓,这可能意味着模型在后期逐渐接近收敛状态,进一步提升的难度增大。同时,由于未给出测试集上的损失或准确率随 Epoch 的变化情况,暂时无法确定是否存在过拟合现象。不过仅从当前训练损失持续下降且测试准确率有所提升来看,模型在一定程度上能够泛化到测试数据,但后续仍需进一步分析验证。

  从这五张随机选取的测试图像可视化结果来看,模型在部分样本上预测准确,但也存在误判情况。其中,第一张、第二张和第四张图像真实标签为 “Real”,模型预测也为 “Real” ,说明对于这类图像,模型能够较好地提取特征并做出正确判断。第五张图像真实标签为 “Fake”,模型预测也为 “Fake”,表明模型在识别这类假脸图像时具备一定能力。

  然而,第三张图像真实标签为 “Fake”,但模型却预测为 “Real” ,出现了误判。这可能是由于该假脸图像具有一些与真脸相似的特征,或者其合成技术较为特殊,导致模型提取的特征不足以准确区分真假。通过对这类误判样本的深入分析,我们可以针对性地改进模型。比如,进一步挖掘该图像中模型未能有效捕捉的特征差异,调整模型结构或训练策略,以增强模型对这类特殊样本的识别能力。这也再次强调了在实际应用中,不能仅依赖模型的准确率指标,还需关注模型在具体样本上的预测表现,通过对误判样本的研究来不断优化模型性能。

四、总结与展望

  本文通过代码实现并对比了 SVM 结合 LBP 特征与 ResNet18 神经网络在人脸真假检测任务中的应用。实验结果表明,ResNet18 在准确率上优于 SVM,展现出深度神经网络在图像分类任务中的强大性能。SVM 结合 LBP 特征的方法虽然计算相对简单,但在复杂图像特征提取方面存在不足,导致准确率受限。

  在实际应用中,对于计算资源有限、数据规模较小的场景,SVM 方法可作为一种轻量级的解决方案;而对于追求高准确率、数据量充足的场景,ResNet18 等深度神经网络更为合适。未来可尝试将两者结合,比如先用 SVM 进行初步筛选,再利用 ResNet18 进行精细分类,发挥各自优势,提升检测性能。

  此外,当前模型的准确率仍有提升空间。未来可从以下几方面改进:一是进一步优化模型结构,如调整 ResNet18 的层数、参数,或尝试其他更先进的神经网络架构;二是扩充数据集,引入更多不同场景、光照条件、合成技术的人脸图像,增强模型的泛化能力。

 

 

 

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

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

相关文章

类加载器, JVM类加载机制

1.类加载器 Java里有如下几种类加载器 1.引导类加载器 负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等 2.扩展类加载器 负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包 3.应用程序类加载器 负责加载Class…

Hadoop 2.x设计理念解析

目录 一、背景 二、整体架构 三、组件详解 3.1 yarn 3.2 hdfs 四、计算流程 4.1 上传资源到 HDFS 4.2 向 RM 提交作业请求 4.3 RM 调度资源启动 AM 4.4 AM运行用户代码 4.5 NodeManager运行用户代码 4.6 资源释放 五、设计不足 一、背景 有人可能会好奇&#xf…

串口屏调试 1.0

http://wiki.tjc1688.com 先把商家的链接贴过来 淘晶驰T1系列3.2寸串口屏tft液晶屏显示屏HMI触摸屏超12864液晶屏 这是主包的型号 打开这个玩意 有十个基本的功能区 新建工程 在界面的右边,指令一定要写在page前面,这里的波特率等等什么的都可以…

《设计数据密集型应用》——阅读小记

设计数据密集型应用 这本书非常推荐看英语版,如果考过了CET-6就可以很轻松的阅读这本书。 当前计算机软件已经不是单体的时代了,分布式系统,微服务现在是服务端开发的主流,如果没有读过这本书,则强力建议读这本书。 …

【SpringMVC】详解cookie,session及实战

目录 1.前言 2.正文 2.1cookie与session概念 2.2返回cookie参数 2.3设置session 3.小结 1.前言 哈喽大家好吖,今天继续来给大家来分享SpringMVC的学习,今天主要带来的是cookie与session的讲解以及通过postman和fiddler来实战,废话不多…

令狐冲的互联网大厂Java面试之旅

场景描绘:互联网大厂Java面试 在某个阳光明媚的上午,令狐冲来到了风清扬所在的互联网大厂,准备迎接他的Java开发工程师面试。风清扬是一位以严谨和深厚技术功底著称的面试官,令狐冲稍显紧张,但他相信自己的准备。 第…

照片to谷歌地球/奥维地图使用指南

软件介绍 照片to谷歌地球/奥维地图是一款由WTSolutions开发的跨平台图片处理工具,能够将带有GPS信息的照片导入Google Earth(谷歌地球)或奥维地图。该软件支持Windows、Mac、iOS、Linux和Android系统,无需下载安装,直…

客户端建立一个连接需要占用客户端的端口吗

客户端建立TCP连接时需占用本地端口,具体机制如下: 一、端口占用的必要性 四元组唯一性‌ TCP连接通过‌源IP、源端口、目标IP、目标端口‌四元组唯一标识。客户端发起连接时,必须绑定本地端口以完成通信标识。 动态端口分配‌ 客户端操作…

【生存技能】ubuntu 24.04 如何pip install

目录 原因解决方案说明 在接手一个新项目需要安装python库时弹出了以下提示: 原因 这个报错是因为在ubuntu中尝试直接使用 pip 安装 Python 包到系统环境中,ubuntu 系统 出于稳定性考虑禁止了这种操作 这里的kali是因为这台机器的用户起名叫kali,我也不知道为什么…

智能时代下,水利安全员证如何引领行业变革?

当 5G、AI、物联网等技术深度融入水利工程,传统安全管理模式正经历颠覆性变革。在这场智能化浪潮中,水利安全员证扮演着怎样的角色?又将如何重塑行业人才需求格局? 水利工程智能化转型对安全管理提出新挑战。无人机巡检、智能监测…

TDengine 在智能制造中的核心价值

简介 智能制造与数据库技术的深度融合,已成为现代工业技术进步的一个重要里程碑。随着信息技术的飞速发展,智能制造已经成为推动工业转型升级的关键动力。在这一进程中,数据库技术扮演着不可或缺的角色,它不仅承载着海量的生产数…

微调ModernBERT为大型语言模型打造高效“过滤器”

ModernBERT(2024 年 12 月)是最近发布的小型语言模型,由 Answer.AI、LightOn 和 HuggingFace 共同开发。它利用了现代优化技术,如用于 8,192 token 上下文窗口的 RoPE 和 GeGLU layers,在保持效率的同时提升性能。jina…

电网拓扑分析:原理与应用

在现代电力系统中,电网拓扑分析是一项至关重要的技术,它为电力系统的安全、稳定和高效运行提供了坚实的基础。电网拓扑描述了电力系统中各元件(如发电机、变压器、输电线路、负荷等)之间的连接关系,通过拓扑分析&#…

OSPF案例

拓扑图: 要求: 1,R5为ISP,其上只能配置IP地址;R4作为企业边界路由器, 出口公网地址需要通过PPP协议获取,并进行chap认证 2,整个OSPF环境IP基于172.16.0.0/16划分;…

2D横板跳跃游戏笔记(查漏补缺ing...)

1.Compression(压缩质量):可以改为None,不压缩的效果最好,但占用内存 2.Filter Mode(过滤模式):可以选择Point(no filter) 3.Pixels Per Unit:是…

MAD-TD: MODEL-AUGMENTED DATA STABILIZES HIGH UPDATE RATIO RL

ICLR 2025 spotlight paper 构建能够在少量样本下学习出优良策略的深度强化学习(RL)智能体一直是一个极具挑战性的任务。为了提高样本效率,近期的研究尝试在每获取一个新样本后执行大量的梯度更新。尽管这种高更新-数据比(UTD&am…

Dia浏览器:AI驱动浏览网页,究竟怎么样?(含注册申请体验流程)

名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、Dia浏览器简介1. 什么是Dia浏览器2. 开发背景与公司简介3. 与传统浏览器的区别 …

SSL/TLS 证书与数字签名:构建互联网信任的详解

在浩瀚的数字世界中,信任是安全通信的基石。当我们通过浏览器访问一个 HTTPS 网站、进行在线支付,或者下载一个重要的软件更新时,我们如何能确信自己正在与合法的、未被仿冒的对方进行交互?我们又如何能保证传输的数据没有被中途窃…

近日部署跑通的若干多模态模型总结与论文概述

CLIP模型概述与落地测试 CLIP模型全称是Contrastive Language-Image Pretraining​​(对比语言图像预训练)。是OpenAI于2021年提出的多模态预训练模型,通过对比学习对齐图像和文本的表示,实现零样本(zero-shot&#x…

Web3 初学者的第一个实战项目:留言上链 DApp

目录 📌 项目简介:留言上链 DApp(MessageBoard DApp) 🧠 技术栈 🔶 1. Solidity 智能合约代码(MessageBoard.sol) 🔷 2. 前端代码(index.html script.js…