异常安全重启运行机制:健壮的Ai模型训练自动化

文章目录

  • 前言
  • 一、热力图主函数代码
    • 1、正规N图热力图运行代码
    • 2、重新迭代循环求解方法
  • 二、中断重启继续推理或训练
    • 1、封装含参主函数
    • 2、终止重启进程管理方法
      • 1、终止启动源码
      • 2、源码解读
  • 三、终止启动主函数源码解读
    • 1、终止启动源码
    • 2、源码解读
      • 关键点解析
  • 四、完整代码Demo
    • 1、完整源码
    • 2、总结实现步骤
    • 3、关键点解析
    • 4、运行结果
  • 结论


前言

在进行机器学习或深度学习模型训练时,经常会遇到由于各种原因导致的异常情况,例如内存不足、数据预处理错误或其他不可预见的问题。这些问题可能导致整个训练过程中断,迫使开发者手动重启训练脚本。为了提高训练过程的健壮性和自动化程度,我们可以设计一种机制,在每次遇到异常时自动终止当前训练任务,并重新启动一个新的训练实例,继续下一次迭代。本文将介绍如何通过 Python 的 multiprocessing 模块实现这一目标,并提供一个高度概括的异常处理方法——异常安全重启机制。当然,每个人动机不一样,我的动机:我对N个图循环求解热力图grad CAM时候,每次迭代都增加显存,尝试很多方法,最终采用投机取巧方式(本篇文章技术)完成N张图热力图图求解。


一、热力图主函数代码

1、正规N图热力图运行代码

如果正规方式应该是如下的方法来调用,然而每次只能成功运行2张图片,显存就炸了。我还是给出主函数,以便后续解说明异常代码,其源码如下:


if __name__ == '__main__':opt = parse_opt()cam_model = sam_yolov5_heatmap(opt)cam_model.heatmap_main(opt.source, opt.save_dir)

2、重新迭代循环求解方法

我想到,既然只能运行2张图片,那我就大不了用一个循环来解决该问题,于是就有了下面修改代码,然而该方法依然不能摆脱显存增加,我也觉得很神奇,估摸是py文件未停止,显存存了之前变量或泄露原因导致。我们先看修改源码:

if __name__ == '__main__':for i in range(21):opt = parse_opt()cam_model = yolov5_heatmap(opt)cam_model.heatmap_main(opt.source, opt.save_dir,N=i)

我也给出heatmap_main修改后的源码,如下:

def heatmap_main(self, img_path, save_path,N=None):self.build_dir(save_path)img_names_lst = np.sort(np.array([n for n in os.listdir(img_path) if n[-3:] in ['jpg','png','PNG']]))if N is not None:i_idx,j_idx=int(2*N+1),int(2*N+3)img_names_lst=img_names_lst[i_idx:j_idx]# print('i_idx-->j_idx:{}-->{}'.format(i_idx,j_idx))for img_name in tqdm(img_names_lst):# try:#     self.computer_heatmap(f'{img_path}/{img_name}', f'{save_path}/{img_name}',rescale=True)# except:#     print('未通过图片:',img_name)self.computer_heatmap(f'{img_path}/{img_name}', f'{save_path}/{img_name}',rescale=True)if N is not None:print('i_idx-->j_idx:{}-->{}'.format(i_idx,j_idx)) 

我以为能解决问题,结果意想不到,显存依然增加。

二、中断重启继续推理或训练

异常安全重启机制,是指在一个循环中运行多个独立的任务(如模型训练),当某个任务遇到异常时,能够安全地终止该任务而不影响主程序的执行,并且可以在主循环中继续尝试新的迭代。这种方法不仅提高了系统的稳定性,还减少了人工干预的需求。

1、封装含参主函数

首先得有个函数将for i in range(21): opt = parse_opt() cam_model = yolov5_heatmap(opt) cam_model.heatmap_main(opt.source, opt.save_dir,N=i)我们这个函数封装,再通过multiprocessing方法来实现异常中断再重启。这里,我给出封装主函数方法,后续读者有需求可以按照我的模板自己进行封装。其代码如下:

