【问题标题】:Deep copy in evolution simulator creating memory leak进化模拟器中的深拷贝造成内存泄漏
【发布时间】:2019-01-18 10:20:13
【问题描述】:

最近我一直在尝试使用前馈神经网络在 Python 中创建一个进化模拟器。除了复制功能外,一切正常。

起初,在开发繁殖时,我只是简单地调用了一个函数,该函数创建了一个新的动物对象,该对象具有与其父母所具有的相同但略有变异的属性。例如,我通过写parent.weights = child.weights 来做到这一点。然而,我了解到这只会创建对父母权重的引用,因此孩子并不独立于其父母。因此,例如,每当一个孩子改变其体重时,所有其他具有参考体重的动物也会发生变化,从而导致整个人群的行为突然发生类似的变化。

后来我发现了 Python 的 copy 库。现在要创建一个子动物,我使用copy.deepcopy() 复制父级的整个对象,然后更改复制的对象以创建子级。这工作了一段时间,但在运行程序大约一个小时后,它太慢了,无法取得任何进展。我发现当一个孩子出生时,如果做了一个深拷贝,程序会完全停止,并且一次加载几秒钟。

我不知道这是什么原因造成的,但我有点怀疑这可能是某种内存泄漏。我的问题是:

  1. 这可能是什么原因?

  2. 是否有任何解决方案或替代方法来创建 没有引用的对象?

这是相关的副本,简化版:

调用再现函数:

#asexual reproduction
if self.energy > (((pow(self.sizeRadius, 2) * 3.14 ))):
    self.birthed_kin += 1
    self.energy -= (pow(self.sizeRadius, 2) * 3.14 ) / 2
    self.birth_timer = 0

    self.copy_animal()

再现功能:

def copy_animal(self):

    copied_animal = copy.deepcopy(self)

    copied_animal.age = 0

    copied_animal.birthed_kin = 0
    copied_animal.sizeRadius = mutate_organ(copied_animal.sizeRadius, 1)
    copied_animal.energy = (pow(copied_animal.sizeRadius, 2) * 3.14) / 2
    copied_animal.health = pow(copied_animal.sizeRadius, 2) * 3.14
    copied_animal.pain = 0

    copied_animal.weights = [ 
mutate_neuralnetwork( copied_animal, copied_animal.input_size, copied_animal.hidden_sizes[0], copied_animal.weights[0], copied_animal.mutation_rate), 
mutate_neuralnetwork( copied_animal, copied_animal.hidden_sizes[0], copied_animal.output_size, copied_animal.weights[1], copied_animal.mutation_rate), 
   ]

    living_animals_array.append(copied_animal)

如果我应该分享更多代码或详细信息,请告诉我。

【问题讨论】:

    标签: python memory-leaks neural-network copy deep-copy


    【解决方案1】:

    我认为可能发生的情况是您的实现是递归的,因此,GC 永远无法释放您以前的所有副本! (或者可能有其他原因导致 GC 无法释放这些物品)

    在进化编程中,如果我没记错的话,你通常只需要保留一定数量的表现最好的“孩子”。您应该保留这些孩子的单独列表并将新的推送到列表中,但也要确保删除旧的!现在,还要确保您的实现不是递归的,并且不再引用旧实例。如果您正确执行此操作,GC 将正确释放您未使用的任何实例,并且您的问题可能会消失 :)


    编辑:在 OP 评论之后:


    我不确定mutate_neuralnetwork 函数的作用。但是查看您的代码并考虑到复制变得越来越慢的事实可能是您的数据结构是递归的。 IE。如果copied_animal 包含对先前实例的引用,该实例又引用甚至更早的版本,然后您可以想象在某些时候链变得如此之长以至于复制它需要很长时间。这些将是旧的参考。确保您没有递归数据结构,或者有时将变量设置为 None 可以帮助 GC 确定不再需要它们。

    【讨论】:

    • 非常感谢您的快速回复! :) 我有一个有效的遗传算法可以做到这一点,我也有关于不同数组长度的信息。这不是我认为的问题。但是,您提到的关于小心并确保不再引用旧实例的事情肯定是这样的!您知道如何通过其中一项检查来查找错误吗?
    • 另外一个问题,如果是有旧引用的情况,那不是只会拖慢程序吗?就我而言,该程序仅在制作新副本时停止。这让我想,也许创建一个副本的副本效率低下?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多