尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

用MLflow统一管理LAT1339平台AFCI电弧故障检测模型版本

用MLflow统一管理LAT1339平台AFCI电弧故障检测模型版本 写这篇笔记的时候我们LAT1339平台上的AFCI电弧故障检测模型已经迭代了四十多版。前三周我还能靠文件夹命名区分模型到后面遍地都是“model_v7_final_0423”、“model_v7_really_final”、“model_v7_new_new”这种名字谁也说不清哪一版才是真正跑在产线固件里的那个。把MLflow引入整个流程之后这个乱象算是告一段落。LAT1339是我们在用的嵌入式AI计算平台AFCIArc Fault Circuit Interrupter电弧故障断路器是它主打的一个电力安全应用方向。简单说就是要从电流波形里判断电弧故障特征在真实故障发生之前提前切断电路防止电气火灾。这个任务放在传统MCU上很难做好因为电弧特征的时域和频域模式并不固定负载类型一换波形形态就全变了。所以我们采用数据驱动的方式在PC端训练模型再交叉编译部署到LAT1339的推理引擎上。模型数量一多版本管理就成了头疼问题——这也就是这篇笔记要讲的核心用MLflow把模型管理这件事系统化。这篇内容适合三类人看一是做AFCI、故障检测、工业异常识别这类嵌入式AI方向的工程师二是团队里模型版本还是一团乱麻、靠“复制一份加后缀”管理的朋友三是想在设备端落地MLOps工具链但不确定从哪里下手的人。下面我会把整个流程拆开讲包括工具选型、环境搭建、训练接入、模型注册以及部署到设备端的衔接方式。1. 先说清楚LAT1339 AFCI项目里MLflow到底管的是什么1.1 AFCI模型开发流程里最乱的部分在哪一个AFCI检测项目的完整开发流程通常长这样用电流采集设备在实验室和真实场景里录制正常负载、轻微电弧、严重电弧等不同工况下的波形数据。对原始波形做预处理比如滑动窗口切分、FFT特征提取、小波包变换把一维电流波形转成特征矩阵。在PC端训练分类模型常见选择是LightGBM、XGBoost或者一维CNN。评估模型在误报率、召回率等指标上的表现和既有规则算法做对比。把合格模型转换格式ONNX、TFLite或自有推理引擎格式集成进LAT1339的固件工程。在设备端跑真实负载测试验证是否满足安全响应时间要求。这个流程里最容易失控的环节不是训练本身而是“模型实验的记录和追踪”。每次调一个超参数换一段训练数据改一版特征提取方式都会产出一个新模型。这些实验之间的差异可能非常小——比如只是把FFT窗口从256点改成512点——但如果不记录一周之后就完全想不起来当时为什么这么改。后期如果我们还面临客户定制需求不同供应商的测试标准不一样需要针对性地微调模型那么“哪个模型对应哪套测试标准”很快就变成一团浆糊。1.2 MLflow在这个场景里扮演的角色MLflow是Databricks开源的一个机器学习生命周期管理平台它解决的核心痛点就是上面这种乱象。它把整个管理过程拆成四个部分Tracking实验跟踪、Projects工程打包、Models模型管理、Registry模型注册与版本控制。在我们这个LAT1339 AFCI项目里最核心用的是Tracking和Registry两部分。注意MLflow本身不参与训练前的数据清洗也不负责设备端的模型加速转换。它更像是一个“实验记录员模型档案室”的角色。训练的时候它在旁边把参数、指标、模型文件、代码快照统统记下来训练完之后它给每个模型打上版本号、标签和阶段标记比如Staging还是Production。当我们需要确认“产线固件里跑的是哪一版模型”的时候去MLflow上看一眼标注就行了不用再去问同事“你上周发给我的那个模型是叫backup_v2还是final_v3”。在团队协作方面这套工具的收益就更直观了。以前我们三个工程师各自在本地跑实验结果A测出来准确率是99.2%B复现的时候只有97.8%两个人背对背对了一下午最后发现是训练集切分方式不一样。接入MLflow之后每次实验的数据集版本、切分随机种子、预处理代码版本都被记录下来复现别人的实验变得非常直接。2. MLflow核心组件与选型思路2.1 四个核心组件到底哪个对我们有用MLflow的四个组件官方文档里都有介绍但落到实际项目里不同组件的价值差异很大。我把它们拆开来说并结合AFCI项目的实际使用情况做一个优先级排序。MLflow Tracking最基础、也最实用。它记录每次训练的模型名称、运行参数、评价指标和产物文件。我们在AFCI项目里用它记录FFT窗口大小、模型结构类型、训练轮数、学习率、准确率、召回率、部署延迟和模型大小。代码里只需要调用几个API改动成本很低。MLflow Models提供统一的模型打包格式和加载接口。它定义了一种标准目录结构模型文件、元数据、依赖环境都放一起。这个组件帮我们解决了一个实际问题不同工程师喜欢用不同方式保存模型有人存pickle有人存h5有人存onnxMLflow把这一切统一起来了。MLflow Registry模型注册中心支持给模型打标签、分配阶段、记录活跃/归档状态。这是在团队协作和后期追溯时最关键的组件。我们规定所有进入产线测试的模型必须先注册到Registry并标记为Staging在设备端通过测试后才改成Production被替代的模型标记为Archived绝不直接删除。MLflow Projects这个组件类似一个代码打包规范把训练脚本和运行参数统一封装成可复现的入口。理论上它能让“点一个命令就重跑某个实验”变成现实但在我们这种嵌入式AI场景下训练环境经常和硬件采集工具关联复用价值没有前三个高所以我暂时没有对它做深度依赖。核心思路是Tracking解决“我记得”的问题Registry解决“谁在用”的问题Models解决“文件格式统一”的问题。2.2 为什么坚持用MLflow而不是自建Excel记录写这套笔记的时候有朋友问我就你们这个小团队用Excel加共享文件夹不也能管理模型吗性能参数写一列、模型文件放网盘、命名规范一点好像也不是不能用。这种说法有一定道理但在实际用了一两个月之后我发现Excel方案有几个硬伤。训练指标进Excel需要手动填漏填、错填的概率很高人一旦忙起来不可能每次都记得。模型文件和Excel记录之间没有强关联Excel里写着“准确率99.5%”但文件是哪个、用的什么数据训练出来的无法自动追溯。一个实验产生几十个指标Excel里要维护几十列很快就不可读了。换工程师来做测试的时候Excel的格式和理解全靠个人经验不具备统一性和可复制性。MLflow解决这些问题的方式非常直接训练脚本里加了记录代码之后参数、指标、模型文件自动进系统人和人之间不需要再做二次交接。数据是自动采集的就不会有“忘了填”的情况发生。再加上我们后续要在LAT1339上做多版本模型对比测试MLflow的API支持直接查询历史实验数据写自动化脚本的时候会方便很多。3. 环境搭建从裸机到可用的Tracking Server3.1 安装与快速启动MLflow的安装过程本身并不复杂它依赖Python环境我们用的是Python 3.9的虚拟环境。这里建议用conda或者venv单独建一个环境给MLflow不要直接装到系统Python里因为MLflow的依赖比如Flask、SQLAlchemy、Quart和嵌入式交叉编译工具链的Python环境可能会相互干扰。conda create -n mlflow-env python3.9 conda activate mlflow-env pip install mlflow2.9.2其实项目里最初已经装过mlflow但当时没在意版本后来发现不同小版本在处理artifact上传路径时有细微差别导致模型文件有时传不上去。所以这里建议固定大版本避免团队里每个人装的版本不一致。安装完成后如果只是想单机快速测试直接跑mlflow ui就能在本地启动一个精简版服务。但这个方案只适合个人调试不适合团队使用因为默认配置下数据和文件都保存在本地。我们要搭建的是能够让几个人同时访问、记录所有实验的Tracking Server。3.2 端口选择与访问配置在网上搜MLflow相关内容时“mlflow 端口”一直是高频词。原因也很简单MLflow在使用时必须要解决端口绑定和访问的问题。我们把Tracking Server部署在一台GPU训练工作站上系统是Ubuntu 20.04内网IP是192.168.1.80。启动服务时我们用的命令是这样的mlflow server \ --backend-store-uri sqlite:///opt/mlflow/mlflow.db \ --default-artifact-root /opt/mlflow/artifacts \ --host 0.0.0.0 \ --port 5000几个参数的含义和选择逻辑说一下--backend-store-uri实验元数据存储位置就是参数、指标、标签这些结构化数据放在哪里。我们初期用SQLite原因是零依赖、配置简单。后面团队大了一些多人并行写数据库时SQLite会出现锁等待问题预计会替换成MySQL这个在问题章节会详细讲。--default-artifact-root模型文件、图片等二进制产物的默认存储目录。这个目录必须放在所有用户都能访问的地方或者用NFS共享盘。我们直接把路径指到了训练工作站的本地磁盘同时用Samba把目录共享给整个内网这样Windows机器上的训练脚本也能正常上传产物。--host 0.0.0.0监听所有网络接口。如果不加这个参数MLflow默认只监听127.0.0.1其他机器根本无法访问。--port 5000MLflow默认使用5000端口。但在实际部署中这个端口经常被MacOS的AirPlay接收器或其它开发服务占用所以如果绑定失败换一个端口重新启动就行。确认服务正常启动的验证方式curl http://192.168.1.80:5000/health返回{status:OK}说明服务已经正常在跑。所有训练脚本所在的主机只需要设置一个环境变量就能把实验记录发送到这个服务器export MLFLOW_TRACKING_URIhttp://192.168.1.80:5000有一点要提醒的是团队多人使用的时候每个人的机器都设置--host 0.0.0.0的Server地址这个环境变量容易写错。我建议在训练脚本里明确写一个通用的配置文件统一导入而不是让每个人手动敲export减少低级失误。3.3 存储后端选型SQLite还是MySQL这部分属于经验之谈。我们项目初期人少、设备少、日实验量大概几十次SQLite完全够用。但到了后期多个人同时提交实验的时候SQLite的问题就显出来了——它的写入锁是整个数据库级别的并发一多就会报database is locked。排查了半天问题本身并不是MLflow配置不对而是后端存储的并发能力瓶颈。如果预计团队规模超过三个人或者每天实验次数超过一百次建议直接上MySQL。初始化命令大致如下mysql -u root -p CREATE DATABASE mlflow_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER mlflow% IDENTIFIED BY your_password; GRANT ALL PRIVILEGES ON mlflow_db.* TO mlflow%; FLUSH PRIVILEGES;再把启动命令里的store地址换成--backend-store-uri mysqlpymysql://mlflow:your_password192.168.1.80:3306/mlflow_db需要先确认安装了pymysql库MySQL能看到的artifacts文件路径也要保持相同不能一个用户写本地路径、另一个用户写网络路径不然注册模型时经常出现finder找不到文件的问题。4. 训练环节接入MLflow Tracking4.1 最小改造方案从零开始在代码里埋点接入MLflow最简单的方式是调用mlflow.autolog()一行代码就能让框架自动记录参数和指标。但这个方式在AFCI项目里并不能一步到位因为我们用的LightGBM和自研的滑动窗口特征提取逻辑autolog只能自动记录模型参数无法记录数据特征层面的内容比如FFT窗口大小、滑动步长、数据采集环境等。所以我选择手动埋点的方式这样能完全控制记录内容。以一次典型的AFCI模型训练为例我们的训练脚本里会加入下面的埋点逻辑import mlflow mlflow.set_tracking_uri(http://192.168.1.80:5000) mlflow.set_experiment(afci_arc_detection) with mlflow.start_run(run_namelgbm_fft512_win256): # 记录数据与特征参数 mlflow.log_param(feature_type, fft_plus_time_domain) mlflow.log_param(fft_window_size, 512) mlflow.log_param(slide_step, 128) mlflow.log_param(sample_rate, 20000) mlflow.log_param(train_data_version, afci_dataset_v3_20240610) mlflow.log_param(label_type, arc_binary) # 训练模型 model lgbm_train(..., params{...}) # 记录评估指标 mlflow.log_metric(val_accuracy, 0.992) mlflow.log_metric(val_recall, 0.988) mlflow.log_metric(val_fp_per_hour, 0.7) mlflow.log_metric(inference_latency_ms, 2.3) # 记录模型文件 mlflow.lgb.log_model(model, artifact_pathlgbm_model) # 记录特征提取代码版本 mlflow.log_param(feature_pipeline_version, feat_pipe_0.4.1)这里有一个值得强调的设计每一条参数的含义都要预先定义好。比如slide_step表示滑窗步长、val_fp_per_hour表示每小时误报次数这些是我们团队内部统一定义的。如果各写各的同一个物理量在不同代码里叫sliding_step、step_len后面做对比分析时数据会非常混乱。MLflow本身不要求参数命名规范但团队项目必须有约定我建议成立项目第一天就定一份“参数与指标命名表”。4.2 实验对比实录一次超参调整的完整记录只有埋点代码还没法直观感受到MLflow的威力。我拿我们最近一次调优举例。当时我们在优化LightGBM在LAT1339上的推理延迟同时希望保持误报率不超标。我们做了三组对比实验第一组是默认参数FFT窗口256点LightGBM树深6层。第二组把FFT窗口提到512点树深不变。第三组保持FFT窗口512但把树深降到4层并换用更小的叶子数。这三组实验在两台电脑上同时跑埋点代码相同只是传入参数不同。如果没有MLflow这三组实验的结果只能靠我们俩各自的终端打印来确认然后手动汇总成表格。但有了MLflow训练结束后打开浏览器在“afci_arc_detection”这个Experiment页面里可以同时看到三组Run的准确率、召回率、模拟误报率和单次推理耗时。结果一目了然第二组召回率最好但推理延迟上升了1.1毫秒第三组延迟最低但个别负载下误报激增。综合设备端的安全响应时间要求我们最终选了第一组作为基线再后续单独优化。这个过程的价值不在于那一分钟看表格的时间节省而在于三组数据之间的对比维度是干净统一的。MLflow用同一个数据结构把所有实验拉平了想从哪个维度排序、过滤都可以。4.3 不用autolog的话手动记录哪些指标如果项目情况和我们类似autolog覆盖不到数据预处理与设备端指标那就手动记录。这里把我的清单分享一下基本都是常规文档不会明确告诉你的数据集信息版本号、采集环境、时间范围、正负样本比例。这几个信息直接影响后面排查模型泛化问题时能不能快速定位根因。特征参数FFT窗口、重叠率、采样率、是否用了小波特征、归一化方式。这些参数稍有变动模型行为就会大变。有效训练指标除了常规的accuracy、precision建议记录fp_per_hour每小时误报次数和response_time_ms检测响应时间。AFCI这种安全设备误报率和延迟的重要性远高于准确率。硬件相关的指标模型在PC上的推理耗时、模型参数量、模型文件大小、INT8量化后的精度损失。设备端资源有限这三个数字决定了一个模型能不能上LAT1339。手动记录时有一个技巧把关键指标的计算统一封装成函数比如log_afci_metrics(y_true, y_pred, sample_rate, window_size)一次调用算好所有指标再统一上报而不是一行一行写。这样既减少漏记又方便统一口径。5. 模型注册与设备端落地的衔接5.1 模型注册与阶段管理在MLflow里单个Run的产物默认保存在Experiment下但它只代表一次训练任务不等于一个被正式认可可用的模型。当一个模型经过评估被选中准备进入设备端联调时我们就把它注册到Model Registrymlflow.register_model( model_uriruns:/run_id/lgbm_model, nameAFCI_Arc_Detector )注册之后可以在MLflow界面里给模型标记阶段。我们的阶段管理规则如下阶段含义进入条件Staging候选模型PC端评估指标达标Production产线可用版本LAT1339实测通过Archived已下线版本被新版本替换或发现缺陷这个规则的价值在于设备端烧录固件或者做产线回归测试的时候大家不需要问“到底用哪个模型”直接查注册表里“Production”阶段的模型就行。我们曾遇到过一个问题同事在本地训练了一个识别精度更高的模型忘了注册结果别人还在用旧版本的固件跑测试白白浪费了三天。有了阶段管理之后这种问题基本杜绝。另外要注意注册模型的时候不要把model_uri指向mlruns/目录下的随机路径一定要用runs:/run_id/lgbm_model这种形式因为后者和实验记录强关联跟踪链路完整。如果直接用文件路径注册模型文件虽然也能进Registry但无法追溯它是从哪个Run来的后续排查问题的难度会大很多。5.2 从MLflow导出模型并部署到LAT1339MLflow不是个推理引擎它不负责模型在设备端的运行。我们的做法是先让MLflow做“模型档案中心”设备端需要更新模型时从MLflow拉取对应版本的产物再转换成LAT1339推理引擎需要的格式。以LightGBM为例拉取指定版本的模型import mlflow client mlflow.tracking.MlflowClient() model_info client.get_latest_versions(AFCI_Arc_Detector, stages[Production]) assert len(model_info) 1 model_uri fmodels:/AFCI_Arc_Detector/{model_info[0].version} model mlflow.lgb.load_model(model_uri)拿到模型对象后用它输出预测结果再把模型保存成LightGBM自带的文本格式编入LAT1339的固件中。如果模型是一维CNN则先导出ONNX格式再调用LAT1339的模型转换工具生成加速指令文件。这个过程中有一个经验可以分享MLflow Model Registry里存的是“模型产物”和“元数据”但不包含让你重新训练这个模型的完整环境和数据。所以如果你想让一个模型可复现除了模型文件本身还要在Run里额外记录训练脚本的git commit号、依赖包版本号和数据集版本号。我们会把这些信息写在Run的Description和Tags里后面排查问题时能省很大力气。5.3 模型与固件版本的对应关系AFCI设备是安全件固件里到底内置了哪个模型这个信息必须能够随时查证。MLflow只管理模型管不到固件版本但在LAT1339的固件工程里我们会加一个简单技巧来打通两边。固件编译时从MLflow的“Production”阶段模型读取一个model_version.txt把这个文件一起打进固件。设备运行时“查询当前固件里的模型版本”就可以通过这个文件读出来。这样一旦设备端出现行为异常能快速对照“这个异常对应的是模型哪个版本”。同时在MLflow里给这个模型版本打上标签比如firmware_releasev2.3.1形成双向往查的闭环。这个习惯是在我们排查过一次现场问题之后总结出来的。当时客户报了一个特定负载下的误报问题但是我们怎么都确定不了他们设备里跑的是哪一版参数。后来用上面的方法把版本号固化进了固件问题定位的效率明显提升不用再靠厂家拍照片来猜模型文件了。6. 常见问题与排查实录6.1 端口占用与访问失败MLflow默认端口5000在我们团队最常碰到的问题就是端口被占用。Ubuntu上用lsof -i :5000一查经常发现是某个开发服务的残留进程占着端口。处理方式有两种杀掉占用进程sudo kill pid一了百了。改MLflow的启动端口改为5001或5002同时更新所有训练脚本里的MLFLOW_TRACKING_URI。需要提醒一下如果改了端口务必要在团队公告里同步并且全局搜索一下代码里是否还有旧的:5000字符串。我们踩过一次坑几个人埋头训练传上去的实验全进了别人机器上的本地MLflow服务完全没进共享服务器白白浪费了将近半天的实验记录。另外访问本机的MLflow服务时用localhost:5000没问题但从团队其他电脑访问时务必用IP地址。有些机器上因为HTTP代理配置原因http://localhost:5000会被解析到本机实际连不上远程服务器。检查时可以用curl -v看实际请求的地址。6.2 参数查询慢与页面卡顿MLflow的Web界面有一个使用率很高的功能Experiment页面里筛选多个Run然后选中几组指标画对比图。但用过一段时间之后在Run数量超过几百个时这个页面的加载速度会明显变慢。我观察下来主要原因有两个一是后端存的实验条目太多SQLite对复杂查询力不从心二是浏览器端的Web页面要一次性渲染所有Run的历史记录和图表页面数据量一大就卡。应对方式按周或者按迭代周期建一个新的Experiment不要把所有实验永远堆在同一个Experiment里。用MLflow的search_runsAPI脚本查询数据而不是过度依赖Web界面。比如要对比最近30次实验的平均准确率用Python API拉回来自己画图速度和灵活性都远好于在页面上操作。如果前端页面十分卡顿可以尝试只保留最近若干天的实验数据在默认视图里历史数据放到归档Experiment。6.3 模型文件上传失败ARTIFACT上传失败是个高频问题。表现是训练日志里显示运行结束但Models页面里找不到模型文件或者显示“FileNotFoundError”。排查时先确认几个点default-artifact-root目录是否存在、是否有写权限。如果使用了NFS/Samba共享目录确认挂载是否正常以及客户端有没有权限创建子目录。MLflow Server所在机器和训练脚本所在机器的文件路径映射是否一致。跨机器访问时如果服务端配置的路径和客户端访问时的路径不一致上传时容易静默失败。我们最终把artifacts目录单独放在一块专门的共享存储里固定路径所有训练机的代码里都写死这个路径不做额外的目录映射才彻底解决了这个问题。6.4 并发写入冲突多人同时向同一个SQLite库写数据时偶尔报database is locked。这不是MLflow的Bug而是SQLite的设计限制每次写入会锁住整个数据库文件。训练任务多、并行度高的时候出错概率会明显增加。我们的应对是短期接受偶尔的失败在自动化训练脚本里加入重试逻辑失败后2秒重试一次最多重试3次。中期后端换成MySQL改造后并发写入冲突完全消失。长期考虑使用PostgreSQL但优先级不高MySQL已经足够应对当前规模。6.5 实验找不到或URI配错经常有同事反馈“我明明跑了实验怎么服务端页面看不到”。问一下他终端里echo $MLFLOW_TRACKING_URI结果十有八九是空值或者配错了地址。MLflow的行为是当MLFLOW_TRACKING_URI未设置时默认只写到本地mlruns目录不会上报到服务端。我的建议是在训练脚本顶部强制设置mlflow.set_tracking_uri(http://192.168.1.80:5000)显式写这一行比依赖环境变量更可控。同时可以在启动训练前先打印一下配置信息print(f[MLflow] tracking uri {mlflow.get_tracking_uri()})确认无误再开始训练避免训练完了发现数据全在本地。7. 我踩过的几个坑单独拿出来说7.1 实验名称太随意后面根本没法筛早期用MLflow的时候我每次实验的运行名直接写“test1”、“222”、“再试一版”。等积累了上百个Run之后想在列表里找一个特定实验简直是在捞针。后来我定了一个规矩运行名必须是模型算法_特征类型_关键参数比如lgbm_fft512_win256_leaf32。这个命名模式后来被团队采纳搜索效率高了很多。7.2 模型文件和标签能对上但代码版本对不上MLflow在记录模型文件时不会自动记录当前训练脚本的git commit号。如果你没有手动记录半年后翻到一个模型只能看到“用了什么参数”看不到“当时跑的是哪份代码”。后来我在每个训练脚本里加了一行mlflow.log_param(code_version, subprocess.check_output([git, rev-parse, HEAD]).decode().strip())代码库有commit号之后配合tag标签能很快定位到当时的训练代码。7.3 只记录了一个最佳模型没记录所有中间产物我们的AFCI训练流程里有时候模型A准确率最高但模型B的误报分布更均匀更适合真实负载。如果只在Run里记录最终模型很多中间模型就丢失了。后来我们在代码里对每个评估阶段都调用log_model把每个候选模型都记录下来方便后续做对比和回退。虽然多点存储空间但对工业场景的模型管理来说非常值得。7.4 服务端时间不对导致实验时间线全部错乱有一回我们发现MLflow页面上的时间排序完全不对后来一查是服务器系统时区没有设置成UTC8。MLflow默认记录UTC时间但页面显示用的是浏览器本地时区如果服务器时区不对显示就会差好几个小时。解决方式很简单sudo timedatectl set-timezone Asia/Shanghai改完重启MLflow服务时间就正常了。这个问题不大但排查起来非常迷惑特别容易让人以为是网络问题。最后再分享一个小技巧。MLflow的UI界面默认展示的是“Table”模式Run多起来之后分组对比实验时可以先勾选需要的Run然后点击“Compare”进入对比视图。在这个视图里可以同时对多个Run的参数和指标做并排比较勾选某个指标之后还能自动生成分布图。每次算法调优时我都用这个页面锁目标实测下来效率提升很大。到这里LAT1339 AFCI项目里MLflow这套流程已经完整跑通了从实验记录、模型注册到设备端版本追溯每个环节都清楚可控。
返回列表