{"id":1061,"date":"2017-10-11T08:02:57","date_gmt":"2017-10-11T08:02:57","guid":{"rendered":"http:\/\/blog.tiran.info\/?p=1061"},"modified":"2017-10-11T08:02:57","modified_gmt":"2017-10-11T08:02:57","slug":"annore-4","status":"publish","type":"post","link":"https:\/\/blog.tiran.stream\/?p=1061","title":{"rendered":"ANN\/ORE #4 &#8211; Performance de neuralnet"},"content":{"rendered":"<p style=\"text-align: justify;\">On a vu dans le <a href=\"http:\/\/blog.tiran.info\/annore-3\">billet pr\u00e9c\u00e9dent<\/a> que la construction du mod\u00e8le avec le package <a href=\"https:\/\/cran.r-project.org\/web\/packages\/neuralnet\/\" target=\"_blank\" rel=\"noopener\">neuralnet<\/a> \u00e9tait consid\u00e9rablement plus rapide qu&rsquo;avec <a href=\"https:\/\/cran.r-project.org\/web\/packages\/nnet\/\" target=\"_blank\" rel=\"noopener\">nnet<\/a>.<\/p>\n<p style=\"text-align: justify;\">Cette diff\u00e9rence m&rsquo;a intrigu\u00e9 dans la mesure ou les deux packages doivent fonctionner &#8211; \u00e0 priori &#8211; selon une logique similaire: gradient de descente, forward et back propagation&#8230;<\/p>\n<p style=\"text-align: justify;\">En observant le profil de charge de la machine \u00e0 l&rsquo;aide de la commande top pendant la phase de construction du mod\u00e8le, j&rsquo;ai rapidement compris l&rsquo;origine de la diff\u00e9rence. En effet, il appara\u00eet que l&rsquo;impl\u00e9mentation de neuralnet est <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Thread_(informatique)\" target=\"_blank\" rel=\"noopener\">multithread\u00e9<\/a> contrairement \u00e0 celle de nnet:<\/p>\n<p style=\"text-align: justify;\"><a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/top_extproc.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1064 size-full alignleft\" src=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/top_extproc.png\" alt=\"\" width=\"605\" height=\"50\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">Dans un contexte ORE, cela signifie que le processus extproc instancie plusieurs threads qui op\u00e8rent en parall\u00e8le. Le champ int\u00e9ressant ici est <a href=\"http:\/\/man7.org\/linux\/man-pages\/man1\/ps.1.html#THREAD_DISPLAY\" target=\"_blank\" rel=\"noopener\">nlwp<\/a> qui indique le nombre de threads du processus extproc:<\/p>\n<p style=\"text-align: justify;\"><a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/extproc_ps.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1063 size-full alignleft\" src=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/extproc_ps.png\" alt=\"\" width=\"874\" height=\"67\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">Le script de collecte (rudimentaire!) suivant a donc \u00e9t\u00e9 lanc\u00e9 pendant la construction des mod\u00e8les avec nnet et neuralnet (fichiers <a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/extproc_nnet.txt\">extproc_nnet<\/a> et <a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/extproc_neuralnet.txt\">extproc_neuralnet<\/a>).<\/p>\n<pre class=\"brush: bash; ruler: true;\">$ cat extproc_ps.sh\n#!\/bin\/bash\n\n&gt;extproc.txt\n\nwhile true\ndo\n        date &gt;&gt;extproc.txt\n        ps -C extproc -o pid,rss,vsz,time,nlwp &gt;&gt;extproc.txt\n        sleep 30\ndone\n\n$\n<\/pre>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">Les donn\u00e9es collect\u00e9es ont \u00e9t\u00e9 exploit\u00e9es \u00e0 l&rsquo;aide d&rsquo;une table externe:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; CREATE OR REPLACE DIRECTORY d1 AS &#039;\/tmp&#039;;\n\nDirectory created.\n\nSQL&gt;\nSQL&gt; CREATE TABLE exttab_extproc\n  2  (\n  3      line VARCHAR2 (300)\n  4  )\n  5  ORGANIZATION EXTERNAL\n  6      (TYPE oracle_loader\n  7       DEFAULT DIRECTORY D1\n  8       ACCESS PARAMETERS (\n  9           RECORDS DELIMITED BY NEWLINE\n 10       )\n 11       LOCATION (&#039;extproc_neuralnet.txt&#039;));\n\nTable created.\n\nSQL&gt;\nSQL&gt;\nSQL&gt; SELECT * FROM exttab_extproc FETCH FIRST 5 ROWS ONLY;\n\nLINE\n----------------------------------------------------------\nTue Sep 12 11:21:35 CEST 2017\n  PID   RSS    VSZ     TIME NLWP\n 9161 51024 362776 00:00:00    1\nTue Sep 12 11:22:05 CEST 2017\n  PID   RSS    VSZ     TIME NLWP\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">La mise en forme est ensuite r\u00e9alis\u00e9e \u00e0 l&rsquo;aide de d&rsquo;<a href=\"https:\/\/docs.oracle.com\/database\/121\/SQLRF\/functions164.htm#SQLRF06303\" target=\"_blank\" rel=\"noopener\">expressions r\u00e9guli\u00e8res<\/a> et de <a href=\"https:\/\/docs.oracle.com\/database\/121\/SQLRF\/statements_10002.htm#BABCGAAJ\" target=\"_blank\" rel=\"noopener\">CTE<\/a>. Le r\u00e9sultat est pr\u00e9sent\u00e9 via une vue:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; CREATE OR REPLACE VIEW evol_process_extproc\n  2  AS\n  3      WITH\n  4          procres\n  5          AS\n  6              (SELECT ROWNUM                                        rn,\n  7                      REGEXP_REPLACE (line, &#039;[[:space:]]{2,}&#039;, &#039; &#039;) line\n  8                 FROM exttab_extproc\n  9                WHERE line NOT LIKE &#039;%PID%RSS%&#039;),\n 10          procres_evol\n 11          AS\n 12              (SELECT line,\n 13                      TRIM (LEAD (line) OVER (PARTITION BY NULL ORDER BY rn))\n 14                          next_line\n 15                 FROM procres)\n 16      SELECT TO_DATE (REPLACE (line, &#039; CEST &#039;, &#039; &#039;),\n 17                      &#039;Dy Mon DD HH24:MI:SS YYYY&#039;)\n 18                 dt,\n 19             REGEXP_SUBSTR (next_line,\n 20                            &#039;(.*?)([[:space:]]|$)&#039;,\n 21                            1,\n 22                            1,\n 23                            NULL,\n 24                            1)\n 25                 pid,\n 26             REGEXP_SUBSTR (next_line,\n 27                            &#039;(.*?)([[:space:]]|$)&#039;,\n 28                            1,\n 29                            2,\n 30                            NULL,\n 31                            1)\n 32                 rss,\n 33             REGEXP_SUBSTR (next_line,\n 34                            &#039;(.*?)([[:space:]]|$)&#039;,\n 35                            1,\n 36                            3,\n 37                            NULL,\n 38                            1)\n 39                 vsz,\n 40               (  TO_DATE (REGEXP_SUBSTR (next_line,\n 41                                          &#039;(.*?)([[:space:]]|$)&#039;,\n 42                                          1,\n 43                                          4,\n 44                                          NULL,\n 45                                          1),\n 46                           &#039;HH24:MI:SS&#039;)\n 47                - TRUNC (TO_DATE (&#039;00:00&#039;, &#039;HH24:MI&#039;)))\n 48             * 86400\n 49                 cpusec,\n 50             REGEXP_SUBSTR (next_line,\n 51                            &#039;(.*?)([[:space:]]|$)&#039;,\n 52                            1,\n 53                            5,\n 54                            NULL,\n 55                            1)\n 56                 nlwp\n 57        FROM procres_evol\n 58       WHERE next_line NOT LIKE &#039;%2017&#039;;\n\nView created.\n\nSQL&gt;\nSQL&gt; column NLWP format a5\nSQL&gt; column PID format a8\nSQL&gt; column RSS format a10\nSQL&gt; column VSZ format a10\nSQL&gt;\nSQL&gt; SELECT * FROM evol_process_extproc FETCH FIRST 10 ROWS ONLY;\n\nDT                PID      RSS        VSZ            CPUSEC NLWP\n----------------- -------- ---------- ---------- ---------- -----\n12\/09\/17 11:21:35 9161     51024      362776              0 1\n12\/09\/17 11:22:05 9161     51024      362776              0 1\n12\/09\/17 11:22:35 9161     51024      362776              0 1\n12\/09\/17 11:23:05 9161     51024      362776              0 1\n12\/09\/17 11:23:35 9161     51024      362776              0 1\n12\/09\/17 11:24:05 9161     200128     529856              7 1\n12\/09\/17 11:24:35 9161     1803592    2132512            35 1\n12\/09\/17 11:25:05 9161     2869720    4926496           164 25\n12\/09\/17 11:25:35 9161     3903716    5960336           499 25\n12\/09\/17 11:26:05 9161     3676520    5733096           785 25\n\n10 rows selected.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Finalement, la requ\u00eate suivante (bas\u00e9e sur des <a href=\"https:\/\/docs.oracle.com\/database\/121\/SQLRF\/functions004.htm#SQLRF06174\" target=\"_blank\" rel=\"noopener\">fonctions analytiques<\/a>) est utilis\u00e9e pour calculer le nombre de threads actifs (champ AAT) par p\u00e9riode d&rsquo;\u00e9chantillonnage:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt;   SELECT dt,\n  2           nlwp,\n  3           vsz,\n  4           rss,\n  5           ROUND (cpusec \/ elaps, 1) aat\n  6      FROM (SELECT dt,\n  7                   86400 * (dt - LAG (dt) OVER (PARTITION BY NULL ORDER BY dt))\n  8                       elaps,\n  9                   cpusec - LAG (cpusec) OVER (PARTITION BY NULL ORDER BY dt)\n 10                       cpusec,\n 11                   nlwp,\n 12                   vsz,\n 13                   rss\n 14              FROM evol_process_extproc)\n 15  ORDER BY dt\n 16  FETCH FIRST 10 ROWS ONLY;\n\nDT                NLWP  VSZ        RSS               AAT\n----------------- ----- ---------- ---------- ----------\n12\/09\/17 11:21:35 1     362776     51024\n12\/09\/17 11:22:05 1     362776     51024               0\n12\/09\/17 11:22:35 1     362776     51024               0\n12\/09\/17 11:23:05 1     362776     51024               0\n12\/09\/17 11:23:35 1     362776     51024               0\n12\/09\/17 11:24:05 1     529856     200128             .2\n12\/09\/17 11:24:35 1     2132512    1803592            .9\n12\/09\/17 11:25:05 25    4926496    2869720           4.3\n12\/09\/17 11:25:35 25    5960336    3903716          11.2\n12\/09\/17 11:26:05 25    5733096    3676520           9.5\n\n10 rows selected.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">On peut alors repr\u00e9senter \u00e0 l&rsquo;aide de <a href=\"http:\/\/ggplot2.org\/\" target=\"_blank\" rel=\"noopener\">ggplot2<\/a>, le profil d&rsquo;activit\u00e9 des threads lors de la construction du mod\u00e8le:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; library(ROracle)\nLoading required package: DBI\n&gt; ora = Oracle()\n&gt; cnx = dbConnect(ora, username=&quot;c##rafa&quot;, password=&quot;Password1#&quot;, dbname=&quot;\/\/clorai2-scan:1521\/pdb_hodba08&quot;)\n&gt; evol_cpu_mem &lt;- dbGetQuery(cnx, &quot;  SELECT dt,\n+          nlwp,\n+          vsz,\n+          rss,\n+          ROUND (cpusec \/ elaps, 1) aat\n+     FROM (SELECT dt,\n+                  86400 * (dt - LAG (dt) OVER (PARTITION BY NULL ORDER BY dt))\n+                      elaps,\n+                  cpusec - LAG (cpusec) OVER (PARTITION BY NULL ORDER BY dt)\n+                      cpusec,\n+                  nlwp,\n+                  vsz,\n+                  rss\n+             FROM evol_process_extproc)\n+ ORDER BY dt&quot;)\n&gt; \n&gt; library(ggplot2)\n&gt; \n&gt; evol_cpu_mem$couleur &lt;- ifelse(evol_cpu_mem$AAT==0, &quot;blue&quot;, \n+                                ifelse(evol_cpu_mem$AAT&lt;0.7, &quot;forestgreen&quot;,\n+                                       ifelse(evol_cpu_mem$AAT == 1, &quot;darkorange&quot;, &quot;red&quot;)\n+                                       )\n+                                )\n&gt; \n&gt; ggplot(evol_cpu_mem[-1,], aes(DT, AAT)) +\n+   geom_point(color=evol_cpu_mem$couleur[-1]) +\n+   geom_line(color=evol_cpu_mem$couleur[-1])  +   \n+   xlab(&quot;Heure&quot;) + \n+   ylab(&quot;Nombre moyen de threads actifs&quot;) +   \n+   theme_classic() +   \n+   ggtitle(&quot;Activit\u00e9 des threads lors de la construction du mod\u00e8le&quot;) +\n+   theme(plot.title = element_text(hjust = 0.5)) +\n+   theme(panel.grid.major = element_line(linetype = &quot;dotted&quot;)) + \n+   scale_y_continuous(breaks = seq(0, 12),limits = c(0,11.5))\n&gt; \n<\/pre>\n<p style=\"text-align: justify;\">Le graphique obtenu est coloris\u00e9 en fonction du niveau d&rsquo;activit\u00e9 des threads. On constate que le profil n&rsquo;est pas uniforme, en particulier ce n&rsquo;est pas la totalit\u00e9 de la construction du mod\u00e8le qui donne lieu \u00e0 une activit\u00e9 multithread\u00e9e :<\/p>\n<ul>\n<li style=\"text-align: justify;\">en rouge, plusieurs threads du processus extproc sont actifs simultan\u00e9ment (une dizaine en moyenne pendant 25 minutes).<\/li>\n<li style=\"text-align: justify;\">en orange, le processus extproc op\u00e8re en mode monothread (~20 minutes).<\/li>\n<li style=\"text-align: justify;\">en vert, le processus est peu actif (~7 minutes) mais une activit\u00e9 r\u00e9siduelle subsiste. Il doit s&rsquo;agir de la phase finale de communication entre extproc et l&rsquo;instance Oracle.<\/li>\n<li style=\"text-align: justify;\">en bleu, le processus est inactif.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/neuralnet_threads.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1079 size-full\" src=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2017\/10\/neuralnet_threads.png\" alt=\"\" width=\"757\" height=\"705\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">A titre de comparaison, si j&rsquo;avais trac\u00e9 un graphique similaire pour la construction du mod\u00e8le avec nnet, le profil aurait \u00e9t\u00e9 tr\u00e8s diff\u00e9rent. L&rsquo;impl\u00e9mentation n&rsquo;\u00e9tant pas multithread\u00e9e, on aurait eu une ligne de charge continue correspondant \u00e0 l&rsquo;activit\u00e9 du processus extproc monothread\u00e9 (\u00e9quivalent de ligne orange ci-dessus).<\/p>\n<p style=\"text-align: justify;\">Cela explique le gain de performance dans la construction de l&rsquo;ANN avec le package neuralnet. N\u00e9anmoins, il subsiste le probl\u00e8me de r\u00e9utilisation de ce mod\u00e8le un fois qu&rsquo;il a \u00e9t\u00e9 sauvegard\u00e9 dans un datastore ORE. Ce sera l&rsquo;objet du prochain billet!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On a vu dans le billet pr\u00e9c\u00e9dent que la construction du mod\u00e8le avec le package neuralnet \u00e9tait consid\u00e9rablement plus rapide<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[2,9],"tags":[],"class_list":["post-1061","post","type-post","status-publish","format-standard","hentry","category-ann","category-oracle-r-enterprise"],"_links":{"self":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/1061","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1061"}],"version-history":[{"count":0,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/1061\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1061"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1061"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1061"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}