Multiprocessing Freezing with Scipy Optimise - python

EDIT: The error does not lie with multiprocessing but rather with another library. I would close the question but #Lukasz Tracewski's point of using joblib may help someone else.
I've got an issue with a task I'm trying to parallelise on windows.
It seems to work for a while then suddenly halts on a particular instance (I can tell as I get the code to print which iteration it's on). I've noticed in the task manager that the CPU usage, which such be about 50%, is minimal for the Python processes. When I then do a keyboard interrupt on the cmd prompt, this suddenly shoots forward a number of instances and the activity goes back up for a short while, only to go back down again.
I've included the bits of my code which I think are relevant. I know it can work (I don't think it's stuck on a problem) and there seems to be a degree of randomness as to when it does freeze.
I'm using the COBYLA solver with max_iter set. I'm not sure if it is relevant, but when I tried to use BFGS, I got a freezing problem.
def get_optimal_angles(G,p,coeff,objective_function,initial_gamma_range,initial_beta_range,seed):
'''
This performs the classical-quantum interchange, improving the values of beta and gamma by reducing the value of
< beta, gamma | C | beta, gamma >. Returns the best angles found and the objective value this refers to. Bounds on the minimiser are set as the starting points
'''
initial_starting_points = random_intial_values((np.array(initial_gamma_range)),(np.array(initial_beta_range)),p,seed)
optimiser_function = minimize(objective_function, initial_starting_points, method='COBYLA', options={'maxiter':1500})
best_angles = optimiser_function.x
objective_value = optimiser_function.fun
return best_angles,objective_value
def find_best_angles_for_graph_6(graph_seed):
print("6:On graph",graph_seed)
#graph = gp.unweighted_erdos_graph(10,0.4,graph_seed)
graph = gp.unweighted_erdos_graph(6,0.4,graph_seed)
graph_coefficients = quantum_operator_z_coefficients(graph,'Yo')
exact_energy =get_exact_energy(graph)
angle_starting_seed = np.arange(1,number_of_angle_points,1)
objective_function= get_black_box_objective_sv(graph,p,graph_coefficients)
list_of_results = []
for angle_seed in angle_starting_seed:
print("On Angle Seed",angle_seed)
best_angles_for_seed, best_objective_value_for_seed = get_optimal_angles(graph,p,graph_coefficients,objective_function,[0,np.pi],[0,np.pi],angle_seed)
success_prob = calculate_energy_success_prob(graph,p,exact_energy, graph_coefficients,best_angles_for_seed,angle_seed)
angle_seed_data_list = [angle_seed,best_objective_value_for_seed,success_prob,best_angles_for_seed]
list_of_results.append(angle_seed_data_list)
list_of_best = get_best_results(list_of_results)
full_results = [graph_seed,exact_energy,list_of_best,list_of_results]
return full_results
import multiprocessing as mp
def main():
physical_cores = 5
pool = mp.Pool(physical_cores)
list_of_results_every_graph_6 = []
list_of_all_graph_results_6 = pool.map(find_best_angles_for_graph_6,range(1,number_of_graphs+1))
print(list_of_all_graph_results_6)
file_name_6 = 'unweighted_erdos_graph_N_6_p_8.pkl'
pickle_6 = open((file_name_6),'wb')
pickle.dump(list_of_all_graph_results_6, pickle_6)
pickle_6.close()
list_of_results_every_graph_10 = []
list_of_all_graph_results_10 = pool.map(find_best_angles_for_graph_10,range(1,number_of_graphs+1))
print(list_of_all_graph_results_10)
file_name_10 = 'unweighted_erdos_graph_N_9_p_8.pkl'
pickle_10 = open((file_name_10),'wb')
pickle.dump(list_of_all_graph_results_10, pickle_10)
pickle_10.close()
if __name__ == "__main__":
main()
EDIT: Here is the full code as a Jupyter notebook. https://www.dropbox.com/sh/6xb7setjsn1c1o3/AAANfH7mEmhuuf9cxh5QWsRQa?dl=0

Related

why my script to present audio stimuli has an unpredictable behaviour?

I am trying to run a simple experiment using python. I want to present two different types of audio stimuli, an higher and a lower pitch. The higher pitch has a fixed duration of 200ms while the lower pitch come in pairs, the first with a fixed duration of 250ms and the second with a variable duration that can take the following values [.4, .6, .8, 1, 1.2]. I need to know at what time (machine) the stimuli start and end, and their duration (precision is not the most important issue, I have a tolerance of ~ 10ms), thus I log this information
I am using the library audiomath to create and present the stimuli and I have create several custom functions to manage the other aspects of the task. I have 3 scripts: one in which I define the functions, one in which I set the specific parameters for the experiment for each subject (source) and one with the main()
My problem is that the main() works erratically: it works sometimes, some other times it seems to enter into an infinite loop and a certain sound is presented and never stop playing. The point is that this behavior seems to be really random, with the problem that presents itself at different trials, or not at all, even with the exact same parameter.
This is my code:
source file
#%%imports
from exp_funcs import tone440Hz, tone880Hz
import numpy as np
#%%global var
n_long = 10
n_short = 10
short_duration = .2
long_durations = [.4, .6, .8, 1, 1.2]
#%%calculations
n_tot = n_long + n_long
trial_types = ['short_blink'] * n_short + ['long_blink'] * n_long
sounds = [tone880Hz] * n_short + [tone440Hz] * n_long
np.random.seed(10)
durations = [short_duration] * n_short + [el for el in np.random.choice(long_durations, n_long)]
durations = [.5 if el < .2 else el for el in durations]
cue_duration = [.25] * n_tot
spacing = [1.25] * n_tot
np.random.seed(10)
iti = [el for el in (3 + np.random.normal(0, .25, n_tot))]
functions
import numpy as np
import audiomath as am
import time
import pandas as pd
TWO_PI = 2.0 * np.pi
#am.Synth(fs=22050)
def tone880Hz(fs, sampleIndices, channelIndices):
timeInSeconds = sampleIndices / fs
return np.sin(TWO_PI * 880 * timeInSeconds)
#am.Synth(fs=22050)
def tone440Hz(fs, sampleIndices, channelIndices):
timeInSeconds = sampleIndices / fs
return np.sin(TWO_PI * 440 * timeInSeconds)
def short_blink(sound, duration):
p = am.Player(sound)
init = time.time()
while time.time() < init + duration:
p.Play()
end = time.time()
p.Stop()
print(f'start {init} end {end} duration {end - init}')
return(init, end, end - init)
def long_blink(sound, duration, cue_duration, spacing):
p = am.Player(sound)
i_ = time.time()
while time.time() < i_ + cue_duration:
p.Play()
p.Stop()
time.sleep(spacing)
init = time.time()
while time.time() < init + duration:
p.Play()
end = time.time()
p.Stop()
print(f'start {init} end {end} duration {end - init}')
return(init, end, end - init)
def run_trial(ttype, sound, duration, cue_duration, spacing):
if ttype == 'short_blink':
init, end, effective_duration = short_blink(sound, duration)
else:
init, end, effective_duration = long_blink(sound, duration,
cue_duration, spacing)
otp_df = pd.DataFrame([[ttype, init, end, effective_duration]],
columns = ['trial type', 'start', 'stop',
'effective duration'])
return(otp_df)
main
import pandas as pd
import sys
import getopt
import os
import time
import random
from exp_funcs import run_trial
from pathlib import PurePath
def main(argv):
try:
opts, args = getopt.getopt(argv,'hs:o:',['help', 'source_file=', 'output_directory='])
except getopt.GetoptError:
print ('experiment.py -s source file -o output directory')
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print ('experiment.py -s source file')
sys.exit()
elif opt in ("-s", "--source_file"):
source_file = arg
elif opt in ("-o", "--output_directory"):
output_dir = arg
os.chdir(os.getcwd())
if not os.path.isfile(f'{source_file}.py'):
raise FileNotFoundError('{source_file} does not exist')
else:
source = __import__('source')
complete_param = list(zip(source.trial_types,
source.sounds,
source.durations,
source.cue_duration,
source.spacing,
source.iti))
# shuffle_param = random.sample(complete_param, len(complete_param))
shuffle_param = complete_param
dfs = []
for ttype, sound, duration, cue_duration, spacing, iti in shuffle_param:
time.sleep(iti)
df = run_trial(ttype, sound, duration, cue_duration, spacing)
dfs.append(df)
dfs = pd.concat(dfs)
dfs.to_csv(PurePath(f'{output_dir}/{source_file}.csv'), index = False)
if __name__ == "__main__":
main(sys.argv[1:])
The 3 files are in the same directory, I browse with the terminal within the directory and run the main as follow python experiment.py -s source -o /whatever/output/directory.
Any help would be more than appreciated
This is too big/complex a program to hope for help on non-specific "erratic" behavior here on stackoverflow. You need to boil it down into a small reproducible example that behaves unexpectedly. If it works sometimes and not others, systematically home in on the conditions that make it fail. I did make one attempt to run the whole thing, but after fixing a few missing imports there was still the matter of the unspecified "source file" content.
So I don't know specifically what your problem is. However, from the audiomath and general real-time-performance perspectives, I can certainly identify a few things you shouldn't be doing:
Although Player instances are designed to be played, stopped or manipulated at time-critical moments, they are not (by default) designed to be created and destroyed at time-critical moments. If you want to create/destroy them fast, pre-initialize a persistent Stream() instance and pass it as the stream argument when creating the Player, as described towards the end of https://audiomath.readthedocs.io/en/release/auto/Examples.html#play-sounds
If you are using Synth instances, you could take advantage of their .duration attribute instead of checking the clock explicitly in a while loop. For example, you can set tone880Hz.duration = 0.5, and then play the sound synchronously with p.Play(wait=True). The big problem with your clock-watching while loops is that they are currently "busy-wait" loops that will thrash the CPU, likely leading to sporadic disruption to your sound (Python's multithreading is far from perfect). However, before you fix this problem you should know...
The strategy "Play(), wait, sleep, Play()" is never going to achieve precise timing of one stimulus relative to the other anyway. First, whenever you issue a command to play a sound in any software, there will unavoidably be a non-zero (and randomly varying!) latency between the command and the physical onset of the sound. Second, sleep() is unlikely to be as precise as you think it is. This applies both to the sleep() you’ve been using to create a gap, and also to the sleep() that would be used internally by Play(wait=True). Sleep implementations suspend operation for "at least" the specified amount of time but they don't guarantee an upper bound on that. This is very hardware- and OS-dependent; on some Windows systems you may even find that the granularity never gets any better than 10ms.
If you really want to use the Synth approach I suppose you could program the gap procedurally into the function definitions of tone440Hz() and tone880Hz(), accessing cue_duration, duration and spacing as global variables (in fact, while you're at it, why not make frequency a global variable too, and only write one function). But I don't see any great advantage in this, either in performance or in code maintainability.
What I would do instead is pre-initialize the following (once, at the start of your program):
max_duration = 1 # length, in seconds, of the longest continuous tone we'll need
tone440Hz = am.Sound(fs=22050).GenerateWaveform(freq_hz=440, duration_msec=max_duration*1000)
tone880Hz = am.Sound(fs=22050).GenerateWaveform(freq_hz=880, duration_msec=max_duration*1000)
m = am.Stream()
Then compose each "long blink" stimulus as a static Sound using the parameters you want.
This will ensure that the tone and gap durations are precise:
s = tone440Hz[:cue_duration] % spacing % tone440Hz[:duration]
For best real-time performance, you could pre-compute a whole set of these stimuli with different parameters. Or, if it turns out that those composition operations (slicing and splicing) happen fast enough, you might decide you can get away with doing that at trial time, in your long_blink() function.
Either way, when it comes to playing the stimulus at trial time:
p = am.Player(s, stream=m) # to make Player() initialization fast, use a pre-initialized Stream() instance
p.Play(wait=True)
Finally: in implementing this, start from scratch—start simple, and test the performance of a few simple cases before compounding things.

Multiprocessing a for loop in Python stops after a while and the program continues to run using a single thread

I am multiprocessing a for loop in Python using Pool in this way:
if __name__ == '__main__':
pool = Pool() # Create a multiprocessing Pool
result = pool.map(process_interp, range(ngal))
where process_interp is a function I have defined. However, when the number of calculations increase, the program seems to almost crash in a way that a 0 byte file is produced as my result and the Python program continues running but htop shows that it is no longer using multiple threads and only a single thread is being used. For not so heavy calculations, everything just works fine and the program runs fast and correctly.
Can someone please give me insight into what is happening here and what causes this problem? I have no clue how to solve this issue. Thanks a lot!
Edit: This is the function process_interp. Basically calculating some values on a grid. The issue arises when I increase the size of the grid (N_a and N_m) and therefore the number of calculations.
def process_interp(k):
#e = data[k][0]+np.random.normal(0, 0.3, len(data[k][0]))
e = data[k][0]
sigma_crit = data[k][1]
r_s = data[k][2]
dev_gamma = data[k][4]
dev_k = data[k][5]
z_d = data[k][6]
like_grid = np.empty((N_a, N_m), dtype='longdouble')
for i in range(N_a):
for j in range(N_m):
gamma_nfw, k_nfw = NFWfunc(m_grid[j], z_d, r_s, sigma_crit)
gamma_dev = dev_gamma*pow(10, alpha_grid[i]-alpha_0)
k_dev = dev_k*pow(10, alpha_grid[i]-alpha_0)
mean = (gamma_nfw+gamma_dev)/(1-k_nfw-k_dev)
loglike = np.zeros(len(e), dtype='longdouble')
loglike = -((mean-e)**2/(2*0.3**2))
like_grid[i,j] = np.prod(np.exp(loglike))
return like_grid

Multiprocessing pool.map does not return from function call

I have a short snippet making the pool.map call to hang up. It does not return in any reasonable amount of time. The idea is to have a couple of point lists and find a measure for the correspondence to another point list.
import numpy as np
import multiprocessing
import scipy.spatial as ss
def dist(args): # returns the sum of distances of the nearest neighbors.
kdSet, points = args
dist, _ = kdSet.query(points)
return np.sum(dist)
#just define some points to play with
points = np.array([[13.27, 25.49], [13.18, 25.39], [13.08, 25.39],
[12.99, 25.39], [12.89, 25.39], [12.80, 25.39],
[12.71, 25.39], [12.61, 25.30], [12.52, 25.30]])
pointList = [points + idx for idx in range(3)] #creates a list of points
#create a list of KDTrees for fast lookup. Add some number to make them a little different from pointList
kdTreeList = [ss.KDTree(pointsLocal + idx/10) for idx, pointsLocal in enumerate(pointList)]
#this part works fine: serial execution
distances = list(map(dist, zip(kdTreeList, pointList)))
print(distances)
#this part hangs, if called as multiprocess, expected the same result as above
with multiprocessing.Pool() as pool:
print('Calling pool.map')
distancesMultiprocess = pool.map(dist, zip(kdTreeList, pointList)) #<-This call does not return, but uses the CPU 100%
print(distancesMultiprocess)
Calling the function sequentially it works fine. But if called in the pool.map function it neither gives an error nor it is returning anything. It just hangs there. The CPU load goes to 100%, so something is happening.
Removing the KDTree class for testing purposes did not show a different result.
Since there is no error thrown, I have no idea whats going wrong here. Any hint?
Thanks a lot to juanpa.arrivillaga
adding
if __name__ == "__main__":
did the trick.

Python Threading inconsistent execution time

Using the threading library to accelerate calculating each point's neighborhood in a points-cloud. By calling function CalculateAllPointsNeighbors at the bottom of the post.
The function receives a search radius, maximum number of neighbors and a number of threads to split the work on. No changes are done on any of the points. And each point stores data in its own np.ndarray cell accessed by its own index.
The following function times how long it takes N number of threads to finish calculating all points neighborhoods:
def TimeFuncThreads(classObj, uptothreads):
listTimers = []
startNum = 1
EndNum = uptothreads + 1
for i in range(startNum, EndNum):
print("Current Number of Threads to Test: ", i)
tempT = time.time()
classObj.CalculateAllPointsNeighbors(searchRadius=0.05, maxNN=25, maxThreads=i)
tempT = time.time() - tempT
listTimers.append(tempT)
PlotXY(np.arange(startNum, EndNum), listTimers)
The problem is, I've been getting very different results in each run. Here are the plots from 5 subsequent runs of the function TimeFuncThreads. The X axis is number of threads, Y is the runtime. First thing is, they look totally random. And second, there is no significant acceleration boost.
I'm confused now whether I'm using the threading library wrong and what is this behavior that I'm getting?
The function that handles the threading and the function that is being called from each thread:
def CalculateAllPointsNeighbors(self, searchRadius=0.20, maxNN=50, maxThreads=8):
threadsList = []
pointsIndices = np.arange(self.numberOfPoints)
splitIndices = np.array_split(pointsIndices, maxThreads)
for i in range(maxThreads):
threadsList.append(threading.Thread(target=self.GetPointsNeighborsByID,
args=(splitIndices[i], searchRadius, maxNN)))
[t.start() for t in threadsList]
[t.join() for t in threadsList]
def GetPointsNeighborsByID(self, idx, searchRadius=0.05, maxNN=20):
if isinstance(idx, int):
idx = [idx]
for currentPointIndex in idx:
currentPoint = self.pointsOpen3D.points[currentPointIndex]
pointNeighborhoodObject = self.GetPointNeighborsByCoordinates(currentPoint, searchRadius, maxNN)
self.pointsNeighborsArray[currentPointIndex] = pointNeighborhoodObject
self.__RotatePointNeighborhood(currentPointIndex)
It pains me to be the one to introduce you to the Python Gil. Is a very nice feature that makes parallelism using threads in Python a nightmare.
If you really want to improve your code speed, you should be looking at the multiprocessing module

Python Multiprocessing Increasing Time delay using pool

I have to solve a complex network optimization problem using a heuristic algorithm (e.g. ant algorithm). This algorithm is decomposed in two steps: 1.) Calculate new solutions using an random component, 2.) Evaluate new Solutions. These two parts are very highly time-consuming and solved the problem parallel using multiprocessing in subprograms. With increasing number of iteration the time duration of the steps increases very fast. I localized the time delay between the initialization of the parallel processes (labels timeMainCalculate and timeMainEvaluate) and the start of the first subprogram (labels timeSubCalculate and timeSubEvaluate). In the first iteration the time difference timeMainCalculate-timeSubCalculate respectively timeMainEvaluate-timeSubEvaluate is nearly 0, after 100 iterations it is about 10 seconds for both steps and after 200 steps the time difference is about 20. This time difference is linear increasing. The time duration for calculation and evaluation in the subprograms is constant. So it might be a problem in the communication between the main program and the subprograms using multiprocessing. Pool.
For your Information: I’m using Python 3.3 on a eight core computer.
opt_heuristic.py:
import multiprocessing.Pool
import datetime
import calculate, evaluate
epsilon = 1e-10
nbOfCpusForParallel = 6
nbCalculation = 6
def calculate_bound_update_information(result):
Do_some_calculation using result
return [bound,x,y,z]
if __name__ == '__main__':
Inititalize x,y,z
while bound > epsilon:
# Calculate new Solution
pool = multiprocessing.Pool(processes=nbOfCpusForParallel)
result_parallel = list()
for i in range(nbCalculation):
result_parallel.append(pool.apply_async(calculate.main,[x,y,z]))
timeMainCalculate = datetime.datetime.now()
pool.close()
pool.join()
resultCalculation = [result_parallel[i].get() for i in range(nbCalculation)]
# Evaluate Solutions
pool = multiprocessing.Pool(processes=nbOfCpusForParallel)
argsEvalute = [[resultCalculation[i][0],resultCalculation[i][1]] for i in range(len(resultCalculation))]
result_evaluate = list()
for i in range(len(resultCalculation)):
result_evaluate.append(pool.apply_async(evaluate.main,argsEvalute[i]))
timeMainEvaluate = datetime.datetime.now()
pool.close()
pool.join()
resultEvaluation = [result_evaluate[i].get() for i in range(len(resultCalculation))]
[bound,x,y,z] = calculate_bound_update_information(resultEvaluation)
calculate.py:
import datetime
def main(x,y,z):
timeSubCalculate = datetime.datetime.now()
Do some random calculation using x,y,z
return result
evaluate.py
import datetime
def main(x,y):
timeSubEvaluate = datetime.datetime.now()
Do some evaluation using x,y
return result
I seems to me that the main program store some information of the parallel process. I tried some things like delete the pool variable but it was not successful.
Has somebody an idea what's the technical problem and how it could be solved? Thanks.

Categories

Resources