# 假设 parse_opt, yolov5_heatmap 和 heatmap_main 是你已定义的函数/类
def run_model_with_param(opt, source, save_dir, N):try:cam_model = yolov5_heatmap(opt)cam_model.heatmap_main(source, save_dir, N=N)print(f"Model process {os.getpid()} completed successfully for iteration {N}.")except Exception as e:print(f"Exception caught in iteration {N}: {e}")sys.exit(1)  # 异常终止模型进程

2、终止重启进程管理方法

1、终止启动源码

我们定义了一个上下文管理器 process_context,它用于启动和管理一个子进程,并确保在退出上下文时正确清理资源。

@contextmanager
def process_context(target, args):p = multiprocessing.Process(target=target, args=args)p.start()try:yield pfinally:if p.is_alive():p.terminate()p.join()

2、源码解读

@contextmanager
def process_context(target, args):
  • 装饰器 @contextmanager:这是 Python 标准库 contextlib 模块中的一个装饰器,用于简化上下文管理器的创建。使用这个装饰器后,函数可以像 with 语句一样被使用。
  • 函数定义 process_context:该函数接受两个参数:
    • target: 这是要在子进程中执行的目标函数。
    • args: 这是一个元组,包含了传递给目标函数的参数。
    p = multiprocessing.Process(target=target, args=args)
  • 创建进程对象 p:这里使用 multiprocessing.Process 创建了一个新的进程实例。target 参数指定了要在新进程中运行的函数,而 args 参数则是传递给该函数的参数列表。
    p.start()
  • 启动进程:调用 start() 方法来启动子进程。这将使目标函数在一个独立的进程中开始执行。
    try:yield p
  • 进入上下文管理器的主体部分yield 语句是上下文管理器的关键。当使用 with process_context(...) as p: 语法时,yield 前面的代码会在进入 with 语句块之前执行,而 yield 后面的代码会在离开 with 语句块之后执行。
  • 返回进程对象 pyield p 将进程对象 p 返回给 with 语句,使得可以在 with 语句块中访问和操作这个进程对象。
    finally:if p.is_alive():p.terminate()p.join()
  • 确保资源释放finally 块中的代码无论如何都会被执行,即使在 try 块中发生了异常。这里的作用是确保子进程在退出上下文时被正确终止和清理。
    • 检查进程是否存活if p.is_alive() 检查进程是否仍然在运行。
    • 终止进程:如果进程还在运行,则调用 terminate() 方法发送终止信号给进程。
    • 等待进程结束p.join() 确保主程序会等待子进程完全终止后再继续执行。这一步很重要,因为它保证了所有资源都被正确释放。

通过 @contextmanagerprocess_context 的结合,我们可以方便地管理子进程的生命周期,确保它们在不再需要时被正确终止,从而避免潜在的资源泄漏问题。这种方法非常适合那些需要频繁启动和终止子进程的任务,如模型训练、批处理作业等。

三、终止启动主函数源码解读

1、终止启动源码

我们定义了一个名为 main_loop 的函数,该函数实现了模型训练的主循环逻辑。它使用了之前定义的 process_context 上下文管理器来确保每个迭代中的模型进程能够被安全地启动和终止,源码如下:

def main_loop():for i in range(21):print(f"Starting iteration {i}...")opt = parse_opt()source = opt.sourcesave_dir = opt.save_dirwith process_context(run_model_with_param, (opt, source, save_dir, i)) as model_process:model_process.join(timeout=6)  # 设置适当的超时时间if model_process.exitcode != 0:print(f"Model process exited with an error on iteration {i}. Restarting...")else:print(f"Model process completed successfully for iteration {i}.")

下面是对这段代码的详细解读:

2、源码解读

def main_loop():
  • 定义主循环函数main_loop 是整个程序的核心逻辑所在,负责管理和控制模型训练的多次迭代。
for i in range(21):
  • 迭代循环:这里使用 for 循环进行 21 次迭代(从 0 到 20),每次迭代都会尝试启动一个新的模型训练进程,并传递一个唯一的参数 i 给模型。
