2 votes

Pourquoi le temps de cycle augmente-t-il continuellement lorsque l'on utilise GEKKO avec le serveur de résolution APM linux ?

J'utilise GEKKO pour étudier l'effet du MPC et du MHE sur la consommation d'énergie des bâtiments. Pour obtenir une augmentation des performances, je suis passé à un serveur de résolution dédié en configurant m.GEKKO(remote=True, server='http://10.0.0.10') . Ce serveur est une machine Ubuntu 20.04.1 fraîchement installée qui héberge uniquement le serveur linux APmonitor. Tout fonctionne bien jusqu'à présent, sauf que mes temps de cycle de contrôle et d'estimation augmentent linéairement avec chaque résolution supplémentaire pour l'option de résolution à distance. J'utilise mon modèle de construction avec IMODE=6 pour les PPM et IMODE=5 pour MHE et les deux montrent le même comportement.

La figure suivante montre les temps de cycle et les temps de résolution pour la résolution locale et la résolution à distance. Ces tests ont été effectués avec le solveur IPOPT MA57, mais d'autres montrent le même comportement. Mon programme ne change pas, sauf pour passer de remote=False sur mon serveur de résolution remote=True, server='http://10.0.0.10' .

Figure of increased cycle time while solving time stays constantly low

En outre, j'ai ajouté la sortie du diagnostic temporel du solveur après quelques étapes (à gauche) et après quelques centaines d'étapes (à droite). Elle montre clairement un temps système beaucoup plus élevé mais un temps de résolution très similaire, mais je n'ai pas pu trouver le coupable ici non plus. À l'exception de ce test, j'ai toujours défini DIAGLEVEL=0 y m.solve(disp=False) pour réduire la sortie de la console.

Timing diagnosis output

Cependant, la réinitialisation du modèle GEKKO et le redémarrage immédiat font chuter les temps de cycle. Cela montre qu'il ne s'agit pas d'un problème de réduction de la capacité de calcul du serveur au fil du temps. Pour moi, il semble qu'un fichier que le processus lit et/ou écrit gonfle avec le nombre d'itérations, mais je n'ai rien trouvé d'important dans le répertoire du modèle actuel. Peut-être que quelqu'un connaît le problème et peut m'aider.

Editer 1 :

En essayant l'exemple script fourni par John Hedengren dans sa réponse, j'ai obtenu un résultat différent. L'image suivante montre à nouveau le même comportement d'augmentation linéaire. J'ai effectué ce test avec une machine physique différente, en utilisant également un adaptateur réseau physique différent au niveau du serveur de résolution. Auparavant, j'avais même changé la machine physique du serveur de résolution. Testé avec les versions 2.7.16, 3.7.7 et 3.8.5 de Python.

Example script output

Pour moi, cela conduit à la conclusion que cette situation n'est pas due à mon application MPC. Elle ne semble pas non plus liée à un problème matériel au niveau du client, du réseau ou du serveur. J'ai l'impression qu'il s'agit d'un problème logiciel au niveau du serveur.

Quelques spécifications ici :

  • Ubuntu 20.04.1
  • Apache 2.4.41
  • PHP 7.4.3
  • APMonitor, version 0.9.2

Editer 2 :

Après avoir utilisé l'exemple de problème de John Hedengrens pour tester plusieurs serveurs de résolution, j'en suis venu à la conclusion que le comportement des temps de cycle croissants n'est pas propre à ma configuration Ubuntu linux. Voici quelques exemples :

  • Serveur APMonitor personnalisé sur CentOS7 avec MA97Solver (LAN) Custom APM on CentOS7

  • Serveur APMonitor sur Windows 10 (LAN) Standard APM on Windows 10

  • Serveur officiel de résolution d'APMonitor (Web) Official APMonitor solving server

    Pour que cela soit plus évident, j'ai supprimé les oulierers dans la suite de l'article. image Official APMonitor solving server (outliers removed)

Dans mon cas, une augmentation du temps de cycle d'environ 1 seconde pour 1000 cycles (pour cet exemple de problème) se produit indépendamment du solveur à distance utilisé (la résolution locale est toujours correcte). L'effet de cette augmentation régulière du temps de cycle n'est pas aussi important si les temps de résolution/cycle sont de toute façon plus longs ou si le nombre de cycles n'est pas assez élevé. Pour mon application, c'est cependant très problématique car je dois exécuter environ 40k cycles aussi vite que possible.

