跳到正文

01 / 05 · 2019.07 — 2020.07

北京云上作科技有限公司

在 AI + 教育方向做算法落地与全栈开发:用 Mask R-CNN + ResNet 做课堂行为实时分析与预警,搭建内部数据标注与训练平台,并负责线上巡课统计后台、人脸核身与截图识别服务。

职位
软件开发工程师
行业
AI + 教育
地点
北京
团队
5 人
在职
1 年 1 个月

关键成果

  • 6 类

    课堂行为分类(抬头、低头、站立、趴桌、扭头、举手);置信度低于 0.95 记为“不确定”,不强行判定

  • 21 个路由

    线上巡课统计引擎后端(约 1650 行 Tornado),基于 Elasticsearch 聚合查询

  • 1 万+ 张

    微信截图识别项目中自己标注的截图数量(另有 1 千+ 张图标)

在这里做的项目

PROJECTS · 4
数据标注:用 Mask R-CNN 预标注后,在 Labelme 里只修正框和行为类别

2019 – 2020 · 全栈工程师(算法 · 后端 · 内部训练平台) · 团队 5人

AI 课堂行为分析系统

用教室摄像头识别学生的上课行为(抬头、低头、举手、趴桌、扭头等),通过人脸识别对应到具体学生,再提供实时预警和多层级的课堂报表。我开发了两个子系统:面向学校的实时分析与预警平台,以及内部使用的数据标注与模型训练平台。

  • 两阶段识别:Mask R-CNN(R-101-FPN)检测学生 → ResNet18 做行为分类(6 类,置信度低于 0.95 记为“不确定”);比让检测模型直接分类更准,且行为类别调整时只需重训小的分类器
  • 实时分析:OpenCV 读 RTSP 流,视频时间戳落后于实际时间就丢帧以保证实时;每个班级一个独立 GPU 进程,启动前用 nvidia-smi 检查剩余显存
  • 跨帧跟踪与身份识别:自研 5 秒窗口的双向重叠率跟踪;face_recognition(dlib)提取 128 维特征与班级人脸库比对,同一轨迹内取出现最多的学生 ID 投票,低头、侧脸时身份仍能认对
  • 趴桌 / 扭头实时告警:裁出学生头像(base64)写入告警;最新结果与逐帧历史分开存入 MongoDB
  • Tornado 后端:账户与三种角色、预警与报表(学生・课堂・年级・学校四个层级)、微信小程序 API 与第三方平台开放 API;对接产品经理的原型并设计接口协议字段
  • 用 scikit-learn 分析行为数据,输出每位学生的周报、月报与学期报告,推送到家长的微信小程序
  • 内部数据标注与训练平台:视频剪辑 → Mask R-CNN 预标注(生成 labelme JSON)→ 人工修正 → 裁图 → 建数据集 → ResNet18 训练(断点续训、loss / 准确率曲线)→ 验证;整节课离线分析模块即实时算法的原型
  • 交付:核心跟踪算法用 Cython 编译为 .so,配合 supervisor 守护与加密狗授权,在多个客户处私有化部署
  • Python
  • Tornado
  • PyTorch
  • maskrcnn-benchmark
  • face_recognition (dlib)
  • OpenCV
  • FFmpeg
  • MongoDB
  • scikit-learn
  • Cython
  • ECharts
  • jQuery

运行演示

  • 实时分析平台:班级监控总览
  • 校长视角大屏
  • 多班级实时画面

系统架构

