<?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: Leonard Püttmann</title>
    <description>The latest articles on DEV Community by Leonard Püttmann (@leonardpuettmann).</description>
    <link>https://dev.to/leonardpuettmann</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%2Fuser%2Fprofile_image%2F874692%2Fafa186b4-fa9e-40b8-b935-43352b0def06.jpg</url>
      <title>DEV Community: Leonard Püttmann</title>
      <link>https://dev.to/leonardpuettmann</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leonardpuettmann"/>
    <language>en</language>
    <item>
      <title>How to deploy ML models on Azure Kubernetes Service (AKS)</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Tue, 11 Apr 2023 19:59:21 +0000</pubDate>
      <link>https://dev.to/leonardpuettmann/how-to-deploy-ml-models-on-azure-kubernetes-service-aks-30o0</link>
      <guid>https://dev.to/leonardpuettmann/how-to-deploy-ml-models-on-azure-kubernetes-service-aks-30o0</guid>
      <description>&lt;p&gt;In this article, I am going to provide a step by step tutorial on how to deploy a machine learning model on Azure Kubernetes Service (AKS). I will also outline when you should and shouldn’t use AKS. Let’s go! &lt;/p&gt;

&lt;h2&gt;
  
  
  Azure Kubernetes Service in a nutshell
&lt;/h2&gt;

&lt;p&gt;Azure Kubernetes Service (AKS) is a fully managed Kubernetes container orchestration service that simplifies the deployment and management of containerized applications. With AKS, you can quickly deploy and scale containerized apps without worrying about the underlying infrastructure.&lt;/p&gt;

&lt;p&gt;AKS is a handy platform for running, managing, and orchestrating containerized applications. It allows developers to focus on building and deploying their applications rather than worrying about infrastructure-related tasks. AKS supports a wide range of container technologies and tools, which makes it versatile and easy to use. Whether you are building a new application from scratch or migrating an existing one to the cloud, AKS provides a seamless experience for deploying and scaling your application. &lt;/p&gt;

&lt;h3&gt;
  
  
  When to use AKS
&lt;/h3&gt;

&lt;p&gt;AKS is meant for production level workloads. One of the big upsides of AKS is its scaling capabilities. If you are processing a lot of data or want to serve large machine learning models to lots of people, AKS could be an option for you. In terms of deployment options, it falls under the “managed” category, because you still have to create and manage the AKS cluster yourself, even if Kubernetes does a lot of the work for you. Azure ML also provides other deployment options which are entirely managed by Azure, so before you deploy on AKS, you should maybe take a look at the other deployment methods that Azure offers. &lt;/p&gt;

&lt;p&gt;In a nutshell, you should use AKS if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you have heavy workloads&lt;/li&gt;
&lt;li&gt;Scalability is important to you&lt;/li&gt;
&lt;li&gt;You want or need to manage your compute resources yourself&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project requirements
&lt;/h2&gt;

&lt;p&gt;Let’s take a look at the steps to deploy on AKS and the requirements for the project. To follow along, you should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An active Azure subscription.&lt;/li&gt;
&lt;li&gt;An Azure ML workspace.&lt;/li&gt;
&lt;li&gt;Azure CLI installed.&lt;/li&gt;
&lt;li&gt;Python &amp;gt; 3.9 and the Azure ML Python SDK v2 installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this tutorial, I am going to use the Azure Portal as well as the Azure CLI to create and configure the Kubernetes cluster. Then, the Azure ML Python SDK v2 will be used to actually connect the compute to Azure ML in order to deploy a model. &lt;/p&gt;

&lt;p&gt;For the actual model deployment we need: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An machine learning model as a &lt;code&gt;.pkl&lt;/code&gt; file (or equivalent).&lt;/li&gt;
&lt;li&gt;A conda env file as a &lt;code&gt;.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;scoring.py&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need a reference on how these files should look, you can get a dummy model, env and scoring script &lt;a href="https://github.com/Azure/azureml-examples/tree/main/sdk/python/endpoints/online/model-1" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Optionally, you can also check out my GitHub for the code used to deploy via the Python SDK v2. &lt;/p&gt;

&lt;h2&gt;
  
  
  Project outline
&lt;/h2&gt;

&lt;p&gt;Next, let’s take a look at the required steps for this project. &lt;/p&gt;

&lt;p&gt;First, we are going to create a new AKS in the Azure Portal. Optionally, this can also be done with the Azure CLI. &lt;/p&gt;

&lt;p&gt;After the AKS cluster is created, we need to provide access from and to the cluster in order to install the Azure ML extention on AKS and access the cluster. &lt;/p&gt;

&lt;p&gt;Then the Azure ML extention is installed on the AKS cluster via the CLI. If you are using an Azure Arc AKS cluster, this can also be done via the Azure Portal. &lt;/p&gt;

&lt;p&gt;Once the extention is installed, the AKS cluster can be attached to a Azure ML workspace to train or deploy ml model. &lt;/p&gt;

&lt;p&gt;The cluster can the be used to deploy a machine learning model using the model and conda env.&lt;/p&gt;

&lt;p&gt;Here's my attempt to visualize this: &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%2Ffjeazrrxq8b2530ckcqx.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%2Ffjeazrrxq8b2530ckcqx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an AKS cluster
&lt;/h2&gt;

&lt;p&gt;Let’s provision the AKS cluster. You can change all these settings, like availability, pricing and so on, so that they suit all your needs. When it comes to the node size, I would advise to opt for a node that has at least 8 GBs of RAM or more. With less powerful nodes I often faced the problem that the Azure ML k8s extention didn’t install because the memory maxed out during installation. Here is my configuration: &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%2F8th0pv5q59mz3dpm1qw6.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%2F8th0pv5q59mz3dpm1qw6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Providing access to the cluster
&lt;/h2&gt;

&lt;p&gt;After the AKS cluster is deployed, we need to configure the service principal so that the cluster is able to install the Azure ML k8s extention to be able to get attached to the Azure ML workspace. This is the part where I struggled a bit and which showed me that I need to brush up my skills regarding Azure AD and access policies. &lt;/p&gt;

&lt;p&gt;Some of the following steps might be overkill. There are probably other approaches that work, too. So feel free to let me know what I could have done better here! &lt;/p&gt;

&lt;p&gt;Anyway. In the Azure Active Directory, we create a new group called AKS-group and add our user and our Azure ML enviroment to that group.&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%2F9eo50fq5dx29lzkpr14n.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%2F9eo50fq5dx29lzkpr14n.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, in the AKS cluster, we need to ensure to set the method of Authentication to &lt;code&gt;Azure AD authentication with Kubernetes RBAC&lt;/code&gt;. We then add the AKS cluster to the previously created group. To be able to attach the cluster to Azure ML later, make sure to aktivate &lt;code&gt;Kubernetes local accounts&lt;/code&gt;. Otherwise, the attachment will fail. &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%2F40072n4dw200cxry878l.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%2F40072n4dw200cxry878l.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, head to &lt;code&gt;Access controll (IAM)&lt;/code&gt; and grant access to and from the AKS cluster. I choose to grant admin rights for a bit of peace of mind here, but you can go for any access level that is enough to allow the installation of extentions and the attachment to Azure ML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Azure ML k8s extention
&lt;/h2&gt;

&lt;p&gt;Now that the access is set, it’s time to acutally install the Azure ML extention so that the cluster can be used in Azure ML. As of writing this in April 2023, this can be done via the Azure Portal for Azure Arc clusters or via the CLI for typical AKS clusters. Having the latter, I used the following command to install the extention:&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%2Fctgab1hi4sgbtva8x9dj.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%2Fctgab1hi4sgbtva8x9dj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az k8s-extension create --name Aml-extension --extension-type Microsoft.AzureML.Kubernetes --config enableTraining=True enableInference=True inferenceRouterServiceType=LoadBalancer allowInsecureConnections=True inferenceLoadBalancerHA=False --cluster-type managedClusters --cluster-name whale --resource-group MlGroup --scope cluster&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Quite a long command. Let’s take a look at what’s happening here: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;—name&lt;/code&gt; is the simple name you would like to give to the extention. Choose any name you like for this. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;—extension-type&lt;/code&gt; is the actual extension we would like to install. In this case, we need the Microsoft.AzureML.Kubernetes extension. &lt;/p&gt;

&lt;p&gt;Depending on if you want to use the cluster for training or inference, you need to set the &lt;code&gt;—enableTraining&lt;/code&gt; and/ or &lt;code&gt;—enableInference&lt;/code&gt; flags.&lt;/p&gt;

&lt;p&gt;Point to the cluster you would like the extension to install on with the &lt;code&gt;—cluster-name&lt;/code&gt; and &lt;code&gt;—resource-group&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;For secure deployments you should configure SSL and set &lt;code&gt;—allowInsecureConnections&lt;/code&gt; to &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That’s it. The installation should take a couple of minutes. If the installation of your extention on the AKS cluster takes too long (15 minutes or more), then the node size is probably to small. If you get an authentication error then you’ll need to re-visit the access rights in the &lt;code&gt;Access control (IAM)&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to the Azure ML workspace
&lt;/h2&gt;

&lt;p&gt;After the extention is install, we can head over to our Azure ML workspace. In the compute section you can find, right besides the compute instances and compute clusters, a column for Kubernetes Clusters. &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%2Ffl7egdkgvexfhixiijow.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%2Ffl7egdkgvexfhixiijow.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To attach our cluster, simply click on “new” &amp;gt; “Kubernetes”. You should then be able to select the previously created AKS cluster and give this compute a name (I usually give the same name as the AKS cluster). &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%2Fvtczitlq13v1nh0nwloi.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%2Fvtczitlq13v1nh0nwloi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit attach and after a couple of seconds your AKS cluster should be usable via Azure ML. Hurray! &lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the machine learning model
&lt;/h2&gt;

&lt;p&gt;For the next step, we are going to use some code with the Azure ML Python SDK v2. Before deploying, an endpoint is needed. This can be set up like this: &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;# deploy the model to AKS
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;azure.ai.ml.entities&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;KubernetesOnlineEndpoint&lt;/span&gt;

&lt;span class="n"&gt;online_endpoint_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k8s-endpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%m%d%H%M%f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# create an online endpoint
&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KubernetesOnlineEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;online_endpoint_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;moby&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;this is a sample k8s endpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;auth_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tags&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;key&lt;/span&gt;&lt;span class="sh"&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;test_deplyoment&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="c1"&gt;# then create the endpoint
&lt;/span&gt;&lt;span class="n"&gt;ml_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;begin_create_or_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;After the endpoint is created, we can deploy a machine learning model. To do that, we provide the path to a machine learning model (in this case a .pkl file) as well as and environment, which requires a conda.yml and a base image, which you can get from Microsoft. For inference, we also need a python script to init the model.&lt;/p&gt;

