目录

摘要

一、项目整体架构与设计思路

1.1 系统模块拆分

1.2 技术选型优势

二、环境初始化与数据集解析

2.1 环境依赖与中文绘图配置

2.2 数据集结构解析

2.3 全局常量定义

三、人脸预处理:OpenCV 人脸裁剪与数据增强

3.1 人脸检测裁剪函数extract_face

3.2 训练数据增强生成器

四、基于 ResNet50 迁移学习的人脸分类模型

4.1 模型搭建核心思路

4.2 模型参数分析

4.3 模型训练过程与曲线解读

训练可视化曲线分析

4.4 全数据集精度测试

五、人脸考勤业务逻辑实现(工程化核心)

5.1 考勤全局变量

5.2 考勤状态判定函数

5.3 核心签到函数face_sign_in

5.4 全员考勤模拟测试

六、考勤报表自动导出与模型保存

6.1 明细表 + 汇总表生成

6.2 多格式文件导出

6.3 报表效果展示

七、系统现存局限与优化拓展方案

7.1 当前项目短板

7.2 进阶优化方向

八、项目总结

摘要

本文完整落地一套人脸检测 + 迁移学习人脸识别 + 智能考勤统计 + 报表导出全链路系统,依托 5 Celebrity Faces 小型名人人脸数据集,采用 ResNet50 迁移学习完成 5 分类人脸识别,识别准确率达 98.92%;配套实现上下班签到逻辑、迟到 / 早退判定、去重签到、Excel/CSV 多格式考勤报表自动导出,全部代码可在 Kaggle Notebook 一键运行,适合人工智能图像分类、计算机视觉工程化落地学习参考。

关键词:ResNet50;迁移学习;人脸识别;OpenCV 人脸裁剪;TensorFlow;人脸考勤系统;图像分类

一、项目整体架构与设计思路

1.1 系统模块拆分

整套工程分为 6 大解耦模块,分层清晰、可独立复用:

  1. 环境与数据集加载模块:Kaggle 数据集路径读取、人员分类解析、全局参数定义
  2. 图像预处理模块:OpenCV Haar 级联人脸裁剪、数据增强、ResNet 官方标准化预处理
  3. 迁移学习模型构建模块:冻结预训练 ResNet50 主干 + 自定义分类头搭建人脸分类网络
  4. 模型训练与评估模块:15 轮迭代训练、训练曲线可视化、全数据集精度测试
  5. 人脸识别推理模块:单图人脸预测、置信度阈值过滤陌生人、批量精度验证
  6. 智能考勤业务模块:上下班签到、重复签到拦截、考勤状态判定、报表自动生成导出

1.2 技术选型优势

  • 迁移学习:小样本场景下复用 ImageNet 预训练视觉特征,仅微调少量参数,收敛速度快、泛化能力强;总参数量 2411 万,可训练参数仅 52 万,训练成本极低
  • 双阶段人脸处理:先 OpenCV 裁剪人脸过滤背景干扰,再送入 ResNet 分类,大幅降低无关像素对识别结果的影响
  • 轻量化工程落地:无复杂 GUI 依赖,纯 Python 脚本实现完整考勤业务,自动输出标准化报表,可快速迁移至企业人脸打卡场景
  • 完备可视化:训练准确率 / 损失曲线、中文绘图支持,训练过程直观可观测

二、环境初始化与数据集解析

2.1 环境依赖与中文绘图配置

工程依赖OpenCV、TensorFlow/Keras、Pandas、Matplotlib,Kaggle Linux 环境预装基础库,仅需安装 Noto 中文字体解决绘图中文乱码问题:

# 安装开源中文字体
!apt-get update -qq && apt-get install -y -qq fonts-noto-cjk
# 加载字体,全局绘图中文渲染
from matplotlib.font_manager import FontProperties
font = FontProperties(fname="/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", size=12)
plt.rcParams['axes.unicode_minus'] = False

日志出现Noto Sans CJK JP not found为无害冗余匹配警告,不影响中文正常显示,生产环境可通过指定通用字体消除。

2.2 数据集结构解析

项目采用公开 5 Celebrity Faces 名人人脸数据集,文件夹层级结构如下:

plaintext

/kaggle/input/datasets/dansbecker/5-celebrity-faces-dataset/train
├─ ben_afflek
├─ elton_john
├─ jerry_seinfeld
├─ madonna
└─ mindy_kaling

