I made a simple class that runs many optimizations simultaneously over a specified range. This way, only one or two of the optimizations need to stumble into the global minima while the others get lost. Example below.
import pandas as pd
import numpy as np
import math
from scipy import optimize
import threading
from threading import Thread
import random
import time
class threaded_opt:
#initializations
def __init__(self, function, min_x0, max_x0, num_threads):
if (len(max_x0) != len(min_x0)): #Error checking
print ("ERROR: max_x0 and min_x0 are not the same length")
return
self.function = function
self.min_x0 = min_x0
self.max_x0 = max_x0
self.num_threads = num_threads
self.lock = threading.Lock()
self.best_result = None
self.all_results_of_run = []
#Run the optimization. Make the threads here.
def run(self):
self.best_result = optimize.minimize(self.function, self.min_x0) #Get an initial value to compare in traget_function
self.all_results_of_run = [] #Clear the all results list for each run
for x in range(self.num_threads): #Make the threads and start them off
t = Thread(target=self.target_function, args=(x,))
t.start()
#Each thread goes through this. Find a random point in the space given, and optimize from it
def target_function(self, thread_ID):
random_x0 = []
for x in range(len(self.max_x0)): #Generate a random point in the allowed space
random_x0.append(random.uniform(self.min_x0[x], self.max_x0[x]))
result = optimize.minimize(self.function, random_x0) #Optimize from that point
with self.lock: #So the threads don't interfere with eachother
self.all_results_of_run.append(result)
if (result.fun < self.best_result.fun):
self.best_result = result
#Returns the proportion of optimizations that returned the correct result
def score(self):
correct = 0
for x in self.all_results_of_run:
if (x.fun == self.best_result.fun):
correct += 1
return (float(correct)/self.num_threads)