&lt;p&gt;Note that we don’t need to populate one node of our AKS with one model. For this dummy model, 0.1 CPUs and 0.5 GB of RAM are enough. Set this to the size suitable for your model. &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;from&lt;/span&gt; &lt;span class="n"&gt;azure.ai.ml.entities&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;KubernetesOnlineDeployment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CodeConfiguration&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;azure.ai.ml.entities._deployment.resource_requirements_settings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ResourceRequirementsSettings&lt;/span&gt;

&lt;span class="c1"&gt;# configure the deployment
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.\model\model\sklearn_regression_model.pkl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;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;conda_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.\model\environment\conda.yml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/azureml/minimal-ubuntu18.04-py37-cpu-inference:latest&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;blue_deployment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KubernetesOnlineDeployment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;endpoint_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;online_endpoint_name&lt;/span&gt;&lt;span class="p"&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;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;code_configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;CodeConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.\model\onlinescoring&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scoring_script&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;instance_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="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;ResourceRequirementsSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;ResourceSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.5Gi&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="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;Finally, it’s time to deploy: &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;ml_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;begin_create_or_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blue_deployment&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You should then see the AKS as a compute option. &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%2F6tr92k283gbwcwz0v3q5.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%2F6tr92k283gbwcwz0v3q5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Maybe you are wondering why we call this blue_deployment. This is done because of the so called Blue-green deployment strategy, which  allows for zero dewntime during the deployment and update of the model later on. When a new version of the machine learning model is ready for deployment, it is deployed to the inactive (green) environment which has 0 % of the traffic. Once the new version has been successfully deployed and tested, the traffic is switched from the active environment to the newly deployed one, making it the new active environment. You can read more on this &lt;a href="https://learn.microsoft.com/en-us/azure/machine-learning/how-to-safely-rollout-online-endpoints?view=azureml-api-2&amp;amp;tabs=azure-cli" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;The nice thing about Azure ML is that it allows you to manage and monitor the deployments with ease and provides you a lot of great tools to keep track of your deployed models. &lt;/p&gt;

&lt;p&gt;In this article we went through the steps needed to deploy a machine learning model on Azures Kubernetes Service. If you have any questions or feedback, feel free to leave them in the comments of hit me up on &lt;a href="https://www.linkedin.com/in/leonard-p%C3%BCttmann-4648231a9/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;Have fun deploying and thank you for reading. 🙂&lt;/p&gt;

</description>
      <category>azure</category>
      <category>kubernetes</category>
      <category>machinelearning</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Alleviate the pain of manual labeling and deploying models with weak supervision</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Tue, 14 Mar 2023 11:24:10 +0000</pubDate>
      <link>https://dev.to/meetkern/alleviate-the-pain-of-manual-labeling-and-deploying-models-with-weak-supervision-3051</link>
      <guid>https://dev.to/meetkern/alleviate-the-pain-of-manual-labeling-and-deploying-models-with-weak-supervision-3051</guid>
      <description>&lt;p&gt;Natural Language Processing (NLP) has seen significant improvements in recent years due to the advent of neural network models that have achieved state-of-the-art performance on a range of tasks like sentiment analysis, named entity recognition, and machine translation. However, these models require vast amounts of labeled data, which can be prohibitively expensive and time-consuming to obtain. With &lt;a href="https://www.kern.ai/"&gt;refinery and gates&lt;/a&gt;, we enable users to leverage the power of weak supervision in their production environment to mitigate the need for expensive manual labeling and costly model deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use weak supervision?
&lt;/h2&gt;

&lt;p&gt;Weak supervision is a promising alternative to traditional supervised learning that can help alleviate the need for vast amounts of labeled data. Weak supervision uses heuristics or rules to create noisy labels for the data. Noisy means that the labels are largely correct, but can contain more errors than labels obtained from manual labeling. These noisy labels can then be used to train a model that can generalize to new, unseen data. Or we can also optimize the weak supervision to use it directly for production! This approach is especially useful when there is no large labeled dataset available for a particular task or domain.&lt;/p&gt;

&lt;p&gt;In the context of NLP, weak supervision can be used to annotate text data, such as social media posts or online reviews, with labels that are less precise than those obtained through manual annotation. For example, a weak supervision approach to sentiment analysis might use a set of rules in the form of programmatic labeling functions to label all tweets containing positive emojis as "positive," and all tweets that use negative emojis as "negative." These noisy labels can then be used to train a model that can classify new tweets into positive or negative categories.&lt;/p&gt;

&lt;p&gt;Despite the challenges, weak supervision has gained popularity in recent years due to its ability to quickly and easily generate labeled data. It can also be used in combination with traditional supervised learning to improve model performance further. For instance, a weak supervision approach can be used to generate initial labels for a dataset, which can then be refined by human annotators in a process called "bootstrapping." This iterative process of weak supervision and human annotation can help reduce the amount of manual labeling required and improve the quality of the final dataset.&lt;/p&gt;

&lt;p&gt;Another advantage of weak supervision is that it can be used to label rare or unusual events that are difficult to label using traditional supervised learning approaches. For example, it can be challenging to obtain labeled data for rare diseases or rare events in social media. However, a weak supervision approach can use domain-specific knowledge to generate labels for these rare events, enabling models to learn from limited data.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to deal with noisy labels
&lt;/h2&gt;

&lt;p&gt;While weak supervision can be a powerful tool for training models with limited labeled data, it comes with its own set of challenges. Cheap labels are often noisy. Noisy labels can introduce errors and biases into the training data, and it can be difficult to quantify the quality of the labels generated by the weak supervision process. However, there are reliable methods that allow us to easily spot errors in labels quickly.&lt;/p&gt;

&lt;p&gt;One of those methods is called confident learning. Confident learning is a technique used to identify and correct errors in noisy labels, so this is perfect for weakly supervised data! The approach involves training a model on the noisy labels generated through weak supervision and then using the model's predictions to estimate the confidence of each label. Labels with low confidence can then be flagged as potentially incorrect and subjected to further scrutiny or correction. This method can help improve the quality of the final dataset and reduce the impact of errors introduced by weak supervision without the need to check all the labels manually.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Heuristics - sources for cheap labels
&lt;/h2&gt;

&lt;p&gt;The classic approach to get labels would of course be to manually annotate the whole dataset. But that would be time-consuming, tedious, slow, and very expensive. Instead, we can only partly label our data by hand and try to find cheaper methods to obtain labels for the rest of our data. These cheap and inexpensive label sources will most likely be noisy. But if we can get labels from many different sources, then the final, weakly supervised label will be greater than the sum of its parts. In other words: It’s going to be accurate. In refinery, we call these sources heuristics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Labeling functions
&lt;/h3&gt;

&lt;p&gt;Labeling functions allow us to programmatically incorporate domain knowledge into the labeling process. Similar to expert systems, which are still in place in many companies. We can do this with programming languages like Python. A domain expert has a mental model in his mind, of how and why he would label things in a certain way. In the field of natural language processing, this could be certain words, the structure of sentences, or the author of a text. All of these can be expressed programmatically. Let’s imagine that we want to build a classifier to detect clickbait. We would quickly notice that a lot of clickbait starts with a number and that clickbait often addresses the reader directly. We could incorporate this simply with just a few lines of code: &lt;/p&gt;

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

&lt;p&gt;These labeling functions won’t be perfect, but as long as they are better than guessing, we’ve already gained something. In the iterative process of getting labels, these functions can also be improved and debugged later on as we gain more insights into our data. &lt;/p&gt;

&lt;h3&gt;
  
  
  Active learner
&lt;/h3&gt;

&lt;p&gt;Active learning is a technique used to select the most informative examples from a large unlabeled dataset to be labeled by a human annotator. The goal is to select examples that will provide the most value in improving the model's performance while minimizing the number of examples that need to be labeled. This approach can be especially useful when labeled data is scarce or expensive to obtain. It involves iteratively training a model on a small subset of labeled data, selecting the most informative examples to label, and retraining the model on the expanded labeled dataset. This process can be repeated until the model's performance reaches a desired level or the budget for labeling is exhausted.&lt;/p&gt;

&lt;p&gt;This is especially powerful if we use this in combination with pre-trained transformer models to embed out text data. These models handle all of the heavy-lifting during the active learning part, so that we can quickly get accurate results, even if we don’t have tons of data available. &lt;/p&gt;

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

&lt;h3&gt;
  
  
  Zero-shot classification
&lt;/h3&gt;

&lt;p&gt;Zero-shot classification allows us to label data without having to explicitly train a model on that particular task or domain. Instead, we can use a pre-trained language model, such as BERT or GPT-3, that has been trained on a large corpus of text to generate labels for new, unseen data.&lt;/p&gt;

&lt;p&gt;To use zero-shot classification, we need to provide the language model with a set of labels or categories that we want to use for classification. The language model can then generate a score or probability for each label, indicating how likely the input text belongs to that label. This approach can be especially useful when we have a small labeled dataset or no labeled data at all for a particular task or domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dIZE9-AE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lf7scinh9d62ylzy1mii.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dIZE9-AE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lf7scinh9d62ylzy1mii.png" alt="Image description" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, let's say we want to classify news articles into different topics, such as politics, sports, and entertainment. We can use a pre-trained language model, such as BERT, to generate probabilities for each label. We would provide the language model with a set of examples for each label, such as news articles that belong to the politics category, and let it learn the patterns and features that are characteristic of each category. Then, when we give the language model a new, unseen news article, it can generate probabilities for each label, indicating how likely the article belongs to each category.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combining heuristics for weak supervision in refinery
&lt;/h2&gt;

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

&lt;p&gt;We now learned why weak supervision is so powerful. Let’s take a closer look at how we use all the possible heuristics for weak supervision in refinery. &lt;/p&gt;

&lt;p&gt;In refinery, labels from different sources are combined and result in a singular, weakly supervised label. The labeling source includes manual labels, labels from labeling functions, active learner models as well as zero-shot labels. Let’s take a closer look at an example project, which contains news headlines. &lt;/p&gt;

&lt;h3&gt;
  
  
  A closer look under the hood
&lt;/h3&gt;

&lt;p&gt;Here are the steps on how we obtain the weakly supervised label. We build a DataFrame out of the source vectors of our heuristics, which contain the label &amp;lt;&amp;gt; record mappings as well as the confidence values for all of our label sources. Afterward, the predictions are calculated for all of the label sources by multiplying the precision with the confidence of each label source. These values then all get added to an ensemble voting system, which integrated all the relevant data from the noisy label matrix into the singular weakly supervised label.&lt;/p&gt;

&lt;p&gt;The ensemble voting system works by retrieving all of the confidence values from all the label sources, aggregating them, and selecting the label with the highest confidence values. The final confidence score is then calculated by subtracting the highest voting confidence score from the sum of voters and then subtracting this from the highest voting confidence score and after that, passing the output of this to a sigmoid function. The resulting weakly supervised label and the final confidence value are then added to our record in refinery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using weak supervision in production with gates
&lt;/h2&gt;