print(f"Starting iteration {i}...")
  • 打印当前迭代信息:在每次迭代开始时,打印一条消息以标识当前是第几次迭代,便于跟踪和调试。
opt = parse_opt()
source = opt.source
save_dir = opt.save_dir
  • 解析配置选项:调用 parse_opt() 函数获取命令行或其他来源的配置选项,并从中提取出 sourcesave_dir 参数,这些参数将用于初始化模型并指定数据源和保存目录。
with process_context(run_model_with_param, (opt, source, save_dir, i)) as model_process:
  • 启动子进程:使用 process_context 上下文管理器启动一个新的子进程来运行 run_model_with_param 函数。这个函数接收四个参数:optsourcesave_diriwith 语句确保即使在子进程中发生异常或错误,资源也会被正确清理。
model_process.join(timeout=6)  # 设置适当的超时时间
  • 等待子进程完成:调用 join() 方法等待子进程结束,同时设置了一个 6 秒的超时时间。这意味着如果子进程在这段时间内没有完成,主程序将继续执行而不等待其完成。你可以根据实际情况调整这个超时值。
if model_process.exitcode != 0:print(f"Model process exited with an error on iteration {i}. Restarting...")
else:print(f"Model process completed successfully for iteration {i}.")
  • 检查子进程退出状态
    • 非零退出码:如果子进程以非零状态码退出(即发生了异常或错误),则打印一条错误消息,并继续下一次迭代。
    • 零退出码:如果子进程成功完成(以零状态码退出),则打印一条成功消息。根据需要,可以在这里添加逻辑来决定是否继续下一次迭代或者提前终止循环。

关键点解析

  1. 迭代控制:通过 for 循环实现对多个模型训练任务的控制,确保每个任务都能独立启动和终止。
  2. 配置解析:每次迭代前都重新解析配置选项,确保使用最新的配置参数。
  3. 多进程管理:利用 multiprocessing.Process 和上下文管理器 process_context 来管理子进程的生命周期,保证资源的安全释放。
  4. 超时处理:为每个子进程设置了合理的超时时间,防止某个任务长时间挂起影响整体进度。
  5. 异常处理:通过检查子进程的退出状态码,可以在遇到异常时及时做出响应,并决定是否重启新的迭代。

四、完整代码Demo

这样,我就解决了热力图显存问题,但这不是正规方法,但这个技术可以应用到其它方式中。

1、完整源码

完整源码如下:

import multiprocessing
import sys
import os
from contextlib import contextmanager# 假设 parse_opt, yolov5_heatmap 和 heatmap_main 是你已定义的函数/类
def run_model_with_param(opt, source, save_dir, N):try:cam_model = yolov5_heatmap(opt)cam_model.heatmap_main(source, save_dir, N=N)print(f"Model process {os.getpid()} completed successfully for iteration {N}.")except Exception as e:print(f"Exception caught in iteration {N}: {e}")sys.exit(1)  # 异常终止模型进程@contextmanager
def process_context(target, args):p = multiprocessing.Process(target=target, args=args)p.start()try:yield pfinally:if p.is_alive():p.terminate()p.join()def main_loop():for i in range(21):print(f"Starting iteration {i}...")opt = parse_opt()source = opt.sourcesave_dir = opt.save_dirwith process_context(run_model_with_param, (opt, source, save_dir, i)) as model_process:model_process.join(timeout=6)  # 设置适当的超时时间if model_process.exitcode != 0:print(f"Model process exited with an error on iteration {i}. Restarting...")else:print(f"Model process completed successfully for iteration {i}.")if __name__ == "__main__":main_loop()

2、总结实现步骤

  1. 封装任务逻辑:将每个任务的执行逻辑封装到一个函数中,该函数接收必要的参数并返回结果。
  2. 使用多进程:利用 multiprocessing.Process 来创建和管理子进程,确保每个任务都在独立的进程中运行。
  3. 异常捕获与处理:在子进程中捕获所有可能发生的异常,并在遇到异常时调用 sys.exit(1) 以非零状态码退出。
  4. 上下文管理器:定义一个上下文管理器来启动和监控子进程,确保即使在发生异常的情况下也能正确清理资源。
  5. 主循环控制:在外层循环中不断尝试启动新的子进程,直到满足特定条件为止。

