2020-04-06

记geatpy-DE算法的一次修改

本周主要修改了geatpy集成到openke的trasne-DE算法,进展如下:

这份代码中存在很多问题,导致训练无法有效进行。

初始代码的设计是运行会输出一个结果,这个结果是实体nbatches=1(即为不使用小minibatch,或者说一个minibatch的大小为全部的数据),dim=20,train_times=1,maxgen=2,nin=40(种群规模)运行结果。即为在DE进化两代的结果,其中结果如下:

由图可见,进化效果并不明显(两代看不出进化效果)。同时,还可以看出代码环境存在问题——matplotlib标签乱码。

为解决该问题,查阅多篇博客后发现原来是字体未下载导致中文乱码。于是,参照下面的链接,问题得到解决:https://blog.csdn.net/sinat_40875078/article/details/104326625

为了进一步查看进化效果,我将训练的maxgen设置为1000,训练次数和维度等不变,开始训练。

训练开始后不久,linux系统没了响应。我觉得很奇怪应该是代码的时间和空间上存在问题。于是,我先查看了代码中的逻辑设置,看看是否出现了局部死循环等问题。通过断点调试等方法仔细检查了几遍后,基本断定在代码的可见部分是不存在死循环的。于是我再次检查空间问题,果不其然,在maxgen=1000的时候,内存全部被占满。

分析过后,发现一个问题,geatpy_de的设置是这样子的,它会保存每一代的染色体,而染色体则是每一个batch 的全部数据组成的行向量,每一代又有种群规模个染色体……

所以,1000的maxgen,数据量为:

1000dim种群规模(头实体总个数+关系实体总个数+尾实体总个数)

明白为什么会内存爆炸了。geatpy的这种设置也限制了每次训练的最大进化代数,无疑。

于是,我把maxgen设为800,同时,usegpu设为true,发现运行报错!原来代码还没有融入cuda加速模块,我猜这个代码就是用来实验一下将geatpy融入到openke上的了,这个代码只是做个尝试而已。考虑到当时已经很晚,第二天还要上课,就姑且不用gpu训练,晚上让它跑着。

第二天,醒来时发现居然还没有跑完800代……(瑟瑟发抖)。于是又等它跑了一个上午。后面来查看的时候,居然……没跑完就崩盘了。

于是,后面的两天,我画时间专门来解决这个cuda加速问题,反复修改代码(改动的地方很多),终于将cuda加速融入到了代码中。并重新进行了一次500=maxgens 的训练,半个小时左右,得到结果如下:

由图可以看出,在最大进化代数500代的,迭代一次的情况下,算法存在逐步收敛的迹象,但是速度依然很慢,没有显著的数值变化。由于代数过大会导致内存爆炸,只好增加迭代次数,让代码多次寻来拿。我把train_times设置为1000。

然而,问题来了,程序每训练完一轮后,会画出本次训练的图线,如上图,然后代码停止执行……

匪夷所思……

莫非代码完成一次训练会自动停止?

或者说每完成一次训练代码就陷入错误?

又或者是上次训练的内存没有释放,第二次训练过程中出现内存爆炸?

是不是也有可能和这个图有关?

开始检查代码……很多小时过去了。前面几个可能的原因基本都否地了,只剩下最后一个原因——这个图造成了训练中断!(一开始我想洗个脚本来扫描桌面,只要这个造成程序阻塞的这线图一旦出现就予以关闭,不过没这样做,因为想想觉得太滑稽了)

我开始在整个代码里边找matplotlib,居然没有发现有导入过这个包!无疑,画图是geatpy干的,然而我又看不到geatpy的代码。我决定检查geatpy的源码。从github上找到geatpy的源码后,我开始仔细观察DE的执行过程。终于发现了原因:

在geatpy中,算法模板的顶级父类定义了如图所示的drawing初始化参数,而DE算法模板将该参数设置为1。至于为什么画图会导致程序阻塞?查阅资料后发现,geatpy中使用了matplotlib的阻塞模式画图(突然智熄)……然而,在代码中,对myalgorithm对DE的继承没有修改该参数。于是,我重新修改了代码中DE的子类:

如图,我将drawing参数设置为0,然后重新编写绘图模块,绘制每次训练后的最低损失值。终于可以连续正常训练了!

开始训练!本以为大功告成,不料,远远不够……问题又来了,如图:

岂有此理,居然毫无收敛迹象!

分析问题之后,我猜造成这个问题的原因由如下几点:

1`算法本身的问题,导致不收敛(随机事故)

2`代码的问题,初始化存在错误。

3`根据图像判断,每次迭代训练都是重新初始化,重新训练,属代码逻辑的问题。

为了排除第一个可能,我反复训练,结果都差不多,毫无收敛迹象。

为了排除第二个可能,我仔细检查了代码的执行过程,仔细分析了代码中的参数传递,传的是引用还是副本,深度拷贝还是浅拷贝。为了避免算法流程上的重复初始化,我把源代码中每次迭代都要重新定义problem,poplation和myAlgorithm的地方修改了,在所有的训练期间,这三个对象都只会初始化

一次。这样,我绝得应该对了,然而仍旧没有收敛迹象!

那么,问题只能实在第三点上了。初始化问题我已经设计好了,可为什么还是反复重新训练呢?我猜,肯定是geatpy中还存在初始化过程。

上图是代码中算法过程的地方,唯一调用geatpy的位置,run方法。

翻阅,geatpy源代码,找到了病根:

果然!在geatpy中,run方法里边存在初始化种群的行为!geatpy的这种设计让人怎么能不吐血三升!

找到了根本原因,加以修改之后,不知经过了多久,终于解决了问题。

以下是算法正在执行的图线,每次50代,训练一次的时间约为129秒,目前还在训练中:

由图可知,算法正常执行,逐步收敛,但是收敛的步幅依然不大。完成1000次迭代需要大概要38个小时,日后的算法实验估计有必要使用gpu服务器来跑。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值