<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ZenML</title>
    <description>The latest articles on DEV Community by ZenML (@zenml).</description>
    <link>https://dev.to/zenml</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5030%2Fea35aa11-ac11-44ba-92c8-b1e0f99341dc.png</url>
      <title>DEV Community: ZenML</title>
      <link>https://dev.to/zenml</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zenml"/>
    <language>en</language>
    <item>
      <title>How to improve your experimentation workflows with MLflow Tracking and ZenML</title>
      <dc:creator>Alex Strick van Linschoten</dc:creator>
      <pubDate>Thu, 24 Feb 2022 15:41:46 +0000</pubDate>
      <link>https://dev.to/zenml/how-to-improve-your-experimentation-workflows-with-mlflow-tracking-and-zenml-2dhe</link>
      <guid>https://dev.to/zenml/how-to-improve-your-experimentation-workflows-with-mlflow-tracking-and-zenml-2dhe</guid>
      <description>&lt;p&gt;Most professional or so-called 'citizen' data scientists will be familiar with the scenario that sees you spending a day trying out a dozen different model training configurations in which you experiment with various hyper parameters or perhaps different pre-trained models. As evening falls, you emerge from the haze of experimentation and you ask yourself: which of my experiments offered the best results for the problem I'm trying to solve?&lt;/p&gt;

&lt;p&gt;At this point, especially for smaller use cases or where you were unsure if a hunch was worth pursuing and just wanted to try a few things out, you might be left empty-handed, unable to give an answer one way or another beyond some hunch that there &lt;em&gt;was&lt;/em&gt; one set of parameters that really performed well, if only you could remember what they were… And if someone asked you to reproduce the steps it took you to create a particular model, would you even be able to do that?&lt;/p&gt;

&lt;p&gt;This would be one of those times where it's worth reminding ourselves that data science includes the word 'science', and that we need to be careful around how we track and reason about models. The workflows and practice of machine learning is sufficiently complicated (and often non-deterministic) that we need rigorous ways of ensuring that we really are doing what we think we are doing, and that we can reproduce our work. (It's not for nothing that 'reproducibility' is &lt;a href="https://petewarden.com/2018/03/19/the-machine-learning-reproducibility-crisis/" rel="noopener noreferrer"&gt;often&lt;/a&gt; &lt;a href="https://www.technologyreview.com/2019/02/18/137357/machine-learning-is-contributing-to-a-reproducibility-crisis-within-science/" rel="noopener noreferrer"&gt;paired&lt;/a&gt; with 'crisis'.)&lt;/p&gt;

&lt;p&gt;There are manual ways that you could use to help address this problem, but they're unlikely to be sufficient. Will your spreadsheet experiment tracker really capture &lt;em&gt;everything&lt;/em&gt; you needed to produce a particular model? (Think about how the particular configuration or random split of data is so central to how your model performs.) What you really want is something that will handle all this tracking of data and parameters, in as automatic a way as is possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use MLflow Tracking?
&lt;/h2&gt;

&lt;p&gt;Enter, &lt;a href="https://mlflow.org/docs/latest/tracking.html" rel="noopener noreferrer"&gt;MLflow Tracking&lt;/a&gt;, part of &lt;a href="https://mlflow.org/docs/latest/concepts.html" rel="noopener noreferrer"&gt;a wider ecosystem&lt;/a&gt; of tooling offered by MLflow to help you train robust and reproducible models. Other commonly-used pieces are &lt;a href="https://mlflow.org/docs/latest/model-registry.html" rel="noopener noreferrer"&gt;the model registry&lt;/a&gt; (which stores any model artifacts created during the training process) as well as their flexible suite of plugins and integrations allowing you to &lt;a href="https://mlflow.org/docs/latest/models.html#built-in-deployment-tools" rel="noopener noreferrer"&gt;deploy the models&lt;/a&gt; you create.&lt;/p&gt;

&lt;p&gt;MLflow Tracking is what allows you to track all those little parts of your model training workflow. Not only does it hook into an artifact store of your choosing (such as that offered by ZenML), but it offers a really useful UI interface which you can use to inspect pipeline runs and experiments you conduct. If you want to compare the performance or accuracy of several experiments (i.e. pipeline runs), some diagrams and charts are only a few clicks away. This flexible interface goes a really long way to solving some of the problems mentioned earlier.&lt;/p&gt;