3、关键点解析

  • 封装任务逻辑:通过 run_model_with_param 函数封装了模型训练的具体逻辑,并允许传递额外的参数 N
  • 使用多进程multiprocessing.Process 创建了一个新的进程来运行模型,确保每个任务都是独立的。
  • 异常捕获与处理:在 run_model_with_param 中捕获所有异常,并通过 sys.exit(1) 终止进程。
  • 上下文管理器process_context 确保了即使发生异常,子进程也会被正确终止。
  • 主循环控制main_loop 函数实现了外层循环,持续尝试启动新的模型进程,直到完成所有迭代或达到其他终止条件。

4、运行结果

运行效果如下:
在这里插入图片描述
我解决问题效果:
在这里插入图片描述

结论

通过上述方法,我们构建了一个异常安全重启机制,它能够在遇到异常时自动终止当前任务并在主循环中继续下一次迭代。这种方法不仅提高了模型训练过程的稳定性和自动化水平,还减少了因意外错误而导致的训练中断问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/63765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis01

springbootredis 特点 1.高效性 2.支持多种数据结构 String,list,set,hash.zset 3.稳定性:持久化,主从复制(集群) 4.其他特性:支持过期时间,支持事务,消息订阅。 安装 1.下载安装包 redis官…

【Unity】Amplify Shader Editor

Amplify Shader Editor (ASE) Amplify Shader Editor,是一个功能强大的基于节点的着色器开发工具,允许开发者在 Unity 中轻松创建和管理复杂的 Shader。 主要功能和特点 基于节点的编辑器: • 提供直观的可视化界面,减少手写 Sh…

Elasticsearch使用(2):docker安装es、基础操作、mapping映射

1 安装es 1.1 拉取镜像 docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/elasticsearch:7.17.3 1.2 运行容器 运行elasticsearch容器,挂载的目录给更高的权限,否则可能会因为目录权限问题导致启动失败: docker r…

scroll-view 实现滑动显示,确保超出正常显示,小程序app,h5兼容

在uniapp 开开发的项目中,滑动操作是很多的 1.在插件市场使用了几款插件,但是都不太好用,要么是 显示的tab 过多,滑动到最后一个,当前显示那个跑左边显示不全,要么是滑动到最后一个后面的无法自动滑动&…

SpringBoot Maven快速上手

文章目录 一、Maven 1.1 Maven 简介:1.2 Maven 的核心功能: 1.2.1 项目构建:1.2.2 依赖管理: 1.3 Maven 仓库: 1.3.1 本地仓库:1.3.2 中央仓库:1.3.3 私服: 二、第一个 SpringBoot…

funcaptcha 验证码逆向协议通过,算法实现

声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

【C语言】浮点数的原理、整型如何转换成浮点数

众所周知C语言中浮点数占四个字节,无论在32位或者64位机器上。不免会发出疑问四个字节是怎么计算出小数的呢?其实物理存放还是按照整型存放的。 IEEE 754 单精度浮点数格式 浮点数在计算机中是使用 IEEE 754 标准进行表示的。在 IEEE 754 标准中&#…

善于运用指针--函数与指针

文章目录 前言一、函数的指针二、函数指针运用 1函数名地址2指针变量调用函数3指向函数的指针变量做函数参数二、返回指针值的函数总结 前言 如果在程序中定义了一个函数,在编译时会把函数的源代码转换为可执行代码并分配一段空间。这段空间有一个起始地址&#xf…

美图撕掉蔡文胜标签

卖掉比特币的美图不投机了。 作者|周立青 编辑|杨舟 12月5日,比特币突破10万美元大关,曾花费1亿美元购入虚拟货币的美图宣布已出售所有加密货币。 美图在港交所发布公告称,自2024年11月起,公司已开始出售其持有的加密货币&…

win11 恢复任务栏copilot图标, 亲测有效