&lt;p&gt;The great thing about weak supervision is that we can directly use it in production as well. We created custom labeling functions, already have machine learning models in our active learners, and include state-of-the-art transformer models to obtain labels. When using weak supervision, we set up a powerful environment to efficiently label data with ease. If this approach works well on unlabeled data in our dataset, chances are that it also works well with new incoming data in a production environment. Even better: We can even enrich our project with new incoming data and react to changes quickly. We can monitor the quality of our weak supervision system via the confidence scores and create or change labeling functions or label some new data manually when needed. This ensures high accuracy but also low cost in regards to maintaining AI in a production environment and removes the stress of monitoring and re-deploying machine learning models regularly. &lt;/p&gt;

&lt;p&gt;That’s why we created gates, which allows you to use information from a weak supervision environment anywhere through an API. Our data-centric IDE for NLP allows you to use all the powerful weak supervision techniques to quickly label data. And through gates, you can access all your heuristics and active learners with the snap of a finger. No need to put models into production, you can access everything right away.&lt;/p&gt;

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

&lt;p&gt;In conclusion, weak supervision is an amazing technique for NLP that can help alleviate the need for vast amounts of labeled data. It can be used to label data quickly and easily, especially for rare or unusual events, and can be combined with traditional supervised learning to improve model performance further. While it comes with its own set of challenges, recent research has shown that combining weak supervision with other techniques can help mitigate these challenges and improve model performance.&lt;/p&gt;

</description>
      <category>weaksupervision</category>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>nlp</category>
    </item>
    <item>
      <title>How we used AI to automate stock sentiment classification</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Tue, 21 Feb 2023 14:40:23 +0000</pubDate>
      <link>https://dev.to/meetkern/how-we-used-ai-to-automate-stock-sentiment-classification-45ph</link>
      <guid>https://dev.to/meetkern/how-we-used-ai-to-automate-stock-sentiment-classification-45ph</guid>
      <description>&lt;p&gt;This article is meant to accompany this video: &lt;a href="https://www.youtube.com/watch?v=yeML0vX0yLw" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=yeML0vX0yLw&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we would like to provide you with a step-by-step tutorial, in which we build a slack bot that sends us a daily message on the sentiment of the news of our stocks. To do this, we need a tool that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automatically fetch data from news sources&lt;/li&gt;
&lt;li&gt;retrieve API calls from our ML model to get predictions&lt;/li&gt;
&lt;li&gt;send out our enriched data to Slack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will build the web scraper in Kern AI workflow, labeled our news articles in refinery, and then enrich the data with gates AI. After that, we will use workflow again to send out the predictions and the enriched data via a webhook to Slack. If you'd like to follow along or explore these tools on your own, you can join our waitlist here:  &lt;a href="https://www.kern.ai/" rel="noopener noreferrer"&gt;https://www.kern.ai/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's dive into the project! &lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping data in workflow
&lt;/h2&gt;

&lt;p&gt;To get started, we first need to get data. Sure, there are some publicly available datasets for stock news available. But we are interested in building a sentiment classifier for only specific companies and, ideally, we want news articles that are not too old and therefore irrelevant. &lt;/p&gt;

&lt;p&gt;We start our project in workflow. Here we can add a Python node, with which we can execute custom Python code. In our case, we use it to scrape some news articles. &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%2Fkk1erikq1nivpm70bgeh.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%2Fkk1erikq1nivpm70bgeh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many ways to access news articles. We decided to use the Bing News API because it offers up to 1000 free searches per month and is fairly reliable. But of course, you can do this part however you like! &lt;/p&gt;

&lt;p&gt;To do this, we use a &lt;code&gt;Python yield&lt;/code&gt; node, which takes in one input (the scraping results) but can return multiple outputs (in this case, one record per found article):&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid4&lt;/span&gt;

    &lt;span class="n"&gt;search_term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AAPL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# You can make this a list and iterate over it so search multiple companies! 
&lt;/span&gt;
    &lt;span class="n"&gt;subscription_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;YOUR_AZURE_COGNITIVE_KEY&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;search_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.bing.microsoft.com/v7.0/news/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;headers&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;Ocp-Apim-Subscription-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subscription_key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;params&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;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;search_term&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;textDecorations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;textFormat&lt;/span&gt;&lt;span class="sh"&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;HTML&lt;/span&gt;&lt;span class="sh"&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;mkt&lt;/span&gt;&lt;span class="sh"&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;en-US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;search_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;headers&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;name&lt;/span&gt;&lt;span class="sh"&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;description&lt;/span&gt;&lt;span class="sh"&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;provider&lt;/span&gt;&lt;span class="sh"&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;datePublished&lt;/span&gt;&lt;span class="sh"&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;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;providers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;search_results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
            &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;part_of_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;search_results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
            &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;part_of_response&lt;/span&gt;

    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_term&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# Scraper the collected urls
&lt;/span&gt;    &lt;span class="n"&gt;texts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; 
            &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;p&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;scraped_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;scraped_text_joined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scraped_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scraped_text_joined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Text not available.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;texts&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;datePublished&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;datePublished&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;item&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;After that, we can store our data in a shared store. There are two store nodes, a "Shared Store send" to receive data into a store and a "Shared Store read" node from which you can access stored data and feed it into other nodes. &lt;/p&gt;

&lt;p&gt;We can create a Shared Store in the store section of Workflow. In the store section, you'll also find many other cool stores, such as spreadsheets or LLMs from OpenAI!&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%2F1zennx52vtawd4if285j.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%2F1zennx52vtawd4if285j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simply click on "add store" and give it a fitting name. Afterward, you'll be able to add the created store in a node in workflow. &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%2Frcx0od1s0fhuddwxcz0i.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%2Frcx0od1s0fhuddwxcz0i.png" alt="Image description"&gt;&lt;/a&gt;&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%2F825kew9d3e3fuc88cdi4.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%2F825kew9d3e3fuc88cdi4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we've scraped some data, we can move on to label and process it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Enriching new incoming data with gates
&lt;/h2&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%2F7dvhbm3hs1uy898c71ka.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%2F7dvhbm3hs1uy898c71ka.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we've run our web scraper and collected some data, we can sync a shared store with refinery. This will load all of our scraped data into a refinery project. Once we run the scraper again, new records will be loaded into the refinery project automatically. &lt;/p&gt;

&lt;p&gt;Refinery is our data-centric IDE for text data and we can use it to label and process our articles very quickly and easily. &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%2F37c2j4vzmpqy1td8r3p1.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%2F37c2j4vzmpqy1td8r3p1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, we can create heuristics or something called an active learner to speed up and semi-automate the labeling process. Click &lt;a href="https://docs.kern.ai/refinery/quickstart" rel="noopener noreferrer"&gt;here&lt;/a&gt; for a quickstart tutorial on how to label and process data with refinery. &lt;/p&gt;

&lt;p&gt;Once the results of the project are satisfactory, all heuristics of ml models of a refinery can be accessed via an API through our second new tool, which is called gates. &lt;/p&gt;

&lt;p&gt;Before we can access a refinery project, we have to go to gates first, open our project there, and start our model and/ or heuristic in the configuration. &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%2F7yq43gzhyaibwt78m7x1.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%2F7yq43gzhyaibwt78m7x1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we've done so, we will be able to select the model of the running gate in our gates AI node in workflow.&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%2F9k5cvdoy9zmt7e0oyero.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%2F9k5cvdoy9zmt7e0oyero.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gates is integrated directly into workflow and we don't need an API token to do this. But of course, the gates API is also usable outside of workflow, for this we would need an API token. But we will cover this in another blog article then. &lt;/p&gt;

&lt;p&gt;After we've passed the data through gates, we get a dictionary as a response containing all the made predictions and confidence values for each of our active learners and heuristics. We also get all the input values returned as well, so if you are only interested in the results, we have to do a little bit of filtering. The Python code below takes in the response from gates and only returns the prediction and the topic. You can use a normal Python node for this.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&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;prediction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prediction&lt;/span&gt;&lt;span class="sh"&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;results&lt;/span&gt;&lt;span class="sh"&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;sentiment&lt;/span&gt;&lt;span class="sh"&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;prediction&lt;/span&gt;&lt;span class="sh"&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;stock&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topic&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterward, we store the filtered and enriched results in a separate store!&lt;/p&gt;

&lt;h2&gt;
  
  
  Aggregate the sentiments
&lt;/h2&gt;

&lt;p&gt;Now we got all of our news articles enriched with sentiment predictions. The only thing that's left is to aggregate the predictions and send them out. You could do this via E-Mail or you could also send the results to a Google Sheet. In our example, we are going to use a webhook to send out the aggregated results to a dedicated slack channel.&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%2Fija381qvzejp5zz9d5r4.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%2Fija381qvzejp5zz9d5r4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our example we simply count the number of positive, neutral and negative articles, but you could also send out the confidence of the articles or the text snippets of articles. To do this, we use a Python aggregate node, which takes in multiple records but sends out only one output. Here's the code for this node:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid4&lt;/span&gt;

    &lt;span class="n"&gt;positive_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;neutral_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;negative_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prediction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rather positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;positive_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prediction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;neutral&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;neutral_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prediction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rather negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;negative_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Beep boop. This is the daily stock sentiment bot. There were &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;positive_count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; positive, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;neutral_count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; neutral and &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;negative_count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; news about Apple today!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then create a webhook store, add the URL of our slack channel and then add the node to our workflow. Afterward, we can run the workflow and it should send out a slack message to us! &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%2Ffrk20s4n9o4tl13dkb4e.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%2Ffrk20s4n9o4tl13dkb4e.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This simple use-case only scratches the surface of what you can do with the Kern AI platform and you have a lot of freedom to customize the project and workflow to your need! &lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, feel free to leave it in the comment sections down below!&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>workflow</category>
    </item>
    <item>
      <title>GPT and BERT: A Comparison of Transformer Architectures</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Thu, 09 Feb 2023 13:37:07 +0000</pubDate>
      <link>https://dev.to/meetkern/gpt-and-bert-a-comparison-of-transformer-architectures-2k46</link>
      <guid>https://dev.to/meetkern/gpt-and-bert-a-comparison-of-transformer-architectures-2k46</guid>
      <description>&lt;p&gt;Transformer models such as GPT and BERT have taken the world of machine learning by storm. While the general structures of both models are similar, there are some key differences. Let’s take a look. &lt;/p&gt;

&lt;h2&gt;
  
  
  The original Transformer architecture
&lt;/h2&gt;

