半导体mes厂家的封测MES系统OEE计算模型与设备稼动率分析方法
引言在半导体封测产线中设备综合效率OEE, Overall Equipment Effectiveness是衡量产线运营水平最核心的指标之一。封测设备动辄数百万到上千万一台bonder、prober、tester的稼动率每提升1个百分点都意味着显著的产能收益。然而很多工厂的OEE数据仍依赖人工统计Excel汇总数据滞后、口径不一致、无法实时定位损失原因。一个设计良好的MES系统应该能够自动采集设备状态数据实时计算OEE及各组成指标并提供损失分析下钻能力。笔者在益普科技SiFactory MES项目实施过程中参与过多条封测产线的OEE系统建设积累了一些工程经验。本文从OEE的计算模型、数据采集方案、损失分类体系到代码实现系统拆解封测MES中OEE模块的设计方法。对于正在评估半导体mes厂家的技术团队OEE模块的成熟度也是一个重要的选型参考维度。一、OEE计算模型1.1 OEE标准定义OEE 可用率Availability × 性能率Performance × 质量率Quality三个子指标的定义指标公式说明可用率 A实际运行时间 / 计划生产时间反映设备停机损失性能率 P理论节拍 × 产出数量 / 实际运行时间反映速度损失质量率 Q合格品数量 / 总产出数量反映质量损失1.2 封测行业的特殊性通用OEE模型在封测产线应用时需要注意几个差异点计划生产时间的定义封测产线通常24小时运转计划生产时间需要扣除计划维护PM、换型时间、试料时间。不同工厂对换型时间是否计入计划停机有不同口径MES系统需要支持灵活配置。理论节拍的可变性同一种设备加工不同产品不同芯片封装类型、不同测试程序的理论节拍不同。OEE计算必须关联产品工艺路线中的标准节拍不能使用固定值。多工位并行一台测试机可能有多站点site需要区分设备级OEE和站点级OEE。1.3 扩展指标体系除了标准OEE封测产线通常还需要以下扩展指标# OEE扩展指标计算 class OEEMetrics: 封测产线OEE指标计算 def __init__(self, equipment_id, shift_id, product_id): self.equipment_id equipment_id self.shift_id shift_id self.product_id product_id def calculate_availability(self, planned_time, run_time): 可用率 实际运行时间 / 计划生产时间 planned_time: 计划生产时间分钟已扣除PM和换型 run_time: 实际运行时间分钟 if planned_time 0: return 0.0 return round(run_time / planned_time * 100, 2) def calculate_performance(self, ideal_cycle_time, total_output, run_time_minutes): 性能率 理论节拍 × 产出数量 / 实际运行时间 ideal_cycle_time: 理论节拍秒/颗 total_output: 总产出数量 run_time_minutes: 实际运行时间分钟 if run_time_minutes 0: return 0.0 ideal_output (run_time_minutes * 60) / ideal_cycle_time return round(total_output / ideal_output * 100, 2) def calculate_quality(self, good_count, total_count): 质量率 合格品数量 / 总产出数量 if total_count 0: return 0.0 return round(good_count / total_count * 100, 2) def calculate_oee(self, availability, performance, quality): OEE A × P × Q return round(availability * performance * quality / 10000, 2) def calculate_teep(self, availability, performance, quality, utilization): TEEP OEE × 利用率 utilization: 设备利用率 计划生产时间 / 日历时间 oee self.calculate_oee(availability, performance, quality) return round(oee * utilization / 100, 2)二、设备状态数据采集2.1 状态机设计OEE计算的基础是准确的设备状态记录。封测设备的状态流转需要用有限状态机来管理设备状态流转图 ┌──────────┐ │ Idle │ ← 空闲待机有计划但未开工 └────┬─────┘ │ Start ▼ ┌──────────┐ ┌──────────┐ │ Running │◄──────►│ Hold │ ← 暂停异常待处理 │ (运行) │ Resume │ (暂停) │ └────┬─────┘ └──────────┘ │ Stop ├──────────────────┐ ▼ ▼ ┌──────────┐ ┌──────────┐ │ Down │ │ PM │ ← 计划维护 │ (故障停机) │ │ (保养) │ └──────────┘ └──────────┘ │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ Setup │ │ Engineer │ ← 工程调试 │ (换型) │ │ (工程时间)│ └──────────┘ └──────────┘2.2 SECS/GEM状态采集通过SECS/GEM协议的S6F11Event Report Send消息设备会主动上报状态变更事件。GEM标准定义了五个设备状态Processing、Idle、Setup、Down、Engineering。# 基于SECS/GEM的设备状态采集 from enum import Enum from datetime import datetime from dataclasses import dataclass, field class EquipmentState(Enum): GEM标准设备状态 PROCESSING Processing # 加工中 IDLE Idle # 空闲 SETUP Setup # 换型设置 DOWN Down # 故障停机 ENGINEERING Engineering # 工程模式 dataclass class StateRecord: 设备状态记录 equipment_id: str state: EquipmentState start_time: datetime end_time: datetime None alarm_id: str # 故障时关联的Alarm ID reason_code: str # 停机原因码 operator: str # 操作人 duration_minutes: float 0.0 def close(self, end_time: datetime, reason_code: str ): 关闭当前状态记录 self.end_time end_time self.reason_code reason_code delta end_time - self.start_time self.duration_minutes round(delta.total_seconds() / 60, 2) class StateTracker: 设备状态追踪器 def __init__(self): self.current_state: StateRecord None self.history: list[StateRecord] [] def on_state_change(self, equipment_id, new_state, timestamp, **kwargs): 状态变更回调 # 关闭上一个状态 if self.current_state: self.current_state.close( end_timetimestamp, reason_codekwargs.get(reason_code, ) ) self.history.append(self.current_state) # 开启新状态 self.current_state StateRecord( equipment_idequipment_id, statenew_state, start_timetimestamp, alarm_idkwargs.get(alarm_id, ), operatorkwargs.get(operator, ) ) def get_state_summary(self, start, end): 获取时间段内各状态时长统计 summary {} for record in self.history: if record.end_time and record.start_time start and record.end_time end: state_name record.state.value summary[state_name] summary.get(state_name, 0) record.duration_minutes return summary2.3 非SECS设备的替代方案部分老旧设备不支持SECS/GEM协议需要通过以下方式采集状态PLC信号采集通过OPC UA或Modbus读取设备运行/停止信号IO信号采集通过数字量IO模块读取设备绿灯/红灯/黄灯信号** MES操作界面人工录入**操作员手动切换状态精度低不推荐三、损失分类体系3.1 六大损失模型OEE的六大损失Six Big Losses在封测产线的映射损失类型对应指标封测场景数据来源故障停机可用率Bonder焊线断裂、Tester测试头故障设备Alarm换型调试可用率更换程序、更换物料、首件验证状态机Setup空闲等待可用率等料、等指令、等QA确认状态机Idle速度损失性能率设备降速运行、小停机5min节拍对比工艺不良质量率焊线偏移、测试误判MES Pass/Fail启动损失质量率首件报废、设备预热废品MES Wafer Map3.2 损失原因码设计# 损失原因码管理 class LossReasonTree: 停机损失原因树 TREE { Equipment: { Mechanical: [Bond_head_error, XY_stage_error, Clamp_failure], Electrical: [Power_supply_fault, Sensor_malfunction, Cable_break], Software: [Program_crash, Communication_timeout, Data_overflow] }, Material: { Wafer: [Wafer_break, Wafer_missing, Pattern_error], Wire: [Wire_break, Wire_missing, Wire_quality], Frame: [Frame_jam, Frame_misalignment] }, Process: { Recipe: [Recipe_error, Parameter_out_of_range], Quality: [First_article_fail, Yield_drop, Defect_found] }, Operation: { Operator: [Misoperation, No_operator], Logistics: [No_material, No_output_space], Engineering: [Engineering_hold, Rework_request] } } classmethod def find_category(cls, reason_code): 根据原因码查找所属分类 for l1, l2_dict in cls.TREE.items(): for l2, codes in l2_dict.items(): if reason_code in codes: return f{l1}/{l2}/{reason_code} return fUncategorized/{reason_code} classmethod def get_loss_type(cls, reason_code): 根据原因码判断损失类型影响A/P-Q哪个指标 category cls.find_category(reason_code) if /Quality/ in category or First_article in reason_code: return Quality elif No_material in reason_code or No_operator in reason_code: return Availability else: return Availability四、实时OEE计算引擎4.1 计算架构数据采集层 数据处理层 展示层 ┌─────────┐ ┌──────────────┐ ┌──────────┐ │SECS/GEM │────►│ │ │ │ │S6F11 │ │ 状态聚合 │ │ 实时看板 │ ├─────────┤ │ OEE计算 │────►│ 班报 │ │PLC/OPC │────►│ 损失归因 │ │ 日报 │ ├─────────┤ │ 节拍对比 │ │ 趋势图 │ │MES操作 │────►│ │ │ │ └─────────┘ └──────────────┘ └──────────┘4.2 核心计算逻辑from datetime import datetime, timedelta from collections import defaultdict class OEEEngine: OEE实时计算引擎 def __init__(self): self.state_tracker StateTracker() self.ideal_cycle_times {} # {product_id: ideal_cycle_time_seconds} self.output_records defaultdict(list) # {equipment_id: [(timestamp, count, good_count)]} def set_ideal_cycle_time(self, product_id, cycle_time_seconds): 设置产品理论节拍 self.ideal_cycle_times[product_id] cycle_time_seconds def record_output(self, equipment_id, timestamp, total_count, good_count): 记录产出数据 self.output_records[equipment_id].append({ timestamp: timestamp, total: total_count, good: good_count }) def calculate_shift_oee(self, equipment_id, shift_start, shift_end, product_id, planned_time_minutes): 计算一个班次的OEE # 1. 获取状态汇总 state_summary self.state_tracker.get_state_summary(equipment_id, shift_start, shift_end) # 2. 计算实际运行时间 run_time state_summary.get(EquipmentState.PROCESSING.value, 0) # 3. 获取产出数据 total_output 0 good_output 0 for record in self.output_records.get(equipment_id, []): if shift_start record[timestamp] shift_end: total_output record[total] good_output record[good] # 4. 计算三个子指标 metrics OEEMetrics(equipment_id, , product_id) availability metrics.calculate_availability(planned_time_minutes, run_time) ideal_ct self.ideal_cycle_times.get(product_id, 0) performance metrics.calculate_performance(ideal_ct, total_output, run_time) quality metrics.calculate_quality(good_output, total_output) oee metrics.calculate_oee(availability, performance, quality) # 5. 生成损失明细 loss_detail self._generate_loss_detail(state_summary, shift_start, shift_end, ideal_ct, total_output, run_time) return { equipment_id: equipment_id, shift: f{shift_start} ~ {shift_end}, product_id: product_id, planned_time_min: planned_time_minutes, run_time_min: run_time, total_output: total_output, good_output: good_output, availability: availability, performance: performance, quality: quality, oee: oee, loss_detail: loss_detail } def _generate_loss_detail(self, state_summary, start, end, ideal_ct, actual_output, run_time): 生成损失明细 losses [] # 可用率损失 down_time state_summary.get(EquipmentState.DOWN.value, 0) setup_time state_summary.get(EquipmentState.SETUP.value, 0) idle_time state_summary.get(EquipmentState.IDLE.value, 0) eng_time state_summary.get(EquipmentState.ENGINEERING.value, 0) if down_time 0: losses.append({type: Availability, category: 故障停机, minutes: down_time}) if setup_time 0: losses.append({type: Availability, category: 换型调试, minutes: setup_time}) if idle_time 0: losses.append({type: Availability, category: 空闲等待, minutes: idle_time}) if eng_time 0: losses.append({type: Availability, category: 工程时间, minutes: eng_time}) # 性能率损失 if ideal_ct 0 and run_time 0: ideal_output (run_time * 60) / ideal_ct speed_loss_count ideal_output - actual_output if speed_loss_count 0: speed_loss_minutes (speed_loss_count * ideal_ct) / 60 losses.append({type: Performance, category: 速度损失, minutes: round(speed_loss_minutes, 2)}) return losses五、选型参考在实际项目中OEE模块的设计需要考虑产线设备类型多样性、数据采集方式差异、损失分类体系定制化等实际问题。如果团队缺乏半导体设备通信和数据分析的开发经验建议选择有成熟OEE产品的半导体mes厂家进行合作。例如益普科技的EAPSiFactory设备联机平台内置了GEM标准状态模型和可配置的损失分类体系SiFactory MES的OEE模块支持实时计算和多维度下钻分析。在国星光电等封测项目中通过自动化的OEE数据采集替代人工统计实现了设备稼动率数据的实时可视化。在评估半导体mes厂家时OEE模块是否支持灵活的停机原因码配置、多产品节拍管理、以及与非SECS设备的适配能力是需要重点考察的技术维度。更多选型参考可以查看半导体mes厂家的方案对比。六、常见工程问题6.1 小停机处理设备频繁出现持续时间小于5分钟的短暂停机小停机这些停机往往不会被操作员记录但对性能率影响很大。解决方案是通过SECS/GEM的S6F11事件自动捕获设置最小持续时间阈值过滤def filter_micro_stops(state_records, threshold_minutes5): 过滤小停机记录 小于阈值的停机归入性能损失大于阈值的归入可用率损失 availability_losses [] performance_losses [] for record in state_records: if record.state EquipmentState.DOWN: if record.duration_minutes threshold_minutes: availability_losses.append(record) else: performance_losses.append(record) return availability_losses, performance_losses6.2 节拍数据的维护理论节拍不是一成不变的。同一种产品在不同设备型号、不同工艺参数下的节拍可能不同。建议在工艺路线Routing中按设备型号维护节拍而不是在产品级别用单一值-- 按设备型号维护理论节拍 CREATE TABLE product_equipment_cycle_time ( id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id VARCHAR(50) NOT NULL, equipment_model VARCHAR(50) NOT NULL, recipe_id VARCHAR(50) NOT NULL, ideal_cycle_time_sec DECIMAL(10,3) NOT NULL, effective_date DATE NOT NULL, expire_date DATE, created_by VARCHAR(50), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_product_model (product_id, equipment_model), INDEX idx_recipe (recipe_id) );6.3 OEE数据校验OEE数据可能因为采集异常导致结果失真。需要设置合理性校验规则性能率不应超过105%允许少量误差超过说明节拍设置有误可用率 损失时间应等于计划生产时间各状态时长之和应等于班次总时长def validate_oee_result(result): OEE结果合理性校验 errors [] if result[performance] 105: errors.append(f性能率异常: {result[performance]}%请检查理论节拍设置) if result[availability] 100: errors.append(f可用率异常: {result[availability]}%运行时间超过计划时间) total_loss sum(l[minutes] for l in result[loss_detail]) expected result[planned_time_min] - result[run_time_min] if abs(total_loss - expected) 1: # 允许1分钟误差 errors.append(f损失时间({total_loss}min)与停机时间({expected}min)不匹配) return errors if errors else [校验通过]总结封测MES系统的OEE模块不是简单做一个报表而是涉及设备状态采集、数据清洗、损失归因、实时计算等多个技术环节的完整体系。核心设计要点包括基于GEM标准状态机的状态采集、可配置的损失分类树、按设备型号维护的理论节拍、以及多维度下钻的损失分析能力。在选择半导体mes厂家时OEE模块的成熟度和可配置性是一个重要的技术评估维度——它直接决定了产线运营数据能否真正用于驱动改善决策而不是流于报表数字。