&lt;p&gt;One really useful feature offered by MLflow Tracking is that of &lt;a href="https://mlflow.org/docs/latest/tracking.html#automatic-logging" rel="noopener noreferrer"&gt;automatic logging&lt;/a&gt;. Many commonly-used machine learning libraries (such as &lt;code&gt;scikit-learn&lt;/code&gt;, Pytorch, &lt;code&gt;fastai&lt;/code&gt; and Tensorflow / Keras) support this. You either call &lt;code&gt;mlflow.autolog()&lt;/code&gt; just before your training code, or you use a library-specific version of that (e.g. &lt;code&gt;mlflow.sklearn.autolog()&lt;/code&gt;). In this way, MLflow will handle logging metrics, parameters and models without the need for explicit log statements. (Note that you can also include the &lt;a href="https://mlflow.org/docs/latest/tracking.html#logging-data-to-runs" rel="noopener noreferrer"&gt;non-automated logging&lt;/a&gt; of whatever custom properties are important for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  ZenML + MLflow Tracking = 🚀
&lt;/h2&gt;

&lt;p&gt;If you're using ZenML to bring together the various tools in your machine learning stack, you'll probably be eager to use some of this tracking goodness and make your own experiments more robust. ZenML actually &lt;em&gt;already&lt;/em&gt; partly supported what MLflow Tracking does in the sense that any artifacts going in or out of the steps of your ZenML pipeline were being tracked, stored and versioned in your artifact and metadata store. (You're welcome!) But until now we didn't have a great way for you to interact with that metadata about your experiments and pipeline runs that was non-programmatic and also visual.&lt;/p&gt;

&lt;p&gt;MLflow Tracking gives you that ability to inspect the various experiments and pipeline runs in the (local) web interface and is probably going to be a friendlier way of interacting with and reasoning about your machine learning experiments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm695n5ozqsakpbm2vb8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm695n5ozqsakpbm2vb8u.png" alt="Tracking machine learning training runs with MLFlow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You could have used MLflow Tracking in the past, too, but with our latest integration updates ZenML handles some of the boilerplate complicated setup that comes with using MLflow. There are &lt;a href="https://mlflow.org/docs/latest/tracking.html#where-runs-are-recorded" rel="noopener noreferrer"&gt;different ways&lt;/a&gt; of deploying the tracking infrastructure and servers and it isn't a completely painless task to set all this up and to get going with MLflow Tracking. This is where we make your life a bit easier: we setup everything you need to use it on your (currently: local) machine, connecting the MLFlow Tracking interface to your ZenML artifact store. It can be a bit tricky to configure the relevant connections between the various modular pieces that talk to each other, and we hide this from you beneath an abstraction.&lt;/p&gt;

&lt;p&gt;We think that this ability to converse between the MLflow universe and the ZenML universe is extremely powerful, and this approach is at the heart of what we are trying to build with our tool to help you work with reproducible and robust machine learning pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just tell me how to use it already!
&lt;/h2&gt;

&lt;p&gt;The best place to see MLflow Tracking and ZenML being used together in a simple use case is &lt;a href="https://github.com/zenml-io/zenml/tree/main/examples/mlflow_tracking" rel="noopener noreferrer"&gt;our example&lt;/a&gt; that showcases the integration. It builds on the quickstart example, but shows how you can add in MLflow to handle the tracking. In order to enable MLflow to track artifacts inside a particular step, all you need is to decorate the step with &lt;code&gt;@enable_mlflow&lt;/code&gt; and then to specify what you want logged within the step. Here you can see how this is employed in a model training step that uses the &lt;code&gt;autolog&lt;/code&gt; feature I mentioned above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Define the step and enable mlflow - order of decorators is important here
&lt;/span&gt;&lt;span class="nd"&gt;@enable_mlflow&lt;/span&gt;
&lt;span class="nd"&gt;@step&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tf_trainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TrainerConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;x_train&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Train a neural net from scratch to recognize MNIST digits return our
    model or the learner&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Flatten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;losses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SparseCategoricalCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_logits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accuracy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tensorflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;autolog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;x_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# write model
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If, for any reason, you need to access the global environment parameters used by ZenML to automatically configure MLflow (which define where and how experiments and runs are displayed and stored in the MLflow Tracking UI/system), we've got you covered. These global parameters can be easily accessed through the &lt;code&gt;Environment&lt;/code&gt; singleton object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;zenml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integrations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mlflow_environment&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MLFLOW_ENVIRONMENT_NAME&lt;/span&gt;
&lt;span class="n"&gt;mlflow_env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="n"&gt;MLFLOW_ENVIRONMENT_NAME&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out &lt;a href="https://apidocs.zenml.io/0.6.1/api_docs/environment/" rel="noopener noreferrer"&gt;the API docs&lt;/a&gt; to learn more about the &lt;code&gt;Environment&lt;/code&gt; object and watch this space for a blog post where we explain more about why we chose to add this recently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Over to you now!
&lt;/h2&gt;

&lt;p&gt;If you're inspired by this illustration of how you can make your machine learning workflow that little bit more reproducible and robust, check out &lt;a href="https://github.com/zenml-io/zenml/tree/main/examples/mlflow_tracking" rel="noopener noreferrer"&gt;the full example&lt;/a&gt; that illustrates the integration. If you use it in your own code base, please do let us know — &lt;a href="https://zenml.io/slack-invite/" rel="noopener noreferrer"&gt;say hi on Slack&lt;/a&gt;! — and as always if you have any questions, we're here for you.&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>machinelearning</category>
      <category>experimentation</category>
      <category>mlops</category>
    </item>
    <item>
      <title>Taking on the ML pipeline challenge: why data scientists need to own their ML workflows in production</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:35:02 +0000</pubDate>
      <link>https://dev.to/zenml/taking-on-the-ml-pipeline-challenge-why-data-scientists-need-to-own-their-ml-workflows-in-production-1gla</link>
      <guid>https://dev.to/zenml/taking-on-the-ml-pipeline-challenge-why-data-scientists-need-to-own-their-ml-workflows-in-production-1gla</guid>
      <description>&lt;p&gt;This article discusses the benefits of giving data scientists ownership of their workflows in a production environment. We also discuss ZenML, an open-source framework that is built specifically to facilitate this ownership.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we need ML pipelines?
&lt;/h2&gt;

&lt;p&gt;Let’s start with the most obvious question: Why do we need ML pipelines in the first place? Here are some solid reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ML pipelines are the best way to &lt;strong&gt;automate ML workflows&lt;/strong&gt; in a repeatable, robust and &lt;strong&gt;reproducible&lt;/strong&gt; manner.&lt;/li&gt;
&lt;li&gt;Organizations can centralize, collaborate, and manage workflows with a &lt;strong&gt;standardized&lt;/strong&gt; interface.&lt;/li&gt;
&lt;li&gt;ML pipelines can be seen as a means of &lt;strong&gt;coordination&lt;/strong&gt; between different departments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, awesome as ML pipelines are, they do come with some inherent questions which might prove problematic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ownership Dilemma
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ojmFC3Sk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gjpjq9um0scfml5vslj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ojmFC3Sk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gjpjq9um0scfml5vslj.png" alt="ML In Production is confusing" width="704" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One question that organizations developing machine learning need to answer is &lt;strong&gt;who owns ML pipelines in production&lt;/strong&gt;? Is it the data scientist who creates the model? Is it the data engineer who deploys it in production? Is it someone else altogether?&lt;/p&gt;

&lt;p&gt;Note: For an overview of the roles involved in the ML process, check out this part of &lt;a href="https://fall2019.fullstackdeeplearning.com/course-content/ml-teams/roles"&gt;UC Berkeley’s Full Stack Deep Learning Course&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The data dimension of ML makes it &lt;a href="https://research.google/pubs/pub46555/"&gt;significantly more complex&lt;/a&gt; than other deployments in production. More often than not, data scientists do not have the skill set to reliably guide a model into production. Therefore, it is only natural for teams to organize in such a way that there is a shift of ownership from the training phase of development to the deployment phase in the direction of the engineering department (&lt;a href="https://wiki.c2.com/?ThrownOverTheWall"&gt;thrown over the wall&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Organizing this way makes it easy enough to get a model in production &lt;strong&gt;once&lt;/strong&gt;. However, the ownership question really comes into play when things (inevitably) &lt;strong&gt;go wrong&lt;/strong&gt;. This could be as the model/concept drifts, or something times out, or the data format changes, or a million other things that the engineering department would know nothing about as they &lt;strong&gt;didn't produce the model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Also, the farther away you push the data scientist from a production setting, the harder it is to establish a &lt;a href="https://blog.modyo.com/posts/data-flywheel-scaling-a-world-class-data-strategy"&gt;data-flywheel effect&lt;/a&gt; of consistent improvement of your models in production. The data scientist needs a wider context in order to be able to make the right calls when training the model. E.g. Should we sacrifice the AUROC a few percent, if that means the model might perform faster in production and yield higher revenue? There is no chance one can even ask that question if just looking at model metrics like AUROC.&lt;/p&gt;

&lt;p&gt;Indeed, the further we push the data scientist from production, &lt;a href="https://multithreaded.stitchfix.com/blog/2019/03/11/FullStackDS-Generalists/#back-1"&gt;the less productive the overall ML process will get, and the higher the coordination costs and wait times will get&lt;/a&gt;. That’s a no-go for ML, which is supposed to be fast and iterative process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the Ownership Dilemma
&lt;/h2&gt;

&lt;p&gt;Recently, there has been a lot of talk about &lt;a href="https://huyenchip.com/2021/09/13/data-science-infrastructure.html"&gt;how data scientists shouldn’t need to know Kubernetes&lt;/a&gt;, or the underlying production infrastructure needs to be necessarily abstracted from them to perform at a high level. I would not only agree with this, but also posit that we have to go one step further. We not only need to abstract the infrastructure from data scientists, but help them take &lt;strong&gt;ownership&lt;/strong&gt; of their models all the way to production.&lt;/p&gt;

&lt;p&gt;If a team leaves writing ML pipelines for later, they will &lt;a href="https://towardsdatascience.com/avoiding-technical-debt-with-ml-pipelines-3e5b6e0c1c93?source=your_stories_page-------------------------------------&amp;amp;gi=9118ab490b18"&gt;quickly accrue technical debt&lt;/a&gt;. With the right abstractions, an organization can incentivize their data scientists to start &lt;a href="https://towardsdatascience.com/why-ml-should-be-written-as-pipelines-from-the-get-go-b2d95003f998"&gt;writing end-to-end ML pipelines early in the development process&lt;/a&gt;. Once data scientists start writing their training/development workflows with easily ‘transferable’ ML pipelines, they would find themselves in a familiar environment once these same pipelines go into production. They would then have the tools necessary to also go into production systems and fix problems as they occur, or make improvements as time goes on.&lt;/p&gt;

&lt;p&gt;Ideally, the pipeline becomes a mechanism through which the producers of the models (i.e. the data scientists) can take ownership of their models all the way to production.&lt;/p&gt;

&lt;p&gt;Note that this does &lt;strong&gt;NOT&lt;/strong&gt; mean that data scientists should now know every toolkit in the engineering toolbox (like complex deployments of Kubernetes clusters). Rather, the argument is that we need to set data scientists up so that they can take their code to production themselves, with the help required from necessary tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter ZenML: A framework designed for modern MLOps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/zenml-io/zenml"&gt;ZenML&lt;/a&gt; is an open-source MLOps Pipeline Framework built specifically to address the problems above. Let’s break it down what a MLOps Pipeline Framework means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MLOps&lt;/strong&gt;: It operates in the domain of operationalizing machine learning, i.e., putting ML workflows in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline&lt;/strong&gt;: It does this by helping create pipelines, i.e., a sequence of steps performed in this case, specifically for a ML setting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework&lt;/strong&gt;: Finally, it creates these pipelines software with abstractions providing generic functionality, which can be selectively changed by additional user-written code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it's a tool that let’s you define pipelines but how is it different from the others? Here is what sets it apart:&lt;/p&gt;

&lt;h3&gt;
  
  
  Accommodating the Exploding ML Tooling Landscape
&lt;/h3&gt;

&lt;p&gt;Everybody knows that we are now &lt;a href="https://huyenchip.com/2020/06/22/mlops.html"&gt;in the midst of an explosion in the ML/MLOps tooling landscape&lt;/a&gt;. ZenML is explicitly designed to have no opinions about the underlying infrastructure/tooling that you would like to use. Rather it exposes higher level concepts like Metadata Stores , Artifact Stores, and Orchestrators that have common interfaces. A ML team can then swap out individual components of their pipelines backends and it will ‘just work’.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bCeAwOJr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3629woe2qow92mt4einq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bCeAwOJr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3629woe2qow92mt4einq.jpeg" alt="Look closer: This isn’t the Hidden Technical Debt Diagram ;-)" width="880" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, if you even want to use &lt;a href="https://mlflow.org/"&gt;MLFlow&lt;/a&gt; to track your experiments, run the pipeline on &lt;a href="https://airflow.apache.org/"&gt;Airflow&lt;/a&gt;, and then deploy a model to a &lt;a href="https://neptune.ai/"&gt;Neptune&lt;/a&gt; Model Registry, ZenML will facilitate this MLOps Stack for you. This decision can be made jointly by the data scientists and engineers. As ZenML is a framework, custom pieces of the puzzle can also be added here to accommodate legacy infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Focus on Machine Learning Workflows (at every phase)
&lt;/h3&gt;

&lt;p&gt;There are many tools that let you define workflows as pipelines but few that focus &lt;strong&gt;explicitly on machine learning use-cases&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;trainer&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;trainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="p"&gt;...&lt;/span&gt; 
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an example, in the above code, ZenML will understand that this is not just a step in the pipeline, but a trainer step. It can use that information to aid in ML-specific use-cases like storing the result in a model registry, deploying this step on GPUs, hyper-parameter tuning etc.&lt;/p&gt;

&lt;p&gt;Also notice that ZenML fully supports objects from common ML frameworks like &lt;code&gt;torch.Dataset&lt;/code&gt; and &lt;code&gt;torch.nn.Module&lt;/code&gt;. These objects can be passed between steps and results cached to enable faster experimentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incentivizing the data scientist to write these pipelines
&lt;/h3&gt;

&lt;p&gt;ZenML understands that pipelines are going to change over time. Therefore, it encourages running these pipelines locally to begin with and experimenting with the results as they are produced. You can query pipelines in a local Jupyter notebook, and materialize it with different pre-made visualizations like statistics visualizations and schema anomalies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AJvHScpc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jib8x5dymzrb0njmbsad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AJvHScpc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jib8x5dymzrb0njmbsad.png" alt="After running pipelines, one can fetch them and see results easily, no matter if run locally or not" width="685" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a different approach to pipeline development, and is more representative of how a data scientist would like to work in the earlier phases of a project → i.e. with fast, quick iterations and visualizations that help them to make informed decisions about experiments. We call this approach &lt;strong&gt;Pipelines As Experiments (PaE)&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;In short, ZenML allows you to create automated ML workflows with simple, extensible abstractions that lift the common pattern burden off of you. In doing so, it does not take opinions on the underlying infrastructure and aims to be cloud- and tooling-agnostic.&lt;/p&gt;

&lt;p&gt;By helping the target audience, i.e. the data scientist, to write their code in ZenML pipelines &lt;strong&gt;early in the development lifecycle&lt;/strong&gt;, the transition from the experimentation phase to the production phase is made much easier. The goal is that by the time the experimentation phase of the ML lifecycle is over, the data scientists can flip a switch to the production ML stack and get their pipelines running in production. At this moment, they would have complete ownership of these pipelines and can manage, update, and debug them as they please.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Story So Far
&lt;/h2&gt;

&lt;p&gt;To date, ZenML has received:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1336 &lt;a href="https://github.com/zenml-io/zenml"&gt;GitHub Stars&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;10 &lt;a href="https://github.com/zenml-io/zenml/graphs/contributors"&gt;Contributors&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;~200 &lt;a href="https://zenml.io/slack-invite"&gt;Slack&lt;/a&gt; Members&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It has been fantastic to see people’s interest in what was initially just a simple idea. We’re now building &lt;a href="https://zenml.io/newsletter"&gt;ZenML out in the open (no stealth here)&lt;/a&gt;, and just made &lt;a href="https://github.com/zenml-io/zenml/releases"&gt;a major release&lt;/a&gt; with a complete refactor of the codebase. So, if any of the above appealed to you, it would be lovely if you gave ZenML a spin with an &lt;a href="https://docs.zenml.io/guides/low-level-api"&gt;end-to-end example of deploying a pipeline in production&lt;/a&gt;. Feedback and contributions are welcome!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My sincerest thanks to Alex Strick and Adam Probst for helping edit this article.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pipelines</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
    </item>
    <item>
      <title>Why ML should be written as pipelines from the get-go</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:31:51 +0000</pubDate>
      <link>https://dev.to/zenml/why-ml-should-be-written-as-pipelines-from-the-get-go-22m2</link>
      <guid>https://dev.to/zenml/why-ml-should-be-written-as-pipelines-from-the-get-go-22m2</guid>
      <description>&lt;p&gt;Today, Machine Learning powers the top 1% of the most valuable organizations in the world (FB, ALPH, AMZ, N etc). However, 99% of enterprises struggle to productionalize ML, even with the possession of hyper-specific datasets and exceptional data science departments.&lt;/p&gt;

&lt;p&gt;Going one layer further into how ML propagates through an organization reveals the problem in more depth. The graphic below shows an admittedly simplified representation of a typical setup for machine learning:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7nSKKCVz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2nszg1xyuzv1fqjdoc0c.png" alt="Why it’s hard to reproduce ML models" width="700" height="393"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Figure 1: Why it’s hard to reproduce ML models&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
There are three stages to the above process:&lt;/p&gt;

&lt;h2&gt;
  
  
  Experimenting &amp;amp; PoCs:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technologies&lt;/strong&gt;: Jupyter notebooks, Python scripts, experiment tracking tools, data exploration tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persona&lt;/strong&gt;: Data scientists&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: Quick and scientific experiments define this phase. The team wants to increase their understanding of the data and machine learning objective as rapidly as possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conversion:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technologies&lt;/strong&gt;: ETL pipelining tools such as Airflow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persona&lt;/strong&gt;: Data Engineers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: Converting finalized experiments into automated, repeatable processes is the aim of this code. Sometimes this starts before the next phase, some times after, but the essence is the same — take the code from the data scientists and try to put them in sort form of an automated framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Productionalization &amp;amp; Maintenance:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technologies&lt;/strong&gt;: Flask/FastAPI, Kubernetes, Docker, &lt;a href="http://cortex.dev/"&gt;Cortex&lt;/a&gt;, &lt;a href="https://www.seldon.io/"&gt;Seldon&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persona&lt;/strong&gt;: ML Engineers / Ops&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: This is the phase that starts at the deployment of the model, and spans monitoring, retraining, and maintenance. The core focus of this phase is to keep the model healthy and serving at any scale, all the while accounting for drift.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these stages requires different skills, tooling, and organization. Therefore, it is only natural that there are many potholes that an organization can run into along the way. Inevitably things that are important downstream are not accounted for in the earlier stages. E.g. If training happens in isolation from the deployment strategy, that is never going to translate well in production scenarios — leading to inconsistencies, silent failures, and eventually failed model deployments.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Solution
&lt;/h1&gt;

&lt;p&gt;Looking at the above multi-phase process in Figure 1, it seems like a no-brainer to simply reduce the steps involved and therefore eliminate the friction that exists between them. However, given the different requirements + skillsets for each step, this is easier said than done. Data scientists are not trained or equipped to be diligent to care about production concepts such as reproducibility — they are &lt;strong&gt;trained to iterate and experiment&lt;/strong&gt;. They don’t really care about code quality and it is probably not in the best interest of the company at an early point to be super diligent in enforcing these standards, given the trade-off between speed and overhead.&lt;/p&gt;

&lt;p&gt;Therefore, what is required is an implementation of a framework that is &lt;strong&gt;flexible but enforces production standards&lt;/strong&gt; from the get-go. A very natural way of implementing this is via some form of pipeline framework that exposes an automated, standardized way to run ML experiments in a controlled environment. ML is inherently a process that can be broken down into individual, concrete steps (e.g. preprocessing, training, evaluating, etc), so a pipeline is a good solution here. Critically, by standardizing the development of these pipelines at the early stages, organizations can lose the cycle of destruction/recreation of ML models through multiple toolings and steps, and hasten the speed of research to deployment.&lt;/p&gt;

&lt;p&gt;If an organization can incentivize their data scientists to buy into such a framework, &lt;strong&gt;then they have won half the battle of productionalization&lt;/strong&gt;. However, the devil is really in the details — how do you give data scientists the flexibility they need for experimentation in a framework that is robust enough to be taken all the way to production?&lt;/p&gt;

&lt;h1&gt;
  
  
  An exercise in finding the right abstractions
&lt;/h1&gt;

&lt;p&gt;Having motivated writing in pipelines from the get-go, it is only fair that I give more concrete examples of frameworks on how to achieve this. However, in my opinion, currently, the tooling landscape is too split into frameworks that are ML tools for ML people, or Ops tools for Ops people, not really satisfying all the boxes I mentioned in the last section. What is missing is an Ops (read pipelines) tool for ML people, with &lt;strong&gt;higher-order abstractions at the right level for a data scientist&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In order to understand why this is important, we can cast an eye towards how web development has matured from raw PHP/jQuery-based scripts (the Jupyter notebooks of web development) with the LAMP stack to the powerful React/Angular/Vue-based modern web development stacks of today. Looking at these modern frameworks, their success has been dictated by providing higher-order abstractions that are easier to consume and digest for a larger audience. They did not change the fundamentals of how the underlying web technology worked. They simply re-purposed it in a way that is understandable and accessible to a larger audience. Specifically, by providing components as first-class citizens, these frameworks have ushered in a new mechanism of breaking down, utilizing, and resharing the HTML and Javascript that powers the modern web. However, ML(Ops) does not have an equivalent movement to figure out the right order of abstraction to have a similar effect.&lt;/p&gt;

&lt;p&gt;To showcase a more concrete example of my more abstract thoughts above, I’ll use &lt;a href="https://github.com/maiot-io/zenml"&gt;ZenML&lt;/a&gt;, an open-source MLOps framework to create iterative, reproducible pipelines.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: I am one of the core maintainers of ZenML.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/maiot-io/zenml"&gt;ZenML&lt;/a&gt; is an exercise in finding the right layer of abstraction for ML. Here, we treat pipelines as first-class citizens. This means that data scientists are exposed to pipelines directly in the framework, but not in the same manner as the data pipelines from the ETL space (&lt;a href="https://www.prefect.io/"&gt;Prefect&lt;/a&gt;, &lt;a href="https://airflow.apache.org/"&gt;Airflow&lt;/a&gt; et al.). Pipelines are treated as experiments — meaning they can be compared and analyzed directly. Only when it is time to flip over to productionalization, can they be converted to classical data pipelines.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JErD6H63--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7zozf732n2foq9lygu3.png" alt="ZenML abstract pipelines with familiar language to increase ownership of model deployments" width="700" height="393"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Figure 2: ZenML abstract pipelines with familiar language to increase ownership of model deployments.&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Within pipelines are steps, that are abstracted in familiar ML language towards the data scientist. e.g. There is a &lt;code&gt;TokenizerStep&lt;/code&gt;, &lt;code&gt;TrainerStep&lt;/code&gt;, &lt;code&gt;EvaluatorStep&lt;/code&gt; and so on. Paradigms that are way more understandable than plugging scripts into some form of orchestrator wrapper.&lt;/p&gt;

&lt;p&gt;Each pipeline run tracks the metadata, parameters and can be compared to other runs. The data for each pipeline is automatically versioned and tracked as it flows through. Each run is linked to git commits and compiled into an easy-to-read YAML file, which can be optionally compiled to other DSL’s such as on Airflow or Kubeflow Pipelines. This is necessary to satisfy other stakeholders such as the data engineers and ML engineers in the value chain.&lt;/p&gt;

&lt;p&gt;Additionally, the interfaces exposed for individual steps are mostly set up in a way to be easy to extend in an idempotent, and therefore a distributed, manner. The data scientist can therefore scale-out with different processing backends (like Dataflow/Spark) when they are dealing with larger datasets.&lt;br&gt;
All in all, ZenML is trying to get to the following scenario:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MZYrhvuy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/voux52y49jvib4odcigg.png" alt="Figure 3: ZenML unifies the ML process." width="700" height="393"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Figure 3: ZenML unifies the ML process.&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Of course, &lt;a href="https://github.com/maiot-io/zenml"&gt;ZenML&lt;/a&gt; is not the only mechanism to achieve the above — Many companies build their own home-grown abstraction frameworks to solve their specific needs. Often-times these are built on top of some of the other tools I have mentioned above. Regardless of how to get there, the goal should be clear: Get the data scientists &lt;strong&gt;as close to production as possible&lt;/strong&gt; with as little friction as possible, incentivizing them to increase their ownership of the models after deployment.&lt;/p&gt;

&lt;p&gt;This is a win-win-win for every persona involved, and ultimately a big win for any organization that aims to make it to the top 1% using ML as a core driver for their business growth.&lt;/p&gt;

&lt;h1&gt;
  
  
  Plug
&lt;/h1&gt;

&lt;p&gt;If you like the thoughts here, we’d love to hear your feedback on ZenML. It is &lt;a href="https://github.com/maiot-io/zenml"&gt;open-source&lt;/a&gt; and we are looking for early adopters and &lt;a href="https://github.com/maiot-io/zenml"&gt;contributors&lt;/a&gt;! And if you find it is the right order of abstraction for you/your data scientists, then let us know as well via &lt;a href="http://zenml.io/slack-invite"&gt;our Slack&lt;/a&gt; — looking forward to hearing from you!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Spot the difference in ML costs</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:28:00 +0000</pubDate>
      <link>https://dev.to/zenml/spot-the-difference-in-ml-costs-4e1d</link>
      <guid>https://dev.to/zenml/spot-the-difference-in-ml-costs-4e1d</guid>
      <description>&lt;p&gt;Every organization at any scale understands that leveraging the public cloud is a trade-off between convenience and cost. While cloud providers like Google, Amazon and Microsoft have immensely reduced the barrier of entry for machine learning, GPU costs are still at a premium.&lt;/p&gt;

&lt;p&gt;There is an &lt;a href="https://venturebeat.com/2020/06/01/ai-machine-learning-openai-gpt-3-size-isnt-everything/"&gt;increasing fear in the machine learning community&lt;/a&gt; that the true power of machine learning is still within the hands of the few. The flagship example of this is OpenAI's massive GPT-3 model containing 175 billion parameters, a memory footprint of 350GB and reportedly costing at least &lt;a href="https://lambdalabs.com/blog/demystifying-gpt-3/"&gt;$4.6 million&lt;/a&gt; to train. The trend also looks set to continue: Rumours consistently circulate regarding the next generation GPT-4's size, with some estimates ranging in the order of &lt;a href="https://www.metaculus.com/questions/4852/how-many-parameters-will-gpt-4-have-if-it-is-released-in-billions-of-parameters/"&gt;&lt;strong&gt;trillions&lt;/strong&gt; of parameters&lt;/a&gt;. Even with more efficient training techniques, these models will still cost in the order of millions to train.&lt;/p&gt;

&lt;p&gt;For the rest of the ML community, there is now an increasing reliance on their secret weapon: Transfer learning. Just recently, the excellent &lt;a href="https://huggingface.co/"&gt;HuggingFace&lt;/a&gt; library &lt;a href="https://twitter.com/huggingface/status/1351560093658198022"&gt;announced a simple method&lt;/a&gt; to fine-tune large-scale parameter models on a single cloud GPU. This gives hope to ML practitioners that even if they are unable to train models from scratch, utilizing the immense power of modern-day machine learning models is still within reach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The need for the cloud
&lt;/h2&gt;

&lt;p&gt;Whether training from scratch, or fine-tuning, it is still clear that public cloud providers offer the most convenient path to provision and utilize compute resources for most ML practitioners out there. However, even for fine-tuning tasks or smaller models, these costs can quickly grow and become unmanageable. For example, here is a simple breakdown of much it costs to train a machine learning model on a relatively mid-tier configuration suitable for many machine learning tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Provider | Configuration           | Cost ($/h)    |
|----------|-------------------------|---------------|
| GCP      | n1-standard-16 with P4  | 1.36          |
| Azure    | NV6 with M60            | 1.14          |
| AWS      | g3.4xlarge with M60     | 1.14          |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bear in mind that the above costs are just for one training run. Most machine learning projects go through much more experimentation phases, and these numbers add up quickly. Therefore, most ML teams who do not have vast budgets on their hands usually resort to sampling their datasets and portioning out big training runs for when they are sure. This can be slow and tedious, not to mention hard to coordinate. It can also lead to teams converging to the wrong results. If the smaller, sampled datasets are not representative of the larger dataset, it can lead to frustrating and diverging results as the models develop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spot instances: A perfect fit for ML experimentation
&lt;/h2&gt;

&lt;p&gt;Would it not be easy if ML practitioners had the luxury to launch experiments without having to fret so much about the costs exploding over time? There might be just be a solution, offered by all major cloud providers, and severely underutilized by the machine learning community: &lt;strong&gt;Preemptible/Spot instances.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The word preemptible instance is largely a Google Cloud Platform term, while spot instance is used by AWS/Azure. Whatever you call it, the concept is the same: These instances cost a fraction of the cost of normal instances, and the only catch is that there is no guarantee that the instance stays up all the time. Usually, this means that within 24 hours the instance is shut down by the provider.&lt;/p&gt;

&lt;p&gt;These sorts of instances are a mechanism for the cloud providers to maximize the utilization of all their resources at any given time. They are intended for batched, non-critical workloads. Most trainings jobs for the majority of the use-cases out there take less than 24 hours to complete. And even if the job is interrupted before that happens, they can almost always be restarted from checkpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost comparison: 80% cost reduction
&lt;/h2&gt;

&lt;p&gt;Therefore, machine learning training fits the intended use of spot instances perfectly. By using these instances, practitioners stand to gain massive cost reductions. We have conducted a rough analysis across the three major cloud providers to showcase the cost benefits. The raw data can be found &lt;a href="https://docs.google.com/spreadsheets/d/1wErQviA3sI22fh3BscO4CMJyg6w1Qqi468O1bCxUFhc/edit?usp=sharing"&gt;here&lt;/a&gt;. Feel free to share the doc and leave a comment if you find something to add. Here is a snapshot, with the same configurations as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Provider | Configuration           | Cost ($/h) | Spot Cost ($/h) | Savings |
|----------|-------------------------|------------|---------------------------|
| GCP      | n1-standard-16 with P4  | 1.36       | 0.38            | 72%     |
| Azure    | NV6 with M60            | 1.14       | 0.20            | 82%     |
| AWS      | g3.4xlarge with M60     | 1.14       | 0.34            | 70%     |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: All costs in the US region, AWS instance pricing as of January 28, 14:00 CET.&lt;/p&gt;

&lt;p&gt;As can be seen, depending on the configuration, there is up to &lt;strong&gt;82%&lt;/strong&gt; cost reduction by using spot instances, with the average cost savings across multiple cloud and configurations being rougly &lt;strong&gt;74%&lt;/strong&gt;. This can equate to hundreds of dollars worth of savings. Especially for hobbyists, smaller companies, or smaller departments experimenting with Machine Learning, this may mean the difference between getting a model deployed vs crashing and burning before lift-off.&lt;/p&gt;

&lt;p&gt;Using this technique is not new: Way back in 2018, the FastAI team &lt;a href="https://www.fast.ai/2018/08/10/fastai-diu-imagenet/"&gt;trained ImageNet in 18 minutes with 16 AWS spot instances&lt;/a&gt;. This cost $40 at the time, and was the most public display of the insane cost benefits of spot instances in the community.&lt;/p&gt;

&lt;p&gt;However, given the trend of increasingly big models, and the increasing adoption of AI worldwide, I can only see the need for spot instance training increasing over time. Given the dramatic difference in costs, it is almost a no-brainer to use spot instance training as a primary mechanism for training, at least in the experimentation phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  ZenML: A simple tool to orchestrate spot instance training
&lt;/h2&gt;

&lt;p&gt;If you're looking for a head start for spot instance training, check out &lt;a href="https://github.com/zenml-io/zenml"&gt;ZenML&lt;/a&gt;, an open-source MLOps framework for reproducible machine learning. Running spot pipeline in ZenML, is as easy as :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;training_pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrchestratorGCPBackend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;preemptible&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# reduce costs by using preemptible (spot) instances
&lt;/span&gt;        &lt;span class="n"&gt;machine_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'n1-standard-4'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'nvidia-tesla-k80'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;gpu_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/htahir1/62dc4baa12560e8b88ce156f76aaab5f"&gt;See gist here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ZenML not only zips your code up to the instance, it also makes sure the right CUDA-drivers are enabled to take advantage of the accelerator of your choice. It provisions the instance, and spins it down when the pipeline is done. Not to mention the other benefits of experiment tracking, versioning and metadata management which is provided anyway by the framework. Give it a spin yourself: A full code example can be found &lt;a href="https://github.com/zenml-io/zenml/tree/main/examples"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AWS and Azure support is on the horizon, and we'd love your feedback on the current setup. If you like what you see, leave us a &lt;a href="https://github.com/zenml-io/zenml"&gt;star at the GitHub repo&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
    </item>
    <item>
      <title>Is your Machine Learning Reproducible?</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:26:19 +0000</pubDate>
      <link>https://dev.to/zenml/is-your-machine-learning-reproducible-jfk</link>
      <guid>https://dev.to/zenml/is-your-machine-learning-reproducible-jfk</guid>
      <description>&lt;p&gt;It is now widely agreed that &lt;a href="https://blog.ml.cmu.edu/2020/08/31/5-reproducibility/"&gt;reproducibility is an important aspect of any scientific endeavor&lt;/a&gt;. With Machine Learning being a scientific discipline, as well as an engineering one, reproducibility is equally important here.&lt;/p&gt;

&lt;p&gt;There is widespread fear in the ML community that we are living through a &lt;a href="https://www.wired.com/story/artificial-intelligence-confronts-reproducibility-crisis"&gt;reproducibility crisis&lt;/a&gt;. Efforts like the &lt;a href="https://paperswithcode.com/rc2020"&gt;Papers with Code Reproducibility Challenge&lt;/a&gt;, signaled a clear call-to-action for practitioners, after a 2016 Nature survey revealed that &lt;a href="https://www.nature.com/news/1-500-scientists-lift-the-lid-on-reproducibility-1.19970"&gt;70% of results are non-reproducible&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While a lot of the talk amongst the community has centered on &lt;a href="https://www.sciencedirect.com/science/article/pii/S2666389920300933"&gt;reproducing machine learning results in research&lt;/a&gt;, there has been less focus on the production side of things. Therefore, today let’s focus more on the topic of reproducible ML in production and create a larger conversation around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is reproducibility important?
&lt;/h2&gt;

&lt;p&gt;“If you can’t repeat it, you can’t trust it” - All Ops Teams&lt;/p&gt;

&lt;p&gt;A good question to start with is why exactly reproducibility is important, for machine learning in particular. Here are list of benefits one gains by ensuring reproducibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increases &lt;strong&gt;trust&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Promotes &lt;strong&gt;explainability&lt;/strong&gt; of ML results&lt;/li&gt;
&lt;li&gt;Increases &lt;strong&gt;reliability&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Fulfills &lt;strong&gt;ethical&lt;/strong&gt;, &lt;strong&gt;legal&lt;/strong&gt;, and &lt;strong&gt;regulatory&lt;/strong&gt; requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Concretely, ML models tend to go through a lifecycle of being destroyed, forged anew and re-created as &lt;a href="https://blog.zenml.io/technical_debt/"&gt;development evolves from rudimentary notebook snippets to a testable, productionized codebase&lt;/a&gt;. Therefore, we better make sure that every time a model is (re-) trained, the results are what we expect them to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the big deal?
&lt;/h2&gt;

&lt;p&gt;One would think that reproducibility in production ML should be easy. After all, most machine learning is scripting. How hard can it be to simply execute a bunch of scripts again at a later stage and come to the exact same result, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;wrong&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reproducibility of machine learning is hard because it spans many different disciplines, from understanding non-deterministic algorithmic behaviors, to software engineering best practices. Leaving aside the fact that most machine learning code quality tends to err towards the low side (due to the experimental nature of the work), there is an inherent complexity to ML which makes things even harder.&lt;/p&gt;

&lt;p&gt;E.g. Just training a model on the same data with the same configuration does not mean the same model is produced. Perhaps one could achieve a similar &lt;em&gt;overall&lt;/em&gt; accuracy (or whatever other metric), but even a slight change in parameters might skew metrics for slices of your data - leading to &lt;a href="https://www.theverge.com/2018/1/12/16882408/google-racist-gorillas-photo-recognition-algorithm-ai"&gt;sometimes very unpleasant results&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, how can we ensure that stuff like does not happen? In my opinion, one can break down reproducibility in the following aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code&lt;/li&gt;
&lt;li&gt;The configuration&lt;/li&gt;
&lt;li&gt;The environment&lt;/li&gt;
&lt;li&gt;The data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at each of these in turn.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;Checking code into a version control system like Git ensures a clean trace of how code evolves, and the ability to rollback to any point in history. However, Git alone is not a fix for reproducibility, but only for one aspect of it.&lt;/p&gt;

&lt;p&gt;In reality, reproducibility in production is solved by version control, testing of code as well as integrations, and idempotent deployment automation. This is hard to apply in practice. E.g. The main tool for ML is Jupyter notebooks, which are notoriously difficult to check into version control. Even worse, most notebook code is not sequential in its execution, and can have an arbitrary, impossible to reproduce, sequence of execution.&lt;/p&gt;

&lt;p&gt;But even if ML practitioners follow a pattern of refactoring their code into separate modules, simply checking modules into source control is still not enough to ensure reproducibility. One needs to link the commit history to model training runs and models. This can be achieved e.g. by enforcing a standard in your team that pins a git sha to experiment runs. That way there is a global unique ID that ties the code and configuration (see below) to the results it produced.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;Software Engineering preaches separation of application code and application configuration to allow for predictable and deterministic software behavior across environments. This actually translates well in a machine learning code: E.g. one can separate the model definition and training loop code, from the associated hyper-parameters which define the configuration.&lt;/p&gt;

&lt;p&gt;The first step to unlock reproducibility is to actually separate configuration from code in the first place. For me this means, the code itself should NOT define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Features&lt;/li&gt;
&lt;li&gt;Labels&lt;/li&gt;
&lt;li&gt;Split parameters (e.g. 80-20 split)&lt;/li&gt;
&lt;li&gt;Preprocessing parameters (e.g. the fact that data was normalized)&lt;/li&gt;
&lt;li&gt;Training hyper-parameters (including pre-processing parameters)&lt;/li&gt;
&lt;li&gt;Evaluation criteria, .e.g, metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ideally all these are tracked separately in a &lt;a href="https://blog.zenml.io/declarative_configs_for_mlops/"&gt;declarative config&lt;/a&gt; that is human readable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment
&lt;/h3&gt;

&lt;p&gt;If a ML result is produced on a dev local machine, there is a high chance it is not going to be reproducible. Why? Because developers, especially relatively inexperienced ones, are not super diligent in creating and maintaining proper virtual environments.&lt;/p&gt;

&lt;p&gt;The obvious solution for this one is containerizing applications, with lets say, &lt;a href="https://docker.com/"&gt;Docker&lt;/a&gt;. However, here is another example of when skills of ML practitioners begin diverging from conventional software engineers. Most data scientists are not trained in these matters, and require proper organizational support to help and encourage them to produce containerized applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data
&lt;/h3&gt;

&lt;p&gt;And finally, we arrive at the data. Data versioning has become one of the most discussed topics in the production machine learning community. Unlike code, you can't simply check data into version control easily (although tools like &lt;a href="https://dvc.org"&gt;DVC&lt;/a&gt; are attempting just that).&lt;/p&gt;

&lt;p&gt;In the same way as code, achieving basic versioning of data does not necessarily ensure reproducibility. There is a whole bunch of metadata associated with how data is utilized in machine learning development, all of which is necessary to persist to ensure trainings are reproducible.&lt;/p&gt;

&lt;p&gt;Here is a simple, but common, example that illustrates this point. If you have ever worked with machine learning, have you ever created a folder/storage bucket somewhere that has random files in varying preprocessing states? Something like, &lt;code&gt;normalized_1.json&lt;/code&gt; or perhaps even timestamped &lt;code&gt;12_02_19.csv&lt;/code&gt;? Technically, a timestamped file is versioned data, but that does not mean associated runs with it are reproducible: One would have to know how, when and where (i.e. the aforementioned metadata) these versioned files are used to ensure reproducibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete Example
&lt;/h3&gt;

&lt;p&gt;While it may fall outside the scope of this blog, the open-source MLOps framework ZenML showcases a clear example&lt;br&gt;
of putting these principles in action &lt;a href="https://docs.zenml.io/benefits/ensuring-ml-reproducibility.html"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Reproducibility in machine learning is not trivial, and ensuring it in production is even harder. ML teams need to be fully aware of the precise aspects to track in their processes to unlock reproducibility.&lt;/p&gt;

&lt;p&gt;If you’re looking for a head start to enable reproducibility: check out &lt;a href="https://github.com/zenml-io/zenml"&gt;ZenML&lt;/a&gt;, an open-source MLOps framework for reproducible machine learning - and leave a star while you're there.&lt;/p&gt;

&lt;p&gt;Also, hop on over to our &lt;a href="https://zenml.io/slack-invite"&gt;Slack Channel&lt;/a&gt; if you want to continue the discussion.&lt;/p&gt;

&lt;p&gt;I’ll be back in a few days to talk about using Git in a machine learning setting - stay tuned!&lt;/p&gt;

</description>
      <category>reproducibility</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
    </item>
    <item>
      <title>Can you do the splits?</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:24:45 +0000</pubDate>
      <link>https://dev.to/zenml/can-you-do-the-splits-3kdh</link>
      <guid>https://dev.to/zenml/can-you-do-the-splits-3kdh</guid>
      <description>&lt;p&gt;One attempt to ensure that ML models generalize in unknown settings is splitting data. This can be done in many ways, from 3-way (train, test, eval) splits to k-splits with cross-validation. The underlying reasoning is that by training a ML model on a subset of the data, and evaluating on &lt;code&gt;unknown&lt;/code&gt; data, one can reason much better if the model has underfit or overfit in training.&lt;/p&gt;

&lt;p&gt;For me, splitting data is the most under-rated task in all of data science. It is understandable that for most jobs, a simple 3-way split suffices. However, I have stumbled across many problems where there is a need for more complicated splits to ensure generalization. These splits are more complex because they are derived from the actual data, rather than the structure of the data which the hitherto mentioned split methods are based on. This post attempts to break down some of the more &lt;code&gt;unconventional&lt;/code&gt; ways to split data in ML development, and the reasoning behind them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Lets start with a dataset
&lt;/h1&gt;

&lt;p&gt;In order to illustrate the split mechanisms, it helps to start with a sample dataset to do the splits on. To make things easy, lets use a simple multi-variate, timeseries dataset represented in tabular format. This data consists of 3 numerical features, 1 categorical feature and 1 timestamp feature. Below this is visualized:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W8Jdj7sr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o2mqt96nwo9fym8zhqxv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W8Jdj7sr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o2mqt96nwo9fym8zhqxv.png" alt="whole dataset" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This type of dataset is common across many use-cases and industries in machine learning. A concrete example can be multiple timestreams transmitted from different machines with multiple sensors on a factory floor. The categorical variable would then be the ID of the machine, the numerical features would be what the sensors are recording (e.g. pressure, temperature etc.), and the timestamp would be when the data was transmitted and recorded in the database.&lt;/p&gt;

&lt;h1&gt;
  
  
  Doing the splits
&lt;/h1&gt;

&lt;p&gt;Imagine you receive this dataset as a csv file from your data engineering department and are tasked with writing a classification or a regression model. The label in such a case could be any of the features or an additional column. Regardless, the first thing to do would be to try to split up the data into sets that are meaningful.&lt;/p&gt;

&lt;p&gt;To make things easy, you decide to go make a simple split with &lt;code&gt;train&lt;/code&gt; and &lt;code&gt;eval&lt;/code&gt;. You know immediately that a naive random split with shuffling won't fly here - the data does have multple sensor streams that are indexed by time after all. So how do you split the data so that order is maintained and subsequent models are sufficiently generalizable?&lt;/p&gt;

&lt;h2&gt;
  
  
  Another view of the data
&lt;/h2&gt;

&lt;p&gt;The most straightforward transformation we can do is to represent the data per categorical class (in our running example, visualize the data per machine). This would yield the following result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SgVIw16P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsmx9gh2jgompoe1gk2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SgVIw16P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsmx9gh2jgompoe1gk2y.png" alt="grouped" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Horizontal Split
&lt;/h2&gt;

&lt;p&gt;The grouping together suddenly makes the issue of splitting a bit simpler, and largely dependant on your hypothesis. If the machines are running under similar conditions, one question you might ask is: &lt;code&gt;How would a ML model trained on one group generalize to other groups&lt;/code&gt;. That is, if trained on &lt;code&gt;class_1&lt;/code&gt;, &lt;code&gt;class_2&lt;/code&gt; and &lt;code&gt;class_3&lt;/code&gt; timestreams how would the model fair on &lt;code&gt;class_4&lt;/code&gt; and &lt;code&gt;class_5&lt;/code&gt; timestreams. Here is a visualization of that split:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AvSEsK6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zt7wpt9hlai674o3r012.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AvSEsK6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zt7wpt9hlai674o3r012.png" alt="horizontal" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I call this the &lt;code&gt;Horizontal&lt;/code&gt; split due to nature of the cut line in the above visualization. This split can be easily achieved in most ML libraries by simply grouping by the categorical feature and partitioning along it. A successful training with this split would show evidence that the model has picked up signals that generalize across previously unseen groups. However, it would not showcase that it is able to predict future behavior of one group.&lt;/p&gt;

&lt;p&gt;Its important to note that the the split decision did &lt;code&gt;NOT&lt;/code&gt; account for time as a basis of the split itself. One can assume however that you would also sort by time per timestream to maintain that relationship in your data. Which brings us to the next split..&lt;/p&gt;

&lt;h2&gt;
  
  
  The Vertical Split
&lt;/h2&gt;

&lt;p&gt;But what if you want to split across time itself? For most time-series modelling, a common way to split the data is &lt;code&gt;past&lt;/code&gt; and &lt;code&gt;future&lt;/code&gt;. That is, to take in the training set historical data relative to the data in the eval set. The hypothesis in this case would be: &lt;code&gt;How would a ML model trained on historical data per group generalize to future data for each group?&lt;/code&gt;. This question might be answered by the so called &lt;code&gt;Vertical&lt;/code&gt; split:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6x9JvNCF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8rj2cwbhewrb28tqn2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6x9JvNCF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8rj2cwbhewrb28tqn2g.png" alt="vertical" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A successful training with this split would showcase that the model is able to pick up patterns across timestreams it has already seen, and make accurate predictions of behavior in the future. However, this itself would not show that this model will generalize well to other timestreams from different groups.&lt;/p&gt;

&lt;p&gt;Of course, your multiple timestreams have to be sorted now individually, so we still need to group. However, this time, rather than cutting across groups, we take a sample of the &lt;code&gt;past&lt;/code&gt; of each group and put it in train and the &lt;code&gt;future&lt;/code&gt; of each group in eval. In this idealized example, all the timestreams are of the same length, i.e., each timestream has exactly the same number of data points. However, in the real world, this maybe not be the case - so you would require a system to build an index across each group to make this split.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hybrid Split
&lt;/h2&gt;

&lt;p&gt;An inquisitive ML researcher might at this point wonder if they could produce a model that would generalize under both constraints of the &lt;code&gt;Horizontal&lt;/code&gt; and the &lt;code&gt;Vertical&lt;/code&gt; split. The hypothesis in that case would be: &lt;code&gt;How would a model trained on historical data for SOME groups generalize to future data of these groups AND all data from other groups?&lt;/code&gt;. A visualization of this &lt;code&gt;Hybrid&lt;/code&gt; split would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gAfwM1Z3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxkllhbflfbt4hs5nl98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gAfwM1Z3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxkllhbflfbt4hs5nl98.png" alt="hybrid" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Naturally, if model training is successful, this model would surely be more robust than the others in a real world setting. It would have displayed evidence to not only learning patterns of some of the groups it has already seen, but also evidence of the fact that it has picked up signals that generalize across groups. This might be useful if we are to add more similar machines to the factory in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-dimensional splits
&lt;/h2&gt;

&lt;p&gt;The notion of the horizontal and vertical splits can be generalized to many dimensions. For example, one might want to do group by two categorical features rather than one to even further isolate sub-groups in the data, and sort them per sub-group. There might also be complex logic in the middle to filter groups that have a lower number of samples, and other business-level logic pertaining to the domain.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The hypothetical example is used to illustrate the endless possibilities of various kinds of machine learning splits that can be created by an astute data scientist. Just like it is important to &lt;a href="https://developers.google.com/machine-learning/fairness-overview"&gt;ensure ML fairness&lt;/a&gt; whilst evaluating your models, it is equally important to spend sufficient time thinking about splitting a dataset and its consequences to bias the model downstream.&lt;/p&gt;

&lt;p&gt;One easy way to do the &lt;code&gt;Horizontal&lt;/code&gt;, &lt;code&gt;Vertical&lt;/code&gt; and the &lt;code&gt;Hybrid&lt;/code&gt; split by writing just a &lt;a href="https://docs.zenml.io/docs/developer_guide/pipelines_config_yaml#main-key-split"&gt;few lines of YAML is via ZenML&lt;/a&gt;. ZenML is a &lt;a href="https://zenml.io"&gt;MLOps framework&lt;/a&gt; developed while we deployed models to production, for datasets with similar characteristics as the example above. If you are interested in the content above, and would like to try ZenML, please feel free to reach out to me at &lt;a href="//mailto:hamza@zenml.io"&gt;hamza@zenml.io&lt;/a&gt;. Head over to &lt;a href="https://docs.zenml.io"&gt;our docs&lt;/a&gt; to understand more how it works in more detail.&lt;/p&gt;

&lt;p&gt;Thank you and happy splitting!&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>devops</category>
      <category>machinelearning</category>
      <category>mlops</category>
    </item>
    <item>
      <title>Avoiding technical debt with ML pipelines</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:21:14 +0000</pubDate>
      <link>https://dev.to/zenml/avoiding-technical-debt-with-ml-pipelines-9ma</link>
      <guid>https://dev.to/zenml/avoiding-technical-debt-with-ml-pipelines-9ma</guid>
      <description>&lt;p&gt;Okay, lets make it clear at the start: This post is NOT intended for people who are doing one-off, silo-ed projects like participating in Kaggle competitions, or doing hobby projects on jupyter notebooks to learn the trade. The value of throw-away, quick, diry script code is obvious there - and has its place. Rather, it is intended for ML practitioners working in a &lt;em&gt;production&lt;/em&gt; setting. So if you're working in a ML team that is struggling to manage technical debt while pumping out ML models, this one's for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  A typical workflow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iqRfoI_i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmnpstj7flbq73v4ml26.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iqRfoI_i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmnpstj7flbq73v4ml26.jpg" alt='Image Source: &amp;lt;a href="https://www.flickr.com/photos/michael_mayer/8701850930"&amp;gt;Michael Mayer on Flickr' width="880" height="755"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the premise: You're a ML/DL/AI engineer/analyst/scientist working in a startup/SME/enterprise. It's your job to take a bunch of random data from all over the place, and produce value. What do you do? You sit down, somehow get the data on to your local machine, and inevitably do something along the lines of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jupyter notebook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you go to a colab if you're fancy and your teams privacy rules allow it.&lt;/p&gt;

&lt;p&gt;Following is a story ive seen so many times before - pseudo-code of course.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;xyzlibraryforml&lt;/span&gt;

&lt;span class="c1"&gt;# CELL 1: Read
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/path/to/file.*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# INSERT HERE: a 100 more cells deleted and updated to explore data.
&lt;/span&gt;
&lt;span class="c1"&gt;# CELL 2: Split
&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split_the_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# basic
&lt;/span&gt;
&lt;span class="c1"&gt;# INSERT HERE: trying to figure out if the split worked
&lt;/span&gt;
&lt;span class="c1"&gt;# CELL 3: Preprocess
# nice, oh lets normalize
&lt;/span&gt;&lt;span class="n"&gt;preprocess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;preprocess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# exploring preprocessed data, same drill as before
&lt;/span&gt;
&lt;span class="c1"&gt;# CELL 4: Train
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;some_obfuscated_library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# not being petty at all
&lt;/span&gt;
&lt;span class="c1"&gt;# if youre lucky here, just look at some normal metrics like accuracy. otherwise:
&lt;/span&gt;
&lt;span class="c1"&gt;# CELL 5: Evaluate
&lt;/span&gt;&lt;span class="n"&gt;complicated_evaluation_methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# INSERT HERE: do this a 1000 times
&lt;/span&gt;
&lt;span class="c1"&gt;# CELL 6: Export (i.e. pickle it)
&lt;/span&gt;&lt;span class="n"&gt;export_model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you're done right? Thats it - boom. Test set results are great. Lets give it to the ops guy to deploy in production. Lunch break and reddit for the rest of the day!&lt;/p&gt;

&lt;p&gt;Okay, am I grossly exaggerating? &lt;strong&gt;Yes&lt;/strong&gt;. Is this scarily close to the truth for some businesses? &lt;strong&gt;Also yes&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, whats the problem?
&lt;/h2&gt;

&lt;p&gt;The problem is that this notebook above is a ball of technical debt that will keep growing, if not culled early enough. Lets break down what was wrong with it:&lt;/p&gt;

&lt;h3&gt;
  
  
  Not moving towards a bigger picture
&lt;/h3&gt;

&lt;p&gt;When you put generalizable logic into non-versioned, throw-away notebook blocks, it is taking away the ability for your team to take advantage of it. For example, the logic of loading/extracting your data from your static datasource. Sure a &lt;code&gt;pd.read_json&lt;/code&gt; is easy right now, but what happens if the format changes? Worse, what happens if the data grows and is split into multiple files? Even worse, what happens if it wont fit into memory any more? What happens if your colleague runs into the same problem - she'll probably go through the same loops as you did not even knowing its an already solved problem. Sure, there are solutions to all these problems but are you going to keep solving them in your local notebook?&lt;/p&gt;

&lt;p&gt;The answer is probably no (&lt;a href="https://netflixtechblog.com/open-sourcing-polynote-an-ide-inspired-polyglot-notebook-7f929d3f447"&gt;unless you're netflix or something&lt;/a&gt;). Usually, the logical thing to do is to extract the loading into a logically separate service. This way, you can abstract the actual extraction of data away from yourself and into a maintainable layer transparent to everyone. For example, this could be some form of &lt;code&gt;feature store&lt;/code&gt; that collects all the various data streams in your organizations into one point, which can then be consumed in defined APIs by everyone in your team.&lt;/p&gt;

&lt;p&gt;The same applies to the pre-processing, training and evaluation part of the script above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building logic locally (and therefore again and again)
&lt;/h3&gt;

&lt;p&gt;As in the above example, when you write code to explore data, you generate tons of great stuff - visualizations, statistical dataframes, cleaned and preprocessed data, etc. The random, arbitrary order of execution of jupyter notebooks ensures that the path taken to realize these artifacts is forever lost in overridden local variables and spontaneous kernel restarts. Even worse, the logic has complex, easily overridden configurations embedded deep inside the code itself - making it much harder to recreate artifacts.&lt;/p&gt;

&lt;p&gt;Look, I understand - I do it all the time. Data wrangling is a random, grinding process, and its gonna be messy. But setting up some framework to keep a track of your data exploration pipelines is going to pay off big time. Similar to commenting your code, the biggest beneficiary of keeping track is going to be yourself. Also, your team will be faster and avoid redundant work if these artifacts and mini-answers to questions were made transparent and clear to everyone automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not owning the deployment
&lt;/h3&gt;

&lt;p&gt;The last part of this notebook is probably the most frustrating. I really do not believe that the job of the person writing that notebook ends with exporting the model for ops. It does not make any sense.&lt;/p&gt;

&lt;p&gt;First of all, that preprocessing() function has to go with it, otherwise training-serve skew is going to crash your model from the get-go. Secondly, how on earth is the ops person supposed to know what assumptions you took while building the model? Are you going to write extensive documentation of what data goes in, how it should be preprocessed, and which shape it should be in when deploying to an endpoint? I mean there are now automated ways of doing this - so own the deployment!&lt;/p&gt;

&lt;p&gt;One aspect lacking in the above script is a disregard for measuring the performance of a model. Most data scientists I know do not care how big the model is, how much memory it consumes for predictions, and how fast/efficient it is in deployment. The model does not produce value if it does not fulfill the performance criteria of the end application. Again, the person developing the models should have ownership of its end deployment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Suggestions
&lt;/h1&gt;

&lt;p&gt;The easiest way to fix the above is to develop a framework where a ML team can balance throw-away exploratory code development with maintainable, easy-to-share code. If you are to do this, you might want to keep the following in mind:&lt;/p&gt;

&lt;h3&gt;
  
  
  Create well-defined interfaces (i.e decompose into pipelines)
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;split&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;, &lt;code&gt;train&lt;/code&gt;, &lt;code&gt;evaluate&lt;/code&gt;, &lt;code&gt;deploy&lt;/code&gt; components of your workflow are logically independent entities/services. Architect a setup where individual components of your ML workflow are abstracted away from concrete implementations. This could be by defining actual interfaces object-oriented style, or simple ensuring that your repo has some form of structure that is easy for everyone to contribute to and extend. This does not have to be rocket-science at the start, but it will help enormously.&lt;/p&gt;

&lt;p&gt;This is where the notion of ML pipelines come into play: Pipelines are abstract representations that define a series of data processing tasks. Thinking in &lt;code&gt;pipelines&lt;/code&gt; would help your team separate out logical entities in their workflow, and have data flow through it independently. This would inevitably yield a more robust, maintainable codebase. Also, defining ML pipelines like this ensures you can automate continuous training of your stale models on new data as it comes in. However, you need to also track your data metadata for that (See below).&lt;/p&gt;

&lt;h3&gt;
  
  
  Make a plan for your ML Metadata
&lt;/h3&gt;

&lt;p&gt;Every experiment you run yields ML metadata: who ran it, when was it run, what data went in, where are the results stored etc. Make sure you map these out and provide a convenient way to add to this store. Important to note: I am not just talking about experiment tracking either. There are many wonderful libraries out there that will help in tracking the model-centric metadata, i.e., metrics etc. However, what is often neglected is the data-centric metadata - especially if the data keeps changing. Stuff like data versioning, statistics, visualizations, what seed was used when random splitting - stuff like that. There should be an easy way to trace the various routes your data takes in your development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensure that your workloads can run in any environment
&lt;/h3&gt;

&lt;p&gt;Running a workload on a single machine is always going to be easier than making the same code run on any arbitrary environment. I know Docker is inapproachable and hard for many ML people, but at least make a &lt;code&gt;requirements.txt&lt;/code&gt; and add a &lt;code&gt;__init__.py&lt;/code&gt;! Ideally, containerize your code and run experiments on some form of orchestration framework. Doing this one step now will save a lot of pain when you scale and automate this whole thing to work on bigger data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do not separate deployment from training
&lt;/h3&gt;

&lt;p&gt;This is perhaps the most no-brainiest of all no-brainer suggestions so far. End to end ownership lead to the whole DevOps revolutions 20 years ago, and that has not gone away in ML development either. Provide a smooth mechanism to transfer a trained model to an endpoint, and make sure the Ops people are sitting in the same room (not always literally) as your ML developers. Put in place processes where everyone understands the end goal in production. Automate things when possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do not compromise on repeatability and traceability
&lt;/h3&gt;

&lt;p&gt;You know when people start coding in Python and then move to C++ or Java and they do not understand concepts like pointers and static typing? They think: "What is the use of giving a variable a type, &lt;strong&gt;I&lt;/strong&gt; know what it is so why am I &lt;strong&gt;forced&lt;/strong&gt; to do this?". Well, sorry to break it to you, but pointers and static typing have a purpose - knowing them protects your code from your own failings and ensures high quality robust output. Ultimate flexibility can be a bad thing, especially with developers who tend to err towards laziness (like me).&lt;/p&gt;

&lt;p&gt;Something very similar happens in Jupyter notebooks - the freedom of running any arbitrary code in any order gives freedom but makes you lose the very important notion of repeatability and traceability, two corner-stones of any robust, production ready engineering discipline. Please, at least ensure that your notebooks are executable top-down and in a repeatable manner. Cluttered and randomly ordered jupyter notebooks should be punished with long rants like this one on Code Review meetings.&lt;/p&gt;

&lt;p&gt;One way of ensuring both traits is to extract 'settings' of your code from the implementation. Which brings me to my next point...&lt;/p&gt;

&lt;h3&gt;
  
  
  Separate configuration from implementation
&lt;/h3&gt;

&lt;p&gt;Separating configuration from actual code implementation is definitely a pain. Yet, this is another one of those 'pays off in the long run' sort of things. &lt;a href="https://dev.to/declarative_configs_for_mlops"&gt;We've written about it before&lt;/a&gt; but to summarize: Separating your configuration allows you to automate repetitive tasks, increases predictability of results, and ensures reproducibility. Ideally, configuration should be treated as code, versioned, and maintained.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;ML practitioners in many organizations are heavily incentivized to make quick-wins to product early results. However, this leads to accumulated technical debt which eventually slows down the team over time. The solution is to follow proper software engineering principles from the get-go, and lean on guidelines to strike a balance between rapid results and high quality software development.&lt;/p&gt;

&lt;p&gt;The thoughts above are very personal lessons I have learnt over the last 3 years deploying models in production. As a result at zenml, we have created ZenML to provide a framework for ML developers to solve some, if not all, of the problems noted above. Reach out to me at &lt;a href="//mailto:hamza@zenml.io"&gt;hamza@zenml.io&lt;/a&gt; if you are interested in giving the platform a go. Head over to &lt;a href="https://docs.zenml.io"&gt;our docs&lt;/a&gt; to understand more how it works in more detail.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>pipelines</category>
    </item>
    <item>
      <title>Deep Learning on 33,000,000 data points using a few lines of YAML</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:11:38 +0000</pubDate>
      <link>https://dev.to/zenml/deep-learning-on-33000000-data-points-using-a-few-lines-of-yaml-1ie0</link>
      <guid>https://dev.to/zenml/deep-learning-on-33000000-data-points-using-a-few-lines-of-yaml-1ie0</guid>
      <description>&lt;p&gt;Over the last few years at &lt;a href="//https:/zenml.io"&gt;zenml&lt;/a&gt;, we have regularly dealt with datasets that contain millions of data points. Today, I want to write about how the we use our machine learning platform, &lt;a href="https://zenml.io"&gt;ZenML&lt;/a&gt;, to build production-ready distributed training pipelines. These pipelines are capable of dealing with millions of datapoints in a matter of hours. If you also want to build large-scale deep learning pipelines, sign up for &lt;a href="https://zenml.io/signup/"&gt;ZenML for free here&lt;/a&gt; and follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Datasource&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A good way to get a hold of a dataset of the size we want is &lt;a href="https://cloud.google.com/bigquery/public-data"&gt;public Google BigQuery tables&lt;/a&gt;.&lt;br&gt;
The one I chose for today's example is the &lt;a href="https://console.cloud.google.com/marketplace/details/city-of-new-york/nyc-citi-bike"&gt;New York Citi Bike dataset&lt;/a&gt;, which contains 33 million data points, holding information about various bike sharing trips in New York City. Here is a snippet of what the datasource looks like (*only relevant columns shown):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   birth_year | gender   |   end_station_id |   start_station_id |   tripduration | usertype
--------------+----------+------------------+--------------------+----------------+------------
         1977 | Female   |              103 |                100 |           1012 | Subscriber
         1991 | Male     |             1089 |                 23 |            530 | Customer
... etc. etc. 33 million more times
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our mission (if we choose to accept it) is to see if we can infer the &lt;code&gt;birth_year&lt;/code&gt; of the person,&lt;br&gt;
given all the rest of the data in this table.&lt;/p&gt;

&lt;p&gt;Sound interesting? Alright, let's begin.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Building the Pipeline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When dealing with a dataset this large, its difficult to do some Pandas magic in a Jupyter notebook to wrangle with our data - I won't subject my poor ThinkPad to that punishment. Thats why we created &lt;a href="https://zenml.io/signup/"&gt;ZenML&lt;/a&gt; to deal with this problem (&lt;a href="https://dev.to/deep_learning_in_production_is_broken/"&gt;amongst others&lt;/a&gt;).&lt;br&gt;
For this post, I will assume you have the &lt;code&gt;cengine&lt;/code&gt; CLI &lt;a href="https://docs.zenml.io/docs/installation"&gt;installed&lt;/a&gt; and ready to go.&lt;/p&gt;

&lt;p&gt;As a summary, the &lt;code&gt;cengine&lt;/code&gt; CLI will create, register and execute training pipelines,&lt;br&gt;
which will be managed by us on our cloud platform. One can create the pipeline declaratively by&lt;br&gt;
specifying a YAML configuration file.&lt;/p&gt;

&lt;p&gt;For this example, I created a &lt;strong&gt;simple feedforward neural network&lt;/strong&gt; pipeline. Here's how I did it:&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 0: Add the datasource&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;First thing to do is create a data source. As the BigQuery table is public, it can be added by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cengine datasource create bq --name citibike_trips \
  --project "bigquery-public-data" \
  --dataset new_york \
  --table citibike_trips \
  --table_type public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that you can run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cengine datasource list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And see the following details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Selection   |   ID | Name               |     Rows |   Cols |   Size (MB)
-------------+------+--------------------+----------+--------+-------------
 *           |   16 | citibike_trips     | 33319019 |     15 |        4689

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data contains 33,319,019 rows with 15 columns.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Configure YAML - Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now we can build our YAML config. Usually I would use an easy-to-follow&lt;br&gt;
&lt;a href="https://docs.zenml.io/docs/developer_guide/pipelines_configure"&gt;configure command&lt;/a&gt; to create this, but for this post its easier to go section by section and build it manually. So open up a text editor&lt;br&gt;
(I'm a &lt;a href="https://www.sublimetext.com/"&gt;Sublime Text&lt;/a&gt; guy but do it in &lt;a href="https://www.vim.org/"&gt;VIM&lt;/a&gt; if you wish, whatever floats your boat):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;end_station_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;start_station_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;tripduration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;usertype&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will define the features we want to use for our pipeline. I dropped some features that I thought were redundant or could bias the model (like &lt;code&gt;Bike ID&lt;/code&gt;). I mean, the model should have a challenge, right?&lt;/p&gt;

&lt;p&gt;Also note that I didn't to any fancy embedding of start and end stations.&lt;br&gt;
As Andrew Ng says: &lt;em&gt;"Don’t start off trying to design and build the perfect system. Instead, build&lt;br&gt;
and train a basic system quickly"&lt;/em&gt;. So lets get to a baseline first.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Configure YAML - Label&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Ok next part is the label. Thats also easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;birth_year&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;loss&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mse&lt;/span&gt;
    &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;mae&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we define &lt;code&gt;birth_year&lt;/code&gt; as the label, and say we want a &lt;code&gt;mse&lt;/code&gt; (mean_squared_error) loss on the model. The metric I'll be tracking are &lt;code&gt;mae&lt;/code&gt; (mean absolute error).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Configure YAML - Split&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So we need to split our data for this to make any sense. ZenML let's you split up the data in a variety of ways into &lt;code&gt;train&lt;/code&gt; and &lt;code&gt;eval&lt;/code&gt; (more splits support on its way!). Lets write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;categorize_by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;start_station_name&lt;/span&gt;
  &lt;span class="na"&gt;index_ratio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;train&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;0.9&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;eval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;0.1&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines of YAML, but they pack a punch. ZenML will let you &lt;a href="https://docs.zenml.io/docs/developer_guide/pipelines_yaml"&gt;categorize your data before splitting it&lt;/a&gt;.&lt;br&gt;
For our case, we want all start stations to be equally represented to avoid any biases. So we grouped by the &lt;code&gt;start_station_name&lt;/code&gt; and divided each possible group in a 90-10 split. For you SQL folk, this is similar to doing a &lt;code&gt;GROUP BY&lt;/code&gt; and then taking a partition over an index. This way our training and test data will have data with all the stations.&lt;/p&gt;

&lt;p&gt;I feel like splitting up data is a very under-appreciated part of machine learning and plays an important part in ML fairness, so I tried to make an appropriate split here.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4: Configure YAML - Trainer (Model definition)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We have arrived at, undoubtedly, the most interesting part of our YAML. The trainer, i.e., the actual model definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trainer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;dense&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;units&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;64&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# a dense layer 64 units&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;dense&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;units&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;32&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# a dense layer with 32 units&lt;/span&gt;
  &lt;span class="na"&gt;architecture&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;feedforward&lt;/span&gt; &lt;span class="c1"&gt;# can be feedforward or sequential&lt;/span&gt;
  &lt;span class="na"&gt;last_activation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linear&lt;/span&gt; &lt;span class="c1"&gt;# last layer: we can take relu, but linear should also be fine&lt;/span&gt;
  &lt;span class="na"&gt;num_output_units&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# How many units in the last layer? We choose 1 because we want to regress one number (i.e. date_of_birth)&lt;/span&gt;
  &lt;span class="na"&gt;optimizer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adam&lt;/span&gt; &lt;span class="c1"&gt;# optimizer for loss function&lt;/span&gt;
  &lt;span class="na"&gt;save_checkpoints_steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15000&lt;/span&gt; &lt;span class="c1"&gt;# how many steps before we do a checkpoint evaluation for our Tensorboard logs&lt;/span&gt;
  &lt;span class="na"&gt;eval_batch_size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;256&lt;/span&gt; &lt;span class="c1"&gt;# batch size for evalulation that happens at every checkpoint&lt;/span&gt;
  &lt;span class="na"&gt;train_batch_size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;256&lt;/span&gt; &lt;span class="c1"&gt;# batch size for training&lt;/span&gt;
  &lt;span class="na"&gt;train_steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;230000&lt;/span&gt; &lt;span class="c1"&gt;# two epochs&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regression&lt;/span&gt; &lt;span class="c1"&gt;# choose from [regression, classification, autoencoder]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's quite straightforward really - we define 2 dense layers, set the optimizer and a few more nuts and bolts. The whole trainer follows quite closely the &lt;a href="https://www.tensorflow.org/guide/keras"&gt;Keras&lt;/a&gt; API, so it would be quite straightforward for most people. The interesting bit about this trainer is the &lt;code&gt;train_steps&lt;/code&gt; and &lt;code&gt;batch_size&lt;/code&gt;. One step is one whole batch passing through the network, so with a &lt;strong&gt;33 million datapoint dataset&lt;/strong&gt;, &lt;strong&gt;230,000&lt;/strong&gt; steps of &lt;strong&gt;256&lt;/strong&gt; would be roughly &lt;strong&gt;2&lt;/strong&gt; epochs of the data. Trust me, I did the math.&lt;/p&gt;

&lt;p&gt;At this point you might be wondering what are the types of models you can create with this &lt;code&gt;trainer&lt;/code&gt; key - so go ahead and read the developer &lt;a href="https://docs.zenml.io/docs/developer_guide/pipelines_yaml"&gt;docs&lt;/a&gt; for it. This part we're really trying to nail down and support for different sorts of models are always a priority.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5: Configure YAML - Evaluation (Splitting Metrics)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Almost there! One last thing we might want to do is to add some evaluator slices. What does that mean? Well it means that we might may not just want to look at the overall metrics (i.e. overall &lt;code&gt;mae&lt;/code&gt;) of the model, but the &lt;code&gt;mae&lt;/code&gt; across a categorical column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;evaluator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;birth_year&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;# I'd like to see how I did across each year&lt;/span&gt;
  &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;# I'd like to see if the model biases because of gender&lt;/span&gt;
  &lt;span class="na"&gt;start_station_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;# I'd like to see how I did across each station&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I defined three such columns which I was interested in seeing sliced metrics across. You'll see how this plays into the evaluation part of our pipeline in a bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  The full config YAML
&lt;/h3&gt;

&lt;p&gt;There are some things that I have intentionally skipped in the config for the sake of brevity. For reference, you can find the pipeline configuration ready to download &lt;a href="///assets/posts/train_30_mil_few_lines_yaml/citibike.yaml"&gt;here&lt;/a&gt;. I tried to annotate it with comments for clearer explanation. For further clarity, there is also always the &lt;a href="https://docs.zenml.io/docs/developer_guide/pipelines_yaml"&gt;docs&lt;/a&gt; to refer to. Most notably, the &lt;code&gt;default&lt;/code&gt; key is perhaps important to look at as it defines the pre-processing steps that we took to normalize the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Run the pipeline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ok now I can register a pipeline called &lt;code&gt;nyc_citibike_experiment&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cengine pipeline push my_config.yaml nyc_citibike_experiment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ZenML will check your active datasource, and give an ops configuration that it deems suitable for the size of the job you're about to run. For this experiments, ZenML registered the pipeline with 4 &lt;code&gt;workers&lt;/code&gt; at 96 &lt;code&gt;cpus_per_worker&lt;/code&gt;. You can always change this if you want, but I decided to go for this configuration and ran the pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cengine pipeline run &amp;lt;pipeline_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter &lt;code&gt;Y&lt;/code&gt; for the safety prompt that appears, and let it run!&lt;/p&gt;

&lt;p&gt;You should see a success message with your chosen configuration. The platform will provision these resources in the cloud, connect automatically to the datasource, and create a machine learning pipeline to train the model. All preprocessing steps of the pipeline will be distributed across the workers and cpus. The training will happen on a &lt;a href="https://www.nvidia.com/en-gb/data-center/tesla-k80/"&gt;Tesla K80&lt;/a&gt; (distributed training coming soon!).&lt;/p&gt;

&lt;p&gt;So now, you can sit back and relax. You don't need to watch dying Jupyter kernels or stare at as the steps go by on your terminal. Just grab a coffee, browse reddit, and chill.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Evaluate the results&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;While running, the status of a pipeline can be checked with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cengine pipeline status &lt;span class="nt"&gt;--pipeline_id&lt;/span&gt; &amp;lt;pipeline_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ID | Name                              | Pipeline Status   | Completion   |   Compute Cost (€) |   Training Cost (€) |   Total Cost (€) | Execution Time
-----------+-----------------------------------+-------------------+--------------+--------------------+---------------------+------------------+------------------
   1  | nyc_citibike_experiment           | Running           | 13%          |                  0 |                   0 |                0 | 0:14:21.187081
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the pipeline hits the 100% completion mark, I can see the compute (preprocessing + evaluation) cost and training cost it incurred. For me, this pipeline took &lt;strong&gt;74 minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Preprocessing and training 33 million datapoints in just over an hour. Not too bad.&lt;/p&gt;

&lt;p&gt;At that point, I can also evaluate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cengine pipeline evaluate &amp;lt;pipeline_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This opens up a pre-configured Jupyter notebook where I can view &lt;a href="https://www.tensorflow.org/tensorboard"&gt;Tensorboard&lt;/a&gt; logs, along with the excellent &lt;a href="https://github.com/tensorflow/model-analysis"&gt;Tensorflow Model Analysis (TFMA)&lt;/a&gt; plugin. Both of these will show me different things about the pipeline.&lt;/p&gt;

&lt;p&gt;Tensorboard will show tensorboard things: The model graph, the train and eval loss etc. Here's how mine looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--McJ1nz2R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/utx50s5dp787ae1rvezl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--McJ1nz2R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/utx50s5dp787ae1rvezl.png" alt="tensorboardlogs" width="880" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is pretty cool - Maybe we overtrained it at the 180,000th step as it took a jump in the loss, but the &lt;code&gt;mae&lt;/code&gt; seems to keep decreasing. We're close to 9.6 &lt;code&gt;mae&lt;/code&gt; overall, which isn't bad at all for this baseline model.&lt;/p&gt;

&lt;p&gt;How about a deeper dive into the metrics? Thats where TFMA comes into play.&lt;br&gt;
TFMA will show the metrics defined in the YAML and add the ability to slice the metric across the columns defined in the &lt;code&gt;evaluator&lt;/code&gt; key. E.g. Lets slice it across &lt;code&gt;birth_year&lt;/code&gt; to see how well it did for each year.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LuCcLqOe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18eyr84v47sw0qmtjlb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LuCcLqOe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18eyr84v47sw0qmtjlb2.png" alt="Image description" width="880" height="887"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If you want to replicate this step just add &lt;code&gt;birth_year&lt;/code&gt; in the generated notebook code where its specified.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A deeper dive reveals that the model actually guessed the year of people born in 1977 pretty well (Thats tested on ~11000 samples from that year). So its definitely learning something. We can now dive which years it did worse, and also other slices and see if we can gain anything from that when we iterate on our model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;Now that we have the baseline model, its very simple to iterate on different sorts of models very quickly. The cool thing is that ZenML has stored all &lt;a href="https://docs.zenml.io/docs/developer_guide/caching"&gt;intermediate states of the pipeline&lt;/a&gt; (i.e. the preprocessed data) in an efficient and compressed binary format. Subsequent pipeline runs will &lt;strong&gt;warmstart&lt;/strong&gt; the pipeline straight to the training part, given that everything else stays the same. This caching mechanism is actually quite powerful at this stage and can save up to 80% on time and cost. But I would leave that for a seperate post, where we can take the same pipeline and iterate on quickly to arrive at a more accurate model! So stay tuned for that.&lt;/p&gt;

&lt;p&gt;If you liked this post, please make sure to follow us on &lt;a href="https://twitter.com/zenml_io"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/company/zenml/"&gt;LinkedIn&lt;/a&gt; or just chat with us on our &lt;a href="https://discord.gg/HPBUKru"&gt;Discord&lt;/a&gt; server.&lt;/p&gt;

&lt;p&gt;We're actively looking for beta testers to test the platform and we have a whole bunch of features coming up, including distributed training, automatic model serving, hyper-parameter tuning and image support.&lt;br&gt;&lt;br&gt;
Please visit the &lt;a href="https://docs.zenml.io"&gt;docs&lt;/a&gt; for details about&lt;br&gt;
the platform, and if interested &lt;a href="//mailto:support@zenml.io"&gt;contact us&lt;/a&gt; directly!&lt;/p&gt;

&lt;p&gt;In the meantime, stay safe and hope to see you all soon!&lt;/p&gt;

</description>
      <category>pipelines</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>mlops</category>
    </item>
    <item>
      <title>Why deep learning development in production is (still) broken</title>
      <dc:creator>Hamza Tahir</dc:creator>
      <pubDate>Mon, 06 Dec 2021 12:07:28 +0000</pubDate>
      <link>https://dev.to/zenml/why-deep-learning-development-in-production-is-still-broken-3ah9</link>
      <guid>https://dev.to/zenml/why-deep-learning-development-in-production-is-still-broken-3ah9</guid>
      <description>&lt;p&gt;Around 87% of machine learning projects do not survive to make it to production. There is a disconnect between machine learning being done in Jupyter notebooks on local machines and actually being served to end-users to provide some actual value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2Ku6f075--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5695tlrasfub63h591bj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2Ku6f075--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5695tlrasfub63h591bj.png" alt="MLOps" width="880" height="288"&gt;&lt;/a&gt; Source: Hidden Technical Debt in Machine Learning Systems (Sculley et al.)&lt;/p&gt;

&lt;p&gt;The oft-quoted Hidden Technical Debt paper, whose diagram can be seen here, has been in circulation since 2017, yet still, deep learning in production has a ways to go to catch up to the quality standards attained by more conventional software development. Here is one take on what is broken:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Data is not treated as a first-class citizen&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In traditional software development, code is (rightly-so) **a first-class citizen. In ML development, there is a further need for data to be a first-class citizen as well. Therefore, data has to be treated with the same care that most developers give to the code they write.&lt;/p&gt;

&lt;p&gt;Right now in most organizations, data is spread everywhere and inaccessible. This is not just about raw data either-even if an organization spends a lot of money into centralizing their data into lakes, critical data is spread across the organization in colabs, notebooks, scripts and pre-processed flat files. This causes, amongst other things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wasted compute on redundant transformations of data&lt;/li&gt;
&lt;li&gt;No transparency and accountability of what data trains what models&lt;/li&gt;
&lt;li&gt;Inability to transfer important training phase to the serving phase (see below)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Different requirements in training and serving&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Teams often find it surprising when a well-trained model starts to give spurious results in the real world. The transition from training a model to serving it is far from trivial.&lt;/p&gt;

&lt;p&gt;For examples, there is a skew in training and production data, that needs to be taken into account. Secondly, one has to be very careful in making sure that production data goes through the same preprocessing steps in production as in training. Lastly, while training involves running experiments and quickly iterating, serving has even further requirements on the application level, e.g. inference time and costs at scale. All these need to be taken into account to avoid unnecessary surprises when the transition from training to serving happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;No gold standard yet for ML Ops&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Applying DevOps principles for ML development (or MLOps) is all the rage right now. However, there is yet no gold standard for it. The field in its infancy needs to tackle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resources (compute, GPU etc) are scattered and not being used efficiently across teams&lt;/li&gt;
&lt;li&gt;No proper CI/CD pipelines&lt;/li&gt;
&lt;li&gt;No proper monitoring in production (change in data quality etc.)&lt;/li&gt;
&lt;li&gt;Scaling is hard - in training and in serving&lt;/li&gt;
&lt;li&gt;Machine learning compute works in spikes, so systems need to be equipped to deal with that&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Collaboration is hard&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In conventional software development, we use workflows that integrate tickets and version control to make collaboration as seamless and transparent as possible. Unfortunately, ML development still lags behind on this front. This is largely due to the fact that ML developers tend to create silos which include glue-code scripts, preprocessed data pickles, and jupyter notebooks. While all these are useful for research and experimentation, they do not translate well into a robust, long-running, production environment.&lt;/p&gt;

&lt;p&gt;In short, in the ML world, there is largely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-transparency coupled with individual experimentation&lt;/li&gt;
&lt;li&gt;Notebook Hell with glue-code scripts&lt;/li&gt;
&lt;li&gt;No versioning, in data, code or configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Most of the problems highlighted above can be solved by proper attention being paid to machine learning development in production, from the first training onwards. The field is catching up, slowly but surely, but it is inevitable that machine learning will catch up with traditional software engineering quickly. Will we see new, even improving, and exciting ML products in our lives at that point? Lets hope so!&lt;/p&gt;

&lt;p&gt;Our attempt to solve these problems is ZenML, an extensible, open-source MLOps framework. We recently launched and are now looking for practitioners to solve their problems in production use-cases! So, head over to &lt;a href="https://github.com/zenml-io/zenml"&gt;GitHub&lt;/a&gt;, and don't forget to leave us a star if you like what you see!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>mlops</category>
      <category>deeplearning</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
