基于OpenCV与TensorFlow 2.0的Win10人脸识别自动锁屏实战

发布时间:2026/9/23 7:40:38
基于OpenCV与TensorFlow 2.0的Win10人脸识别自动锁屏实战 简介一套基于OpenCV与TensorFlow 2.0的CNN人脸识别实战项目面向计算机视觉方向的毕业设计、课程设计以及人脸识别入门学习者覆盖从人脸检测、特征提取到识别判断的完整流程用于解决Win10屏幕的自动锁定与解锁需求。资源包共7个文件由4个Python脚本、1个VBS脚本、1个Bat批处理和1个Markdown说明文档组成压缩包整体仅13KBPython脚本承载识别主逻辑VBS脚本实现无窗口隐藏调用Bat文件一键启动Markdown文档提供配置说明与使用指引。目前已有302人学习下载。通过这套方案读者能快速搭建人脸识别锁定/解锁环境理解CNN在真实Windows场景中的部署方式并借鉴脚本组织与批处理调用技巧项目结构清晰、代码量小适合作为二次开发与功能扩展的起点。1. 为什么用OpenCVTensorFlow 2.0做Win10锁屏这个方案解决什么问题人脸识别锁屏这个需求最早是在知乎上一个“离开工位不锁屏被同事恶搞”的帖子里看到的。后来发现做这套方案的人远不止被恶搞的那一批——实验室防止外人动工作站、教室多媒体电脑防止学生乱插U盘、宿舍里防止别人用自己电脑诉求完全一样人离开自动锁人回来自动解。市面上能买到的方案是带人脸识别的Windows Hello但很多旧笔记本没有对应硬件外接一个成本也不低。用OpenCV做图像采集、TensorFlow 2.0跑一个CNN分类模型再通过win32 API调用系统锁屏与模拟键盘输入几百行Python就能在普通Win10机器上跑通。这个项目适合手里有一台装了Win10的电脑、会一点Python、愿意花一下午调模型的人。本文会把环境、训练、联动、排错整个链路讲透。2. 环境搭建与模型选型先解决“装得上、跑得动”再谈识别率2.1 安装OpenCV与TensorFlow 2.0Anaconda环境下的依赖隔离做这类项目我最不建议直接往系统Python里pip装一堆包尤其是OpenCV和TensorFlow。两个库的依赖树很深OpenCV底层依赖numpy版本范围很窄TensorFlow 2.x对numpy的版本要求又跟OpenCV冲突过好几轮。用conda建一个独立环境能省掉后面一大半的玄学报错。conda create -n face python3.8 conda activate face pip install opencv-python4.8.1.78 tensorflow2.6.0 pillow numpy1.24.3这里Python版本我固定在3.8TensorFlow用2.6.0。原因是TensorFlow在Windows平台从2.11开始不再官方支持GPU版而2.10及之前的版本对Python 3.8~3.10支持最稳。如果你机器只有核显CPU版本推理这个项目也够用后面章节会聊怎么把推理速度压进100毫秒内。OpenCV版本用4.8系列接口稳定CascadeClassifier和dnn模块都完整。装完后执行下面这段验证代码确认两个库能同时被导入且版本符合预期import cv2 import tensorflow as tf print(OpenCV:, cv2.__version__) print(TensorFlow:, tf.__version__) print(GPU Available:, tf.config.list_physical_devices(GPU))如果最后一行打印出来是空列表不用慌。这个项目用单张96×96人脸图做推理CNN参数量不大CPU跑到20~30毫秒一帧完全能接受。之前有同学非要在旧笔记本上折腾CUDA版OpenCV结果搞了两天没搞定换成纯CPU方案当天就出结果了——深度学习这块模型小的时候CPU反而省心。2.2 CNN方案选型分类模型还是度量学习为什么先从分类做起人脸识别领域常见的方向有三类直接训练一个多分类CNN、用孪生网络做度量学习、或者加载预训练的FaceNet模型提取128维特征向量再比对。这个锁屏项目的人脸库通常只有1~5个人自己、家人或实验室同门属于典型的“小规模固定人群识别”用最简单的分类CNN就能解决。分类模型的做法是把每个人的名字当作一个类别最后一层接softmax输出属于每个人的概率。优点是训练简单、收敛快、单帧推理无需额外计算缺点是新增一个人要重新训练。度量学习比如FaceNet那套三元组损失虽然支持增量添加人脸库但需要精心构造训练样本对数据量少时很容易不收敛。我一般建议先做分类CNN跑通全流程等人多了再迁到特征向量比对不要把第一步搞复杂。另外要提醒一点很多人习惯直接调用cv2.face.LBPHFaceRecognizer_create()这类OpenCV自带的人脸识别模块它内部不是深度学习方案光照变化和角度偏转一大就翻车。既然标题点名了TensorFlow 2.0和CNN就用tf.keras搭一个小型卷积网络识别率比传统方法高一截。2.3 人脸检测与对齐用OpenCV的Haar Cascade还是dnn模块人脸识别模型吃的是“只有人脸”的小图所以流程里要先用人脸检测器从摄像头帧里把人脸框出来裁剪缩放后才能送进CNN。OpenCV里现成的方案有两个老牌的Haar Cascade和较新的dnn模块基于SSD或YuNet。Haar Cascade是OpenCV最经典的人脸检测器一个xml文件搞定CPU上跑一帧3~5毫秒侧脸和戴口罩时检测率明显下降。dnn模块的YuNet在WIDER Face数据集上效果更好对角度和遮挡的容忍度高但需要额外下载模型权重文件初始化也慢一点。这个项目是“人在不在一体机前面”这种近正面场景Haar Cascade完全够用而且少一个文件依赖分发起来省心。import cv2 cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) def extract_face_roi(frame): gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces cascade.detectMultiScale( gray, scaleFactor1.1, minNeighbors5, minSize(48, 48) ) roi_list [] for (x, y, w, h) in faces: face gray[y:y h, x:x w] face cv2.resize(face, (96, 96)) face_rgb cv2.cvtColor(face, cv2.COLOR_GRAY2RGB) roi_list.append((x, y, w, h, face_rgb)) return roi_list几个参数需要解释。scaleFactor1.1表示每次搜索窗口缩小10%这个值越小检测越慢但越准1.1是速度和精度的折中。minNeighbors5表示一个候选框周围至少要有5个相邻检测确认才算人脸越大误检越少但真脸也可能被滤掉。minSize(48, 48)是检测窗口下限小于这个尺寸的候选区直接忽略过滤掉远处的小人脸的思路。我把灰度图转成了RGB再返回是后面CNN输入需要三通道灰度图单通道虽然也能训但会少一部分可学特征。3. 训练CNN人脸识别模型数据采集、网络结构与梯度下降3.1 人脸数据采集每人50张图覆盖三个关键维度训练数据是整个项目里最容易被忽视、却最决定成败的环节。模型结构是公开的损失函数是现成的但数据拍得不讲究识别率就是上不去这就是典型的“输入垃圾输出垃圾”。我工位旁边有暖光灯、下午三点有西晒、我平时戴眼镜敲代码——所以给每个人采集数据时至少覆盖三种场景正常坐姿正面、稍微侧头说话、戴上眼镜或摘下眼镜的对比。用摄像头录一段10秒的视频然后逐帧抽帧比手动按N张“摆拍”效率高很多也能自然采集到不同角度和表情。import cv2 import os def collect_faces(name, save_dirdataset, num_frames150): cap cv2.VideoCapture(0) save_path os.path.join(save_dir, name) os.makedirs(save_path, exist_okTrue) cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) count 0 while count num_frames: ret, frame cap.read() if not ret: continue gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces cascade.detectMultiScale(gray, 1.1, 5, minSize(96, 96)) for (x, y, w, h) in faces: face gray[y:yh, x:xw] face cv2.resize(face, (96, 96)) cv2.imwrite(f{save_path}/{count:04d}.jpg, face) count 1 cv2.imshow(collect, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows() collect_faces(zhangsan) collect_faces(lisi)采集代码里我用了num_frames150作为每人照片数上限。实践下来150张足够让CNN拟合一个人的人脸特征再多边际收益很小反而拖慢训练。数据里记得混合“戴眼镜”和“不戴眼镜”的照片最好各占一半。如果摄像头固定不动150张里可能有一半是几乎相同的帧我习惯在写入前做一次像素差判断前后两帧差异小于某个阈值就跳过。3.2 CNN网络结构三层卷积加BN层为什么不用预训练模型这个锁屏场景的输入是96×96小图任务是最多分类五六个人用不着ResNet50或EfficientNet这种百层级的骨干网络。模型大反而容易在小数据集上过拟合——训练loss降到0.1验证loss却有2.0这是典型的在背训练集而不是学特征。我用的网络结构是一个三层卷积加两个全连接的小网络总参数量约80万在CPU上推理单张人脸耗时约20毫秒。import tensorflow as tf def build_cnn(num_classes): model tf.keras.Sequential([ tf.keras.layers.Conv2D(32, (3, 3), activationrelu, paddingsame, input_shape(96, 96, 3)), tf.keras.layers.BatchNormalization(), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Conv2D(64, (3, 3), activationrelu, paddingsame), tf.keras.layers.BatchNormalization(), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Conv2D(128, (3, 3), activationrelu, paddingsame), tf.keras.layers.BatchNormalization(), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Flatten(), tf.keras.layers.Dense(256, activationrelu), tf.keras.layers.Dropout(0.5), tf.keras.layers.Dense(num_classes, activationsoftmax) ]) return model model build_cnn(num_classes2) model.compile( optimizertf.keras.optimizers.Adam(learning_rate1e-3), losscategorical_crossentropy, metrics[accuracy] ) model.summary()网络设计上我刻意在每层卷积后加了BatchNormalization这个小改动对训练稳定性帮助极大。不带BN时学习率稍微调大一点loss就直接跳成NaN加了BN之后学习率在1e-3到1e-4之间都能正常收敛。Dropout只接了全连接层、没接卷积层是参照CNN的惯例——卷积层本身有参数共享做正则全连接层才是过拟合的重灾区。如果你只有一个人要识别二分类的模型一样能用只是“陌生人也输出一个高概率”这种误判要在后处理里拦。3.3 训练与数据增强用ImageDataGenerator减少对样本量的依赖150张照片说多不多说少不少但人脸会受光照、角度影响产生分布偏移。我习惯在训练时做在线数据增强相当于把150张图扩展成更多变体让模型见过“变化”而不是“死记”。from tensorflow.keras.preprocessing.image import ImageDataGenerator datagen ImageDataGenerator( rotation_range15, width_shift_range0.1, height_shift_range0.1, brightness_range(0.8, 1.2), horizontal_flipTrue, validation_split0.2 ) train_gen datagen.flow_from_directory( dataset, target_size(96, 96), batch_size32, class_modecategorical, subsettraining, color_modergb ) val_gen datagen.flow_from_directory( dataset, target_size(96, 96), batch_size32, class_modecategorical, subsetvalidation, color_modergb ) early_stop tf.keras.callbacks.EarlyStopping( monitorval_loss, patience8, restore_best_weightsTrue ) history model.fit( train_gen, validation_dataval_gen, epochs30, callbacks[early_stop] )一个很容易踩的坑是flow_from_directory的目录结构dataset目录下每个子目录名就是类别名子目录里放对应人的照片。类名千万不要用中文opencv的imwrite在中文路径上偶尔会抽风模型保存和加载也可能遇到编码问题。brightness_range(0.8, 1.2)这个参数是我调过好几轮后留下的工位上午和下午的光照差异用这个范围基本都能覆盖。EarlyStopping的耐心值设成8个epoch一般20个epoch以内就会触发不会真跑满30轮。3.4 导出SavedModel给后面的实时识别留好接口训练完别光拿一个model.h5跑测试生产环节建议存成TensorFlow的SavedModel格式。h5格式虽然也能用但SavedModel里包含了签名定义后面用OpenCV的dnn模块加载转出来的模型文件会更顺畅。如果你只打算用纯TensorFlow推理h5也无所谓——但要记得把类别名一并保存模型权重里只有索引没有名字。import json model.save(face_model) with open(face_model/class_names.json, w) as f: json.dump([zhangsan, lisi], f)model.save(face_model)会生成一个目录里面是assets和variables等子目录这是TF标准的模型打包方式。类别名的顺序要和训练时flow_from_directory拿到的一致可以在保存前打印一下train_gen.class_indices确认。这个json文件后面实时识别脚本要读丢了它模型输出就是一个“不知道是谁”的数字索引。4. 把模型接到Win10锁屏上实时检测循环与系统API联动4.1 实时识别循环控制推理频率与置信度阈值训练好的模型要能长时间稳定跑在后台不能一上来就每帧都做人脸检测和模型推理那样CPU占用率会飙到60%以上风扇声比拖拉机还响。我一般用“检测帧率”和“识别帧率”分离的策略OpenCV的摄像头采集是30fps但人脸检测每2帧做一次就够了检测到人脸后再做CNN识别也只有这个时候才调用模型。import cv2 import numpy as np import json import tensorflow as tf model tf.keras.models.load_model(face_model) with open(face_model/class_names.json, r) as f: class_names json.load(f) cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) cap cv2.VideoCapture(0) def predict_face(face_rgb): img cv2.resize(face_rgb, (96, 96)) img img.astype(float32) / 255.0 img np.expand_dims(img, axis0) probs model.predict(img, verbose0)[0] idx int(np.argmax(probs)) return class_names[idx], float(probs[idx]) frame_counter 0 while True: ret, frame cap.read() if not ret: break frame_counter 1 if frame_counter % 2 ! 0: continue gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces cascade.detectMultiScale(gray, 1.1, 5, minSize(96, 96)) for (x, y, w, h) in faces: face_rgb cv2.cvtColor( gray[y:yh, x:xw], cv2.COLOR_GRAY2RGB ) name, score predict_face(face_rgb) if score 0.7: cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2) cv2.putText(frame, f{name}:{score:.2f}, (x, y-8), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) else: cv2.rectangle(frame, (x, y), (xw, yh), (0, 0, 255), 2) cv2.putText(frame, unknown, (x, y-8), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.imshow(face lock monitor, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()代码里verbose0这个参数是TensorFlow 2.6之后才有的老版本会打印一行进度条在循环里调用会刷屏刷到怀疑人生。置信度阈值0.7是经验值——调得越高越不容易误判成自己人但人也可能被当成陌生人调得太低长得像的人就能开你电脑。我实测过0.6到0.85之间0.7最能平衡误锁和误开。4.2 锁定Win10屏幕直接调用LockWorkStationlock在Win10里其实是最简单的一步不需要任何界面自动化一个系统API调用就行。Windows提供了LockWorkStation这个函数对应的是user32.dllPython里用ctypes直接调。import ctypes import time def lock_screen(): ctypes.windll.user32.LockWorkStation() def check_face_absent(frames, absent_seconds10): absent_count 0 checked_frames 0 while checked_frames frames: ret, frame cap.read() if not ret: continue gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces cascade.detectMultiScale(gray, 1.1, 5, minSize(96, 96)) if len(faces) 0: absent_count 1 else: absent_count 0 checked_frames 1 if absent_count * (absent_seconds / frames) absent_seconds: return True return False这段代码的思路是“连续N秒没人脸才锁屏”而不是“一帧没人脸立刻锁”。真实场景里人会低头、会转头、会把手放到脸上单帧没人脸很正常。我习惯设10秒窗口摄像头30fps每2帧检查一次10秒大约检查150帧其中连续100帧没人脸就锁屏。这个参数在工位场景比较舒服——低头捡个笔不会被锁起身去接水走两步就锁上了。4.3 解锁Win10屏幕模拟键盘输入密码的完整路径锁屏后的解锁环节是这个项目真正的难点。Windows出于安全考虑锁屏恢复时要求用户按CtrlAltDel进入登录框这个“安全注意序列”普通用户态程序无法用SendInput模拟——这是写死在系统安全策略里的。同时锁屏后摄像头会被LogonUI进程占用你后台的Python程序再想去读摄像头大概率读到的是黑帧或者直接报错。所以“锁屏状态下重新识别人脸然后解锁”这条路在纯Python方案里基本走不通。社区里能跑通的方案普遍是兜底设计先通过注册表关闭CtrlAltDel要求再用模拟键盘输入密码的方式解锁。具体来说在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon下建一个DisableCAD的REG_DWORD值置为1。重启后锁屏界面就不再要求CtrlAltDel只会停留在一个登录输入框。这样你的Python程序才能在后台用模拟键盘操作。import ctypes import time import subprocess def press_key(hex_key): ctypes.windll.user32.keybd_event(hex_key, 0, 0, 0) time.sleep(0.05) ctypes.windll.user32.keybd_event(hex_key, 0, 2, 0) def unlock_screen(password): time.sleep(2) press_key(0x0D) # Enter唤出登录密码框 time.sleep(1) for ch in password: ctypes.windll.user32.keybd_event( ord(ch.upper()), 0, 0, 0 ) time.sleep(0.05) ctypes.windll.user32.keybd_event( ord(ch.upper()), 0, 2, 0 ) press_key(0x0D) # 回车确认登录 unlock_screen(your_password_here)这段代码有个正在踩的坑keybd_event只能发送字母和数字的虚拟键码密码里如果包含特殊符号比如!#$ord(ch.upper())拿到的虚拟键对不上。更离谱的是Windows的登录密码框在锁屏后会有一个动效动画如果程序在动画结束前就开始模拟输入第一两个字符会被吞掉。我一般会在锁屏后等2秒再发键盘事件密码前加一个回车先唤出输入框再输密码。4.4 完整的“检测-锁屏-解锁”状态机把上面的代码拼起来就是一个简单的状态机。程序有两个状态MONITOR监控中和LOCKED已锁定。在监控状态持续检测人脸超时无人脸就调用锁屏并切换状态。在锁定状态等几秒后直接模拟密码输入解锁。这个流程有一个安全弱点锁屏后程序并不知道坐在电脑前的是谁只是“锁屏后自动输入密码”相当于人脸识别只负责了“该不该锁”没负责“该不该解”。真正严格的做法要等解锁后再做一次人脸验证确认是本人否则就再次锁定。下面把这个校验逻辑也写进代码class FaceLockStateMachine: def __init__(self, password): self.password password self.locked False def run(self): while True: if not self.locked: if check_face_absent(150, absent_seconds10): lock_screen() self.locked True else: time.sleep(3) unlock_screen(self.password) time.sleep(2) ret, frame cap.read() if ret: gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces cascade.detectMultiScale( gray, 1.1, 5, minSize(96, 96) ) if len(faces) 0: lock_screen() # 解锁后又没人脸再次锁上 else: face_rgb cv2.cvtColor( faces, cv2.COLOR_GRAY2RGB ) name, score predict_face(face_rgb) if score 0.7: lock_screen() else: self.locked False这个状态机的思路是“解锁后立刻做一次人脸复核”如果屏幕前坐的不是授权用户马上重新锁屏。它能兜住“人离开后有人趁机坐过来”的场景虽然有一两秒的窗口期但对于个人电脑的威胁模型来说可以接受。放进后台跑的时候记得把cap.read()的摄像头也纳入异常处理不然锁屏期间LogonUI占用摄像头会直接让整个程序崩溃。5. 实战避坑5个让人脸锁屏翻车的细节与排查方法5.1 锁屏后摄像头被LogonUI独占程序直接卡死现象锁屏后程序不再刷新画面控制台报Unable to grab image或cv2.error: OpenCV(4.8.1) ... CAP_IMAGES: cant find starting number。原因Win10的锁屏界面会独占摄像头设备特别是登录页显示人脸图标时。Python进程此时拿不到视频帧cap.read()返回(False, None)如果代码里没做判空处理后续的detectMultiScale就直接抛异常退出。解决在状态机的锁屏分支里加了if not ret: continue并且在锁定状态下不再读取摄像头等模拟解锁完成后再重新初始化VideoCapture。还有一种“不锁摄像头”的思路是把Win10设置里的“动态锁”关闭但实测对LogonUI无效别浪费时间。5.2SendInput模拟不了CtrlAltDel解锁卡在安全注意序列现象代码里用keybd_event发了Ctrl、Alt、Del三个键锁屏界面纹丝不动程序自己也拿不到任何错误提示。原因安全注意序列SAS是Windows安全边界普通用户态程序模拟不了这是设计使然。只有登录进程能响应这对组合键。解决注册表DisableCAD1关闭锁屏登录的CAD要求。改注册表前先把密码设好改完重启一次确认能正常关机启动。这个方法让锁屏安全性降低了——别人不需要按CtrlAltDel也能直接输密码但个人电脑场景下这个风险可接受。另外提醒一句别把这个方案部署到公司合规要求严格的机器上。5.3 模型在夜间误锁光照变化让CNN“六亲不认”现象白天识别率95%到了晚上开了暖光灯明明坐在屏幕前也被锁屏置信度跌到0.3。原因训练数据里没有覆盖夜间灯光场景。CNN学到的特征里混入了大量肤色在特定色温下的统计规律灯光一变特征空间偏离。解决重新采集数据分别在白天自然光、晚上白色LED灯、晚上暖光灯三个场景各录一段。训练时的brightness_range从(0.8, 1.2)放宽到(0.6, 1.4)并加上少量高斯噪声增强。调完之后夜间误锁率基本消失代价是白天偶尔出现一次置信度降低、需要重新坐正才能识别。5.4 从Anaconda Prompt启动后找不到OpenCV环境名与路径的问题现象刚刚用conda装好了opencv-python关掉终端再重新打开Anaconda Prompt输入import cv2报ModuleNotFoundError: No module named cv2。原因新开的终端默认在base环境之前装的包在face环境里。两个环境的site-packages目录完全隔离没激活环境自然找不到。解决每次运行前先conda activate face。如果激活后还是报错执行python -c import cv2; print(cv2.__file__)看打印出来的路径是不是在face环境目录下。很多同学卡在这一步是习惯了PyCharm里直接选解释器命令行跑脚本时忘了配环境变量。建议把实时识别脚本的启动命令写成一个run.bat里面第一行就是conda activate face双击就能跑。5.5 开机自启程序黑匣子式崩溃工作目录与摄像头索引变化现象把python脚本做成开机启动后程序没有窗口、没有日志一天后才发现根本没在跑。查看Windows事件查看器才发现进程早就退出了。原因两个隐藏点。第一开机自启的工作目录不是脚本所在目录程序里用相对路径face_model加载模型会直接FileNotFoundError第二不同USB摄像头比如笔记本自带摄像头和显示器上的外接摄像头在开机时的设备索引不稳定VideoCapture(0)拿到的未必是你想要的设备。解决先用os.path.abspath(__file__)推导出脚本目录再基于该目录拼出模型和xml文件的绝对路径。摄像头索引可以通过cv2.VideoCapture(0)尝试打不开就试1两个都打不开就报警。更稳妥的做法是程序把日志写到C:\Users\你的用户名\face_lock.log崩溃前至少能看到最后一行在干什么不然出了错全靠猜。6. 进阶TFLite量化加速、多用户支持与可靠性验证识别循环跑通后下一步优化推理速度和流畅度。把模型转成TensorFlow Lite的float16量化版本在保持精度几乎不变的前提下CPU推理速度能提升30%~50%。转换代码很简洁但要注意量化后模型路径要从face_model_quant.tflite加载接口也变成了TFLite的Interpreter。import tensorflow as tf converter tf.lite.TFLiteConverter.from_saved_model(face_model) converter.optimizations [tf.lite.Optimize.DEFAULT] converter.target_spec.supported_types [tf.float16] tflite_model converter.convert() with open(face_model_quant.tflite, wb) as f: f.write(tflite_model) # 推理侧 interpreter tf.lite.Interpreter(model_pathface_model_quant.tflite) interpreter.allocate_tensors()量化模型推理时输入数据要做同样的float32 / 255.0归一化只是不再经过tf.keras的model.predict封装。实测在四代i5 CPU上96×96人脸单次推理从25毫秒降到15毫秒左右100毫秒内完成“检测识别”不成问题。如果你的电脑支持TensorFlow GPU版float16量化反而会慢因为GPU的float32计算单元利用率更高——这个需要在自己机器上对比别盲信网上结论。多用户支持这块如果新增一个人就要重新训练整个模型体验很痛。一个过渡方案是保留之前的分类模型作为“第一层闸门”新用户单独算一个特征向量存起来每次识别时先过分类模型置信度低于0.7再走特征比对。这样新增用户时不需要重训旧模型只需存一段新的特征向量。最后说说验证方法。不要靠肉眼看几秒画面就宣布“成功了”那是自己骗自己。我一般会录制一段10分钟的工位视频作为回放测试集视频里包含正常办公、起身、带陌生人进画面、转身背对摄像头等动作。然后用这个视频循环回放跑状态机统计三个指标漏锁率人走了没锁、误锁率人还在却锁了、误解锁率陌生人解锁成功。三个指标都低于1%才敢正式启用。这个习惯是吃过一次亏后才养成的——之前测试时只坐了5分钟觉得“很稳定”结果跑了一下午被锁了十几次同事以为我电脑中病毒了。人脸识别锁屏这个方向做到能用的程度不难难的是在不同光照、不同坐姿、不同设备下保持稳定。如果你的电脑配置不高先跑CPU版如果你需要更严格的解锁验证考虑引入Windows Hello兼容摄像头如果你要部署到多人环境分类模型可能撑不住换FaceNet或SFace这类Embedding方案是正路。希望这篇把环境、训练、锁屏联动和排错串起来的实战笔记能帮到你。本文还有配套的精品资源点击获取