{"id":4205,"date":"2020-08-24T20:35:33","date_gmt":"2020-08-24T18:35:33","guid":{"rendered":"https:\/\/mribeirodantas.xyz\/blog\/?p=4205"},"modified":"2025-01-31T04:37:50","modified_gmt":"2025-01-31T02:37:50","slug":"continuous-machine-learning-parte-i","status":"publish","type":"post","link":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/","title":{"rendered":"Continuous Machine Learning \u2013 Parte I"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\"><b>Reading time: <\/span> <span class=\"rt-time\"> 11<\/span> <span class=\"rt-label rt-postfix\">minutes<\/b><\/span><\/span>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"523\" data-attachment-id=\"3972\" data-permalink=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/10\/continuous-machine-learning\/mlops\/\" data-orig-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?fit=1470%2C1202&amp;ssl=1\" data-orig-size=\"1470,1202\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"MLOps\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?fit=300%2C245&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?fit=640%2C523&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?resize=640%2C523&#038;ssl=1\" alt=\"\" class=\"wp-image-3972\" srcset=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?resize=1024%2C837&amp;ssl=1 1024w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?resize=300%2C245&amp;ssl=1 300w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?resize=768%2C628&amp;ssl=1 768w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?w=1470&amp;ssl=1 1470w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><figcaption>Image by <a href=\"https:\/\/medium.com\/@taras_tymoshchuck?source=post_page-----c52b49af38c9----------------------\">Taras Tymoshchuck<\/a> from <a href=\"https:\/\/medium.com\/datadriveninvestor\/mlops-practices-and-its-benefits-c52b49af38c9\">here<\/a>.<\/figcaption><\/figure>\n\n\n\n<p>Esse texto faz parte de uma s\u00e9rie de 3 partes sobre Continuous Machine Learning. Voc\u00ea pode checar a parte II aqui e a parte III aqui.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">O que \u00e9 isso?<\/h2>\n\n\n\n<p>Continuous Machine Learning (<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>) segue o mesmo conceito de <a href=\"https:\/\/en.wikipedia.org\/wiki\/CI\/CD\">Continuous Integration and Continuous Delivery (CI\/CD)<\/a>, famosos concenitos da <span id=\"wiki-tooltip-1\" data-tooltip-content=\"#wiki-tooltip-box-1\" data-wiki_num=\"1\" data-wiki_id=\"27010\" data-wiki_title=\"Software engineering\" data-wiki_section=\"\" data-wiki_base_url=\"https:\/\/en.wikipedia.org\/w\/api.php\" data-wiki_url=\"https:\/\/en.wikipedia.org\/wiki\/Software_engineering\" data-wiki_thumbnail=\"default\"><a class=\"wiki-tooltip\" href=\"https:\/\/en.wikipedia.org\/wiki\/Software_engineering\" target=\"_blank\" rel=\"noopener noreferrer\" onclick=\"return isClickEnabled( 'hover', 'none' );\">Software Engineering<\/a><\/span> \/ <span id=\"wiki-tooltip-2\" data-tooltip-content=\"#wiki-tooltip-box-2\" data-wiki_num=\"2\" data-wiki_id=\"27488100\" data-wiki_title=\"DevOps\" data-wiki_section=\"\" data-wiki_base_url=\"https:\/\/en.wikipedia.org\/w\/api.php\" data-wiki_url=\"https:\/\/en.wikipedia.org\/wiki\/DevOps\" data-wiki_thumbnail=\"default\"><a class=\"wiki-tooltip\" href=\"https:\/\/en.wikipedia.org\/wiki\/DevOps\" target=\"_blank\" rel=\"noopener noreferrer\" onclick=\"return isClickEnabled( 'hover', 'none' );\">DevOps<\/a><\/span>, mas aplicado a projetos de Aprendizado de M\u00e1quina e Ci\u00eancia de Dados.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">O que vou aprender com esse post?<\/h2>\n\n\n\n<p>Eu irei abordar aqui um conjunto de ferramentas que podem fazer sua vida como Cientista de Dados muito mais interessante. N\u00f3s utilizaremos o <a href=\"http:\/\/github.com\/miicTeam\/miic_R_package\" target=\"_blank\" rel=\"noreferrer noopener\">MIIC<\/a>, um algoritmo de infer\u00eancia de redes causais, para inferir a rede de um famoso <em>dataset<\/em> (<a href=\"https:\/\/rdrr.io\/cran\/bnlearn\/man\/alarm.html\" target=\"_blank\" rel=\"noreferrer noopener\">alarm do pacote bnlearn<\/a>). A ideia \u00e9 utilizar (1) o <a href=\"https:\/\/git-scm.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">git<\/a> para versionar nosso c\u00f3digo, (2) o <a href=\"https:\/\/dvc.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">DVC<\/a> para versionar nosso <em>dataset<\/em>, arquivos de sa\u00edde e at\u00e9 o <em>pipeline<\/em>! (3) Utilizaremos o <a href=\"http:\/\/github.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a> como <em>git remote<\/em> e (4) o <a href=\"http:\/\/drive.google.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Google Drive<\/a> como <em>DVC remote<\/em>. Pense nos <em>remotes<\/em> como tendo uma c\u00f3pia do seu reposit\u00f3rio remotamente, em um outro computador. Eu tamb\u00e9m escrevi um tutorial sobre gerenciamento de projetos de ci\u00eancia de dados com o DVC e se voc\u00ea estiver interessado, <a href=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/03\/05\/r-dvc-and-rmarkdown\/\" target=\"_blank\" rel=\"noreferrer noopener\">clique aqui para abrir o tutorial em uma nova aba<\/a> para voc\u00ea l\u00ea-lo depois.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Uma coias que me incomoda um pouco \u00e9 frequentemente ter que abrir a p\u00e1gina do GitHub e utilizar a interface deles. \u00c9 muito mais pr\u00e1tico poder fazer tudo pelo terminar e aqui vou te apresentar o <a href=\"https:\/\/github.com\/cli\/cli\">gh<\/a>, a aplica\u00e7\u00e3o de linha de comando oficiial do GitHub. Tamb\u00e9m iremos utilizar o <a href=\"https:\/\/cml.dev\/\" target=\"_blank\" rel=\"noreferrer noopener\"><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span><\/a>, uma biblioteca <em>open source<\/em> para implementar <em>continuous integration &amp; delivery<\/em> (CI\/CD) em projetos de aprendizagem de m\u00e1quina. O <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> ir\u00e1 conectar o git, DVC e <em>GitHub Actions<\/em> (Sistema de CI\/CD <em>built-in<\/em> do GitHub). A ideia \u00e9 criar um gatilho que ser\u00e1 disparado toda vez que voc\u00ea fizer uma determinada a\u00e7\u00e3o no seu reposit\u00f3rio, como um <em>push<\/em>. Essa a\u00e7\u00e3o pode ser processamento, qualquer tipo de computa\u00e7\u00e3o, e ir\u00e1 por padr\u00e3o acontecer em um GitHub Runner (Esse \u00e9 o nome que o GitHub da a uma m\u00e1quina virtual na infraestrutura deles. Veja mais sobre isso <a href=\"https:\/\/docs.github.com\/en\/actions\/reference\/virtual-environments-for-github-hosted-runners\">aqui<\/a>). Um exemplo seria utilizar <em>branches<\/em> do git como experimentos no seu projeto de ci\u00eancia de dados. Imagine executar seu c\u00f3digo uma vez, alterar algum par\u00e2metro do algoritmo, execut\u00e1-lo novamente, mais uma altera\u00e7\u00e3o qui e outra ali e assim por diante at\u00e9 voc\u00ea ter v\u00e1rias <em>branches<\/em> e experimentos. Toda vez que voc\u00ea der um <em>git push<\/em>, por exemplo, um GitHub Runner poderia ser acionado para comparar as m\u00e9tricas desse experimento com os outros e imprimir na tela (como um coment\u00e1rio na p\u00e1gina do <em>Pull Request<\/em>) um relat\u00f3rio. Parece legal, n\u00e9?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hora de arrega\u00e7ar as mangas<\/h2>\n\n\n\n<p>Vamos criar nosso reposit\u00f3rio no GitHub e fazer uma c\u00f3pia local dele. Faremos isso a partir da linha de comando! (Instru\u00e7\u00f5es <a href=\"https:\/\/github.com\/cli\/cli\">aqui<\/a> de como instalar o gh).<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4123\" data-id=\"4123\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4123\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-1\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 1\">mkdir $HOME\/dev\r\ncd dev\r\ngh repo create dvc-miic-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> -d 'GitHub repo to play with DVC, MIIC and <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>' --public<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Voc\u00ea ser\u00e1 perguntado se deseja criar uma c\u00f3pia local do reposit\u00f3rio. Se voc\u00ea disser n\u00e3o, voc\u00ea ter\u00e1 que clonar o reposit\u00f3rio mais tarde, portanto responda com <strong>Y<\/strong> e pressione <em>enter<\/em>. Ap\u00f3s isso, entre no diret\u00f3rio.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4124\" data-id=\"4124\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4124\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-2\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 2\">cd dvc-miic-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span><\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Vamos criar um arquivo LEIAME, onde iremos colocar uma descri\u00e7\u00e3o do nosso reposit\u00f3rio. No GitHub isso costuma ser colocado em um arquio chamado README.md, escrito com formata\u00e7\u00e3o <a href=\"https:\/\/github.com\/adam-p\/markdown-here\/wiki\/Markdown-Cheatsheet\" target=\"_blank\" rel=\"noreferrer noopener\">Markdown<\/a>.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4125\" data-id=\"4125\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4125\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-3\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 3\">echo '# DVC-MIIC-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>' &gt; README.md\r\necho 'This is a sample repository for testing DVC, MIIC and <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> in GitHub.' &gt;&gt; README.md\r\necho 'The analyses will be performed using [MIIC](https:\/\/github.com\/miicTeam\/miic_R_package) to infer the network from the [alarm dataset](https:\/\/rdrr.io\/cran\/bnlearn\/man\/alarm.html).' &gt;&gt; README.md<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Tamb\u00e9m iremos fazer o <em>download<\/em> de um arquivo de licen\u00e7a (GNU GPLv3) a partir do site do projeto <a href=\"http:\/\/gnu.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">GNU<\/a> e salv\u00e1-lo como um arquivo chamado LICENSE, como costuma ser feito em reposit\u00f3rios no GitHub.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4126\" data-id=\"4126\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4126\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-4\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 4\">wget -c https:\/\/www.gnu.org\/licenses\/gpl-3.0.txt -O LICENSE<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ap\u00f3s isso, iremos adicionar esses dois novos arquivos para o \u00edndice (<em>index<\/em>) do nosso reposit\u00f3rio git atrav\u00e9s do comando <code>git add<\/code> e ap\u00f3s isso fazer um <em>commit<\/em> do estado atual do reposit\u00f3rio (uma esp\u00e9cie de <em>snapshot<\/em>, caso voc\u00ea n\u00e3o tenha o <em>workflow<\/em> \/ linguajar do git na ponta da l\u00edngua). Com o <em>commit<\/em> realizado, iremos enviar o estado atual do reposit\u00f3rio para o remote no GitHub atrav\u00e9s do comando <code>git push<\/code>. Desse modo, qualquer pessoa que solicite uma c\u00f3pia atual do reposit\u00f3rio para o GitHub, receber\u00e1 tamb\u00e9m as nossas modifica\u00e7\u00f5es. Como essa \u00e9 a primeira vez que estamos dando um <code>git push<\/code>, precisamos informar ao git quem \u00e9 a <em>branch<\/em> principal, padr\u00e3o, do nosso reposit\u00f3rio. Faremos isso atrav\u00e9s do par\u00e2metro <em><code>--set-upstream<\/code><\/em>. No futuro, quando quisermos dar um novo <code>git push<\/code>, n\u00e3o precisaremos desse par\u00e2metro. Apenas <code>git push<\/code> ser\u00e1 suficiente.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4127\" data-id=\"4127\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4127\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-5\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 5\"># The dot when provided to git add means everything in the current folder\r\ngit add .\r\ngit commit -m 'Initial commit'\r\ngit push --set-upstream origin master<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Voc\u00ea pode checar o seu reposit\u00f3rio no GitHub agora. Ele deve estar atualizado! O <a href=\"https:\/\/github.com\/mribeirodantas\/dvc-miic-cml\/tree\/72e420f47300d998d02e85b35df869c911a2b740\" target=\"_blank\" rel=\"noreferrer noopener\">meu est\u00e1<\/a>! O git n\u00e3o foi feito para versionar datasets e arquivos grandes, nem muito menos pipelines. \u00c9 nessa lacuna que o DVC cai como uma luva. Vamos come\u00e7ar a utiliz\u00e1-lo para versionar o <em>dataset<\/em> que iremos analisar. Voc\u00ea pode baixar o <em>dataset<\/em> alarm atrav\u00e9s do site oficial do MIIC clicando <a href=\"https:\/\/miic.curie.fr\/datasets\/alarm1000samples.txt\">aqui<\/a>. Na linha de comando, voc\u00ea deve digitar:<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4128\" data-id=\"4128\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4128\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-6\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 6\">wget -c https:\/\/miic.curie.fr\/datasets\/alarm1000samples.txt -O alarm.tsv<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Eu particularmente n\u00e3o gosto quando os reposit\u00f3rios git s\u00e3o u amontoado de arquivos jogados na base do diret\u00f3rio. Prefiro organizar em sub diret\u00f3rios. Vamos fazer isso.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4129\" data-id=\"4129\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4129\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-7\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 7\">mkdir data\r\nmv alarm.tsv data\/<\/pre>\n\t\t\t<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">O DVC entra em cena<\/h2>\n\n\n\n<p>Se voc\u00ea digitar <code>git status<\/code>, voc\u00ea ir\u00e1 ver que a pasta est\u00e1 como <em>untracked<\/em>, n\u00e3o versionada, o que de certo modo \u00e9 um pouco irritante porque (a) git n\u00e3o deveria estar preocupado com arquivos de dados e (b) ainda que algumas pessoas forcem a barra e fa\u00e7am-no versionar <em>datasets<\/em>, voc\u00ea n\u00e3o quer isso. Afinal, temos o DVC, certo? Uma das coisas que o DVC faz automaticamente, ap\u00f3s voc\u00ea inform\u00e1-lo que voc\u00ea quer que ele versione alguns arquivos, \u00e9 dizer para o git ignorar esses arquivos j\u00e1 que o DVC ir\u00e1 tomar conta deles. Assim como antes de come\u00e7ar a dizer o git o que fazer, com o DVC \u00e9 o mesmo: Voc\u00ea precisa inicializar o DVC no reposit\u00f3rio. Com o git, digitamos <code>git init<\/code>, e com o DVC n\u00e3o ser\u00e1 diferente. Instru\u00e7\u00f5es sobre como instalar o DVC podem ser encontradas <a href=\"https:\/\/dvc.org\/doc\/install\">aqui<\/a>.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4130\" data-id=\"4130\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4130\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-8\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 8\">dvc init\r\ndvc add data\/alarm.tsv<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ap\u00f3s ser inicializado, o DVC ir\u00e1 criar arquivos arquivos. Esses meta-dados s\u00e3o arquivos que precisam ser versionados pelo git. Acho \u00fatil pensar no DVC como algo que complementa o git, portanto o git segue sendo o ator principal j\u00e1 que ele versiona os arquivos do DVC. Vamos adicionar esses arquivos ao \u00edndice do git, <em>index<\/em>, e realizar um <em>commit<\/em>. Nosso <em>dataset<\/em> n\u00e3o ser\u00e1 adicionado nem comitado poqrue o DVC j\u00e1 o adicionou ao .gitignore, um arquivo oculto que o git uso para esse prop\u00f3sito: saber que arquivos deve ignorar.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4131\" data-id=\"4131\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4131\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-9\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I -  9\">git add .\r\ngit commit -m 'Initiates DVC and asks it to track alarm dataset'<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Dependendo do quanto voc\u00ea est\u00e1 familiarizado com o git, isso pode ser uma surpresa ou n\u00e3o mas voc\u00ea n\u00e3o precisa dar <code>git push<\/code> (enviar a vers\u00e3o mais atual do reposit\u00f3rio para um git <em>remote,<\/em> como o GitHub). N\u00f3s n\u00e3o iremos fazer isso agora, por exemplo (ainda que pud\u00e9ssemos). E do mesmo modo que o GittHub \u00e9 um <em>remote<\/em> do git, voc\u00ea tamb\u00e1m pode ter um <em>remote<\/em> do DVC. O Dropbox, um <em>bucket<\/em> do Amazon S3, Google Drive ou at\u00e9 uma pasta no seu computador ou em um disco externo, qualquer uma dessas op\u00e7\u00f5es pode ser um DVC <em>remote.<\/em> Por quest\u00f5es de simplicidade, iremos aqui utilizar o Google Drive.<\/p>\n\n\n\n<p>O primeiro passo \u00e9 ir ao site do Google Drive, autenticar-se na sua conta, e criar uma pasta. Eu criei uma com o nome <em>dvc-miic-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> example<\/em>. A URL na barra de endere\u00e7o do meu navegador ficou assim: <strong><a href=\"https:\/\/drive.google.com\/drive\/u\/1\/folders\/188CmpQIYqKOgvcgaLZOxz1GqlwTasv8c\">https:\/\/drive.google.com\/drive\/u\/1\/folders\/188CmpQIYqKOgvcgaLZOxz1GqlwTasv8c<\/a><\/strong><\/p>\n\n\n\n<p>O pr\u00f3ximo passo \u00e9 extrair a \u00faltima parte dessa URL, ap\u00f3s o <strong>folders\/<\/strong>, ou seja, <strong>188CmpQIYqKOgvcgaLZOxz1GqlwTasv8c<\/strong>. Vamos agora informar o DVC que queremos que essa pasta do Google Drive seja nosso DVC <em>remote.<\/em><\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4132\" data-id=\"4132\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4132\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-10\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 10\">dvc remote add -d myremote gdrive:\/\/188CmpQIYqKOgvcgaLZOxz1GqlwTasv8c<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>O par\u00e2metro <strong>-d<\/strong> \u00e9 importante pois ele diz ao DVC que esse \u00e9 nosso <em>remote <\/em> padr\u00e3o. Assim como \u00e9 poss\u00edvel ter mais de um <em>remote<\/em> no git, tamb\u00e9m \u00e9 poss\u00edvel ter mais de um no DVC. Sem informar qual o <em>remote<\/em> padr\u00e3o, toda vez que d\u00e9ssemos um <code>git push<\/code>, o DVC perguntaria qual o remote desejado. O pr\u00f3ximo passo \u00e9 enviar as atualiza\u00e7\u00f5es do nosso reposit\u00f3rio local para o GitHub, nosso git <em>remote<\/em>, com o <code>git push<\/code>. Consegue adivinhar qual o comando para enviarmos as atualiza\u00e7\u00f5es do reposit\u00f3rio local para o DVC <em>remote<\/em>? Tenho certeza que voc\u00ea adivinhou corretamente!<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4133\" data-id=\"4133\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4133\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-11\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 11\">dvc push<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Para ter certeza que est\u00e1 tudo claro pra voc\u00ea: Os c\u00f3digos fonte e meta dados do DVC ir\u00e3o para o GitHub <em>remote<\/em>. Os dados, pipelines e sa\u00edda de algoritmos ir\u00e3o para o DVC <em>remote<\/em>.<\/p>\n\n\n\n<p>Se voc\u00ea for conferir a sua pasta no Google Drive agora, voc\u00ea ver\u00e1 que a pasta n\u00e3o est\u00e1 mais vazia. O nome das pastas e seus conte\u00fados l\u00e1 n\u00e3o fazem muito sentido, mas acredite em mim: O DVC sabe como interpretar isso :P. Por for\u00e7a do h\u00e1bito, voc\u00ea digita <code>git status<\/code> e percebe que algo mudou no seu reposit\u00f3rio. Como assim?! Ao adicionar um <em>remote<\/em>, um arquivo de configura\u00e7\u00e3o do DVC foi alterado. Voc\u00ea poderia executar um <code>git add<\/code> para adicionar o arquivo ao \u00edndice e um <code>git commit<\/code> para salvar um novo <em>snapshot<\/em> do seu reposit\u00f3rio, mas por uma quest\u00e3o did\u00e1tica, eu irei fazer algo diferente: Eu irei emendar o \u00faltimo <em>commit<\/em>, e ao fazer isso atualizar a mensagem de <em>commit<\/em>. Amending, ou emendamento, \u00e9 \u00fatil quando voc\u00ea realiza um <em>commit<\/em> e pouco tempo depois percebe que esqueceu de algo, ou decide melhorar a mensagem do seu <em>commit<\/em>. A ideia \u00e9 alterar o seu \u00faltimo <em>commit<\/em>, em vez de fazer um novo.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4134\" data-id=\"4134\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4134\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-12\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 12\">git add .\r\ngit commit --amend -m 'Initiates DVC, sets the default remote and asks it to track alarm dataset'<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ok, vamos dar um <code>git push<\/code> agora.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4135\" data-id=\"4135\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4135\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-13\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 13\">git push<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>A p\u00e1gina do GitHub do seu reposit\u00f3rio deve estar parecida com essa <a href=\"https:\/\/github.com\/mribeirodantas\/dvc-miic-cml\/tree\/d2249961e24e331e53428ada9071aedb93a42517\" target=\"_blank\" rel=\"noreferrer noopener\">aqui<\/a>. Talvez voc\u00ea esteja se perguntando por que existem dois arquivos na sua pasta <code>data\/<\/code> do GitHub se eu te disse que o git n\u00e3o ir\u00e1 versionar <em>datasets<\/em>. Um desses arquivos \u00e9 o <code>.gitignore<\/code>, respons\u00e1vel por informar o git para ignorar arquivos nesse diret\u00f3rio. O arquivo com a extens\u00e3o <code>.dvc<\/code> \u00e9 utilizado pelo DVC e cont\u00e9m uma <em>hash<\/em> constru\u00edda a partir do conte\u00fado do <em>dataset<\/em>. \u00c9 assim que o DVC sabe quando o <em>dataset<\/em> mudou, porque a <em>hash<\/em> ir\u00e1 mudar tamb\u00e9m.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Nota sobre o DVC<\/h2>\n\n\n\n<p>Se algu\u00e9m estiver interessado neste reposit\u00f3rio (talvez voc\u00ea esteja), a ideia \u00e9 fazer como faria com qualquer outro reposit\u00f3rio do GitHub. \u00c9 s\u00f3 clon\u00e1-lo!<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4136\" data-id=\"4136\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4136\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-14\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 14\">git clone https:\/\/github.com\/mribeirodantas\/dvc-miic-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.git\r\ncd dvc-miic-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span><\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ao listar os arquivos dentro do reposit\u00f3rio com o comando <code>ls data<\/code>, voc\u00ea perceber\u00e1 que o <em>dataset<\/em> n\u00e3o est\u00e1 l\u00e1. Bem, claro que ele n\u00e3o est\u00e1, certo? Voc\u00ea apenas clonou o reposit\u00f3rio git, com c\u00f3digo. Vamos executar o comando <code>dvc pull<\/code> para baixar os dados versionados pelo DVC.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4137\" data-id=\"4137\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4137\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-15\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 15\">dvc pull<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Agora sim \ud83d\ude42 . Hora de come\u00e7ar a escrever nosso <em>script<\/em> de infer\u00eancia de rede. Utilizaremos o MIIC (Multivariate information-based inductive causation) para isso. Crie um arquivo chamado <code>infer_network.R<\/code> com o conte\u00fado abaixo:<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4138\" data-id=\"4138\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4138\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-16\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-r\" title=\"CML Part I - 16\">library(miic)\r\nalarm_dataset &lt;- read.table('data\/alarm.tsv', header = TRUE)\r\nres &lt;- miic(input_data = alarm_dataset)\r\ntotal_edges &lt;- nrow(res$all.edges.summary)\r\nretained_edges &lt;- nrow(res$all.edges.summary[res$all.edges.summary$type == 'P', ])\r\nratio_edges &lt;- paste0('Ratio of retained edges: ', retained_edges\/total_edges)\r\nwrite.table(ratio_edges, file = 'metrics.txt', col.names = FALSE, row.names = FALSE)<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Esse c\u00f3digo carrega o pacote do R <code>miic<\/code>, l\u00ea o <em>dataset<\/em>, trazendo-o para dentro do ambiente R, chama o algoritmo <code>miic<\/code> para inferir a rede a partir desse <em>dataset<\/em> e calcula a raz\u00e3o de arestas mantidas com rela\u00e7\u00e3o ao total poss\u00edvel. Ap\u00f3s isso, essa raz\u00e3o \u00e9 salva em um arquivo chamado <code>metrics.txt<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">GitHub Actions<\/h2>\n\n\n\n<p>Agora \u00e9 hora de come\u00e7ar a brincar com o GitHub Actions e deixar o <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> fazer sua m\u00e1gica. Toda vez que fizermos um novo <em>commit<\/em> para esse reposit\u00f3rio e fazemos um <em>push<\/em>, o modelo ser\u00e1 constru\u00eddo novamente e a m\u00e9trica ser\u00e1 recalculada.<\/p>\n\n\n\n<p>Para utilizar o GitHub Actions, precisamos criar um arquivo especial em uma pasta especial. O caminho dentro de nosso reposit\u00f3rio git \u00e9: <strong>.github\/workflows<\/strong><\/p>\n\n\n\n<p>Dentro da pasta, voc\u00ea precisar criar o arquivo que o GitHub Action ir\u00e1 buscar por instru\u00e7\u00f5es. Voc\u00ea pode escolher qualquer nome, mas precisa estar no formato <a href=\"https:\/\/en.wikipedia.org\/wiki\/YAML\" target=\"_blank\" rel=\"noreferrer noopener\">YAML format<\/a>. Vamos come\u00e7ar criando o caminho para nosso arquivo do GitHub Action.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4139\" data-id=\"4139\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4139\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-17\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 17\">mkdir -p .github\/workflows\r\ncd .github\/workflows<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ap\u00f3s isso, criaremos um arquivo chamado <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> e escreveremos o c\u00f3digo abaixo. Essas instru\u00e7\u00f5es basicamente pedem por uma m\u00e1quina rodando a \u00faltima vers\u00e3o do Ubuntu, com o R devidamente instalado, clona o nosso reposit\u00f3rio git, instala o MIIC, DVC, as suas depend\u00eancias, executa o comando <code>dvc pull<\/code> para baixar nosso <em>dataset<\/em>, e chama o <em>script<\/em> <code>infer_network.R<\/code> que ir\u00e1 inferir a rede e salvar a m\u00e9trica para um arquivo que, no final de tudo, ser\u00e1 impresso na tela.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4140\" data-id=\"4140\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4140\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-18\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-yaml\" title=\"CML Part I - 18\">name: dvc-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>-miic\r\non: [push]\r\njobs:\r\n  run:\r\n    runs-on: [ubuntu-latest]\r\n    steps:\r\n      - uses: r-lib\/actions\/setup-r@master\r\n        with:\r\n          version: '3.6.1'\r\n      - uses: actions\/checkout@v2\r\n      - name: cml_run\r\n        env:\r\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\r\n          GDRIVE_CREDENTIALS_DATA: ${{ secrets.GDRIVE_CREDENTIALS_DATA }}\r\n        run: |\r\n          # Install miic and dependencies\r\n          wget -c https:\/\/github.com\/miicTeam\/miic_R_package\/archive\/v1.4.2.tar.gz\r\n          tar -xvzf v1.4.2.tar.gz\r\n          cd miic_R_package-1.4.2\r\n          R --silent -e &quot;install.packages(c(\\&quot;igraph\\&quot;, \\&quot;ppcor\\&quot;, \\&quot;scales\\&quot;, \\&quot;Rcpp\\&quot;))&quot;\r\n          R CMD INSTALL . --preclean\r\n          cd ..\r\n          # Install Python packages\r\n          pip install --upgrade pip\r\n          pip install wheel\r\n          pip install PyDrive2==1.6.0 --use-feature=2020-resolver\r\n          # Install DVC\r\n          wget -c https:\/\/github.com\/iterative\/dvc\/releases\/download\/1.4.0\/dvc_1.4.0_amd64.deb\r\n          sudo apt install .\/dvc_1.4.0_amd64.deb\r\n          # Run DVC\r\n          dvc pull\r\n          Rscript infer_network.R\r\n          # Write your <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> report\r\n          echo &quot;MODEL METRICS&quot;\r\n          cat metrics.txt<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Em vez de fazer um <em>commit<\/em> com essas novas altera\u00e7\u00f5es na <em>branch<\/em> principal,m a <em>master<\/em>, n\u00f3s iremos criar uma <em>banch<\/em> de experimento. \u00c9 assim que voc\u00ea deve usar o git com o DVC! N\u00f3s iremos analisar a vers\u00e3o <em>raw<\/em>, bruta, do <em>datase<\/em> <em>alarm<\/em>, sem pr\u00e9-processamento, portanto eu irei chamar essa <em>branch<\/em> de  <code>raw_alarm_dataset<\/code>.<\/p>\n\n\n\n<p>Voc\u00ea j\u00e1 usou o <code>dvc pull<\/code>, portanto sua m\u00e1quina j\u00e1 est\u00e1 autentiada com o Google Drive. <a href=\"https:\/\/docs.github.com\/en\/actions\/configuring-and-managing-workflows\/creating-and-storing-encrypted-secrets\" target=\"_blank\" rel=\"noreferrer noopener\">Crie um GitHub secret<\/a> com o conte\u00fado do arquivo <code>.dvc\/tmp\/gdrive-user-credentials.json<\/code> e nomeie esse GitHub <em>secret<\/em> como GDRIVE_CREDENTIALS_DATA.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4141\" data-id=\"4141\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4141\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-19\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 19\">git checkout -b raw_alarm_dataset\r\n# infer_network.R is not in this folder, therefore `git add .` wouldn't\r\n# add it to the index of your git repository. -A adds everything.\r\ngit add -A\r\ngit commit -m 'Infers alarm network with MIIC and default parameters'\r\ngit push origin raw_alarm_dataset\r\ngh pr create --title 'Network inference of alarm dataset'<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Agora, <a href=\"https:\/\/github.com\/mribeirodantas\/dvc-miic-cml\/pull\/1\/checks\" target=\"_blank\" rel=\"noreferrer noopener\">v\u00e1 para o GitHub e veja o que est\u00e1 acontecendo<\/a>. Se tudo ocorrer de acordo com o plano, voc\u00ea ir\u00e1 ver algo parecido com a imagem abaixo quando a checagem estiver conclu\u00edda.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"223\" data-attachment-id=\"3943\" data-permalink=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/10\/continuous-machine-learning\/screen_2020-08-10_22-16-29\/\" data-orig-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?fit=3427%2C1196&amp;ssl=1\" data-orig-size=\"3427,1196\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"screen_2020-08-10_22-16-29\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?fit=300%2C105&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?fit=640%2C223&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?resize=640%2C223&#038;ssl=1\" alt=\"\" class=\"wp-image-3943\" srcset=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?resize=1024%2C357&amp;ssl=1 1024w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?resize=300%2C105&amp;ssl=1 300w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?resize=768%2C268&amp;ssl=1 768w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?resize=1536%2C536&amp;ssl=1 1536w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?resize=2048%2C715&amp;ssl=1 2048w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?w=1280&amp;ssl=1 1280w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-16-29.png?w=1920&amp;ssl=1 1920w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p>Ok&#8230; Voc\u00ea imprimiu sua m\u00e9trica no <em>log<\/em>. Massa mas vamos l\u00e1, seria mais interessante ter algo ao menos um pouquinho mais interessante, n\u00e9? `^^<\/p>\n\n\n\n<p>Vamos adicionar mais algumas linhas no <em>script<\/em> <code>infer_network.R<\/code> para faz\u00ea-lo plotar a rede inferida para uma imagem, e alterar a parte final para fazer uso de algumas funcionalidades do <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>. O c\u00f3digo do novo <code>infer_network.R<\/code> deve estar assim:<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4142\" data-id=\"4142\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4142\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-20\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-r\" title=\"CML Part I - 20\">library(miic)\r\nalarm_dataset &lt;- read.table('data\/alarm.tsv', header = TRUE)\r\nres &lt;- miic(input_data = alarm_dataset)\r\ntotal_edges &lt;- nrow(res$all.edges.summary)\r\nretained_edges &lt;- nrow(res$all.edges.summary[res$all.edges.summary$type == 'P', ])\r\nratio_edges &lt;- paste0('Ratio of retained edges: ', retained_edges\/total_edges)\r\nwrite.table(ratio_edges, file = 'metrics.txt', col.names = FALSE, row.names = FALSE)\r\n# Plot network\r\npng(file='network_diagram.png')\r\nmiic.plot(res)\r\ndev.off()<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>E o novo arquivo <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> deve estar como no c\u00f3digo abaixo. A altera\u00e7\u00e3o \u00e9 que agora iremos instalar o <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> para poder utiliz\u00e1-lo.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4143\" data-id=\"4143\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4143\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-21\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-yaml\" title=\"CML Part I - 21\">name: dvc-<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>-miic\r\non: [push]\r\njobs:\r\n  run:\r\n    runs-on: [ubuntu-latest]\r\n    steps:\r\n      - uses: r-lib\/actions\/setup-r@master\r\n        with:\r\n          version: '3.6.1'\r\n      - uses: actions\/checkout@v2\r\n      - name: cml_run\r\n        env:\r\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\r\n          GDRIVE_CREDENTIALS_DATA: ${{ secrets.GDRIVE_CREDENTIALS_DATA }}\r\n        run: |\r\n\r\n          # Install miic and dependencies\r\n          wget -c https:\/\/github.com\/miicTeam\/miic_R_package\/archive\/v1.4.2.tar.gz\r\n          tar -xvzf v1.4.2.tar.gz\r\n          cd miic_R_package-1.4.2\r\n          R --silent -e &quot;install.packages(c(\\&quot;igraph\\&quot;, \\&quot;ppcor\\&quot;, \\&quot;scales\\&quot;, \\&quot;Rcpp\\&quot;))&quot;\r\n          R CMD INSTALL . --preclean\r\n          cd ..\r\n          # Install Python packages\r\n          pip install --upgrade pip\r\n          pip install wheel\r\n          pip install PyDrive2==1.6.0 --use-feature=2020-resolver\r\n          # Install DVC\r\n          wget -c https:\/\/github.com\/iterative\/dvc\/releases\/download\/1.4.0\/dvc_1.4.0_amd64.deb\r\n          sudo apt install .\/dvc_1.4.0_amd64.deb\r\n          # Run DVC\r\n          dvc pull\r\n          Rscript infer_network.R\r\n\r\n          # Install <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>\r\n          npm init --yes\r\n          npm i @dvcorg\/<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>@latest\r\n          # Write your <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> report\r\n          echo &quot;## Model Metrics&quot; &gt; report.md\r\n          cat metrics.txt &gt;&gt; report.md\r\n          echo &quot;## Data visualization&quot; &gt;&gt; report.md\r\n          npx <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>-publish network_diagram.png --md &gt;&gt; report.md\r\n          npx <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>-send-comment report.md<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Hora de fazer um <em>commit<\/em>.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4144\" data-id=\"4144\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4144\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-22\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 22\">git add .\r\ngit commit -m 'Uses <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> to improve PR feedback'\r\ngit push origin raw_alarm_dataset<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ok, agora ap\u00f3s as checagens serem realizadas, voc\u00ea deve ver um coment\u00e1rio autom\u00e1tico no seu <em>Pull Request<\/em> com a figura da rede, como abaixo.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"489\" data-attachment-id=\"3948\" data-permalink=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/10\/continuous-machine-learning\/screen_2020-08-10_22-27-49\/\" data-orig-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?fit=1124%2C860&amp;ssl=1\" data-orig-size=\"1124,860\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"screen_2020-08-10_22-27-49\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?fit=300%2C230&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?fit=640%2C489&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?resize=640%2C489&#038;ssl=1\" alt=\"\" class=\"wp-image-3948\" srcset=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?resize=1024%2C783&amp;ssl=1 1024w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?resize=300%2C230&amp;ssl=1 300w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?resize=768%2C588&amp;ssl=1 768w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-27-49.png?w=1124&amp;ssl=1 1124w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p>Digamos que eu ache que muitas arestas foram removidas e talvez a rede n\u00e3o seja consistente. Irei alterar o c\u00f3digo do <em>script<\/em> <code>infer_network.R<\/code>  para fazer o MIIC buscar por uma rede <a href=\"http:\/\/kinefold.curie.fr\/isambertlab\/research_interpretable_constraint-based-methods.htm\">consistente<\/a>. A terceira linha deve ser agora como abaixo:<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4145\" data-id=\"4145\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4145\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-23\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-r\" title=\"CML Part I - 23\">res &lt;- miic(input_data = alarm_dataset, consistent='orientation')<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Vamos salvar o estado atual do reposit\u00f3rio local com um <em>commit<\/em>.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4146\" data-id=\"4146\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4146\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-24\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 24\">git add .\r\ngit commit -m 'Makes network consistent'\r\ngit push origin raw_alarm_dataset<\/pre>\n\t\t\t<\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"564\" height=\"925\" data-attachment-id=\"3949\" data-permalink=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/10\/continuous-machine-learning\/screen_2020-08-10_22-36-45\/\" data-orig-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-36-45.png?fit=564%2C925&amp;ssl=1\" data-orig-size=\"564,925\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"screen_2020-08-10_22-36-45\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-36-45.png?fit=183%2C300&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-36-45.png?fit=564%2C925&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-36-45.png?resize=564%2C925&#038;ssl=1\" alt=\"\" class=\"wp-image-3949\" srcset=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-36-45.png?w=564&amp;ssl=1 564w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-10_22-36-45.png?resize=183%2C300&amp;ssl=1 183w\" sizes=\"auto, (max-width: 564px) 100vw, 564px\" \/><\/figure>\n\n\n\n<p>Ok, agora est\u00e1 como eu queria e j\u00e1 posso aprovar o <em>pull request<\/em> \ud83d\ude42 . Eu poderia fazer isso clicando no bot\u00e3o verde \u201cMerge pull request\u201d direto no site do GitHub ou eu poderia usar o <code>gh<\/code> novamente.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4147\" data-id=\"4147\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4147\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-25\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 25\">gh pr merge 1<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ele ir\u00e1 te fazer duas perguntas. Eu escolhi criar um <em>commit<\/em> de <em>merge<\/em> (mesclagem) e n\u00e3o remover a <em>branch<\/em>, nem localmente nem no GitHub. Para retornar a <em>branch<\/em> principal, a <em>master<\/em>, execute o seguinte comando:<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4148\" data-id=\"4148\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4148\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-26\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 26\">git checkout master<\/pre>\n\t\t\t<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Usando containers do Docker<\/h2>\n\n\n\n<p>Voc\u00ea provavelmente reparou que o GitHub Runner demora um certo tempo para fazer as checagens e dependendo de quantos pacotes voc\u00ea quer instalar, essa checagem pode demorar bastante. Um modo de evitar essa demora toda vez que voc\u00ea fizer um <em>push<\/em> \u00e9 utilizar um <em>container<\/em> do Docker que j\u00e1 tem tudo instalado, softwares, pacotes, depend\u00eancias, tudo. O modo como temos feito at\u00e9 agora est\u00e1 pronto para voc\u00ea adicionar o seu <em>container<\/em>, j\u00e1 que eu estou instalando o <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> manualmente. Se voc\u00ea n\u00e3o quiser usar um <em>container<\/em> pr\u00f3prio, mas n\u00e3o quer ter que baixar e instalar o <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> em todo <em>push<\/em>, podemos utilizar o <em>container<\/em> oficial do projeto <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.<\/p>\n\n\n\n<p>Se voc\u00ea se lembra bem, h\u00e1 pouco n\u00f3s aceitamos o <em>pull request<\/em>, o que significa que mesclamos aquela <em>branch<\/em> com a principal, a <em>master<\/em>. Embora o <em>remote<\/em> do GitHub esteja atualizado, a nossa c\u00f3pia local n\u00e3o. Vamos atualiz\u00e1-la com um <code>git pull<\/code>, e ap\u00f3s isso criar uma nova <em>branch<\/em>.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4149\" data-id=\"4149\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4149\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-27\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 27\">git pull\r\ngit checkout -b <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>_container<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Altere o arquivo <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> para ficar como no c\u00f3digo abaixo.<\/p>\n\n\n\n<p>scripts<\/p>\n\n\n\n<p>Vamos adicionar esse arquivo ao \u00edndice do git, realizar um <em>commit<\/em>, <em>push<\/em> e criar um <em>Pull Request<\/em> (PR).<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4151\" data-id=\"4151\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4151\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-29\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 29\">git add .\r\ngit commit -m 'Makes use of <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> container'\r\ngit push origin <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>_container\r\ngh pr create --title 'Use <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span> container'<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>Ap\u00f3s isso, tudo deve correr tranquilamente, como aconteceu <a href=\"https:\/\/github.com\/mribeirodantas\/dvc-miic-cml\/pull\/2\/checks\">aqui<\/a>. Voc\u00ea pode mesclar o <em>pull request<\/em> e executar um <code>git pull<\/code> novamente para atualizar seu reposit\u00f3rio local.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4152\" data-id=\"4152\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205?snippet=9ded934fb4&#038;id=4152\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-i-30\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part I - 30\">gh pr merge 2\r\ngit pull<\/pre>\n\t\t\t<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">O que mais?<\/h2>\n\n\n\n<p>O DVC n\u00e3o se limita a versionar <em>datasets<\/em>. N\u00f3s tamb\u00e9m poder\u00edamos criar <em>pipelines<\/em> (sequ\u00eancias de opera\u00e7\u00f5es, do <em>download<\/em> de nossos dados, passando por pr\u00e9-processamento, infer\u00eancia, p\u00f3s-processamento, gera\u00e7\u00e3o de relat\u00f3rios, etc) e version\u00e1-los, assim como os arquivos de sa\u00edde desses <em>scripts<\/em> como as imagens que o <em>script<\/em> <code>infer_network.R<\/code> gerou. Poder\u00edamos ter v\u00e1rios <em>scripts<\/em> para etapas anterior e posterior a de infer\u00eancia e tudo pode ser orquestrado pelo DVC atrav\u00e9s de um simples comando: <code>dvc repro<\/code>. Etapas que n\u00e3o precisam ser executadas (apenas <em>datasets<\/em> que s\u00e3o utilizados em uma etapa maios tardia foram modificados) n\u00e3o s\u00e3o executados. Em vez de ter v\u00e1rios <em>scripts<\/em> sendo chamados no seu GitHub Action file, teria apenas um <code>dvc repro<\/code>.<\/p>\n\n\n\n<p>Al\u00e9m disso, poder\u00edamos ter um <em>container<\/em> do Docker com tudo que n\u00e3o muda entre os <em>commits<\/em> j\u00e1 instalado. R, DVC, <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>, MIIC, depend\u00eancias do MIIC, entre outras coisas. Isso definitivamente nos pouparia de uma espera nada prazerosa, dependendo do que voc\u00ea for fazer. No nosso caso aqui, baixar, compilar e instalar o MIIC leva alguns minutos que poderiam ser poupados. Para o nosso simples exemplos, acho que n\u00e3o \u00e9 o fim do mundo esperar alguns poucos minutos, mas se come\u00e7ar a ficar mais complexo, e com <em>datasets <\/em>maiores, o tempo pode simplesmente se tornar invi\u00e1vel, o que tornaria indispens\u00e1vel criar o seu <em>container<\/em> do Docker (<a href=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/\">Parte II dessa s\u00e9rie<\/a>) e utilizar sua pr\u00f3pria infraestrutura computacional sincronizada com o GItHub Actions (Parte III).<\/p>\n\n\n\n<p>Por hoje \u00e9 s\u00f3 pessoal! \ud83d\ude09<\/p>\n\n\n\n<p>Voc\u00ea provavelmente n\u00e3o estaria lendo esse texto se n\u00e3o fosse pela <a href=\"https:\/\/twitter.com\/DrElleOBrien\">Elle O&#8217;Brien<\/a>, que me mostrou tantas coisas sobre o <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>, apresenta\u00e7\u00f5es e exemplos, e o <a href=\"https:\/\/twitter.com\/g_ortega_david\">David Ortega<\/a> que me ajudou a preparar o ambiente R dentro do container docker oficial do projeto <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.<\/p>\n<script type=\"text\/javascript\"> toolTips('.classtoolTips0','Continuous Machine Learning is the equivalent of Continuous Integration and Continuous Delivery (CI\/CD) for Machine Learning.'); <\/script>","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\"><b>Reading time: <\/span> <span class=\"rt-time\"> 11<\/span> <span class=\"rt-label rt-postfix\">minutes<\/b><\/span><\/span>Esse texto faz parte de uma s\u00e9rie de 3 partes sobre Continuous Machine Learning. Voc\u00ea pode checar a parte II aqui e a parte III aqui. O que \u00e9 isso? Continuous Machine Learning (CML) segue o mesmo conceito de Continuous Integration and Continuous Delivery (CI\/CD), famosos concenitos da \/ , mas aplicado a projetos de &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[61],"tags":[],"class_list":["post-4205","post","type-post","status-publish","format-standard","hentry","category-uncategorized-pt"],"jetpack_publicize_connections":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Continuous Machine Learning \u2013 Parte I - The Dataist Storyteller<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Continuous Machine Learning \u2013 Parte I - The Dataist Storyteller\" \/>\n<meta property=\"og:description\" content=\"Reading time:  11 minutesEsse texto faz parte de uma s\u00e9rie de 3 partes sobre Continuous Machine Learning. Voc\u00ea pode checar a parte II aqui e a parte III aqui. O que \u00e9 isso? Continuous Machine Learning (CML) segue o mesmo conceito de Continuous Integration and Continuous Delivery (CI\/CD), famosos concenitos da \/ , mas aplicado a projetos de ...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/\" \/>\n<meta property=\"og:site_name\" content=\"The Dataist Storyteller\" \/>\n<meta property=\"article:published_time\" content=\"2020-08-24T18:35:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-01-31T02:37:50+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps-1024x837.png\" \/>\n<meta name=\"author\" content=\"mribeirodantas\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"mribeirodantas\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/\"},\"author\":{\"name\":\"mribeirodantas\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957\"},\"headline\":\"Continuous Machine Learning \u2013 Parte I\",\"datePublished\":\"2020-08-24T18:35:33+00:00\",\"dateModified\":\"2025-01-31T02:37:50+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/\"},\"wordCount\":3136,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957\"},\"image\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps-1024x837.png\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/\",\"url\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/\",\"name\":\"Continuous Machine Learning \u2013 Parte I - The Dataist Storyteller\",\"isPartOf\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps-1024x837.png\",\"datePublished\":\"2020-08-24T18:35:33+00:00\",\"dateModified\":\"2025-01-31T02:37:50+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage\",\"url\":\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?fit=1470%2C1202&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?fit=1470%2C1202&ssl=1\",\"width\":1470,\"height\":1202},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/mribeirodantas.xyz\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Continuous Machine Learning \u2013 Parte I\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#website\",\"url\":\"https:\/\/mribeirodantas.xyz\/blog\/\",\"name\":\"The Dataist Storyteller\",\"description\":\"Telling stories backed by data\",\"publisher\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/mribeirodantas.xyz\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957\",\"name\":\"mribeirodantas\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6687720529e55feab1680cbd98da5c7f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6687720529e55feab1680cbd98da5c7f?s=96&d=mm&r=g\",\"caption\":\"mribeirodantas\"},\"logo\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/image\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Continuous Machine Learning \u2013 Parte I - The Dataist Storyteller","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/","og_locale":"en_US","og_type":"article","og_title":"Continuous Machine Learning \u2013 Parte I - The Dataist Storyteller","og_description":"Reading time:  11 minutesEsse texto faz parte de uma s\u00e9rie de 3 partes sobre Continuous Machine Learning. Voc\u00ea pode checar a parte II aqui e a parte III aqui. O que \u00e9 isso? Continuous Machine Learning (CML) segue o mesmo conceito de Continuous Integration and Continuous Delivery (CI\/CD), famosos concenitos da \/ , mas aplicado a projetos de ...","og_url":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/","og_site_name":"The Dataist Storyteller","article_published_time":"2020-08-24T18:35:33+00:00","article_modified_time":"2025-01-31T02:37:50+00:00","og_image":[{"url":"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps-1024x837.png","type":"","width":"","height":""}],"author":"mribeirodantas","twitter_card":"summary_large_image","twitter_misc":{"Written by":"mribeirodantas","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#article","isPartOf":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/"},"author":{"name":"mribeirodantas","@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957"},"headline":"Continuous Machine Learning \u2013 Parte I","datePublished":"2020-08-24T18:35:33+00:00","dateModified":"2025-01-31T02:37:50+00:00","mainEntityOfPage":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/"},"wordCount":3136,"commentCount":1,"publisher":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957"},"image":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage"},"thumbnailUrl":"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps-1024x837.png","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/","url":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/","name":"Continuous Machine Learning \u2013 Parte I - The Dataist Storyteller","isPartOf":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage"},"image":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage"},"thumbnailUrl":"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps-1024x837.png","datePublished":"2020-08-24T18:35:33+00:00","dateModified":"2025-01-31T02:37:50+00:00","breadcrumb":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#primaryimage","url":"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?fit=1470%2C1202&ssl=1","contentUrl":"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/MLOps.png?fit=1470%2C1202&ssl=1","width":1470,"height":1202},{"@type":"BreadcrumbList","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/pt\/2020\/08\/24\/continuous-machine-learning-parte-i\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/mribeirodantas.xyz\/blog\/"},{"@type":"ListItem","position":2,"name":"Continuous Machine Learning \u2013 Parte I"}]},{"@type":"WebSite","@id":"https:\/\/mribeirodantas.xyz\/blog\/#website","url":"https:\/\/mribeirodantas.xyz\/blog\/","name":"The Dataist Storyteller","description":"Telling stories backed by data","publisher":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/mribeirodantas.xyz\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957","name":"mribeirodantas","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6687720529e55feab1680cbd98da5c7f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6687720529e55feab1680cbd98da5c7f?s=96&d=mm&r=g","caption":"mribeirodantas"},"logo":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/image\/"}}]}},"jetpack_featured_media_url":"","uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"mribeirodantas","author_link":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/author\/mribeirodantas\/"},"uagb_comment_info":25,"uagb_excerpt":"Reading time: 11 minutesEsse texto faz parte de uma s\u00e9rie de 3 partes sobre Continuous Machine Learning. Voc\u00ea pode checar a parte II aqui e a parte III aqui. O que \u00e9 isso? Continuous Machine Learning (CML) segue o mesmo conceito de Continuous Integration and Continuous Delivery (CI\/CD), famosos concenitos da \/ , mas aplicado&hellip;","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/paw9jx-15P","jetpack-related-posts":[],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=4205"}],"version-history":[{"count":27,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205\/revisions"}],"predecessor-version":[{"id":4234,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/posts\/4205\/revisions\/4234"}],"wp:attachment":[{"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=4205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=4205"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=4205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}