Tracé pendant le balayage des paramètres avec parfeval
Cet exemple montre comment effectuer un balayage de paramètres en parallèle avec parfeval
et renvoyer les résultats pendant les calculs avec un objet DataQueue
.
parfeval
ne bloque pas MATLAB, vous pouvez donc continuer à travailler pendant que les calculs ont lieu.
L'exemple effectue un balayage de paramètres sur le système de Lorenz d'équations différentielles ordinaires, sur les paramètres et , et montre la nature chaotique de ce système.
Configurer un environnement parallèle
Créez un pool de threads parallèles en utilisant la fonction parpool
.
parpool("Threads");
Starting parallel pool (parpool) using the 'Threads' profile ... Connected to parallel pool with 6 workers.
Créer une grille de paramètres
Définissez la plage de paramètres que vous souhaitez explorer dans le balayage des paramètres.
gridSize = 40; sigma = linspace(5,45,gridSize); rho = linspace(50,100,gridSize); beta = 8/3;
Créez une grille 2D de paramètres en utilisant la fonction meshgrid
.
[rho,sigma] = meshgrid(rho,sigma);
Effectuer un balayage des paramètres en parallèle
Après avoir défini les paramètres, vous pouvez effectuer le balayage des paramètres en parallèle.
Pour visualiser les résultats intermédiaires du balayage des paramètres, créez un graphique de surface. Notez que l'initialisation du composant Z
de la surface avec NaN
crée un tracé vide.
figure; surface = surf(rho,sigma,NaN(size(sigma))); xlabel('\rho','Interpreter','Tex') ylabel('\sigma','Interpreter','Tex')
Pour envoyer des données intermédiaires à partir des workers, créez un objet DataQueue
. Configurez une fonction qui met à jour le tracé de surface chaque fois qu'un worker envoie des données en utilisant la fonction afterEach
. La fonction updatePlot
est une fonction de support définie à la fin de l'exemple.
Q = parallel.pool.DataQueue; afterEach(Q,@(data) updatePlot(surface,data));
parfeval
fonctionne plus efficacement lorsque vous répartissez la charge de travail. Pour répartir la charge de travail, regroupez les paramètres à explorer dans des partitions. Pour cet exemple, divisez en partitions uniformes de taille step
en utilisant l'opérateur deux points (:
). Le tableau résultant partitions
contient les limites des partitions. Notez que vous devez ajouter le point final de la dernière partition.
step = 100; partitions = [1:step:numel(sigma),numel(sigma)+1]
partitions = 1×17
1 101 201 301 401 501 601 701 801 901 1001 1101 1201 1301 1401 1501 1601
Pour de meilleures performances, essayez de diviser en partitions qui sont :
Assez grand pour que le temps de calcul soit important par rapport à la surcharge liée à la planification de la partition.
Assez petit pour qu'il y ait suffisamment de cloisons pour occuper tous les workers.
Pour représenter les exécutions de fonctions sur des workers parallèles et conserver leurs résultats, utilisez des objets futurs.
f(1:numel(partitions)-1) = parallel.FevalFuture;
Déchargez les calculs vers des workers parallèles en utilisant la fonction parfeval
. parameterSweep
est une fonction d'assistance définie à la fin de ce script qui résout le système de Lorenz sur une partition des paramètres à explorer. Il a un argument de sortie, vous devez donc spécifier 1
comme nombre de sorties dans parfeval
.
for ii = 1:numel(partitions)-1 f(ii) = parfeval(@parameterSweep,1,partitions(ii),partitions(ii+1),sigma,rho,beta,Q); end
parfeval
ne bloque pas MATLAB, vous pouvez donc continuer à travailler pendant que les calculs ont lieu. Les workers calculent en parallèle et envoient les résultats intermédiaires via le DataQueue
dès qu'ils sont disponibles.
Si vous souhaitez bloquer MATLAB jusqu'à ce que parfeval
soit terminé, utilisez la fonction wait
sur les futurs objets. L'utilisation de la fonction wait
est utile lorsque le code suivant dépend de la fin de parfeval
.
wait(f);
Une fois que parfeval
a terminé les calculs, wait
termine et vous pouvez exécuter plus de code. Par exemple, tracez une sélection de solutions du système de Lorenz. Utilisez la fonction fetchOutputs
pour récupérer les résultats stockés dans les objets futurs.
results = fetchOutputs(f); idxs = randperm(numel(results),4); figure for n = 1:numel(idxs) nexttile a = results{idxs(n)}; plot3(a(:,1),a(:,2),a(:,3)) grid on xlabel("x") ylabel("y") zlabel("z") title("Lorenz System Solution", ... "\rho = "+ num2str(rho(idxs(n)),'%5.2f') + " \sigma = "+ num2str(sigma(idxs(n)),'%5.2f'),Interpreter="tex") end
Si votre balayage de paramètres nécessite davantage de ressources de calcul et que vous avez accès à un cluster, vous pouvez augmenter vos calculs parfeval
. Pour plus d'informations, voir Scale Up from Desktop to Cluster.
Définir les fonctions d'assistance
Définir une fonction d'aide qui résout le système de Lorenz sur une partition des paramètres à explorer. Envoyez les résultats intermédiaires au client MATLAB en utilisant la fonction send
sur l'objet DataQueue
.
function results = parameterSweep(first,last,sigma,rho,beta,Q) results = cell(last-first,1); for ii = first:last-1 lorenzSystem = @(t,a) [sigma(ii)*(a(2) - a(1)); a(1)*(rho(ii) - a(3)) - a(2); a(1)*a(2) - beta*a(3)]; [t,a] = ode45(lorenzSystem,[0 100],[1 1 1]); send(Q,[ii,a(end,3)]); results{ii-first+1} = a; end end
Définissez une autre fonction d’assistance qui met à jour le tracé de surface lorsque de nouvelles données arrivent.
function updatePlot(surface,data) surface.ZData(data(1)) = data(2); drawnow('limitrate'); end
Voir aussi
parpool
| parallel.pool.DataQueue
| afterEach
| parfeval