数据集核心参数:

  1. 总样本:93 张人脸图片,代码自动按 8:2 切分,训练集 77 张、验证集 16 张;
  2. 分类数量:5 位独立名人,每个文件夹对应 1 个人脸类别;
  3. 标签机制:代码自动读取文件夹名称作为分类标签,生成「数字索引 - 人名」映射字典,后续可直接拓展多人脸数据集。

2.3 全局常量定义

IMG_SIZE = (160, 160)    # 模型输入统一尺寸
BATCH_SIZE = 8           # 训练批次大小
EPOCHS = 15              # 训练迭代轮次
WORK_START_TIME = "09:00:00"  # 上班基准时间
WORK_END_TIME = "18:00:00"    # 下班基准时间

三、人脸预处理:OpenCV 人脸裁剪与数据增强

3.1 人脸检测裁剪函数extract_face

使用 OpenCV 内置正面人脸检测器,实现智能人脸截取兜底逻辑,解决无检测人脸时推理崩溃问题:

  1. 图片转灰度图,detectMultiScale检测所有人脸框
  2. 多人脸场景:选取面积最大人脸,避免局部五官干扰
  3. 无人脸场景:直接缩放原图作为兜底输入,保证推理不中断
  4. BGR 转 RGB、像素归一化至 0~1,统一输入格式与训练流程对齐
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
def extract_face(img_path, target_size=(160, 160)):
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=4)
    if len(faces) == 0:
        img = cv2.resize(img, target_size)
        return (img[...,::-1] / 255.0).astype('float32')
    x, y, w, h = max(faces, key=lambda b: b[2]*b[3])
    face = img[y:y+h, x:x+w]
    face = cv2.resize(face, target_size)
    return (face[...,::-1] / 255.0).astype('float32')

单图测试可正常裁剪人脸,过滤背景冗余信息,为后续分类降低学习难度。

3.2 训练数据增强生成器

使用ImageDataGenerator做在线数据增强,缓解小样本过拟合,同时接入 ResNet 官方预处理逻辑,替代简单像素归一化:

from tensorflow.keras.applications.resnet50 import preprocess_input
train_datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input, # ResNet专属标准化
    rotation_range=10,        # 随机小角度旋转
    width_shift_range=0.1,    # 水平偏移
    height_shift_range=0.1,   # 垂直偏移
    horizontal_flip=True,     # 水平翻转
    validation_split=0.2      # 划分20%数据作为验证集
)
# 分别加载训练/验证集生成器
train_generator = train_datagen.flow_from_directory(
    dataset_path, target_size=IMG_SIZE, batch_size=BATCH_SIZE,
    class_mode='categorical', subset='training', shuffle=True
)
val_generator = train_datagen.flow_from_directory(
    dataset_path, target_size=IMG_SIZE, batch_size=BATCH_SIZE,
    class_mode='categorical', subset='validation', shuffle=False
)

自动读取文件夹名作为分类标签,输出独热编码,适配多分类交叉熵损失函数。


四、基于 ResNet50 迁移学习的人脸分类模型

4.1 模型搭建核心思路

迁移学习分为两大模块:

  1. 冻结预训练主干:加载 ImageNet 预训练 ResNet50,移除顶层全连接分类层,冻结全部权重,仅作为通用视觉特征提取器;复用海量自然图像学到的轮廓、五官纹理特征。
  2. 自定义人脸分类头:全局平均池化压缩特征向量 → 256 维全连接层学习人脸专属特征 → Dropout (0.5) 抑制过拟合 → Softmax 输出 5 分类概率。 完整网络代码:
# 加载预训练ResNet50,去除顶层分类
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(160,160,3))
base_model.trainable = False # 冻结主干权重

# 搭建完整人脸识别模型
model = models.Sequential([
    base_model,
    layers.GlobalAveragePooling2D(),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(5, activation='softmax')
])
# 模型编译
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

4.2 模型参数分析

表格

参数项 数值 说明
总参数量 24,113,541 91.99MB
可训练参数 525,829 仅分类头参与训练,训练速度快
不可训练参数 23,587,712 ResNet50 预训练主干,保留通用视觉特征

4.3 模型训练过程与曲线解读

执行 15 轮迭代训练,关键指标节选:

表格

Epoch 训练准确率 验证准确率 训练损失 验证损失
1 0.2987 0.6875 2.2291 0.8230
6 0.9091 1.0000 0.2110 0.1600
15 0.9610 0.9375 0.0793 0.1230

训练可视化曲线分析
  1. 准确率曲线:训练、验证准确率同步快速上升,前 6 轮验证集达到 100%,后期稳定在 93%~96% 区间;少量震荡源于数据集样本总量仅 93 张,验证集仅 16 张,单轮波动属于小样本正常现象。
  2. 损失曲线:训练与验证损失同步快速收敛至 0.2 以下,两条曲线无明显分离,Dropout 与数据增强有效抑制过拟合。