采集层 流媒体 & 推理层 数据层 服务层 客户端 教室摄像头 RTSP 视频流 演示视频流 infinitevideo.sh FFmpeg 循环推流 直播链路(ClassDetailHandler 打开课堂详情时启动) FFmpeg RTSP→RTMP 转推 nginx-rtmp rtmp://…/mytv/ H5 播放器 ckplayer/video.js 启动 / 停止分析进程(nohup + kill,先查剩余显存) GPU 推理进程 · 每个班级一个 · front_back_frame ①OpenCV 读流 + 丢帧控制 视频时间戳落后于实际时间就跳帧,保证实时 ②Mask R-CNN(R-101-FPN)检测学生 只保留“人”,置信度 ≥ 0.7,重叠框去重(0.8) ③ResNet18 行为分类(6 类) 单人图补成正方形 → 224×224;置信度 < 0.95 记为“不确定” ④face_recognition 识别学生身份 CNN 定位人脸 → 128 维特征 → 与班级人脸库比对 ⑤跨帧跟踪 + 轨迹内身份投票 5 秒窗口双向重叠率关联;轨迹内取出现最多的学生 ID 趴桌 / 扭头 → 裁出头像,base64 写入告警 写入 MongoDB realtimewarning 每班最新一帧结果 record_pics 逐帧历史记录 pg_classes 班级·视频流·人脸库·进程 school/class/student 学校、班级、学生档案 students_performances 每节课的行为表现 bf_kaoqin … 客户考勤等定制数据 Tornado Web :8080 · pymongo 账户系统 安全Cookie·三种角色 预警系统 轮询 /getfaster 报表视图 学生/课堂/年级/学校 客户定制页 客户 A · 客户 B 小程序 API xcx.py 第三方平台开放 API jyd_api.py Amaze UI · ECharts 校长 / 老师 浏览器 微信小程序 家长 / 老师 第三方平台 第三方系统 运维与交付 supervisor 守护 4 个进程(Web · 分析 · 推流 · VPN) | Cython 把核心算法编译成 .so | 加密狗授权 | Linux + NVIDIA GPU(CUDA)
1剪辑视频 /ffmpeg · /ffmpegGetVideotimes 读取时长,按起止时间剪片段 2模型自动预标注 /labelme · infer2labelme_mask Mask R-CNN 推理生成 labelme JSON 3人工修正 labelme 桌面工具 只需修正框和行为类别 4裁图与归类 /cutimg · /gray 按框裁单人图,按行为放进文件夹 5生成数据集 /dataset · DataSet.py 检查类别文件夹是否从 0 连续编号 6训练分类模型 /train · resnet_trainer ResNet18 · SGD · 50 轮 · 断点续训 7模型验证 /behavior · test_jr2_fang 可调阈值,批量测试效果 8整节课离线分析 /upVideo · class_recognition 跟踪→聚类→认人→入库 ↓ 产出 ResNet 分类模型 .pth,部署到实时平台 ↓ 算法后来改成实时版 支撑功能:班级与视频流管理(/addClass /modifyClassStream /removeClass)· 学生与人脸照片管理(/addStu /modifyStu /removeStu)· 模型与文件夹浏览(/getMaskmodel /getFolder)
课堂视频素材 摄像头录像 / 现场采集 Backend 训练平台 标注 · 建数据集 · 训练 · 验证 模型文件 detector.pth (Mask R-CNN) classifier.pth 实时分析平台 实时推理 · 预警 · 报表 上线后持续产生新的课堂视频,回流成新的训练数据
在线英语课现场画面(师生已打码)

2020 · 统计引擎后端、管理后台前端、参与算法分析

AI 诊断性巡课系统