Editer 3 :

Mise en œuvre des modifications apportées à la gekko.py y apm_line.php John Hedengren a suggéré dans sa réponse de résoudre le problème en partie, mais pas entièrement. Il y a toujours une augmentation du temps de cycle. Une fois de plus, un examen plus approfondi et plus long révèle le problème. L'image suivante montre la sortie du test habituel script, cette fois pour les versions mises à jour de gekko.py y apm_line.php un serveur APM linux (Windows a le même comportement) et les étapes 5k. En regardant de très près, vous pouvez même voir cet effet dans le diagramme (1k runs) que John a posté dans son édition de réponse.

Rising cycle times for updated gekko

1voto

John Hedengren Points 1

Voici un exemple de script qui résout 100 cycles avec une résolution à distance (serveur public) ou locale. La résolution à distance (serveur public) se fait sur un serveur Linux avec le solveur IPOPT. La résolution locale se fait sur Windows 10 en utilisant apm.exe . Ces deux problèmes sont résolus avec Python 3.7.

Clock and Solve Time

import numpy as np
from gekko import GEKKO
import matplotlib.pyplot as plt
import time

for ri,r in enumerate([True,False]):
    m = GEKKO(remote=r)
    m.time = np.linspace(0,10,21)
    mass = 500; b = m.Param(value=50); K = m.Param(value=0.8)
    p = m.MV(value=0, lb=0, ub=100); v = m.CV(value=0)
    m.Equation(mass*v.dt() == -v*b + K*b*p)
    m.options.IMODE = 6 #control
    p.STATUS = 1; p.DCOST = 0.1; p.DMAX = 20
    v.STATUS = 1; m.options.CV_TYPE = 2
    v.SP = 40; v.TR_INIT = 1; v.TAU = 5

    s=time.time(); ct=[]; st=[] # cycle time, solve time
    for i in range(100):
        m.solve(disp=False)
        e=time.time(); ct.append(e-s); s=e
        st.append(m.options.SOLVETIME)

    plt.subplot(2,1,1+ri)
    plt.plot(ct,label='clock time')
    plt.plot(st,label='solve time')
    plt.legend()
    if r:
        plt.title('Remote Solve')
    else:
        plt.title('Local Solve')
        plt.xlabel('cycle');
    plt.ylabel('time (sec)')
plt.show()

Il n'y a pas d'augmentation linéaire du temps de résolution dans cet exemple. Il se peut que quelque chose d'autre se produise dans la boucle de résolution de votre application qui donne lieu à une augmentation linéaire du temps de résolution de remote=True . Il peut également s'agir d'un problème de réseau.

Informations provenant de gekko.py

La bibliothèque gekko a des méthodes différentes pour résoudre les problèmes à distance et localement. Lors de la résolution à distance, les fichiers sont créés et envoyés au serveur. Les résultats sont ensuite générés et renvoyés dans le répertoire temporaire local m.path o m._path qui peut être consultée avec m.open_folder() . Une chose à essayer est de chronométrer les étapes de la gekko.py dossier. Il convient également d'observer la taille des fichiers transmis au serveur.

def send_if_exists(extension):
    path = os.path.join(self._path,self._model_name + '.' + extension)
    if os.path.isfile(path):
        with open(path) as f:
            file = f.read()
        cmd(self._server, self._model_name, extension+' '+file)

#clear apm and csv files already on the server
cmd(self._server,self._model_name,'clear apm')
cmd(self._server,self._model_name,'clear csv')

#send model file
with open(os.path.join(self._path,self._model_name + '.apm')) as f:
    model = f.read()
cmd(self._server, self._model_name, ' '+model)
#send csv file
send_if_exists('csv')
#send info file
send_if_exists('info')
#send dbs file
with open(os.path.join(self._path,'measurements.dbs')) as f:
    dbs = f.read()
cmd(self._server, self._model_name, 'option '+dbs)
#solver options
if self.solver_options:
    opt_file=self._write_solver_options()
    cmd(self._server,self._model_name, ' '+opt_file)