4.4 全数据集精度测试

推理函数recognize_face实现和训练完全对齐的预处理逻辑,设置置信度阈值 0.6 过滤陌生人,遍历全部 93 张样本做批量精度验证:

def recognize_face(img_path, threshold=0.6):
    img = cv2.resize(cv2.imread(img_path), IMG_SIZE)
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img_input = preprocess_input(img_rgb)
    img_input = np.expand_dims(img_input, axis=0)
    pred = model.predict(img_input, verbose=0)[0]
    pred_idx = np.argmax(pred)
    confidence = pred[pred_idx]
    if confidence < threshold:
        return "陌生人", confidence
    return idx_to_name[pred_idx], confidence

批量遍历测试结果:

  • 总样本数:93
  • 识别正确数:92
  • 整体识别准确率:98.92% 极高精度验证迁移学习在小样本人脸分类场景的优越性。

五、人脸考勤业务逻辑实现(工程化核心)

本项目区别于单纯图像分类 Demo,完整落地企业级考勤业务逻辑,包含签到去重、考勤状态判定、全流程记录。

5.1 考勤全局变量

from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")
attendance_records = []  # 存储每条签到明细
signed_in_set = set()    # 上班签到去重集合
signed_out_set = set()   # 下班签退去重集合

5.2 考勤状态判定函数

根据签到时间区分正常、迟到、早退三种状态:

def check_attendance_status(sign_time_str, sign_type="in"):
    if sign_type == "in":
        return "迟到" if sign_time_str > WORK_START_TIME else "正常"
    else:
        return "早退" if sign_time_str < WORK_END_TIME else "正常"

5.3 核心签到函数face_sign_in

串联人脸识别、陌生人拦截、重复签到校验、记录存储全流程:

  1. 调用人脸识别函数获取姓名与置信度,置信不足判定为陌生人,直接返回签到失败
  2. 生成当日唯一签到 Key,存入集合实现去重,同一人员当日无法重复签到 / 签退
  3. 获取当前系统时间,判定考勤状态
  4. 组装签到明细字典存入全局列表,返回签到结果提示
def face_sign_in(img_path, sign_type="in"):
    name, confidence = recognize_face(img_path)
    if name == "陌生人":
        return f"❌ 签到失败:未识别到有效人员(置信度:{confidence:.2f})"
    unique_key = f"{today}_{name}_{sign_type}"
    type_name = "上班签到" if sign_type == "in" else "下班签退"
    # 重复签到拦截
    if sign_type == "in" and unique_key in signed_in_set:
        return f"⚠️ {name} 今日已完成上班签到,无需重复操作"
    if sign_type == "out" and unique_key in signed_out_set:
        return f"⚠️ {name} 今日已完成下班签退,无需重复操作"
    # 记录考勤信息
    now_time = datetime.now().strftime("%H:%M:%S")
    status = check_attendance_status(now_time, sign_type)
    record = {
        "日期": today, "姓名": name, "签到类型": type_name,
        "签到时间": now_time, "考勤状态": status, "识别置信度": round(confidence, 4)
    }
    attendance_records.append(record)
    # 加入去重集合
    if sign_type == "in":
        signed_in_set.add(unique_key)
    else:
        signed_out_set.add(unique_key)
    return f"✅ {name} {type_name}成功 | 时间:{now_time} | 状态:{status}"

5.4 全员考勤模拟测试

遍历 5 位人员图片,分别模拟上班签到、下班签退流程,输出日志:

人脸识别考勤项目开题报告

  • 上班签到:当前时间早于 9 点,全部判定为「正常」
  • 下班签退:当前时间早于 18 点,全部判定为「早退」
  • 同一人员重复调用签到函数会触发重复操作拦截提示

六、考勤报表自动导出与模型保存

6.1 明细表 + 汇总表生成

  1. 考勤明细表:将attendance_records列表转为 Pandas DataFrame,存储每一条签到原始记录,包含日期、姓名、签到时间、置信度、考勤状态全维度信息。
  2. 考勤汇总表:自动统计当日核心指标:应到人数、实到签到人数、缺勤人数、迟到人数、完成签退人数、早退人数。