&lt;p&gt;The first transformer was presented in the famous paper &lt;a href="https://arxiv.org/abs/1706.03762" rel="noopener noreferrer"&gt;"attention is all you need"&lt;/a&gt; by Vaswani et al. The transformer models were intended to be used for machine translation and used as encoder-decoder architecture that didn't rely on things like recurrence. Instead, the transformer focused on something called attention. In a nutshell, attention is like a communication layer that is put on top of tokens in a text. This allows the model to learn the contextual connections of words in a sentence. &lt;/p&gt;

&lt;p&gt;From this original transformer paper, different models emerged, some of which you might already know. If you spent a little of your time exploring transformers already, you've probably come across this image, outlining the architecture of the first transformer model. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F45qzl5vs8t811nphbr8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F45qzl5vs8t811nphbr8c.png" alt="Image description" width="432" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The approach to using an encoder and a decoder is nothing new. It means that you train two neural networks and use one of them for encoding and one of them for decoding. This is not limited to transformers, as we can use the encoder-decoder architecture with other types of neural networks like LSTM (Long-Short Term Memory). This is especially useful if we would like to convert an input into something else, like a sentence of one language into another language. Or an image into a text description.&lt;/p&gt;

&lt;p&gt;The crux of the transformer is the use of (self-)attention. Things like recurrence are dropped completely, hence the name "attention is all you need" of the original paper!&lt;/p&gt;

&lt;h2&gt;
  
  
  GPT vs BERT: What’s The Difference?
&lt;/h2&gt;

&lt;p&gt;The original transformer paper sprouted lots of really cool models, such as the all-mighty GPT or BERT.&lt;/p&gt;

&lt;p&gt;GPT stands for Generative Pre-trained Transformer, and it was developed by OpenAI to generate human-like text from given inputs. It uses a language model that is pre-trained on large datasets of text to generate realistic outputs based on user prompts. One advantage GPT has over other deep learning models is its ability to generate long sequences of text without sacrificing accuracy or coherence. In addition, it can be used for a variety of tasks, including translation and summarization. &lt;/p&gt;

&lt;p&gt;BERT, which stands for Bidirectional Encoder Representations from Transformers, was developed by the Google AI Language team and open-sourced in 2018. Unlike GPT, which only processes input from left to right like humans read words, BERT processes input both left to right and right to left in order to better understand the context of given texts. Furthermore, BERT has also been shown to outperform traditional NLP models such as LSTMs on various tasks related to natural language understanding. &lt;/p&gt;

&lt;p&gt;There is, however, an extra difference in how BERT and GPT are trained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;BERT is a Transformer encoder, which means that, for each position in the input, the output at the same position is the same token (or the [MASK] token for masked tokens), that is the inputs and output positions of each token are the same. Models with only an encoder stack like BERT generate all its outputs at once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GPT is an autoregressive transformer decoder, which means that each token is predicted and conditioned on the previous token. We don't need an encoder, because the previous tokens are received by the decoder itself. This makes these models really good at tasks like language generation, but not good at classification. These models can be trained with unlabeled large text corpora from books or web articles.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The special thing about transformer models is the attention mechanism, which allows these models to understand the context of words more deeply.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does attention work?
&lt;/h2&gt;

&lt;p&gt;The self-attention mechanism is a key component of transformer models, and it has revolutionized the way natural language processing (NLP) tasks are performed. Self-attention allows for the model to attend to different parts of an input sequence in parallel, allowing it to capture complex relationships between words or sentences without relying on recurrence or convolutional layers. This makes transformer models more efficient than traditional recurrent neural networks while still being able to achieve superior results in many NLP tasks. In essence, self-attention enables transformers to encode global context into representations that can be used by downstream tasks such as text classification and question answering.&lt;/p&gt;

&lt;p&gt;Let's take a look at how this work. Imagine that we have a text &lt;em&gt;x&lt;/em&gt;, which we convert from raw text using an embedding algorithm. To then apply the attention, we map a query (&lt;em&gt;q&lt;/em&gt;) as well as a set of key-value pairs (&lt;em&gt;k&lt;/em&gt;, &lt;em&gt;v&lt;/em&gt;) to our output &lt;em&gt;x&lt;/em&gt;. Both &lt;em&gt;q&lt;/em&gt;, &lt;em&gt;k&lt;/em&gt;, as well as v, are vectors. The result &lt;em&gt;z&lt;/em&gt; is called the attention-head and is then sent along a simple feed-forward neural network. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ftu6mtxdgeyxjtyepkmyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ftu6mtxdgeyxjtyepkmyy.png" alt="Image description" width="112" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this sound confusing to you, here is a visualization that highlights connections that are built by the attention mechanism: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fefybju109l9xkiytczmk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fefybju109l9xkiytczmk.gif" alt="Image description" width="493" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can explore this yourself in this super cool Tensor2Tensor Notebook &lt;a href="https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb#scrollTo=OJKU36QAfqOC" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In conclusion, while both GPT and BERT are examples of transformer architectures that have been influencing the field of natural language processing in recent years, they have different strengths and weaknesses that make them suitable for different types of tasks. GPT excels at generating long sequences of text with high accuracy whereas BERT focuses more on the understanding context within given texts in order to perform more sophisticated tasks such as question answering or sentiment analysis. Data scientists, developers, and machine learning engineers should decide which architecture best fits their needs before embarking on any NLP project using either model. Ultimately, both GPT and BERT are powerful tools that offer unique advantages depending on the task at hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get refinery today
&lt;/h2&gt;

&lt;p&gt;Download refinery, our data-centric IDE for NPL. In our tool, you can use state-of-the-art transformer models to process and label your data. &lt;/p&gt;

&lt;p&gt;Get it for free here: &lt;a href="https://github.com/code-kern-ai/refinery" rel="noopener noreferrer"&gt;https://github.com/code-kern-ai/refinery&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further articles: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;NanoGPT by Andrej Kaparthy &lt;a href="https://github.com/karpathy/nanoGPT/blob/master/train.py" rel="noopener noreferrer"&gt;https://github.com/karpathy/nanoGPT/blob/master/train.py&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BERT model explained &lt;a href="https://www.geeksforgeeks.org/explanation-of-bert-model-nlp/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/explanation-of-bert-model-nlp/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encoder-decoder in LSTM neural nets &lt;a href="https://machinelearningmastery.com/encoder-decoder-long-short-term-memory-networks/" rel="noopener noreferrer"&gt;https://machinelearningmastery.com/encoder-decoder-long-short-term-memory-networks/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The illustrated transformer by Jay Alammar &lt;a href="http://jalammar.github.io/illustrated-transformer/" rel="noopener noreferrer"&gt;http://jalammar.github.io/illustrated-transformer/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>howto</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Active Learning with Transformer-Based Machine Learning Models</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Thu, 19 Jan 2023 14:09:33 +0000</pubDate>
      <link>https://dev.to/meetkern/active-learning-with-transformer-based-machine-learning-models-536</link>
      <guid>https://dev.to/meetkern/active-learning-with-transformer-based-machine-learning-models-536</guid>
      <description>&lt;p&gt;The combination of active learning and transformer-based machine learning models provides a powerful tool for efficiently training deep learning models. By leveraging active learning, data scientists are able to reduce the amount of labeled data required to train a model while still achieving high accuracy. This post will explore how transformer-based machine learning models can be used in an active learning setting, as well as which models are best suited for this task. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Active Learning?
&lt;/h2&gt;

&lt;p&gt;Active learning is an iterative process that uses feedback from previously acquired labels to inform the selection of new data points to label. It works by continuously selecting the most informative unlabeled data points that have the greatest potential to improve the model’s performance when labeled and incorporated into training. This iterative process creates an efficient workflow that allows you to quickly get high quality models with minimal effort. With each iteration, the performance increases, allowing to observe the improvement of a machine learning model. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fznlr61ok4whqcic0bw0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fznlr61ok4whqcic0bw0q.png" alt="Image description" width="800" height="494"&gt;&lt;/a&gt; &lt;em&gt;Source: &lt;a href="https://huggingface.co/blog/autonlp-prodigy" rel="noopener noreferrer"&gt;Active Learning with AutoNLP and Prodigy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For example, an &lt;a href="https://towardsdatascience.com/transformers-meet-active-learning-less-data-better-performance-4cf931517ff6" rel="noopener noreferrer"&gt;experiment&lt;/a&gt; on the MRPC dataset with the bert-base-uncased transformer model found that 21 % fewer examples were needed using the active learning approach in contrast to using a fully labeled dataset from the start. &lt;/p&gt;

&lt;h2&gt;
  
  
  Transformer-Based Machine Learning Models for Active Learning
&lt;/h2&gt;

&lt;p&gt;Transformer-based machine learning models such as &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/bert-base-uncased" rel="noopener noreferrer"&gt;BERT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/gpt2" rel="noopener noreferrer"&gt;GPT-2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/xlnet-base-cased" rel="noopener noreferrer"&gt;XLNet &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;are well suited for active learning due to their ability to capture context information in text data. These models have been shown to achieve state-of-the-art results on many natural language processing tasks such as question answering, sentiment analysis, and document classification. By utilizing these types of models in an active learning setting, you can quickly identify the most important samples that need labeling and use them to effectively train your model. Additionally, these models are very easy to deploy on cloud platforms like AWS or Azure, making it even more convenient to use them in an active learning environment.  &lt;/p&gt;

&lt;h2&gt;
  
  
  How we approach active learning in Kern AI refinery
&lt;/h2&gt;

&lt;p&gt;In refinery, we use SOTA transformer models from Huggingface to create embeddings from text datasets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fent7g0qe6e848xw4qkrc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fent7g0qe6e848xw4qkrc.png" alt="Image description" width="800" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is usually done at the start of a new project because having the embedding for all of our text data allows us to quickly find similar records by calculating the cosine similarity of each embedded text. This can drastically increase the labeling speed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F41iq2wccy1ky5vthveu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F41iq2wccy1ky5vthveu2.png" alt="Image description" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some labeling of the data is done, we are able to use these text embeddings to train simple machine learning algorithms, such as a Logistic Regression or a Decision Tree. We do not use these embeddings to train a transformer-based model again, because the embeddings are of such a high quality that even simple models provide high-accuracy results. While you save time and money through the active learning approach, you also save a lot of computational workload down the road.&lt;/p&gt;

