{"id":3996,"date":"2020-08-18T00:54:53","date_gmt":"2020-08-18T00:54:53","guid":{"rendered":"https:\/\/mribeirodantas.xyz\/blog\/?p=3996"},"modified":"2025-01-31T04:37:50","modified_gmt":"2025-01-31T02:37:50","slug":"continuous-machine-learning-part-ii","status":"publish","type":"post","link":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/","title":{"rendered":"Continuous Machine Learning &#8211; Part II"},"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\"> 3<\/span> <span class=\"rt-label rt-postfix\">minutes<\/b><\/span><\/span>\n<p>This is a 3-part series about Continuous Machine Learning. You can check Part I <a href=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/10\/continuous-machine-learning\/\">here<\/a> and Part III here. This post is a continuation of the previous one, in which we initiated our experience on automating Data Science in GitHub with <a href=\"https:\/\/cml.dev\"><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span><\/a>. We will basically make use of Docker to improve the computation time in our GitHub Actions checks.<\/p>\n\n\n\n<p>You can think of a Docker image as taking a snapshot of the software environment of a project, and then being able to setup that snapshot on any other computer. When GitHub Actions is called, it loads your Docker image in their infrastructure and then runs your code. That&#8217;s why it&#8217;s quicker, because when you use a Docker container with your dependencies already installed, you don\u2019t have to spend time setting them up all over again on your GitHub Actions runner every time it is triggered, which is the way we did in <a href=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/10\/continuous-machine-learning\/\">the first part of this series<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Creating a Docker image<\/h4>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"317\" data-attachment-id=\"3999\" data-permalink=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/docker\/\" data-orig-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?fit=1260%2C624&amp;ssl=1\" data-orig-size=\"1260,624\" 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=\"docker\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?fit=300%2C149&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?fit=640%2C317&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?resize=640%2C317&#038;ssl=1\" alt=\"\" class=\"wp-image-3999\" srcset=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?resize=1024%2C507&amp;ssl=1 1024w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?resize=300%2C149&amp;ssl=1 300w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?resize=768%2C380&amp;ssl=1 768w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?w=1260&amp;ssl=1 1260w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><figcaption>Image from \u201c<a href=\"https:\/\/medium.com\/platformer-blog\/practical-guide-on-writing-a-dockerfile-for-your-application-89376f88b3b5\">Build a Docker Image just like how you would configure a VM<\/a>\u201d.<\/figcaption><\/figure>\n\n\n\n<!--more-->\n\n\n\n<p>As you can see on the image above, you write a text file called Dockerfile and the Docker app will create a Docker image based on the instructions contained in the Dockerfile. Then, with the Docker engine running in some infrastructure (GitHub&#8217;s infra, in our case), this image will be converted into a real container, like in the image below (There are three containers)..<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"592\" height=\"415\" data-attachment-id=\"4000\" data-permalink=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/docker2\/\" data-orig-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker2.png?fit=592%2C415&amp;ssl=1\" data-orig-size=\"592,415\" 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=\"docker2\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker2.png?fit=300%2C210&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker2.png?fit=592%2C415&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker2.png?resize=592%2C415&#038;ssl=1\" alt=\"\" class=\"wp-image-4000\" srcset=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker2.png?w=592&amp;ssl=1 592w, https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker2.png?resize=300%2C210&amp;ssl=1 300w\" sizes=\"auto, (max-width: 592px) 100vw, 592px\" \/><figcaption>Image from \u201c<a href=\"https:\/\/www.antemeta.fr\/docker-metait-conte-2eme-partie-plongee-a-linterieur-conteneurs\/\">Si Docker m\u2019\u00e9tait cont\u00e9\u2026 2\u00e8me partie : plong\u00e9e \u00e0 l\u2019int\u00e9rieur des conteneurs<\/a>\u201d.<\/figcaption><\/figure>\n\n\n\n<p>We will base our Dockerfile on <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>&#8217;s official Dockerfile and it will look like the code below.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4112\" data-id=\"4112\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996?snippet=62096d1bb8&#038;id=4112\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/4112\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-dockerfile\" title=\"CML Part II - Dockerfile\">FROM dvcorg\/<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>\r\nRUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 &amp;&amp; \\\r\n    add-apt-repository 'deb https:\/\/cloud.r-project.org\/bin\/linux\/ubuntu bionic-cran35\/' &amp;&amp; \\  \r\n    apt update &amp;&amp; \\\r\n    apt install -y r-base &amp;&amp; \\\r\n    R --silent -e &quot;install.packages(c(\\&quot;igraph\\&quot;, \\&quot;ppcor\\&quot;, \\&quot;scales\\&quot;, \\&quot;Rcpp\\&quot;))&quot; &amp;&amp; \\\r\n    wget -c https:\/\/github.com\/miicTeam\/miic_R_package\/archive\/v1.4.2.tar.gz &amp;&amp; \\\r\n    tar -xvzf v1.4.2.tar.gz &amp;&amp; \\\r\n    R CMD INSTALL miic_R_package-1.4.2\/. --preclean<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>As you can see, it has a lot of the code that we used to have in our <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> file (in the first post of this series). That&#8217;s the magic! Because of that, our <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> file is much shorter and should look like this:<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4116\" data-id=\"4116\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996?snippet=62096d1bb8&#038;id=4116\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-ii-cml-yaml\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-yaml\" title=\"CML Part II - cml.yaml\">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    container: docker:\/\/mribeirodantas\/cml-test:r\r\n    steps:\r\n      - uses: actions\/checkout@v2\r\n\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 --version\r\n\r\n          dvc pull\r\n          Rscript infer_network.R\r\n\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          <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>-publish network_diagram.png --md &gt;&gt; report.md\r\n          <span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>-send-comment report.md<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>You can see the difference between the old and new <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> in the image below (move the slider in the center to either side to see). You can also view it directly on GitHub clicking <a href=\"https:\/\/github.com\/mribeirodantas\/dvc-miic-cml\/commit\/ac1e25907c412e1c5b8cd7c16649abb83d02e509\">here<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-jetpack-image-compare\"><div class=\"juxtapose\" data-mode=\"horizontal\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" id=\"4108\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-19_12-35-44.png?resize=640%2C524&#038;ssl=1\" alt=\"\" width=\"640\" height=\"524\" class=\"image-compare__image-before\"\/><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" id=\"4109\" src=\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/screen_2020-08-19_12-35-49.png?resize=640%2C646&#038;ssl=1\" alt=\"\" width=\"640\" height=\"646\" class=\"image-compare__image-after\"\/><\/div><\/figure>\n\n\n\n<p>You can save the Dockerfile showed here in a file named Dockerfile in your repository (that right now should look like <a href=\"https:\/\/github.com\/mribeirodantas\/dvc-miic-cml\/tree\/44a135b1287c9417f842ce30f981e9d93f669026\">this<\/a>) and update your <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> like the code above.<\/p>\n\n\n\n<p>To build it and publish it in Docker Hub (Think of it like GitHub but for Docker images), you gotta type the following Docker commands. You need Docker installed for that (instructions for Ubuntu <a href=\"https:\/\/docs.docker.com\/engine\/install\/ubuntu\/\">here<\/a>). The first command takes a while, it&#8217;s creating your image and that&#8217;s the only time that it will really download and install everything. If you understood what I explained earlier, it should be clear that having a container pays off \ud83d\ude42<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4118\" data-id=\"4118\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996?snippet=62096d1bb8&#038;id=4118\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-ii-create-docker-file\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part II - Create docker file\"># Create the Docker image from the Dockerfile\r\nsudo docker build -t mribeirodantas\/<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>:r -f .\/Dockerfile .\r\n# Login to Docke Hub\r\nsudo docker login\r\n# Upload it to Docker Hub. GitHub will always download the\r\n# Docker image from there.\r\nsudo docker push mribeirodantas\/<span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>:r<\/pre>\n\t\t\t<\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Testing Docker image<\/h4>\n\n\n\n<p>We are not sure if this will work so we should create a branch and check what happens. Instead of creating pull requests from GitHub&#8217;s web interface, we will use the official GitHub command line <code>gh<\/code>, just like we did in <a href=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/10\/continuous-machine-learning\/\">the first part of this series<\/a>.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4120\" data-id=\"4120\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996?snippet=62096d1bb8&#038;id=4120\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-ii-testing-docker-image\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part II - Testing Docker Image\">git checkout -b docker_ghactions\r\ngit add -A\r\ngit commit -m 'Makes use of Docker to speed up GH Actions checks'\r\ngit push origin docker_ghactions\r\ngh pr create --title 'Makes use of Docker to speed up GH Actions checks'<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>In the first part of this series, you probably remember that the checks took around 7 minutes to finish. In this branch that uses a Docker container it took less than 2 minutes. Taking into consideration this is a very simple project example and other projects could have much more dependencies, the benefits can be even larger than the ones we see here. Great, right? Let&#8217;s merge this push request.<\/p>\n\n\n<div class=\"snippetcpt-wrap\" id=\"snippet-4121\" data-id=\"4121\" data-edit=\"\" data-copy=\"\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996?snippet=62096d1bb8&#038;id=4121\" data-fullscreen=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/code-snippets\/cml-part-ii-finishing\/?full-screen=1\">\n\t\t\t\t<pre class=\"prettyprint linenums lang-sh\" title=\"CML Part II - Finishing\"># This command will merge all open push requests.\r\n# We only have one, so it will merge the one we have opened.\r\ngh pr merge<\/pre>\n\t\t\t<\/div>\n\n\n\n<p>One question that you may have is why leaving <code>dvc pull<\/code> in the <code><span class='tooltipsall tooltipsincontent classtoolTips0'>CML<\/span>.yaml<\/code> file instead of doing it only once in the Docker. After all, downloading big datasets every time should take a while right? Well, you are right, it may take a while. However, if nothing changed, <code>dvc pull<\/code> quickly will sa yso and nothing will be done. And in case you changed your raw datasets, for example, it will download them.<\/p>\n\n\n\n<p>That&#8217;s it for today folks \ud83d\ude42<\/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\"> 3<\/span> <span class=\"rt-label rt-postfix\">minutes<\/b><\/span><\/span>In this second part of the series \u201cContinuous Machine Learning\u201d, we will use Docker to speed up our GitHub Actions checks.<\/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":[196,69,24,209,1],"tags":[9],"class_list":["post-3996","post","type-post","status-publish","format-standard","hentry","category-causality","category-data-science","category-r","category-tools","category-uncategorized","tag-causality"],"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 - Part II - 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\/2020\/08\/18\/continuous-machine-learning-part-ii\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Continuous Machine Learning - Part II - The Dataist Storyteller\" \/>\n<meta property=\"og:description\" content=\"Reading time:  3 minutesIn this second part of the series \u201cContinuous Machine Learning\u201d, we will use Docker to speed up our GitHub Actions checks.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/\" \/>\n<meta property=\"og:site_name\" content=\"The Dataist Storyteller\" \/>\n<meta property=\"article:published_time\" content=\"2020-08-18T00:54:53+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\/docker-1024x507.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=\"3 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\/2020\/08\/18\/continuous-machine-learning-part-ii\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/\"},\"author\":{\"name\":\"mribeirodantas\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957\"},\"headline\":\"Continuous Machine Learning &#8211; Part II\",\"datePublished\":\"2020-08-18T00:54:53+00:00\",\"dateModified\":\"2025-01-31T02:37:50+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/\"},\"wordCount\":676,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957\"},\"image\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker-1024x507.png\",\"keywords\":[\"causality\"],\"articleSection\":[\"Causality\",\"Data Science\",\"R\",\"tools\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/\",\"url\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/\",\"name\":\"Continuous Machine Learning - Part II - The Dataist Storyteller\",\"isPartOf\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker-1024x507.png\",\"datePublished\":\"2020-08-18T00:54:53+00:00\",\"dateModified\":\"2025-01-31T02:37:50+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage\",\"url\":\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?fit=1260%2C624&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?fit=1260%2C624&ssl=1\",\"width\":1260,\"height\":624},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/mribeirodantas.xyz\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Continuous Machine Learning &#8211; Part II\"}]},{\"@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 - Part II - 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\/2020\/08\/18\/continuous-machine-learning-part-ii\/","og_locale":"en_US","og_type":"article","og_title":"Continuous Machine Learning - Part II - The Dataist Storyteller","og_description":"Reading time:  3 minutesIn this second part of the series \u201cContinuous Machine Learning\u201d, we will use Docker to speed up our GitHub Actions checks.","og_url":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/","og_site_name":"The Dataist Storyteller","article_published_time":"2020-08-18T00:54:53+00:00","article_modified_time":"2025-01-31T02:37:50+00:00","og_image":[{"url":"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker-1024x507.png","type":"","width":"","height":""}],"author":"mribeirodantas","twitter_card":"summary_large_image","twitter_misc":{"Written by":"mribeirodantas","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#article","isPartOf":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/"},"author":{"name":"mribeirodantas","@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957"},"headline":"Continuous Machine Learning &#8211; Part II","datePublished":"2020-08-18T00:54:53+00:00","dateModified":"2025-01-31T02:37:50+00:00","mainEntityOfPage":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/"},"wordCount":676,"commentCount":2,"publisher":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/#\/schema\/person\/2856ebf8edffabf1f4bbca59bade5957"},"image":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage"},"thumbnailUrl":"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker-1024x507.png","keywords":["causality"],"articleSection":["Causality","Data Science","R","tools"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/","url":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/","name":"Continuous Machine Learning - Part II - The Dataist Storyteller","isPartOf":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage"},"image":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage"},"thumbnailUrl":"https:\/\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker-1024x507.png","datePublished":"2020-08-18T00:54:53+00:00","dateModified":"2025-01-31T02:37:50+00:00","breadcrumb":{"@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#primaryimage","url":"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?fit=1260%2C624&ssl=1","contentUrl":"https:\/\/i0.wp.com\/mribeirodantas.xyz\/blog\/wp-content\/uploads\/2020\/08\/docker.png?fit=1260%2C624&ssl=1","width":1260,"height":624},{"@type":"BreadcrumbList","@id":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/2020\/08\/18\/continuous-machine-learning-part-ii\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/mribeirodantas.xyz\/blog\/"},{"@type":"ListItem","position":2,"name":"Continuous Machine Learning &#8211; Part II"}]},{"@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":24,"uagb_excerpt":"Reading time: 3 minutesIn this second part of the series \u201cContinuous Machine Learning\u201d, we will use Docker to speed up our GitHub Actions checks.","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/paw9jx-12s","jetpack-related-posts":[],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996","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=3996"}],"version-history":[{"count":53,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996\/revisions"}],"predecessor-version":[{"id":4171,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3996\/revisions\/4171"}],"wp:attachment":[{"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=3996"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=3996"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mribeirodantas.xyz\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=3996"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}