Я создал изображение, аппроксимирующее генетический алгоритм, используя python 3 и opencv. Что он делает, так это создает популяцию людей, которые рисуют на чистом изображении круги произвольного цвета, размера и непрозрачности. В конце концов, сильнейшие насытят население через несколько сотен поколений.
Я попытался реализовать многопроцессорность, потому что рендеринг изображений требует времени, соответствующего размеру популяции и размеру круга, а также размеру целевого изображения (важно для детализации деталей)
Я использовал многопроцессорную обработку и пул с массивом отдельных объектов в качестве итерируемого и отображал только пригодность и идентификатор. По сути, в основном процессе ни у одного из участников нет собственного холста, тогда как в многопроцессных процессах каждый из них визуализирует свой холст и вычисляет пригодность / разницу.
Однако, похоже, что многопроцессорность замедляет работу всей программы? На самом деле процесс рендеринга, похоже, требует той же скорости по сравнению с сериализованной обработкой, но медленнее из-за многопроцессорности.
class PopulationCircle:
def renderPop(self, individual):
individual.render()
return [individual.index, individual.fitness]
class IndividualCircle:
def render(self):
self.genes.sort(key=lambda x: x[-1], reverse=False)
self.canvas = np.zeros((self.height,self.width, 4), np.uint8)
for i in range(self.maxCount):
overlay=self.canvas.copy()
cv2.circle(overlay, (self.genes[i][0], self.genes[i][1]), self.genes[i][2], (self.genes[i][3],self.genes[i][4],self.genes[i][5]), -1, lineType=cv2.LINE_AA)
self.canvas = cv2.addWeighted(overlay, self.genes[i][6], self.canvas, 1-self.genes[i][6], 0)
diff = np.absolute(np.array(self.target)- np.array(self.canvas))
diffSum = np.sum(diff)
self.fitness = diffSum
def evolution(mainPop, generationLimit):
p = mp.Pool()
for i in range(int(generationLimit)):
start_time = time.time()
result =[]
print(f"""
-----------------------------------------
Current Generation: {mainPop.generation}
Initial Score: {mainPop.score}
-----------------------------------------
""")
#Multiprocessing used for rendering out canvas since it takes time.
result = p.map(mainPop.renderPop, mainPop.population)
#returns [individual.index, individual.fitness]; results is a list of list
result.sort(key = lambda x: x[0], reverse=False)
#Once multiprocessing is done, we only receive fitness value and index.
for k in mainPop.population:
k.fitness = result[k.index][1]
mainPop.population.sort(key = lambda x: x.fitness, reverse = True)
if mainPop.generation == 0:
mainPop.score = mainPop.population[-1].fitness
"""
Things to note:
In main process, none of the individuals have a canvas since the rendering
is done on a different process tree.
The only thing that changes in this main process is the individual's
fitness.
After calling .renderHD and .renderLD, the fittest member will have a canvas
drawn in this process.
"""
end_time = time.time() - start_time
print(f"Time taken: {end_time}")
if i%50==0:
mainPop.population[0].renderHD()
cv2.imwrite( f"../output/generationsPoly/generation{i}.jpg", mainPop.population[0].canvasHD)
if i%10==0:
mainPop.population[0].renderLD()
cv2.imwrite( f"../output/allGenPoly/image{i}.jpg", mainPop.population[0].canvas)
mainPop.toJSON()
mainPop.breed()
p.close()
p.join()
if __name__ == "__main__":
#Creates Population object
#init generates self.population array which is an array of IndividualCircle objects that contain DNA and render methods
pop = PopulationCircle(targetDIR, maxPop, circleAmount, mutationRate, mutationAmount, cutOff)
#Starts loop
evolution(pop, generations)
если я использую 600 населения с 800 кругами,
Серийный номер взял: 11сегментация, ср.
многопроцессорность: 18 с / итерация, средняя.
Я очень плохо знаком с многопроцессорностью, поэтому любая помощь будет принята.