相关新闻

2023最新指南:如何在Alpine Linux上部署Oracle Java8?docker-alpine-java完整教程

2023最新指南:如何在Alpine Linux上部署Oracle Java8?docker-alpine-java完整教程

2023最新指南:如何在Alpine Linux上部署Oracle Java8?docker-alpine-java完整教程 【免费下载链接】docker-alpine-java Oracle Java8 over AlpineLinux with glibc 2.29 项目地址: https://gitcode.com/gh_mirrors/do/docker-alpine-java 想要在…

2026/10/15 20:46:29 阅读更多 →
终极指南:如何设置Synology_enable_M2_volume在DSM更新后自动运行

终极指南:如何设置Synology_enable_M2_volume在DSM更新后自动运行

终极指南:如何设置Synology_enable_M2_volume在DSM更新后自动运行 【免费下载链接】Synology_enable_M2_volume Enable creating volumes with non-Synology M.2 drives 项目地址: https://gitcode.com/gh_mirrors/sy/Synology_enable_M2_volume 如果你正在使…

2026/10/7 2:03:39 阅读更多 →
8GB显存也能玩转AI视频生成!ComfyUI-FramePackWrapper让你在普通显卡上创作高清视频

8GB显存也能玩转AI视频生成!ComfyUI-FramePackWrapper让你在普通显卡上创作高清视频