&lt;p&gt;In conclusion, transformer-based machine learning models provide a powerful tool for efficiently training deep learning models using active learning techniques. By leveraging their ability to capture contextual information from text data, you can quickly identify which samples should be labeled next in order to effectively train your model with minimal effort and cost. Furthermore, these types of models are highly scalable and easy to deploy on cloud platforms making them ideal for use in an active learning setting. With all these advantages combined together, it’s no wonder why transformer-based machine learning models are becoming increasingly popular among developers and data scientists alike.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tooling</category>
      <category>devops</category>
    </item>
    <item>
      <title>Drastically decrease the size of your Docker application</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Tue, 03 Jan 2023 17:15:15 +0000</pubDate>
      <link>https://dev.to/meetkern/drastically-decrease-the-size-of-you-docker-application-jfa</link>
      <guid>https://dev.to/meetkern/drastically-decrease-the-size-of-you-docker-application-jfa</guid>
      <description>&lt;p&gt;Containers are amazing for building applications. Because they allow you to pack up a program together with all it's dependencies and execute it wherever you like. That is why our application consists of 20+ individual containers, forming our data-centric IDE for NLP, which you can check out here: &lt;a href="https://github.com/code-kern-ai/refinery" rel="noopener noreferrer"&gt;https://github.com/code-kern-ai/refinery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don't know what Docker or a container is, here's a short rundown: Docker is a tool designed to make it easier to create, deploy, and run applications by using containers. Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other dependencies, and ship it all out as one package.&lt;/p&gt;

&lt;p&gt;Using Docker, you can run many containers simultaneously on a single host. This can be useful for a variety of purposes, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolating different applications from each other, so they don't interfere with each other.&lt;/li&gt;
&lt;li&gt;Testing new software in a contained environment, without the need to set up a new machine or install any dependencies.&lt;/li&gt;
&lt;li&gt;Running multiple versions of the same software on the same machine, without having to worry about version conflicts.&lt;/li&gt;
&lt;li&gt;Packaging and distributing applications in a consistent and easy-to-use way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, Docker allows developers to easily create, deploy, and run applications in a containerized environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem of size
&lt;/h2&gt;

&lt;p&gt;One problem of Docker containers is that they can get quite large. Because the container, well, contains everything that the program needs to run, the total size of a single container can quickly get to a couple of gigabytes. &lt;/p&gt;

&lt;p&gt;Version 1.4 of our application took up about 10.96 GB of disk space. While that's not absolutley enormous for a modern application, we saw a lof of potential to increase the usability by decreasing the total size. In the end, smaller is always better, especially when keeping in mind that not all of our users have incredible internet and almost 11 GB can sometimes take quite some time to download. &lt;/p&gt;

&lt;p&gt;In the end, we managed to cut the needed disk space by almost 50 % to 5.2 GB. How did we manage to do this? &lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing smaller parent images
&lt;/h2&gt;

&lt;p&gt;First, let's take a look at parent images for Docker containers. In Docker, a parent image is the image from which a new image is built. When you create a new Docker image, you are usually creating it based on an existing image, which serves as the parent image for the new image.&lt;/p&gt;

&lt;p&gt;For example, let's say you want to create a new Docker image for a web application. You might start by using an existing image such as &lt;code&gt;ubuntu:18.04&lt;/code&gt; as the base, or parent, image. You would then add your application code and any necessary dependencies to the image, creating a new child image.&lt;/p&gt;

&lt;p&gt;The parent image provides a foundation for the child image, and all of the files and settings in the parent image are inherited by the child image. This allows you to create new images that are based on a known, stable foundation, and ensures that your new images have all of the necessary dependencies and configurations.&lt;/p&gt;

&lt;p&gt;The new child image can then be used to build you container and run your application. &lt;/p&gt;

&lt;p&gt;There are many parent images you could choose. You can check them out at &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;https://hub.docker.com/&lt;/a&gt;. Most of our containers used the &lt;code&gt;python:3.9&lt;/code&gt; parent image. This image comes with a full Python installation build on top of Linux. Technically, this is just fine for what we do. Thing is, the image alone is 865 MB large, at lease for the amd64 architecture. &lt;/p&gt;

&lt;p&gt;Maybe something smaller would do the job just as well. The &lt;code&gt;python:3.9-alpine&lt;/code&gt; image for example is build on alpine Linux, a super tiny Linux distribution. The image &lt;code&gt;python:3.9-slim&lt;/code&gt; is also substantially smaller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fs9f2juzmn3aadczxhi6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fs9f2juzmn3aadczxhi6u.png" alt="Image description" width="734" height="114"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then tried out the smaller parent images for all of our child images to see if they still run. For some images we had to stay with the normal &lt;code&gt;python:3.9&lt;/code&gt; image, but the majority of images are just running normally with &lt;code&gt;python:3.9-alpine&lt;/code&gt; or &lt;code&gt;python:3.9-slim&lt;/code&gt;. This reduced the total size of the application quite a lot!&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared layers
&lt;/h2&gt;

&lt;p&gt;Another thing we optimized was the use of shared layers. Docker images consist of multiple layers, which can be shared between different images. These shared layers have to be downloaded and stored on disk only once. Therefore, increasing the usage of shared layers reduces download time and disk consumption. Following this approach, we created custom docker parent images, which have already preinstalled the python dependencies needed by the refinery services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdnmlik5jyx9kczluzc15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdnmlik5jyx9kczluzc15.png" alt="Image description" width="800" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above you can see a comparison of the image sizes before and after. In the size column the effect of the choice of the smaller parent images is visible. The effect of the shared layers is shown in the shared and unique size columns.&lt;/p&gt;

&lt;p&gt;Those are some tricks we used to decrease the needed disk space for our application. If you found this article useful please leave a like or follow our author. If you have great tips on how to reduce the size of an application that uses containers, please leave them in the comments below!&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>How we managed to build our open-source content library crazy fast</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Thu, 15 Dec 2022 16:57:07 +0000</pubDate>
      <link>https://dev.to/meetkern/how-we-managed-to-build-our-open-source-content-library-crazy-fast-3me</link>
      <guid>https://dev.to/meetkern/how-we-managed-to-build-our-open-source-content-library-crazy-fast-3me</guid>
      <description>&lt;p&gt;Our newest project here at Kern AI offers you a fantastic library of modules called bricks, with which you can enrich your NLP text data. Our content library seamlessly integrates into our main tool, Kern AI refinery. But it also provides the source code for all the modules, providing you with maximum control. All modules can also be tested by calling an endpoint via an API. &lt;/p&gt;

&lt;p&gt;We managed to build this incredible tool in just less than two months, thanks in large part to the amazing team at Kern, but also in part to the stunning capabilities of DigitalOcean's App Platform. We also managed to increase development by automating large parts of our content management system. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://bricks.kern.ai/home" rel="noopener noreferrer"&gt;You can try out bricks here!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's first talk about the general structure of bricks and then dive into a little bit more detail! &lt;/p&gt;

&lt;h2&gt;
  
  
  How bricks is structured
&lt;/h2&gt;

&lt;p&gt;Bricks is built using four components: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend using next.js built with Tailwind UI&lt;/li&gt;
&lt;li&gt;Backend with Strapi and a managed PostgreSQL database&lt;/li&gt;
&lt;li&gt;Service to serve the live endpoints on bricks&lt;/li&gt;
&lt;li&gt;A separate search module to easily find modules&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;p&gt;The overall design of bricks should be fitting to the one that is also used in refinery. The bricks UI is created using React and deployed via NextJS. We also used Tailwind for the UI elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;For the backend, we use Strapi, which is an awesome open-source content management system. Strapi is connected to a PostgreSQL database to store all the content that is displayed on bricks. The frontend connects to the backend via an API to then display all the content.&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%2F8f7k44vtg4vox4im0eaf.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%2F8f7k44vtg4vox4im0eaf.png" alt="Image description"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Managing content with Strapi itself is super easy, but to make things even more easier for us, we wrote an automation script that is able to fetch new modules created for bricks and automatically add them to Strapi. That's why the source code of a bricks module needs to be in a specific format in order to be added to Strapi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Live endpoints
&lt;/h3&gt;

&lt;p&gt;Every module can be tested right from bricks itself. On the right side of every module, you'll see a window that allows you to try out the module without the need to install anything. &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%2F29daj47dx1sqwj5wj57i.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%2F29daj47dx1sqwj5wj57i.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Providing this was very important for us, as we want users to find out what exactly they get with every module and test the module with some of their own data. The default input is usually some text or sometimes some additional parameters for the endpoint. &lt;/p&gt;

&lt;h3&gt;
  
  
  Search module
&lt;/h3&gt;

&lt;p&gt;To quickly find the right modules, we also build a custom search module. The search module uses a small transformer model to embed all the names of the module, which can be searched very quickly. &lt;/p&gt;

&lt;p&gt;Let's now take a closer look at the technologies we used to quickly get bricks live.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leveraging DigitalOcean's App Platform
&lt;/h2&gt;

&lt;p&gt;The App Platform is a convenient and cheap way to deploy your web apps. Instead of deploying an app on a virtual machine that you'll have to manage yourself, the app will run in a Docker container. That way you don't have to think about the underlying infrastructure and also get the benefit of easy scalability. It's also a bit cheaper than hosting your app on a single VM. In the case of DigitalOcean, you also get the option to auto-deploy from a GitHub repository, which is super handy.&lt;/p&gt;

&lt;p&gt;There are many cloud platforms out there offering such a service, but for our purposes, we chose to use DigitalOcean. This post is not sponsored by them, we just like their service a lot. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/deployment/hosting-guides/digitalocean-app-platform.html#add-environment-variables" rel="noopener noreferrer"&gt;To get started with bricks, we used this tutorial on how to deploy Strapi to DigitalOcean&lt;/a&gt;. We highly recommend you to check it out as well if you would like to use Strapi on DigitalOcean, as it was really helpful to get us started with the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-deploy from a GitHub repository
&lt;/h2&gt;

&lt;p&gt;To deploy on DigitalOcean, you can simply attach a GitHub repository, from which the app will automatically get deployed. In our case, we use the auto-deploy function for our endpoint service, so that new modules added to bricks will automatically get integrated. &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%2Fqaa98o9xcyk4dw51f9td.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%2Fqaa98o9xcyk4dw51f9td.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But before we can do that do that, we first need to deploy our backend and frontend components. To keep things clear, we deploy them separately and also store backend and frontend in a different repository. DigitalOcean also allows you to connect your app to a managed database, which is super convenient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a managed database
&lt;/h2&gt;

&lt;p&gt;Before we can deploy the backend, we need a managed PostgreSQL database first. DigitalOcean offers many different database types, but PostgreSQL should be just fine for our needs. When deploying Strapi on DigitalOcean, you can also choose a cheaper dev database for your app. However, we had a lot of trouble getting that dev database to run, so we instead directly went for the managed database that is meant to be used in production anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an App on DigitalOcean
&lt;/h2&gt;