# 明细表
df_detail = pd.DataFrame(attendance_records)
# 汇总统计
total_person = 5
sign_in_count = len(signed_in_set)
absent_count = total_person - sign_in_count
late_count = len(df_detail[(df_detail["签到类型"]=="上班签到") & (df_detail["考勤状态"]=="迟到")])
early_leave_count = len(df_detail[(df_detail["签到类型"]=="下班签退") & (df_detail["考勤状态"]=="早退")])
summary_data = {
    "统计日期": [today], "应到人数": [total_person], "实到签到人数": [sign_in_count],
    "缺勤人数": [absent_count], "迟到人数": [late_count],
    "完成签退人数": [len(signed_out_set)], "早退人数": [early_leave_count]
}
df_summary = pd.DataFrame(summary_data)

6.2 多格式文件导出

兼容 Excel(双工作表)、CSV 通用格式,同时保存训练完成的人脸识别模型:

# 导出Excel(汇总+明细双工作表)
excel_path = "人脸考勤系统报表.xlsx"
with pd.ExcelWriter(excel_path, engine="openpyxl") as writer:
    df_summary.to_excel(writer, sheet_name="考勤汇总", index=False)
    df_detail.to_excel(writer, sheet_name="考勤明细", index=False)
# 导出CSV
df_detail.to_csv("考勤明细表.csv", index=False, encoding="utf-8-sig")
df_summary.to_csv("考勤汇总表.csv", index=False, encoding="utf-8-sig")
# 保存训练模型
model.save("人脸识别模型.h5")

最终输出 4 份可下载文件:Excel 综合报表、明细 CSV、汇总 CSV、h5 格式人脸识别模型。

保存 h5 文件会弹出版本警告,为 TensorFlow 官方提示,推荐生产环境替换为.keras格式存储模型。

6.3 报表效果展示

明细表共 10 条记录(5 人签到 + 5 人签退),每条记录附带识别置信度;汇总表当日 5 人全部签到签退,无缺勤、无迟到、全部早退,统计数据和签到日志完全匹配,数据一致性可靠。


七、系统现存局限与优化拓展方案

7.1 当前项目短板

  1. 人脸检测器限制:Haar 级联仅适配正面无遮挡人脸,侧脸、口罩遮挡、暗光场景检测失效,兜底逻辑会直接送入原图,降低识别精度。
  2. 数据集规模偏小:仅 93 张样本,验证集波动大,泛化能力受限,真实企业场景需扩充千人级人脸库。
  3. 考勤存储临时化:当前签到记录仅存储在内存列表,Notebook 会话关闭数据丢失,无持久化数据库支持。
  4. 单阈值识别:全局固定 0.6 置信度阈值,无法针对不同人员动态调整识别门槛。

7.2 进阶优化方向

  1. 人脸检测升级:替换 Haar 检测器为 MTCNN/RetinaFace,支持多角度、遮挡、弱光人脸检测,大幅提升复杂场景鲁棒性。
  2. 模型训练优化
    • 训练后半段解冻 ResNet50 底层网络,微调全部权重,提升人脸特征适配性;
    • 加入 L2 正则、早停策略EarlyStopping,进一步抑制震荡与过拟合。
  3. 工程化持久化
    • 接入 SQLite/MySQL 数据库存储每日考勤记录,支持跨会话数据查询;
    • 增加日期筛选函数,实现历史考勤汇总导出。
  4. 业务功能拓展
    • 增加陌生人抓拍存储、人员人脸库新增接口;
    • 接入摄像头实时流推理,实现实时打卡 GUI 界面;
    • 增加月度考勤统计、迟到早退频次可视化图表。
  5. 模型存储规范:将model.save("xxx.h5")替换为官方推荐格式model.save("人脸识别模型.keras")消除版本警告。

八、项目总结

本项目跳出传统仅做图像分类的 Demo 开发,以企业人脸考勤真实业务为目标,完成从数据集加载、人脸预处理、迁移学习模型训练、推理识别到考勤业务、自动报表导出的完整工程闭环。

  1. 技术价值:完整演示迁移学习在小样本视觉分类场景的落地方法,讲解 ResNet 特征提取 + 自定义分类头的搭建思路,训练曲线、精度测试环节可作为深度学习课程实践案例。
  2. 工程价值:代码分层解耦、业务逻辑完整,签到去重、考勤状态判定、多格式报表等模块可直接复用至实际人脸打卡系统,快速完成二次开发。
  3. 学习门槛低:全部代码兼容 Kaggle Notebook,无需本地 GPU 环境,复制即可运行,适合计算机视觉入门、人工智能工程化实践学习。

整套工程完整代码已拆分至 19 段 Notebook 单元,按照本文模块顺序依次执行即可复现全部训练、考勤、报表导出效果,同时预留充足拓展空间,可根据企业实际需求迭代优化。


更多推荐