在线英语课场景(疫情的原因改为线上课程)下实时采集师生音视频,经 ASR / CV / VAD 结构化后:对红线行为(说中文、老师说话过久、学生参与过少、离开镜头、黑屏或掉线)做准实时告警;并输出教质指标报表,按总部 / 分公司 / 校区、课程、教师、学生多维度对比排名。

  • 统计引擎后端(Tornado,约 1650 行、21 个路由):课堂 / 教师 / 学生的列表、详情与历史趋势,教学态度时序曲线,样板课堂 TopN
  • Elasticsearch 查询:bool + terms + range 组合,terms 聚合下嵌套 avg 子聚合(按课堂算教师平均 happy 概率、词数、语速),大结果集用 scan / scroll 遍历;CV 与 ASR 多源结果在应用层合并后排序
  • 管理后台前端(vue-element-admin 4.4):基于角色的动态路由权限、数据大屏、课堂 / 教师 / 学生列表与详情、排名、趋势、筛选;ECharts 可视化,Docker 化与多环境配置
  • 参与算法分析:综合学员说话比例、连贯表达与情绪正向程度,找出约 30 秒的“高光时刻”片段,并标记噪音、课件语音干扰、家长陪同等异常,用于给家长的学员表现报告
  • Python
  • Tornado
  • Elasticsearch
  • Redis
  • Vue 2
  • Element UI
  • ECharts
  • MQTT
  • Docker
  • Alibaba Cloud

系统架构

数据采集到告警展示的链路
采集端 接入 · 存储 · 事件 结构化算法(gRPC) 检索 · 分析 · 展示 浏览器 <video> web-video-capture.js 每秒 1 帧 · 音频每 10 秒一段 上行约 30kbps · 开销 <5% IOAuthProxy 授权服务 :9001 Aliyun OSS 公有云 MinIO 私有化部署 Notification Hub OSS 触发器 → MNS ASR Worker中英文语音转文字 CV Worker人脸位置/朝向/表情 Sound (VAD)发声起止和时长 Elasticsearch当时序库用 Analyse TaskQueue Analyse Enginestats_engine :9002 ReportDB+ ClassDB 排课 管理 后台 Vue MQTT 事件队列 1883 / 8083 / 8084 申请 Token webpwebm 红线事件 WebSocket 推送 → 老师页面告警

2020 · 算法与服务开发

FaceID 人脸核身与人脸检索

为在线教育客户做的人脸核身:从上课视频中确认出镜学员是否为本人,并支持全库 / 增量 / 指定人的人脸检索,用来发现“一人多号”或“多人共号”。

  • 推理流程:随机抽帧 → YuFaceDetectNet 检测 + 5 点关键点 → 仿射对齐 → 遮挡 / 姿态模糊 / 年龄三个模型过滤 → ResNet18 提取特征并做余弦相似度比对;取年龄最小的人脸(< 17 岁)锁定学员本人、排除家长
  • 多框架混合推理:检测与特征提取用 PyTorch,遮挡、姿态、年龄用 MXNet Gluon,统一跑在 CPU 上;从 v1.0 到 v3.4 持续迭代(dlib 68 点 + Laplacian 模糊检测 → 更换模型与对齐 → 加入三个质量模型 → 重写全库检索与视频校验)
  • 用 Redis 存放特征,支持全局、增量、指定人三种检索;全库两两比对按代码注释估算约 4000 万次
  • 商业授权控制:调用次数、到期时间、每日额度经 AES 加密存入 Redis,SETNX 做分布式锁,校验设备 SN;核心模块用 Cython 编译为 .so 交付
  • 配置按“命令行参数 > 环境变量 > JSON / YAML”的优先级读取;Docker 部署,构建时从 OSS 拉取模型权重
  • Python
  • PyTorch
  • MXNet
  • dlib
  • ResNet18
  • Redis
  • Cython
  • Docker
  • OSS

系统架构

核身与检索的推理流程(v3)
视频 上课视频文件 随机抽帧 缩放到 320×240 人脸检测 YuFaceDetectNet · PyTorch 5 点关键点 仿射对齐 逐张人脸 质量过滤(MXNet Gluon · CPU) 遮挡 眼 / 鼻 / 嘴 > 0.5 则跳过 姿态 / 模糊 偏航 · 俯仰 · 翻滚 · 模糊度超限则跳过 年龄 取最小年龄(< 17 岁)锁定学员 ResNet18 特征 PyTorch · 余弦相似度 比对与存储 首次:录入特征 存入 Redis hash 之后:核身 / 检索 全局 · 增量 · 指定人 授权控制 + Cython 交付 AES 额度 · SETNX 锁 · .so
朋友圈广告截图样例(人物已打码)