&lt;p&gt;Next up, we are going to create our first App on DigitalOcean. The app will host the Strapi backend of the site and will be connected to the managed PostgreSQL database we created in the previous step. Deploying the backend is fairly easy, you simply select the GitHub repo and the fitting directory you want to deploy, and DigitalOcean will handle all the rest for you. You can also opt-in for auto-deploy, and your app will be redeployed whenever there is a new change to your repository. &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a second App for the frontend
&lt;/h2&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%2F84ozbi7o5e24gsoimhcf.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%2F84ozbi7o5e24gsoimhcf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While it is technically possible to host the backend and the frontend on the same app, we chose not to do that. Setting up the frontend was much easier in a separate app, and apps are very cheap in general, so we would only save a few dollars if we would've deployed on the same app. So we thought it would not be worth the hassle. The frontend gets all the information from the backend via a simple API call, so the frontend and backend don't need to be connected in any other way, too. &lt;/p&gt;

&lt;p&gt;Building the second app for the frontend is essentially the same procedure as for the backend. You simply select the repository and the directory and let DigitalOcean do the work for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the endpoint app
&lt;/h2&gt;

&lt;p&gt;Once backend and frontend are up and running, we need to deploy the service that is running our endpoints. Otherwise, a user would still be able to access bricks and check out the modules, but they couldn't directly try them out on the site itself. &lt;/p&gt;

&lt;p&gt;The procedure is the same as before: connect your GitHub repository and deploy a containerized application via DigitalOcean. The endpoint service is using FastAPI to deliver the results of each endpoint to bricks. So far, a single service is enough to serve all the 50+ endpoints we have available on bricks so far.   &lt;/p&gt;

&lt;h2&gt;
  
  
  Using bricks to quickly enrich dataset for NLP
&lt;/h2&gt;

&lt;p&gt;We hope that you liked this insight into the structure behind bricks. You can &lt;a href="https://bricks.kern.ai/home" rel="noopener noreferrer"&gt;try out bricks here&lt;/a&gt; to inspect the result for yourself. &lt;/p&gt;

&lt;p&gt;If you have any questions or feedback you would like to share, feel free to post it in the comments down below. Have fun using bricks! &lt;/p&gt;

</description>
      <category>nlp</category>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Introducing bricks, an open-source content-library for NLP</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Thu, 08 Dec 2022 14:50:54 +0000</pubDate>
      <link>https://dev.to/meetkern/introducing-bricks-an-open-source-content-library-for-nlp-2pg5</link>
      <guid>https://dev.to/meetkern/introducing-bricks-an-open-source-content-library-for-nlp-2pg5</guid>
      <description>&lt;p&gt;This week we launched bricks, an open-source library which provides enrichments for your natural language processing projects. Our main goal with bricks is to shorten the amount of time that you need from idea to implementation. Bricks also seamlessly integrates into our main tool, the &lt;a href="https://www.kern.ai/" rel="noopener noreferrer"&gt;Kern AI refinery&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Let's take a closer look at the structure of bricks and how to use it. You'll find bricks here&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bricks.kern.ai/home" rel="noopener noreferrer"&gt;https://bricks.kern.ai/home&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure of a brick module
&lt;/h2&gt;

&lt;p&gt;In each module of bricks, you will find the source code for the function. You can directly use a bricks module in refinery, either by directly copying the source code or via the bricks integration that will be available in the next release of refinery 1.7. Of course, this code could also be used outside of refinery. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fove9b1tcqejzn6avwflw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fove9b1tcqejzn6avwflw.png" alt="Image description" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the right hand side, you can directly try out the module over an live endpoint that we've deployed. You can try out the module with the example input that is already provided, or you can type something yourself and try it out! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F18vibwemyo4hpyqtd06c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F18vibwemyo4hpyqtd06c.png" alt="Image description" width="602" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of bricks modules
&lt;/h2&gt;

&lt;p&gt;Currently, there are three main types of modules in refinery:&lt;/p&gt;

&lt;h3&gt;
  
  
  Classifiers:
&lt;/h3&gt;

&lt;p&gt;As the name suggests, these modules can be used to classify something. Need to find out the language of your text or get the complexity of it? You'll find what you need in the classifiers! &lt;/p&gt;

&lt;h3&gt;
  
  
  Extractors:
&lt;/h3&gt;

&lt;p&gt;The extractors are really useful if you would like to pull certain information or entities from your text. The most bricks modules can currently be found here, where you'll find modules to extract metrics, time, names, adresses and many more useful thing! We've built all of these modules in a way that they can instantly be used for labeling functions in refinery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generators:
&lt;/h3&gt;

&lt;p&gt;This type of module generates some new form of output, such as a translation or a cleaned or corrected version of a text. In the generators, you will also find two premium functions, for which you'll need an API key of an external provider to use them, in this case for language translation. However, it's also very important to us to always provide similar modules that don't need an API key. &lt;/p&gt;

&lt;h2&gt;
  
  
  Using a bricks module in refinery
&lt;/h2&gt;

&lt;p&gt;Let's say that we have a dataset with news articles, and we want to categorize them by their complexity. We then go to the &lt;code&gt;sentence complexity&lt;/code&gt; module in bricks and copy all the source code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqi6kba2gr2j4oll1h4c8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqi6kba2gr2j4oll1h4c8.png" alt="Image description" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then go back to our project in refinery and create a new attribute calculation, which we can do on the settings page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Feyshgrwb8p259n1748lk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Feyshgrwb8p259n1748lk.png" alt="Image description" width="788" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then paste in the code and put in the name of our attribute, in our case the &lt;code&gt;headlines&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkrs9osg8fupdgpd50nnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkrs9osg8fupdgpd50nnn.png" alt="Image description" width="800" height="390"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;As a result, we'll then get the sentence complexity of each of our headlines that we have in our dataset. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F9ejar2tk2i7pzffiy32e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F9ejar2tk2i7pzffiy32e.png" alt="Image description" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of this takes less than a minute to implement. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing to bricks
&lt;/h2&gt;

&lt;p&gt;As all projects at Kern, bricks is open-source, meaning that you get access to the source-code. You can also contribute to bricks if you built something that you would like to share and that you think would be useful to others. Should you have a great idea or implementation, feel free to just open an issue on our GitHub page.&lt;a href="https://github.com/code-kern-ai/bricks" rel="noopener noreferrer"&gt;You can check bricks GitHub page here.&lt;/a&gt; On our GitHub page, you'll also find a detailed explaination of how to contribute to bricks. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=S0cPZ5fqsNo" rel="noopener noreferrer"&gt;We've also made a tutorial on YouTube&lt;/a&gt; in which our DevRel guy Div shows you all the neccessary steps to contribute. &lt;/p&gt;

&lt;p&gt;You may also join our Discord community, where you can ask questions and discuss things with the wonderful Kern community. Join us here: &lt;a href="https://discord.gg/WAnAgQEv" rel="noopener noreferrer"&gt;https://discord.gg/WAnAgQEv&lt;/a&gt;&lt;/p&gt;

</description>
      <category>portfolio</category>
    </item>
    <item>
      <title>Host your ML model as a serverless function on Azure</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Fri, 11 Nov 2022 15:03:49 +0000</pubDate>
      <link>https://dev.to/leonardpuettmann/deploying-a-machine-learning-model-as-a-serverless-function-on-azure-1d22</link>
      <guid>https://dev.to/leonardpuettmann/deploying-a-machine-learning-model-as-a-serverless-function-on-azure-1d22</guid>
      <description>&lt;p&gt;Building machine learning models is fun. But to deliver real business value, machine learning models need to be put into production. Often, that's easier said than done. &lt;/p&gt;

&lt;p&gt;The logical solution is to make the model accessible via an endpoint that is hosted in the cloud. One option for this is to host the machine learning model on a virtual machine in the cloud. With this, however, comes the need to manage the VM. This can quickly become a hassle, especially when you need to serve a lot of endpoints.&lt;/p&gt;

&lt;p&gt;One interesting alternative is to run your machine learning model as a serverless function in the cloud. While I think that the name &lt;em&gt;serverless&lt;/em&gt; is not quite fitting, because we still use a server to run the code, the concept by itself is still amazing. Instead of managing hardware resources yourself, you just provide the code you would like to run and the provider will handle all the rest. Serverless functions are also dirty cheap. The code of the serverless function is usually packed up inside a Docker image, which is started up every time you call your model. This means that you don't pay for a resource 24/7, you only pay as you go. &lt;/p&gt;

&lt;p&gt;For today's article, we will be using serverless functions on Microsoft's Azure Cloud. The first million executions for cloud functions there are free. So if your needs for hosting an ML model are manageable, you should be able to provide your model without paying even a single cent. &lt;/p&gt;

&lt;p&gt;**In a nutshell, serverless functions are great, if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model is small and efficient.&lt;/li&gt;
&lt;li&gt;You need the model only sometimes or in regular intervals and&lt;/li&gt;
&lt;li&gt;response times of a couple of seconds are alright for you.&lt;/li&gt;
&lt;li&gt;You don't want to pay a lot of money (or you don't have any).**&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deploying serverless functions of Azure is super easy. In this article, we are going to deploy a decision tree model, which was trained on data from a wind turbine to predict energy production. You'll need at least a basic understanding of the concepts of cloud computing as well as some knowledge of Python. However, if you'll have any questions along the way of this article, feel free to ask anything in the comments. To follow along, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An actvive subscription in Azure&lt;/li&gt;
&lt;li&gt;VS Code as well as some Azure Extentions&lt;/li&gt;
&lt;li&gt;Python 3.8 or higher&lt;/li&gt;
&lt;li&gt;Optional: &lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash" rel="noopener noreferrer"&gt;Azure function core tools&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we start building a serverless function app, we'll first take a look at our machine learning model as well as the data we trained the model with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/LeonardPuettmann/wind-forecasting-serverless" rel="noopener noreferrer"&gt;The whole code + data of the project is accessible here.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Predicting energy production of a wind turbine
&lt;/h2&gt;

&lt;p&gt;The machine learning model meant for deployment is a simple decision tree that was trained on two and a half years of data from a wind turbine. The goal of the model is to predict the energy production of the wind turbine given information such as the ambient temperature, technical conditions of the turbine and, of course, the current wind speed. The dataset is really interesting and fun and I encourage you to dive deeper into it. When looking at the energy produced by the wind turbine, we can see that between July and September, the energy output seem to be the highest, usually outputting max energy. After that, the energy production is much lower.&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%2Ffpb1jr5p9ugx4pgu0awn.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%2Ffpb1jr5p9ugx4pgu0awn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To predict the energy production of the wind turbine, we are going to use a decision tree. While a decision tree will most likely yield worse results than, say, a random forest, XGBoost regressor or a neural net, a simple model such as a decision tree also has upsides. For one, it's very fast and lightweight, making it ideal to run as a serverless function. It's also very interpretable, making it easy to understand why exactly the model came to make its prediction. And when the underlying data itself is very good, decision trees can be very powerful. This is why this model, together with a logistic regression, is my first go-to model when first tackling any problem. &lt;/p&gt;

&lt;p&gt;That being said, we probably won't see stunning results from the model. Before training the model, I shifted the data in a way that the model tries to predict the energy production for the next 10 minutes. The further the prediction is in the future, the more likely I expect the model to become unaccurate, but for demonstration purposes, I think this should be fine. &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an intital function in the Azure portal
&lt;/h2&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%2Fcl9hu9eccw6limhshtib.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%2Fcl9hu9eccw6limhshtib.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to get started with the creation of the serverless function. Go to the Azure portal and click on &lt;em&gt;function app&lt;/em&gt; to create a new function app. Choose to publish the function as code and select Python 3.9 as the runtime stack and version. I am going to deploy the function in northern Europe, as it is the nearest location to me. But feel free to choose any other location that's closest to you. As for the plan type we want to select the consumption (serverless) plan. After that, hit review + create to create the function app. &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%2Fev966oba3utup5oe3ini.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%2Fev966oba3utup5oe3ini.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While it is technically possible to write and deploy code directly from the Azure portal, it's much easier to just do that from VS code. Let's jump into VS Code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing VS Code extentions
&lt;/h2&gt;

&lt;p&gt;Deploying from VS Code has some benefits as opposed to writing the code directly in Azure. First, we can debug and try out our function locally, which I think is great. Second, when deploying from VS Code, you have more options to customize your model. For example, we might upload a machine learning model as a .pkl file packed up with our function, which is exactly what we are interested in. &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%2F546cp16db52qcay1rsa2.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%2F546cp16db52qcay1rsa2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go into the extensions section of VS Code and install the Azure Tools as well as the Azure Functions extension. To test functions locally, you also need to install the &lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash" rel="noopener noreferrer"&gt;Azure function core tools&lt;/a&gt;. The last step is optional, but I highly recommend testing our functions locally before deploying them. Make sure to log in to your Azure account as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing an empty function in VS code
&lt;/h2&gt;

&lt;p&gt;Once all the extensions are installed, open the directory you want to work in, hit F1 and search for "Azure Functions: create new function...". We've already created a function app in Azure, but this will only serve as the shell, to which we will later deploy our actual function.&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%2Fcjvk5pgq0q48zdjisp90.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%2Fcjvk5pgq0q48zdjisp90.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the first step, you can select the programming language. I'm going to use Python, but there are many other programming languages available, such as Java, C# or JavaScript. After that, you can choose to select a runtime for a virtual environment, in which you can run your function. &lt;/p&gt;

&lt;p&gt;You can also select a template for your function, which determines the way that your function gets triggered. For example, you can create a time trigger to trigger your function at a given interval or time of day. A function might also get triggered whenever there is a new entry in data storage. I am going to use the HTTP Trigger, which triggers the function every time it receives a POST request. &lt;/p&gt;

&lt;p&gt;After that, you can set the name of the function as well as the access rights. If you need to access other tools from Azure, I recommend that you set the auth settings to "Admin". &lt;/p&gt;

&lt;p&gt;Everything is set now, and all the needed components will automatically get created for us in the directory we initialized the function. Time to write some code! &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%2F5q2dp3zta0zjvufsstj3.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%2F5q2dp3zta0zjvufsstj3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing our function
&lt;/h2&gt;

&lt;p&gt;Inside your directory, you should find a folder with the name that you have given to your function. In there, you'll find a file called &lt;code&gt;__init__.py&lt;/code&gt;. All the code that we want to run in the serverless function goes into this file. The file also contains a python function called main, which is crucial for the serverless function. You may also add more python functions, but you need to have the main functions as well!&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="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&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="n"&gt;joblib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;

&lt;span class="c1"&gt;# Load the decision tree model
&lt;/span&gt;&lt;span class="n"&gt;dtr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;joblib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;windpred_model.pkl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&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;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;# Parse the received data as a JSON file
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# If the data is not empty, convert to a pandas DataFrame 
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&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="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&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;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&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;to_numeric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;coerce&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Create new prediction for every entry in the df
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
            &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&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;iloc&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
            &lt;span class="n"&gt;y_hat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dtr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Store results in a dict
&lt;/span&gt;            &lt;span class="n"&gt;results&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;energy_production&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;y_hat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;# Append results to a list 
&lt;/span&gt;            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Return the predictions as a JSON file
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# If no JSON data is recieved, print error response
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please pass a properly formatted JSON object to the API&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploying the function
&lt;/h2&gt;

&lt;p&gt;Now we have everything in place for our serverless function and we are ready to deploy. Click on the Azure Extention and click on your subscription in the resources section. Search for the function app, in which you'll find the function app that we previously deployed in the Azure Portal. Right-click on the function and click on "Deploy to Function App...". This will automatically push the function app we configured in VS Code to Azure. &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%2F0cwhgixwg6lolhlmv778.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%2F0cwhgixwg6lolhlmv778.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying out our serverless function
&lt;/h2&gt;

&lt;p&gt;After a couple of minutes, the function app should be deployed and ready to use. Because our function is triggered by HTTP requests, we can test out our app with the help of the Python requests library. &lt;/p&gt;

&lt;p&gt;To be able to send the data, we need to have it in JSON format. Luckily, Pandas is capable to save a DataFrame to JSON by calling .to_json on a DataFrame. I have taken a subset of the test data, which looks like this as a JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"AmbientTemperatue"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;38.039763&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;29.4031836&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;33.7847183784&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;33.6842655556&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;25.8910933&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"BearingShaftTemperature"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;44.663637&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;40.0134959&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;47.901935875&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;40.8214605&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;42.1678136&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"Blade1PitchAngle"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;45.7368925375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;45.7368925375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;45.7368925375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;34.3081334429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;45.7368925375&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"Blade2PitchAngle"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;32.3317821077&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"Blade3PitchAngle"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;32.3317821077&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.6993571429&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"GearboxBearingTemperature"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;65.5114258&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;61.7971398&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;77.119133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;49.5740933&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;69.9417784&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"GearboxOilTemperature"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;59.7925489&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;56.3766701&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;64.204399375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;54.2150616667&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;58.2121131&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"GeneratorRPM"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1053.90176&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1030.01957&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1751.7155625&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;115.3844747778&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1433.95605&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"GeneratorWinding1Temperature"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;66.001735&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;56.8643122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;113.29087075&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;57.8011734444&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;70.1916634&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"GeneratorWinding2Temperature"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;65.1331282&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;56.0960214&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;112.59216325&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;57.2828797778&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;69.546118&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"HubTemperature"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.996185&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;36.0191189&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;42.996094375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;39.5969365&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;34.0113608&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"MainBoxTemperature"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;49.83125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;39.95625&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;41.89842625&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.1738124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;36.2125&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"NacellePosition"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;135.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;173.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;60.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;183.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;172.0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"ReactivePower"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;49.440134&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;18.04336296&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;-9.3880610405&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;-10.1450863947&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;0.1142242497&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"RotorRPM"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;9.4539536&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;9.2260374&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;15.708135375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1.0182516089&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;12.841184&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"TurbineStatus"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"WindDirection"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;135.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;173.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;60.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;183.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;172.0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"WindSpeed"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"1553427000000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;4.49369983&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1547726400000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;3.690674815&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1524628800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.5373755703&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1558305600000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.7541209632&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"1545313800000"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;7.19549971&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there is a lot of information that we are passing to the model packed up inside the JSON file. We may load in the JSON data and call our function like this:&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;# Load the JSON data
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Send request to our serverless function
&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;URL OF MODEL GOES HERE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;headers&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;Content-type&lt;/span&gt;&lt;span class="sh"&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;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&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://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%2F3th11bx1s3ht12yd086r.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%2F3th11bx1s3ht12yd086r.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can get the URL of the function in the Azure portal in the &lt;em&gt;code + test&lt;/em&gt; section of your function. The output is the predicted energy output for the next 10 minutes. &lt;/p&gt;

&lt;p&gt;I hope you found this small article about deploying machine learning models as serverless functions useful. If you have any thoughts or questions you would like to share, let me know in the comments! :-)&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>azure</category>
      <category>serverless</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>How we automated license checking for our Python &amp; JS dependencies</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Fri, 28 Oct 2022 10:06:03 +0000</pubDate>
      <link>https://dev.to/meetkern/how-we-automated-license-checking-for-our-python-js-dependencies-5900</link>
      <guid>https://dev.to/meetkern/how-we-automated-license-checking-for-our-python-js-dependencies-5900</guid>
      <description>&lt;p&gt;There are many popular license types for open-source software out there, such as the MIT, BSD or Apache Software License. When building software privately, these license types are minor. However, things get way more complicated when building a commercial product, even if it's open-source. For us as a company, that meant a lot of insecurities about how to handle these licenses.&lt;/p&gt;

&lt;p&gt;In a nutshell, when using a dependency, you'll need to ensure that the dependency allows for commercial use. That's not a problem with the majority of the licenses, but there are some lesser-known ones that could cause some trouble. &lt;/p&gt;

&lt;p&gt;For our tool, the Kern AI refinery, we use dozens of different libraries. Checking all the dependencies manually for all the repositories would be an extremely tedious task, to say the least. So, our machine learning engineer Felix thought to himself "why don't I automate this then?". And that's exactly what he did! &lt;/p&gt;

&lt;h2&gt;
  
  
  Checking Python licenses with LicenseCheck
&lt;/h2&gt;

&lt;p&gt;We have a lot of Python dependencies, so checking these licenses was our biggest priority. When it comes to checking licenses of Python dependencies, we've found a really cool tool called &lt;a href="https://github.com/FHPythonUtils/LicenseCheck" rel="noopener noreferrer"&gt;LicenseCheck&lt;/a&gt;, which can check the requirements.txt file of a GitHub repository and find the licenses for all the dependencies listed inside the file. LicenseCheck can simply be installed via pip and can then be used to print out all the licenses. This already helps a lot, but when you have 50+ repositories, it's still a lot of manual work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Python script
&lt;/h2&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%2Fgjyuj4zgofy9tv364ik5.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%2Fgjyuj4zgofy9tv364ik5.png" alt="Image description"&gt;&lt;/a&gt;&lt;em&gt;Code snipped from the script&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To check &lt;strong&gt;all&lt;/strong&gt; of our repositories, our ML engineer Felix build an amazing Python script that completely automates the whole license checking of our Python dependencies. You can find the whole script &lt;a href="https://github.com/code-kern-ai/util-scripts" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you are interested in using it! &lt;/p&gt;

&lt;p&gt;How does the script work? In a nutshell, you simply paste in the repositories you want to check by putting the name and the URL of the repo inside of a dictionary. Feel free to select as many repos as you like. The script then loops over all the repositories and checks the requirements.txt file from each repo. &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%2Fg5s12yu11ogmqv29434s.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%2Fg5s12yu11ogmqv29434s.png" alt="Image description"&gt;&lt;/a&gt;&lt;em&gt;Using the script, you can simply check all the licenses in your repository&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Checking the results
&lt;/h1&gt;