1、修改C:\Windows\System32\IntegratedServicesRegionPolicySet.json,解除中国不能使用copilot的限制。 使用Notepad搜索copilot全文搜索,将下面两处的“CN,”删除,删除后如下: {"$comment": "Show Copilot on t…

鹦鹉的饮食偏好:探索多彩的食物世界

鹦鹉,作为聪明且迷人的鸟类,其饮食习性一直是鸟类爱好者关注的焦点。了解鹦鹉喜欢吃什么食物,对于确保它们的健康与幸福至关重要。 鹦鹉的食物种类丰富多样,首先是各类种子与谷物。例如,葵花籽富含脂肪和蛋白质&#…

番外篇 | YOLO-ELA:高效的局部注意力建模,用于高性能实时缺陷检测 !

前言:Hello大家好,我是小哥谈。现有的从无人机(UAV)上进行的绝缘子缺陷识别方法在处理复杂背景场景和小型物体时,准确率较低且存在较多的假阳性检测。为解决这一问题,本文提出了一种基于局部注意力建模的新注意力基础架构,即YOLO-ELA。在YOLOv8的一阶段架构的Neck部分添…

【密码学】SM4算法

一、 SM4算法简介 SM4算法是中国国家密码管理局于2012发布的一种分组密码算法,其官方名称为SMS4(SMS4.0),相关标准为GM/T 0002-2012《SM4分组密码算法》。SM4算法的分组长度和密钥长度均为128比特,采用非平衡Feistel结构。采用32…

【实现多网卡电脑的网络连接共享】

电脑A配备有两张网卡,分别命名为eth0和eth1(对于拥有超过两张网卡的情况,解决方案相似)。其中,eth0网卡能够连接到Internet,而eth1网卡则通过网线直接与另一台电脑B相连(在实际应用中&#xff0…

VBA API 概述 | 宏编程

注:本文为 “VBA API 概述 | 宏编程 | 执行速度慢” 相关文章合辑。 VBA API 详解 Office 二次开发于 2020-12-17 22:27:10 发布 Office 版本变动 在 Office 2010 之前,微软仅提供 32-bit 版本的 Office。而自 Office 2010 起,出现了 32-b…

科技潮头浪接天,一桥飞架两界连。EthernetIP转Profinet互译连

本案例介绍的是西门子1200PLC通过稳联技术PROFINET转EtherNetIP网关(WL-ABC2006)连接HCS-6100系统配置案例。 打开稳联技术Ethernetip转profient网关(WL-ABC2006)配置软件,因为网关作为EtherNetIP从站,所以选择PN2EIP。设置网关Pr…

EasyPlayer.js播放器如何在iOS上实现低延时直播?

随着流媒体技术的迅速发展,H5流媒体播放器已成为现代网络视频播放的重要工具。其中,EasyPlayer.js播放器作为一款功能强大的H5播放器,凭借其全面的协议支持、多种解码方式以及跨平台兼容性,赢得了广泛的关注和应用。 那么要在iOS上…

LeetCode - #158 用 Read4 读取 N 个字符 II

文章目录 摘要描述题目描述方法定义 题解答案题解代码题解代码分析示例测试及结果示例测试代码示例运行结果 时间复杂度空间复杂度总结关于我们 摘要 本文将详细解读一道与文件读取相关的编程问题:如何使用 read4 实现按需读取 n 个字符的 read 方法。我们不仅会提…

Navigaiton源码解析(二)—— costmap、全局规划算法

1 costmap概述 红点代表障碍物,蓝色点代表膨胀后的障碍物。红色的多边形表示机器人的footprint(足迹),用来做碰撞检查。机器人的footprint与红色的障碍物点不应该相交,footprint的中心不应该与蓝色点重合 costmap_2d包提供了一个机器人在其中导航的占据栅格地图。costmap接收…

Oracle EBS PAC 如何复修非标任务单生产生非常大的PAC成本?

系统环境 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题症状 非标准任务单组件和装配相同物料A,俗称投入A产A。该物料A的期初数量为0。 上期成本假设为20,而本期成本爆增至563.674234。关键问题点: 由于该物料没有期初数量,无法通过“更新定期成本”指定“新期本…