2020 · 训练、推理、服务与部署

微信截图智能识别(朋友圈广告投放核查)

对上传的微信截图做自动识别,用于核查朋友圈广告投放:判定截图类型(会话 / 朋友圈列表 / 朋友圈详情),提取发布时间、广告文案、海报 ID、二维码链接以及点赞与评论数。

  • YOLOv5s 主检测(7 类界面元素)并用规则判定截图类型;自行标注 1 万多张截图与 1 千多张点赞 / 评论图标,k-means 聚类先验框
  • 朋友圈详情:PaddleOCR(PP-OCR,DB 检测 + CRNN 识别)按版面位置取发布时间、广告文案与海报 ID;二维码解码;右下角裁剪后用 YOLOv5 检测点赞 / 评论图标,再用 3 层 CNN 识别数字
  • Tornado + PyTorch + PaddlePaddle 服务:token 与 MD5 完整性校验,nanoid 请求追踪,原图存 OSS,全量结果与耗时写入 Elasticsearch,用于排查线上异常返回
  • 升级 PP-OCR 模型版本,提高海报 ID 与发布时间的识别率
  • Python
  • PyTorch
  • YOLOv5
  • PaddleOCR
  • PaddlePaddle
  • Tornado
  • Elasticsearch
  • OSS
  • Docker

系统架构

截图识别流程
截图上传Tornado POST 校验 + 存 OSStoken · MD5 · nanoid YOLOv5s 主检测7 类图标 / 二维码 规则分类按目标和相对位置 会话消息 · 有加号或三点图标 朋友圈列表 · 有相机图标 → 检测分组可见 其他 朋友圈详情 · 二维码在详情页的相对位置 PaddleOCR(DB 检测 + CRNN 识别) 按位置取发布时间 · 按和二维码的相对位置取文案 按"ID"关键词取海报 ID 二维码解码 检测框裁剪 → 解出 URL 点赞数 / 评论数 裁剪右下角 → YOLOv5 找图标 → 3 层 CNN 识别数字(验证集 98.25%) 汇总 JSON 返回 · 全量结果和耗时写入 Elasticsearch · 自定义错误码(212 / 218 …)

系统数据流

抽象示意 · 不含内部细节
  1. 教室摄像头

    RTSP 实时视频流

  2. OpenCV 读流

    时间戳落后则丢帧

  3. Mask R-CNN 检测

    定位学生 · 置信度 ≥ 0.7

    ▲ 我负责的部分

  4. ResNet18 行为分类

    6 类 · 趴桌 / 扭头即告警

    ▲ 我负责的部分

  5. 人脸识别 + 跟踪

    128 维特征 · 轨迹内投票

    ▲ 我负责的部分

  6. MongoDB → Tornado

    实时告警 · 报表 · 小程序

在这里学到了什么

毕业后入职 AI + 教育行业,走出校园,在工作中应用并学习了更多的语言。在业务逻辑中基于 PyTorch 实现物体检测与分类(Mask R-CNN、ResNet);Web 服务采用 Tornado,公司前端架构也由 HTML / JS / CSS 转向 Vue。

做课堂行为分析时,学到的是把问题拆开:先检测人、再分类行为,识别不确定时单独归类而不是强行判定;用跨帧跟踪和轨迹内投票补足单帧识别的不足,用丢帧策略保证实时。也第一次系统地做了交付工程:Cython 保护算法源码、supervisor 守护进程、多客户私有化部署,以及线上巡课里 Elasticsearch 聚合查询的写法。

TECH STACK

  • Python
  • PyTorch
  • Mask R-CNN
  • ResNet
  • YOLOv5
  • MXNet
  • PaddleOCR
  • dlib
  • Tornado
  • Elasticsearch
  • MongoDB
  • Redis
  • Cython
  • Vue 2
  • Docker