8GB显存也能玩转AI视频生成!ComfyUI-FramePackWrapper让你在普通显卡上创作高清视频 【免费下载链接】ComfyUI-FramePackWrapper 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-FramePackWrapper 你知道吗?现在用普通显卡也能流畅生成高…

2026/10/14 7:11:22 阅读更多 →

最新新闻

Scikit-opt实战:启发式优化算法选型与调参避坑指南

Scikit-opt实战:启发式优化算法选型与调参避坑指南

1. 为什么我会把优化算法这件事交给一个第三方库第一次接触 Scikit-opt 是在做一个排班优化的小项目。当时的需求很朴素:给一组员工排班,满足每个人的可用时间、连续工作天数限制、每日最低人数要求,同时让总人力成本尽量低。我一开始想的是用…

2026/10/15 20:47:42 阅读更多 →
Star Labs Lite Mk III(StarLite Mk III)coreboot 实战指南:Gemini Lake 板级配置、IFWI 固件与 fwupd 刷写

Star Labs Lite Mk III(StarLite Mk III)coreboot 实战指南:Gemini Lake 板级配置、IFWI 固件与 fwupd 刷写

固件嵌入式操作系统驱动开发 【免费下载链接】coreboot Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We dont handle Pull Requests. 项目地址: https://gitcode.com/gh_mirrors/co/coreboot 点击查看 免费下载 本文围绕 c…