#extra files (eg solver.opt, cspline.data)
for f_name in self._extra_files:
    with open(os.path.join(self._path,f_name)) as f:
        extra_file_data = f.read() #read data
        extra_file_data = 'File ' + f_name + '\n' + extra_file_data + 'End File \n'
    cmd(self._server,self._model_name, ' '+extra_file_data)

#solve remotely
response = cmd(self._server, self._model_name, 'solve', disp, debug)

#print APM error message and die
if (debug >= 1) and ('@error' in response):
    raise Exception(response)

#load results
def byte2str(byte):
    if type(byte) is bytes:
        return byte.decode().replace('\r','')
    else:
        return byte

try:
    results = byte2str(get_file(self._server,self._model_name,'results.json'))
    f = open(os.path.join(self._path,'results.json'), 'w')
    f.write(str(results))
    f.close()
    options = byte2str(get_file(self._server,self._model_name,'options.json'))
    f = open(os.path.join(self._path,'options.json'), 'w')
    f.write(str(options))
    f.close()
    if self.options.CSV_WRITE >= 1:
        results = byte2str(get_file(self._server,self._model_name,'results.csv'))
        with open(os.path.join(self._path,'results.csv'), 'w') as f:
            f.write(str(results))
        if self.options.CSV_WRITE >1:
            results_all = byte2str(get_file(self._server,self._model_name,'results_all.csv'))
            with open(os.path.join(self._path,'results_all.csv'), 'w') as f:
                f.write(str(results_all))
except:
    raise ImportError('No solution or server unreachable.\n'+\
                      '  Show errors with m.solve(disp=True).\n'+\
                      '  Try local solve with m=GEKKO(remote=False).')

Si une variable telle que response augmente, certaines opérations sur les chaînes de caractères peuvent prendre plus de temps.

Editer : J'ai essayé le script avec 1000 cycles et il y a une augmentation du temps de cycle pour le serveur distant.

1000 cycles

J'ai vérifié le répertoire du serveur et le problème se situe au niveau du fichier overrides.dbs qui croît à chaque cycle lors de l'utilisation de remote=True .

-rw-r--r--. 1 apache apache  76911 Jan 26 07:43 overrides.dbs
-rw-r--r--. 1 apache apache 119305 Jan 26 07:43 overrides.dbs
-rw-r--r--. 1 apache apache 219745 Jan 26 07:44 overrides.dbs

Au fur et à mesure que ce fichier s'allonge, l'interprétation de la longue liste d'options prend plus de temps. Pour résoudre ce problème, j'ai apporté des modifications à Gekko gekko.py et au fichier du serveur apm_line.php .

Modifications apportées à gekko.py apparaîtra dans la prochaine version de Gekko (au-delà de la 0.2.8) ou dans la version GitHub :

            cmd(self._server,self._model_name,'clear meas')

            cmd(self._server, self._model_name, 'meas '+dbs)

Modifications apportées à apm_line.php également sur GitHub .

        } elseif (strtolower(substr($add, 0, 5))=="meas ") {
                $option = trim(substr($add,5)); // starting at 5th position - extract option
                $fn_opt = $d . "/measurements.dbs";
                if ( !file_exists($fn_opt)) {
                    $meas = fopen ($fn_opt, 'w');
                } else {
                    $meas = fopen ($fn_opt, 'a');
                }
                fwrite ($meas, "\n".$option);
                fclose($meas);
                echo "Successfully added meas: " . $meas;
                fclose($handle);

        } elseif  (strtolower($add)=="clear meas") {
                // clear file contents by opening in write mode
                $fn_csv = $d . "/measurements.dbs";
                $meas_file = fopen ($fn_csv, 'w');
                // write a space to the file to clear contents
                fwrite ($meas_file, " ");
                fclose ($meas_file);

                //$clear = "! Cleared measurements.dbs file contents";
                //fwrite ($handle, "\n".$clear);
                fclose($handle);
                echo "Cleared measurements.dbs file";

Cela permet d'obtenir de meilleurs résultats sans augmenter le temps de travail.

Improved results

Merci pour votre aide dans la recherche de ce bug !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X