Глубокая копия в симуляторе эволюции, создающая утечку памяти - PullRequest
0 голосов
/ 18 января 2019

Недавно я пытался создать симулятор эволюции в 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)

Пожалуйста, дайте мне знать, если я должен поделиться каким-либо кодом или деталями.

1 Ответ

0 голосов
/ 18 января 2019

Я думаю, что может произойти, что ваша реализация рекурсивна, и из-за этого GC никогда не сможет выпустить все ваши предыдущие копии! (Или, может быть, есть какая-то другая причина, по которой GC не может выпустить эти предметы)

В эволюционном программировании вам часто нужно сохранять только определенное количество самых результативных «детей», если я правильно помню. Вы должны хранить отдельный список этих детей и вставлять новых в список, но также обязательно удалять старые! Теперь также убедитесь, что ваша реализация не является рекурсивной, и больше нет ссылок на старые экземпляры. Если вы сделаете это правильно, GC правильно освободит все экземпляры, которые вы не используете, и ваши проблемы могут просто исчезнуть:)


РЕДАКТИРОВАТЬ: После комментария ОП:


Я не совсем уверен, что делает функция mutate_neuralnetwork. Но, глядя на ваш код и принимая во внимание тот факт, что копирование становится все более медленным, возможно, ваша структура данных рекурсивна. То есть если copied_animal содержит ссылку на предыдущий экземпляр, который, в свою очередь, ссылается на более раннюю версию, и тогда вы можете представить, что в какой-то момент цепочка становится настолько длинной, что ее копирование занимает много времени. Это были бы старые ссылки. Убедитесь, что у вас нет рекурсивной структуры данных, ИЛИ иногда установка переменных на None может помочь GC определить, что они больше не нужны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...