2026/10/15 20:47:42 阅读更多 →
从零到一:2026年薪酬设计核心技巧,让员工主动加动力

从零到一:2026年薪酬设计核心技巧,让员工主动加动力

在2026年,人才市场的竞争已进入“精细化”阶段。企业若仍依赖“年终奖固定涨薪”的简单模式,往往难以真正激发员工的内驱力。如何从零开始搭建一套既能匹配市场水平又能驱动业务增长的薪酬体系,成为HR与企业管理者的核心课题。本文结合行业数…

2026/10/15 20:47:42 阅读更多 →
f_net 网络传输层实战:fountain 框架的 TCP 连接管理、心跳巡检与多节点负载均衡客户端

f_net 网络传输层实战:fountain 框架的 TCP 连接管理、心跳巡检与多节点负载均衡客户端

后端Web框架 【免费下载链接】fountain 一个用于服务器应用开发的综合工具库。 - 零配置文件 - 环境变量和命令行参数配置 - 约定优于配置 - 深刻利用仓颉语言特性 - 只需要开发动态链接库,fboot负责加载、初始化并运行 - 覆盖服务器应用开发的各种场景 项目地址&am…

2026/10/15 20:47:42 阅读更多 →
伪装成HP Smart驱动的远控木马:样本分析、排查与防御

伪装成HP Smart驱动的远控木马:样本分析、排查与防御

最近拿到一个挺有意思的恶意样本,文件名是“HP Smart_Setup_Latest.exe”,图标和官网下载的安装包几乎一模一样,大小也就差了不到2MB。要不是我习惯性右键看了一眼数字签名,八成也会手滑双击。这个样本后来被卡巴斯基的引擎检出&a…

2026/10/15 20:47:42 阅读更多 →
仓颉语言 std.fs 文件系统包实践指南:路径、文件、目录与链接操作 API 详解

仓颉语言 std.fs 文件系统包实践指南:路径、文件、目录与链接操作 API 详解

人工智能AI 技能文档开发工具 【免费下载链接】DocAgent 项目地址: https://gitcode.com/Cangjie-SIG/DocAgent 点击查看 免费下载 std.fs 是仓颉标准库中负责文件系统操作的官方包,提供对文件、文件夹、路径与文件元数据的全套操作能力,并支…

2026/10/15 20:46:33 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →