我尝试每小时运行一次ML训练脚本,但每次小时后内存使用量大约增加20%,在3-4小时后,内存使用量达到90%,然后脚本会抛出内存错误。我想知道为什么在训练函数完成后内存没有被释放。
尽管如果我手动运行训练函数(不使用任何线程调度器,并且连续调用训练函数两次或三次),这种行为不会出现。
有什么建议可以在每个特定间隔后训练模型吗?
这是代码。
import pickleimport pandas as pdfrom pymongo import MongoClientimport datetimefrom apscheduler.schedulers.blocking import BlockingSchedulerdef train(): client = MongoClient(databaseURI) db = client['mydb'] movie_data = [] for index, obj in enumerate(db.movies.find({})): movie_obj = {} movie_obj['_id'] = obj['_id'] movie_obj['title'] = obj['title'] movie_obj['rating'] = obj['rating'] movie_data.append(movie_obj) user_data = [] for index, obj in enumerate(db.users.find({})): user_obj = {} user_obj['_id'] = obj['_id'] user_obj['username'] = obj['username'] user_obj['movie_id'] = obj['movie_id'] user_obj['rating'] = obj['rating'] user_data.append(user_obj) movie_data_df = pd.DataFrame(movie_data) user_data_df = pd.DataFrame(user_data) # 一些ML训练算法 trainedModel = algo.train(user_data_df, movie_data_df) trained.to_pickle('files/trained.pkl')scheduler = BlockingScheduler()scheduler.add_job(train, 'interval', hours=1, next_run_time=datetime.datetime.now())scheduler.start()
回答:
作业存储保存了预定的作业。默认的作业存储只是将作业保存在内存中,但其他存储方式会将它们保存在各种类型的数据库中。作业的数据在保存到持久性作业存储时会被序列化,并且在从中加载回来时被反序列化。作业存储(除了默认的)不会将作业数据保存在内存中,而是作为中间人来保存、加载、更新和搜索后端的作业。
我建议尝试以下解决方案之一:
-
将
jobstore
从默认(即内存)更改为某个持久位置(示例)。 -
或者尝试将参数
replace_existing
设置为True
(因为默认值是False
)。scheduler.add_job(train, 'interval', hours=1, next_run_time=datetime.datetime.now(), replace_existing=True)
附注:
我认为可能还有另一种丑陋的解决方法(我没有尝试过!),就是你可以添加一个Listener
来监听崩溃并重启整个进程!(如果你可以尝试并以更符合Python风格的方式修改它!)
scheduler = BlockingScheduler()scheduler.add_job(train, 'interval', hours=1, next_run_time=datetime.datetime.now())def my_listener(event): if event.exception: global scheduler scheduler.shutdown() gc.collect() scheduler = BlockingScheduler() scheduler.add_job(train, 'interval', hours=1, next_run_time=datetime.datetime.now()) scheduler.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR) scheduler.start()scheduler.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)scheduler.start()