&lt;p&gt;Finally, the script then saves all the results into a handy Excel spreadsheet, in which you'll get a list with all your dependencies and the corresponding license. &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%2Frm5sklzojsrglejo8em4.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%2Frm5sklzojsrglejo8em4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using this script we were able to have the licenses of 114 dependencies in one list just by running this script. In the future, we might have even more dependencies, but with this tool, we can easily check them again in the future with very little effort. &lt;/p&gt;

&lt;h2&gt;
  
  
  Finding licenses for JavaScript dependencies
&lt;/h2&gt;

&lt;p&gt;Python is not the only programming language that we use. Our application is also build with JavaScript, mainly for the UI and the dashboards for our admins. Sadly, the LicenseCheck tool doesn't work for JavaScript or any other language other than Python. &lt;/p&gt;

&lt;p&gt;As an alternative, we've found &lt;a href="https://github.com/pivotal/LicenseFinder" rel="noopener noreferrer"&gt;LincenseFinder&lt;/a&gt;, which is an awesome open-source tool to check dependencies for JavaScript. The tool checks the package.json file of a repository and tells you the used licenses. You can also create a list of permitted licenses and LicenseFinder will check if your dependencies are in that list. It basically works very similar as the LicenceChecker for Python did. &lt;/p&gt;

&lt;p&gt;We hope that you'll find this helpful. Let us know in the comments if you found similar tools for other programming languages as well so that other people can also see them. &lt;/p&gt;

&lt;p&gt;Make sure to check out our GitHub page to find out more about our open-source, data-centric IDE which we are building! &lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Data-centric AI for NLP is here, and it's here to stay!</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Thu, 20 Oct 2022 18:39:52 +0000</pubDate>
      <link>https://dev.to/meetkern/data-centric-ai-for-nlp-is-here-and-its-here-to-stay-5ffb</link>
      <guid>https://dev.to/meetkern/data-centric-ai-for-nlp-is-here-and-its-here-to-stay-5ffb</guid>
      <description>&lt;p&gt;When a machine learning model performs poorly, many teams intuitively try to improve the model and the underlying code - let’s say switching from a logistic regression to a neural network. Knowing that this can be helpful, it isn’t the only approach you can take to implement your use case. Taking a data-centric approach and improving the underlying data itself is often a more efficient approach to increase the performance of your models. In this article, we want to show you how that can be done - for instance, but not limited to - using our open-source tool &lt;a href="https://github.com/code-kern-ai/refinery"&gt;refinery&lt;/a&gt;. Let’s demystify data-centric AI!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Starting from scratch
&lt;/h2&gt;

&lt;p&gt;In our case, let's imagine that we have some unprocessed text data, with which we would like to build a classifier. For instance, a model to differentiate between topics of a text.&lt;/p&gt;

&lt;p&gt;The first step is to carefully look at the data we have. Can we already spot repeating patterns in the data, such as regular expressions or keywords? How is the data structured, i.e. are there short and long paragraphs and such? Does the data capture the information I need to achieve my goals, or do I need to process it firsthand in some other way? These are not easy questions, but answering them (at least to some extent) early on will ensure the success of your projects later down the road. &lt;/p&gt;

&lt;p&gt;Generally, you can do this by labeling a few of the examples. You will require some manually labeled examples in any way. As you understand patterns and have some reference data, you will get (imperfect, maybe noisy) ideas for automation patterns. Let’s dive into how they can look like. &lt;/p&gt;

&lt;p&gt;One way to create signals for automated labels is labeling functions. These labeling functions allow us to programmatically express and label patterns found in the data, even if these patterns are a bit noisy. We’ll look into this a bit later, don’t worry about that now. For example, we can write a Python function to assign a label once certain words are found in a data point.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4G2rOm_D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gaz9zb780r2df50woq23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4G2rOm_D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gaz9zb780r2df50woq23.png" alt="Image description" width="802" height="354"&gt;&lt;/a&gt;&lt;em&gt;A simple labeling function in refinery&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can also use an active learner for labeling text data. The active learner is a machine learning model that is trained on a subset of the data which has already been labeled manually. Because the data has been processed into high-quality embeddings by SOTA transformer models (e.g. distilbert-base-uncased), we can use simple models such as a logistic regression as the active learner. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dp9rabci--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6svhtr8wfm6yz4i4y97o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dp9rabci--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6svhtr8wfm6yz4i4y97o.png" alt="Image description" width="880" height="384"&gt;&lt;/a&gt;&lt;em&gt;Code for the active learner&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The active learner then automatically applies labels to the unlabeled data. The more data we label manually, the more accurate the active learner becomes, creating a positive feedback loop.&lt;/p&gt;

&lt;p&gt;We could even think of more ideas, e.g. integrating APIs or crowd labeling, but for now, let’s just think of these two examples. We’re also currently building a really cool content library, which will help you to come up with the best ideas for your automation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UwMdh0aa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmvna0qzskge6x9borb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UwMdh0aa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmvna0qzskge6x9borb9.png" alt="Image description" width="607" height="487"&gt;&lt;/a&gt;&lt;em&gt;Results from an active learner&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The labels from our labeling functions and the active learner can then be used for weak supervision, which takes all the labels and aggregates them into a weak supervision label. Think of weak supervision as a framework for really simple integration and denoising of noisy labels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving the labeled data quality
&lt;/h2&gt;

&lt;p&gt;Your data will rarely be perfect from the get-go. Usually, the data will be messy. That means that it's important to continuously improve on the existing training data. How can we do this? The output of the weak supervision also gives us confidence for each label assigned, which is super helpful!&lt;/p&gt;

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

&lt;p&gt;We can then look at all the labels with particularly low confidence, create a new data slice and improve on that specific part of our data. We can manually label some more data out of that low-confidence data slice and write more labeling functions (or ask someone from our team to do that for us, as each slice is tagged with a URL), which then further improves the active learner as well. This not also allows us to improve the labels of our data, but we can also spot noisy labels which differ from the ground truth.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--48umxnte--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2o1inixa0dzwsmlsghcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--48umxnte--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2o1inixa0dzwsmlsghcl.png" alt="Image description" width="880" height="342"&gt;&lt;/a&gt;&lt;em&gt;Confidence distribution of our labels&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can also compare the manual labels with the labels from the weak supervision. The data browser makes it very easy to spot differences. Again, this shows how data-centric AI is not only about scaling your labeling. It really is about adding metadata to your records that help you build large-scale, but especially high-quality training datasets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NwfEr7jo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbojx0c1ux8w1c6m2uk9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NwfEr7jo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbojx0c1ux8w1c6m2uk9.png" alt="Image description" width="880" height="444"&gt;&lt;/a&gt;&lt;em&gt;The data browser in refinery&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the problem at hand easier
&lt;/h2&gt;

&lt;p&gt;There are also further steps we can take towards the goal of data-centric AI. For example, in the domain of NLP, we can further improve the embeddings we use. Let's have a quick refresher on what embeddings are.&lt;/p&gt;

&lt;p&gt;To work with text data for NLP, we can embed sentences into a vector space. The words are represented as numeric values in this vector space. Positioning words in this space make sure that the underlying information and meaning of the words are kept intact while also enabling the processing of the texts by an algorithm. &lt;/p&gt;

&lt;p&gt;State-of-the-art embeddings are created using modern transformer models. These embeddings are very rich with information, but can also be super complex, occasionally having hundreds of dimensions. Fine-tuning these embeddings often lead to huge improvements.  &lt;/p&gt;

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

&lt;p&gt;Instead of using more and more complex models, we can do something else. An alternative approach is to improve the data at hand in a way that the information within the data is preserved, but we don't need super complex models like Transformer or LSTM neural nets in our downstream tasks to make use of the data. By improving the vector space itself, even simple models such as logistic regressions or decision trees can give tremendously great results!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why data-centric AI is here to stay
&lt;/h2&gt;

&lt;p&gt;Now, if you’re thinking: “Wait, but isn’t this also changing the model parameters, and thus again model-centric AI?”. Well, you’re not wrong - but you’re effectively spending the biggest chunk of your time on improving the data, and thus improving the model. That is what data-centric AI is all about.&lt;/p&gt;

&lt;p&gt;We just explored some of the upsides of data-centric AI. Weak supervision provides us with an interface to easily integrate heuristics, such as labeling functions and active learning, to (semi-)automate the labeling process. Further, it helps us to enrich our data with confidence scores or metadata for slicing our records, such that we can easily use weakly supervised labels to manage our data quality. Last but not least, similarity learning can be used to simplify the underlying problem itself, which is much easier than increasing the complexity of the model used.&lt;/p&gt;

&lt;p&gt;Enriching data and treating it like a software artefact enables us to build better and more robust machine learning models. This is why we are confident that data-centric AI is here to stay. &lt;/p&gt;

&lt;p&gt;If you think so too, please make sure to check out our GitHub repository with the open-source &lt;a href="https://github.com/code-kern-ai/refinery"&gt;refinery&lt;/a&gt;. We’re sure it will be super helpful for you, too :)&lt;/p&gt;

</description>
      <category>nlp</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Live session: A first peek into the Kern AI refinery.</title>
      <dc:creator>Leonard Püttmann</dc:creator>
      <pubDate>Fri, 07 Oct 2022 10:31:56 +0000</pubDate>
      <link>https://dev.to/meetkern/live-session-a-first-peek-into-the-kern-ai-refinery-elg</link>
      <guid>https://dev.to/meetkern/live-session-a-first-peek-into-the-kern-ai-refinery-elg</guid>
      <description>&lt;p&gt;We are going live on Twitch! Have you ever thought about integrating refinery into your NLP projects but did not know where to start? On October 13th, Leonard and Moritz will give you a practical overview of the application with an easy-to-understand dataset. &lt;/p&gt;

&lt;p&gt;When? (CEST timezone)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;6pm - 7pm: Livestream on twitch.tv/MeetKern&lt;/li&gt;
&lt;li&gt;7pm - 7.30pm: Live Q&amp;amp;A on our Community Discord server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the livestream you will learn:&lt;br&gt;
👉 How to install refinery&lt;br&gt;
👉 How to set up a project&lt;br&gt;
👉 How to use all the features of refinery&lt;/p&gt;

&lt;p&gt;Our CTO Jens will accompany the livestream and Q&amp;amp;A so that you can get all these burning questions off your chest.&lt;br&gt;
We very much look forward to this, as we greatly value your feedback and engagement. Refinery was built to make your life easier and we think that sessions like this will help you get the hang of this fantastic application.&lt;/p&gt;

&lt;p&gt;Sign up for the event now! See you next Thursday 🥳&lt;/p&gt;

</description>
      <category>nlp</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>livesession</category>
    </item>
  </channel>
</rss>
