<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Tales Marra on Medium]]></title>
        <description><![CDATA[Stories by Tales Marra on Medium]]></description>
        <link>https://medium.com/@talesmarra?source=rss-770f787e930b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*C_kAQbkGyeFa9QJZOtwdmg.jpeg</url>
            <title>Stories by Tales Marra on Medium</title>
            <link>https://medium.com/@talesmarra?source=rss-770f787e930b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 22 May 2026 00:40:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@talesmarra/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Simple MLOps #4: Monitoring]]></title>
            <link>https://medium.com/@talesmarra/simple-mlops-4-monitoring-ebbb6293cf79?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/ebbb6293cf79</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[mlops]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Sat, 04 Nov 2023 18:02:23 GMT</pubDate>
            <atom:updated>2023-11-04T18:02:23.354Z</atom:updated>
            <content:encoded><![CDATA[<p>Building monitoring systems is a crucial step when we’re talking about MLOps. It’s like the saying goes: “<em>if you can’t measure it, you can’t improve it</em>”. Monitoring however implies much more than that. It requires setting up vigilant systems capable of alerting errors to the team as well as capturing key metrics to represent the health of the system.</p><p>Some benefits of implementing a monitoring system include:</p><ul><li>1. Getting alerts when errors occur on your prediction system: Monitoring for errors in real-time ensures swift response to issues, maintaining service reliability.</li><li>2. Checking closely performance and engineering metrics that can highly impact the user experience when interacting with the prediction service: Analyzing key metrics helps optimize performance and user satisfaction.</li><li>3. Catching data and concept drifts, which are silent killers of performance: Detecting shifts in data or model concepts is crucial for maintaining prediction accuracy over time.</li></ul><p>And many more.</p><p>There are many tools available, but as usual, we’ll try to build already something simple yet functional and able to make into production with little adaptations.</p><p>Even though monitoring systems should be all over the place, we’ll start implementing one to the most crucial part of the system: the inference. But the concepts and techniques you’ll learn here are easily transcribed to the other parts of our MLOps stack, and I invite you to implement them by yourself as a challenge.</p><h3>Diving into the architecture</h3><p>To answer the main functionalities we have discussed earlier, we are going to use mainly Cloudwatch, mostly known as the logging service of AWS, but if you play your cards right, it can be much more than that.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0HclNAii1V7Uec9k_Kw6xw.png" /><figcaption>Monitoring System architecture</figcaption></figure><p>We’ll use Cloudwatch for:</p><ol><li>Log and Metric Collection: CloudWatch’s gonna be our trusty sidekick for rounding up all those logs and metrics from our system. It’s like having a watchful eye over everything that’s happening.</li><li>Alerts: CloudWatch will also be our alarm bell. It’ll ping us the moment something fishy goes down in our system. We’re talking instant notifications when things aren’t as they should be.</li><li>Dashboard Magic: We’re gonna whip up a slick monitoring dashboard with CloudWatch. This dashboard will give us real-time snapshots and data, helping us make decisions and keep an eye on how our system’s doing.</li></ol><p>And to make sure we’re in the loop, we’re bringing in AWS Simple Notification Service (SNS). It’s the messenger of the group, following a PubSub model. In our setup:</p><ul><li><em>Alerts (Publisher)</em>: The alert system is the chatterbox that’s gonna shout out about any system hiccups.</li><li><em>Email Addresses (Subscribers)</em>: Email addresses are the eager listeners on the topic of system errors; they’ll get all the updates when our system runs into issues.</li></ul><h3>Build the infrastructure</h3><p>If you have been following the series so far, you already know what’s coming. If not, just a heads up. We’ll be using Terraform to set up the infrastructure for this system, but don’t worry, we’ll do it step by step.</p><p>Note: if you didn’t yet create a log group to your function and gave it permissions to lambda to publish logs to it, refer to the logging section in <a href="https://medium.com/@talesmarra/simple-mlops-3-inference-pipeline-2a413e08be45">Issue #3</a> to set it up.</p><h4>Setting up the dashboard</h4><p>We are developing a dashboard to track the inference duration, a critical metric that significantly impacts the user experience of our machine learning-based product. To ensure smooth operations, we plan to compute the average duration within 300-second intervals. However, feel free to customize this interval to suit your specific requirements.</p><pre># declare a lambda function that already exists<br>data &quot;aws_lambda_function&quot; &quot;lambda&quot; {<br>  function_name = &quot;inference-function&quot;<br>}<br><br># set up the dashboard<br>resource &quot;aws_cloudwatch_dashboard&quot; &quot;lambda_dashboard&quot; {<br>    dashboard_name = &quot;inference_monitoring_dashboard&quot;<br><br>    dashboard_body = jsonencode({<br>        widgets = [<br>            {<br>                type = &quot;metric&quot;<br>                x    = 0<br>                y    = 0<br>                width = 12<br>                height = 6<br>                properties = {<br>                    metrics = [<br>                        [&quot;AWS/Lambda&quot;, &quot;Duration&quot;, &quot;FunctionName&quot;, data.aws_lambda_function.lambda.function_name, { &quot;stat&quot;: &quot;Average&quot;, &quot;period&quot;: 300 }],<br>                    ],<br>                    view = &quot;timeSeries&quot;,<br>                    stacked = false,<br>                    region = &quot;eu-west-3&quot;,<br>                    title = &quot;Lambda Function Duration (ms)&quot;<br>                }<br>            }<br>        ]<br>    })<br>}</pre><h4>Creating the alarm</h4><p>Now, we’ll create a CloudWatch Alarm that monitors the “Errors” metric for a the inference AWS Lambda function. If the “Errors” metric value is greater than or equal to 1 in a 60-second period, the alarm will be triggered, and a notification will be sent to an SNS topic.</p><pre># create an alarm for the lambda function errors <br>resource &quot;aws_cloudwatch_metric_alarm&quot; &quot;lambda_errors_alarm&quot; {<br>  alarm_name          = &quot;lambda_errors_alarm&quot;<br>  comparison_operator = &quot;GreaterThanOrEqualToThreshold&quot;<br>  evaluation_periods  = &quot;1&quot;<br>  metric_name         = &quot;Errors&quot;<br>  namespace           = &quot;AWS/Lambda&quot;<br>  period              = &quot;60&quot;<br>  statistic           = &quot;Sum&quot;<br>  threshold           = &quot;1&quot;<br>  alarm_description   = &quot;This metric monitors lambda errors&quot;<br>  alarm_actions       = [aws_sns_topic.sns_topic.arn]<br>  dimensions = {<br>    FunctionName = data.aws_lambda_function.lambda.function_name<br>  }<br>}</pre><h4>Creating an SNS topic</h4><p>Now we’ll create the SNS topic, that will be used to forward the alert to the email addresses concerned.</p><pre># create an SNS topic to send the alarm to<br>resource &quot;aws_sns_topic&quot; &quot;sns_topic&quot; {<br>  name = &quot;lambda_errors_topic&quot;<br>}</pre><h4>Subscribing the email to the topic</h4><p>Then we need to subscribe the email to the error topic so that it can receive messages.</p><pre># create a subscription to the SNS topic<br>resource &quot;aws_sns_topic_subscription&quot; &quot;sns_topic_subscription&quot; {<br>  topic_arn = aws_sns_topic.sns_topic.arn<br>  protocol  = &quot;email&quot;<br>  endpoint  = &quot;YOUR_MAIL@MAIL.com&quot;<br>}</pre><h3>Deploying the infrastructure</h3><p>The final step consists in planning and applying the infrastructure changes. Just use the command below, and you’ll deploy everything we have set up to AWS!</p><pre>terraform plan &amp;&amp; terraform apply</pre><h3>Checking the results</h3><p>You can now test the different things we have set up! Modify the code for the inference to raise Exceptions and see if you receive an email.</p><p>If you go to the Cloudwatch console, you’ll be able to see both the alarm we have created and the dashboard, and it should look something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/976/1*4yYj90M0Nmkx_tNvmuOZyg.png" /></figure><h3>Conclusion</h3><p>Good job! You’ve got yourself a monitoring service ready to go to production! Your new MLOps stack project is now monitored properly!</p><p>The code for this tutorial is in my <a href="https://github.com/talesmarra/simple-mlops/tree/master/simple-monitoring">GitHub</a>.</p><p>Hit that follow button to stay updated on future explorations! 🔥🤖 Let’s continue this journey of coding, machine learning, and MLOps.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ebbb6293cf79" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simple MLOps #3: Inference Pipeline]]></title>
            <link>https://medium.com/@talesmarra/simple-mlops-3-inference-pipeline-2a413e08be45?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a413e08be45</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[mlops]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Sun, 29 Oct 2023 17:49:14 GMT</pubDate>
            <atom:updated>2023-10-29T17:49:14.246Z</atom:updated>
            <content:encoded><![CDATA[<p>In this third article of the Simple MLOps series, we’ll cover the step I imagine most of you are interested in: the inference pipeline. But don’t fool yourself, having the other steps properly done (feature/continuous training pipeline and the model registry) is crucial to ensuring the inference process will go smoothly.</p><p>Following our philosophy on the series, we’ll strive for simplicity, while building a system that can be put to production.</p><p>Without further due, let’s go through the architecture.</p><h3>Understanding the inference pipeline components</h3><p>Our architecture will be again serverless based, and will consist of a Lambda function coupled with an API gateway, so we’ll get an API-based prediction service.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5Yu1wJU02iF6JcUA7828Sg.png" /><figcaption>The architecture of the prediction API</figcaption></figure><p>The inference function must be able to retrieve the latest model version from the model registry versioning table, and pull the latest model object from the storage. Then it will read the payload it has received through the API and perform the prediction on it. The result will be then forwarded via the API to the requester.</p><h4>Creating an ECR repository to store Lambda image</h4><p>Like we did for the <a href="https://medium.com/@talesmarra/simple-mlops-1-continuous-training-pipeline-5e6ddbf4c398">training pipeline</a>, the first thing we need to do is to create the ECR repository to store the image for our inference function. It’s recommended that you use a different repository than the one for the training function.</p><pre>aws ecr create-repository \<br>    --repository-name inference-image-repo \<br>    --image-scanning-configuration scanOnPush=true \<br>    --region region</pre><h4>Setting up .env file</h4><p>To ensure the security of your credentials, we’ll use .env to load environment variables. Adding to the already set training environment variables the ones related to the inference, so the end file will look like this:</p><pre>AWS_REGION=(YOUR AWS REGION)<br>AWS_CT_ECR_REPO=(YOUR ECR REPO)<br>CT_FUNCTION_NAME=ct-function<br>AWS_INF_ECR_REPO=(YOUR NEW CREATED REPOSITORY FOR INFERENCE)<br>INF_FUNCTION_NAME=inference-function</pre><h4>The inference function</h4><p>We’ll now dive into the code of the inference function itself. As we discussed earlier, we’ll mostly need to implement three things.</p><ul><li>Retrieving the latest model tag from the versioning table: We’ll use <em>boto</em> to do it, performing a scan on the table and then ordering the items. Notice that this is not the most efficient way to do it in a large table, but for the sake of simplicity we’ll do it like this. The code that allows us to do it is here:</li></ul><pre>table_name = &#39;simple-registry&#39;<br># use dynamodb as the service<br>dynamodb = boto3.resource(&#39;dynamodb&#39;)<br># get a table object<br>table = dynamodb.Table(table_name)<br># perform a scan on it. this retrieves all the rows from the table<br>response = table.scan()<br><br>if &#39;Items&#39; in response and len(response[&#39;Items&#39;]) &gt; 0:<br>    # sort by id in reverse<br>    tag_value = sorted(response[&#39;Items&#39;], key=lambda x: x[&#39;id&#39;], reverse=True)[0][&#39;tag&#39;]<br>    print(&quot;Latest_tag_value: &quot;, tag_value)<br>else:<br>    return {<br>        &#39;statusCode&#39;: 404,<br>        &#39;body&#39;: json.dumps(&#39;No models found&#39;)<br>        }  </pre><ul><li>Getting the latest model object from S3: Once we are in possession of the latest model tag, we can simply pull it from S3. The code to do it is the following:</li></ul><pre>s3 = boto3.client(&#39;s3&#39;)<br>model = s3.get_object(Bucket=&#39;registry-bucket-simple-ct&#39;, Key=f&#39;model_{tag_value}.pkl&#39;)<br>model = pickle.loads(model[&#39;Body&#39;].read())</pre><ul><li>Finally we call the predict method on the data. Notice the importance of using pipelines here. As we saved all the pre-processing transformations we need to apply to the data directly on the model, we don’t need to worry about anything, the model will take care of the pre-processing as well.</li></ul><pre>payload = json.loads(event[&#39;body&#39;])<br>preds = model.predict(pd.DataFrame([payload]))[0]<br>return {<br>    &#39;statusCode&#39;: 200,<br>    &#39;statusCode&#39;: 200,<br>    &#39;body&#39;: json.dumps(str(preds))<br>}</pre><h4>Packaging code and dependencies using Docker</h4><p>Docker is used to package our code and the required dependencies. We’ll build a docker image that will install our requirements and package the code. Similarly to what we did on the training pipeline, we’ll build, tag and push the docker image to the inference image repository.</p><pre>FROM public.ecr.aws/lambda/python:3.8</pre><pre># Install the function&#39;s dependencies using file requirements.txt<br># from your project folder.</pre><pre>COPY requirements.txt  .<br>RUN  pip3 install -r requirements.txt --target &quot;${LAMBDA_TASK_ROOT}&quot;<br># Copy function code to /var/task<br>COPY lambda_handler.py ${LAMBDA_TASK_ROOT}</pre><pre># Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)<br>CMD [ &quot;lambda_handler.lambda_handler&quot; ]</pre><h4>Placing the Docker image in the cloud</h4><p>If you’ve followed my advice and installed Just, you can go ahead and just execute the following:</p><pre>just build-inf-image<br>just tag-inf-image<br>just push-ct-image</pre><h3>Building the Infrastructure</h3><p>We’ll now use Terraform to build the necessary infrastructure.</p><h4>Building the function</h4><p>Similarly to what we did on the training pipeline, we’ll declare a lambda function resource, along with a role to which we’ll add permissions later on.</p><pre># Declare the ECR repository you&#39;ve created previously<br>data &quot;aws_ecr_repository&quot; &quot;inference_image_repo&quot; {<br>  name = &quot;inference-image-repo&quot;<br>}<br><br># create a new role for the lambda function<br>resource &quot;aws_iam_role&quot; &quot;simple_inference_role&quot; {<br>  name = &quot;simple-inference-role&quot;<br><br>  assume_role_policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action = &quot;sts:AssumeRole&quot;,<br>        Effect = &quot;Allow&quot;,<br>        Principal = {<br>          Service = &quot;lambda.amazonaws.com&quot;<br>        }<br>      }<br>    ]<br>  })<br>}<br><br># declare a lambda function resource<br>resource &quot;aws_lambda_function&quot; &quot;simple-inference&quot; {<br>  function_name    = &quot;inference-function&quot;<br>  role             = aws_iam_role.simple_inference_role.arn<br># notice we use the image from the repository for the lambda function<br>  image_uri     = &quot;${data.aws_ecr_repository.inference_image_repo.repository_url}:latest&quot;<br>  package_type  = &quot;Image&quot;<br>  timeout          = 900<br>  memory_size      = 128<br>  depends_on = [<br>    aws_iam_role_policy_attachment.cloudwatch_logs_attachment,<br>    aws_cloudwatch_log_group.simple_inference_log_group,<br>  ]<br>}</pre><h4>Defining the interactions</h4><p>The inference function will need read permissions both for S3 and DynamoDB in order to get model objects and versions. The way to give those permissions in AWS is to create a policy, and then attach the policy to the role of the resource, in our case, the role of the inference function we have just declared.</p><pre><br># create a policy to read from the dynamodb table<br>resource &quot;aws_iam_policy&quot; &quot;dynamodb_access_policy_inference&quot; {<br>  name        = &quot;dynamodb-access-policy-inference&quot;<br>  description = &quot;IAM policy for DynamoDB access&quot;<br><br>  policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action = [<br>          &quot;dynamodb:GetItem&quot;,<br>          &quot;dynamodb:Scan&quot;,<br>          &quot;dynamodb:Query&quot;<br>        ],<br>        Effect   = &quot;Allow&quot;,<br>        Resource = data.aws_dynamodb_table.simple_registry.arn,<br>      },<br>    ],<br>  })<br>}<br><br># attach the policy to the role<br>resource &quot;aws_iam_role_policy_attachment&quot; &quot;dynamodb_access_attachment&quot; {<br>  policy_arn = aws_iam_policy.dynamodb_access_policy_inference.arn<br>  role       = aws_iam_role.simple_inference_role.name<br>}<br><br># create a policy to read from the s3 bucket<br>resource &quot;aws_iam_policy&quot; &quot;s3_access_policy_inf&quot; {<br>  name        = &quot;s3-access-policy-inf&quot;<br>  description = &quot;IAM policy for S3 access for inference&quot;<br><br>  policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action   = [&quot;s3:GetObject&quot;],<br>        Effect   = &quot;Allow&quot;,<br>        Resource = [<br>          &quot;${data.aws_s3_bucket.model_registry_bucket.arn}/*&quot;,<br>        ],<br>      },<br>    ],<br>  })<br>}<br><br># attach the policy to the role<br>resource &quot;aws_iam_role_policy_attachment&quot; &quot;s3_access_attachment&quot; {<br>  policy_arn = aws_iam_policy.s3_access_policy_inf.arn<br>  role       = aws_iam_role.simple_inference_role.name<br>}</pre><h4>Creating the API</h4><p>Now we need to set up the API and the methods which will be used to call our function. The API needs therefore the permission to call Lambda on our behalf. The following code does exactly that.</p><pre># create an HTTP API gateway for the lambda function<br>resource &quot;aws_apigatewayv2_api&quot; &quot;simple_inference_api&quot; {<br>  name          = &quot;simple-inference-api&quot;<br>  protocol_type = &quot;HTTP&quot;<br>}<br><br>resource &quot;aws_lambda_permission&quot; &quot;apigw_lambda_permission&quot; {<br>  statement_id  = &quot;AllowAPIGatewayInvoke&quot;<br>  action        = &quot;lambda:InvokeFunction&quot;<br>  function_name = aws_lambda_function.simple-inference.function_name<br>  principal     = &quot;apigateway.amazonaws.com&quot;<br>  source_arn    = &quot;${aws_apigatewayv2_api.simple_inference_api.execution_arn}/*/*&quot;<br>}<br><br>resource &quot;aws_apigatewayv2_integration&quot; &quot;simple_inference_integration&quot; {<br>  api_id            = aws_apigatewayv2_api.simple_inference_api.id<br>  integration_type  = &quot;AWS_PROXY&quot;<br>  integration_uri   = aws_lambda_function.simple-inference.invoke_arn<br>  integration_method = &quot;POST&quot;<br>}<br><br>resource &quot;aws_apigatewayv2_stage&quot; &quot;simple_inference_stage&quot; {<br>  api_id      = aws_apigatewayv2_api.simple_inference_api.id<br>  name        = &quot;simple-inference-stage&quot;<br>  auto_deploy = true<br>}</pre><p>We’ll now add a new route to the API that will be attached to the function. Notice that we add it on POST, so that we can send a payload along with it.</p><pre>resource &quot;aws_apigatewayv2_route&quot; &quot;simple_inference_route&quot; {<br>  api_id    = aws_apigatewayv2_api.simple_inference_api.id<br>  route_key = &quot;POST /inference&quot;<br>  target    = &quot;integrations/${aws_apigatewayv2_integration.simple_inference_integration.id}&quot;<br>}</pre><h4>Logging</h4><p>We’ll now add <a href="https://aws.amazon.com/fr/cloudwatch/">Cloudwatch</a> logging to our function, which can be used both for debugging and more advanced monitoring things, something we are going to see in the next article of the series.</p><pre># create a cloudwatch log group for the lambda function<br>resource &quot;aws_cloudwatch_log_group&quot; &quot;simple_inference_log_group&quot; {<br>  name              = &quot;/aws/lambda/inference-function&quot;<br>  retention_in_days = 7<br>}<br><br><br># attach the policy to the role for CloudWatch Logs<br>resource &quot;aws_iam_policy&quot; &quot;cloudwatch_logs_policy&quot; {<br>  name        = &quot;cloudwatch-logs-policy&quot;<br>  description = &quot;IAM policy for CloudWatch Logs access&quot;<br><br>  policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action   = [&quot;logs:CreateLogGroup&quot;, &quot;logs:CreateLogStream&quot;, &quot;logs:PutLogEvents&quot;],<br>        Effect   = &quot;Allow&quot;,<br>        Resource = [&quot;arn:aws:logs:*:*:*&quot;]<br>      },<br>    ],<br>  })<br>}<br><br># attach the policy to the role<br>resource &quot;aws_iam_role_policy_attachment&quot; &quot;cloudwatch_logs_attachment&quot; {<br>  policy_arn = aws_iam_policy.cloudwatch_logs_policy.arn<br>  role       = aws_iam_role.simple_inference_role.name<br>}</pre><h3>Deploying the infrastructure</h3><p>The final step consists in planning and applying the infrastructure changes. Just use the command below, and you’ll deploy everything we have set up to AWS!</p><pre>terraform plan &amp;&amp; terraform apply</pre><p>Or, just deploy your infra with:</p><pre>just deploy-inference</pre><h3>Testing the prediction service</h3><p>Everything looks good! Now let’s test the prediction service we have created! You can go to AWS, take the endpoint of your API and called using cURL or Postman!</p><p>You can use this payload:</p><pre>{<br>    &quot;age&quot;: 19,<br>    &quot;sex&quot;: &quot;female&quot;,<br>    &quot;bmi&quot;: 27.9,<br>    &quot;children&quot;: 0,<br>    &quot;smoker&quot;: &quot;yes&quot;,<br>    &quot;region&quot;: &quot;southwest&quot;<br>}</pre><h3>Conclusion</h3><p>And BAM! You’ve got yourself a prediction pipeline, coupled with a continuous training pipeline and a model registry! This is already a great project to showcase on your portifolio. And we are going to make it even better!</p><p>The code for this tutorial is in my <a href="https://github.com/talesmarra/simple-mlops/tree/master/simple-inference">GitHub</a>.</p><p>Hit that follow button to stay updated on future explorations! 🔥🤖 Let’s continue this journey of coding, machine learning, and MLOps.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a413e08be45" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simple MLOps #2: Model Registry]]></title>
            <link>https://medium.com/@talesmarra/simple-mlops-2-model-registry-39a106bb7daf?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/39a106bb7daf</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[education]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[mlops]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Sun, 15 Oct 2023 18:11:28 GMT</pubDate>
            <atom:updated>2023-10-15T18:11:28.463Z</atom:updated>
            <content:encoded><![CDATA[<p>Continuing our Simple MLOps series, we’ll now explore the model registry.</p><p>But what is a model registry?</p><p>The model registry is the place where the models live once they’re trained, and can be retrieved at inference time to perform predictions. The main functionalities a model registry must have are:</p><ul><li>Capacity to retrieve the latest model: Once the continuous training pipeline has deployed a new model into production, the inference pipeline must be able to automatically recognize and retrieve this new version;</li><li>Capacity to rollback: If a version is judged flawed but it’s already in production, the engineering team must be able to remove that version from production and return to a previous state as quickly as possible.</li><li>Capacity of packaging metadata with the model including details about training and evaluation metrics, compatible code versions etc.</li></ul><p>And again, this doesn’t have to be complicated! Starting simple and building up from that always gets the best results. And that’s what we’ll be doing it today! Implementing a simple version registry that already has those capacities.</p><h4>Understanding the registry components</h4><p>From the functionalities we saw earlier, can deduce we are going to need mainly two things:</p><ul><li><strong>Object Storage</strong>: the place where the model objects are going to be stored. For this we are going to use AWS S3, a managed cloud object storage;</li><li><strong>Version and metadata table</strong>: this is where the inference pipeline will search for the latest trained model, and where you can also store relevant information about the training_date, the code version compatible with that model, metrics and many more. For this, we’ll use a DynamoDB table.</li></ul><p>Our architecture will therefore look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Bonh0MyeTZSCNzZ5HVARCg.png" /></figure><h4>Creating the object storage</h4><p>Starting on the repository, you can create a new <em>main.tf </em>file.</p><p>If you already deployed the continuous-training pipeline we created in the <a href="https://medium.com/@talesmarra/simple-mlops-1-continuous-training-pipeline-5e6ddbf4c398">first article of the series</a>, your bucket to store models already exists so no need to re-create one.</p><p><em>Note: if you’re implementing only the registry, you can create your object storage by doing:</em></p><pre>resource &quot;aws_s3_bucket&quot; &quot;model_registry_bucket&quot; {<br>   bucket = &quot;registry-bucket-simple-ct&quot;<br>}</pre><h4>Creating the versioning table</h4><p>In our design, the versioning table will also include metadata, however there are other design choices you can choose from:</p><ul><li>creating a dedicated table to store metadata;</li><li>packaging metadata along with model objects and storing them on object storage;</li><li>store the metadata on the object storage separated from the model;</li></ul><p>The design choice will mostly be defined by the easiness to request and analyze that data later on by your monitoring/dashboard solutions.</p><p>We’ll use AWS DynamoDB, a NoSQL managed database service to do it.</p><p>To create the table, we’ll declare a table resource, declaring also the fields along with their types. We also create another index for evaluation metrics.</p><pre>resource &quot;aws_dynamodb_table&quot; &quot;simple-registry&quot; {<br>  name     = &quot;simple-registry&quot;<br>  hash_key = &quot;id&quot;<br>  range_key = &quot;published_at&quot;<br>  billing_mode = &quot;PROVISIONED&quot;<br>  read_capacity = 1<br>  write_capacity = 1<br>  attribute {<br>    name = &quot;id&quot;<br>    type = &quot;N&quot;<br>  }<br>  attribute {<br>    name = &quot;published_at&quot;<br>    type = &quot;S&quot;<br>  }<br>  attribute {<br>    name = &quot;tag&quot;<br>    type = &quot;S&quot;<br>  }<br>  attribute {<br>    name = &quot;evaluation_metrics&quot;<br>    type = &quot;S&quot;<br>  }<br>  global_secondary_index {<br>    name            = &quot;tag-index&quot;<br>    hash_key        = &quot;tag&quot;<br>    range_key       = &quot;evaluation_metrics&quot;<br>    projection_type = &quot;ALL&quot;<br>    read_capacity = 1<br>  write_capacity = 1<br>  }<br>}</pre><h4>Plugging into our stack</h4><p>The registry needs to interact both with the training and the inference pipeline.</p><p>At training time, the training pipeline pushes the model object to the object storage, and also writes a new entry to the versioning table pointing to the updated version.</p><p>At its turn, the inference pipeline (which we will develop on next article) will read the versioning table to find the latest version of the model and then load it from the object storage to perform inference on newly received data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Nmes2B0UmrK8cuKm8kDc8Q.png" /></figure><h4>Setting training pipeline permissions</h4><p>In the first article of the series, we already gave permissions for our training pipeline to write to the object storage, so no action needed!</p><p>If you didn’t, you can give permissions by attaching a policy to the role of your training pipeline:</p><pre>data &quot;aws_iam_role&quot; &quot;ct_role&quot; {<br>  name = &quot;ct-role&quot;<br>} <br><br># define a policy for the Lambda function to read and write to the 2 buckets<br>resource &quot;aws_iam_policy&quot; &quot;s3_access_policy&quot; {<br>  name        = &quot;s3-access-policy&quot;<br>  description = &quot;IAM policy for S3 access&quot;<br>  <br>  policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action   = [&quot;s3:PutObject&quot;],<br>        Effect   = &quot;Allow&quot;,<br>        Resource = [<br>          &quot;${aws_s3_bucket.model_registry_bucket.arn}/*&quot;,<br>        ],<br>      },<br>    ],<br>  })<br>}<br><br># Attach the S3 access policy to the IAM role<br>resource &quot;aws_iam_role_policy_attachment&quot; &quot;s3_access_attachment&quot; {<br>  policy_arn = aws_iam_policy.s3_access_policy.arn<br>  role       = aws_iam_role.ct_role.name<br>}</pre><p>All we need to do now is set the permissions for the training pipeline to write to the versioning table, like this.</p><pre>data &quot;aws_iam_role&quot; &quot;ct_role&quot; {<br>  name = &quot;ct-role&quot;<br>} <br><br># add policy to dynamodb to allow the lambda function to write to it<br>resource &quot;aws_iam_policy&quot; &quot;dynamodb_access_policy&quot; {<br>  name        = &quot;dynamodb-access-policy&quot;<br>  description = &quot;IAM policy for DynamoDB access&quot;<br><br>  policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action = [<br>          &quot;dynamodb:PutItem&quot;,<br>          &quot;dynamodb:Scan&quot;,<br>        ],<br>        Effect   = &quot;Allow&quot;,<br>        Resource = aws_dynamodb_table.simple-registry.arn,<br>      },<br>    ],<br>  })<br>}<br><br># attach the policy to the lambda execution role<br>resource &quot;aws_iam_role_policy_attachment&quot; &quot;dynamodb_access_attachment&quot; {<br>  policy_arn = aws_iam_policy.dynamodb_access_policy.arn<br>  role       = data.aws_iam_role.ct_role.name<br>}</pre><h4>Deploying the infrastructure</h4><p>The final step consists in planning and applying the infrastructure changes. Just use the command below, and you’ll deploy everything we have set up to AWS!</p><pre>terraform plan &amp;&amp; terraform apply</pre><p>Or if you have become a Just fan and would like to use it more, insert this recipe into your <em>justfile, </em>located outside of the training and registry folders.</p><pre># ---------------------------<br># Registry Recipes<br># ---------------------------<br>deploy-registry:<br>    cd simple-registry &amp;&amp; terraform plan &amp;&amp; terraform apply -auto-approve</pre><p>Then execute:</p><pre>just deploy-registry</pre><h4>Updating the training function code to write to the versioning table</h4><p>Now, all that’s left is to modify the Python code of our Lambda training function to write to the versioning table. Much like the S3 case, we’ll use <em>boto3 </em>but with <em>dynamodb</em> instead of S3.</p><p>Just insert the following code right after the uploading of the model to S3:</p><pre># after deploying the registry you can write to dynamodb table<br>    dynamodb = boto3.resource(&#39;dynamodb&#39;)<br>    table = dynamodb.Table(&#39;simple-registry&#39;)<br>    # insert the item with the fields id, published_at, tag, and evaluation metrics<br>    table.put_item(Item={<br>        &#39;id&#39;: int(pd.Timestamp.now().timestamp()), <br>        &#39;published_at&#39;: pd.Timestamp.now().isoformat(),<br>        &#39;tag&#39;: model_sha,<br>        &#39;metrics&#39;: json.dumps({<br>            &#39;f1_score&#39;: f1<br>        })})</pre><p>⚠️ Don’t forget to re-build, tag, push the new image of your continuous training pipeline to ECR and updating the lambda with the new image using the Just commands we saw previously.</p><h3>Checking on AWS</h3><p>Now you can go to AWS and re-run your lambda function. Once it’s completed, check out the DynamoDB table to check the new entries!</p><h3>Conclusion</h3><p>Congratulations! You have just set up your model registry and made a big new step in your MLOps journey!</p><p>The code for this tutorial is in my <a href="https://github.com/talesmarra/simple-mlops/tree/master/simple-registry">GitHub</a>.</p><p>Hit that follow button to stay updated on future explorations! 🔥🤖 Let’s continue this journey of coding, machine learning, and MLOps.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=39a106bb7daf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simple MLOps #1: Continuous training pipeline]]></title>
            <link>https://medium.com/@talesmarra/simple-mlops-1-continuous-training-pipeline-5e6ddbf4c398?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/5e6ddbf4c398</guid>
            <category><![CDATA[mlops]]></category>
            <category><![CDATA[education]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Sat, 07 Oct 2023 16:47:30 GMT</pubDate>
            <atom:updated>2023-10-07T16:47:30.633Z</atom:updated>
            <content:encoded><![CDATA[<p>We all know the importance of re-training a model. It ensures that your model stays up to date with your data, and keeps the good performance through its life cycle.</p><p>However, it doesn’t have to be a complex process! In this first article of the Simple MLOps Series, you’ll learn how to simply implement a continuous training pipeline!</p><h4>Understanding Continuous Training Components</h4><p>The basic components you need are a trigger, a pipeline for data processing and training, evaluation and deployment, and a registry.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6cxNTnFIL4Uw6kDaFtrQ_w.png" /></figure><ul><li><strong>Trigger</strong>: The trigger is your MLOps ignition switch. Depending on your strategy, opt for a scheduler or a database check to determine if it&#39;s time to launch training. This decision hinges on the volume of new data received, ensuring efficient resource allocation.</li><li><strong>Data Processing and Training Pipeline</strong>: The core of continuous training resides here. You can choose between a container-based or serverless compute resource for the training process. This step yields your model and triggers the subsequent phase.</li><li><strong>Evaluation and Deployment Pipeline</strong>: This pipeline can share the compute resource chosen for the previous step. It&#39;s imperative to employ the same environment as your inference. Here, evaluation spans infrastructure, business metrics, and classic model performance metrics.</li><li><strong>The Registry</strong>: The safe haven for your models, the registry is where you store the latest iterations and maintain older versions as backups</li></ul><p>In this article, we will guide you on how to implement these components using popular frameworks such as Terraform, aws-cli, and Docker.</p><h4>Setting up credentials and tools</h4><p>Before diving into the implementation, it’s essential to install aws-cli and set up the necessary credentials. Additionally, you need to install Terraform, a tool that provides a consistent CLI workflow for managing and provisioning infrastructure.</p><h4>Creating an ECR repository to store Lambda image</h4><p>Once you have everything installed and permissions set up, you can create an ECR repository where the image for the lambda function will be stored. This can be done by running a specific command in aws-cli.</p><pre>aws ecr create-repository \<br>    --repository-name ct-image-repo \<br>    --image-scanning-configuration scanOnPush=true \<br>    --region region</pre><h4>Setting up .env file</h4><p>To ensure the security of your credentials, we’ll use .env to load environment variables. This is where you’ll store your AWS region, ECR repo, and function name.</p><pre>AWS_REGION=(YOUR AWS REGION)<br>AWS_CT_ECR_REPO=(YOUR ECR REPO)<br>FUNCTION_NAME=ct-function</pre><h4>The training function</h4><p>The Lambda function will handle both the preprocessing of the data and the training of the model. For our example, we’ll train a model to predict if the insurance charges of someone will exceed 10k. The code for this can be found on <a href="https://github.com/talesmarra/simple-mlops/blob/master/simple-continuous-training/python/lambda_handler.py">GitHub</a>.</p><h4>Packaging code and dependencies using Docker</h4><p>Docker is used to package our code and the required dependencies. We’ll build a docker image that will install our requirements and package the code.</p><pre>FROM public.ecr.aws/lambda/python:3.8<br><br># Install the function&#39;s dependencies using file requirements.txt<br># from your project folder.<br><br>COPY requirements.txt  .<br>RUN  pip3 install -r requirements.txt --target &quot;${LAMBDA_TASK_ROOT}&quot;<br># Copy function code to /var/task<br>COPY lambda_handler.py ${LAMBDA_TASK_ROOT}<br><br># Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)<br>CMD [ &quot;lambda_handler.lambda_handler&quot; ]</pre><h4>Placing the Docker image in the cloud</h4><p>To push your image to the ECR repository, you’ll have to build, tag and push it. You can use your <a href="https://github.com/talesmarra/simple-mlops/blob/master/justfile">Just file recipes</a> to make your life easier if you’re already familiar with Docker. If not, I invite you to go to the Just file and familiarize yourself with them. Once you’ve done it, just run:</p><pre>just build-ct-image<br>just tag-ct-image<br>just push-ct-image</pre><h4>Deploying Infrastructure</h4><p>The rest of the infrastructure will be deployed using Terraform. Terraform is an open-source infrastructure as code software tool that provides a consistent CLI workflow for managing and provisioning infrastructure. The <em>main.tf</em> file is the default filename for a file which defines what Terraform will do. Let’s break it down in parts!</p><ol><li>AWS Provider Configuration:</li></ol><p>The Terraform script begins by configuring the AWS provider. Here, we specify the AWS region as <em>eu-west-3</em>, indicating that all resources will be created in the European Union (Paris) region.</p><pre>hcl<br>provider &quot;aws&quot; {<br> region = &quot;eu-west-3&quot;<br>}</pre><p>2. ECR Repository Declaration:</p><p>Next, we declare an Amazon Elastic Container Registry (ECR) repository named <em>ct-image-repo</em> using the <em>aws_ecr_repository</em> data block. This repository will store our container images.</p><pre>data &quot;aws_ecr_repository&quot; &quot;ct_image_repo&quot; {<br> name = &quot;ct-image-repo&quot;<br>}</pre><p>3. IAM Role and Policy for Lambda Execution:</p><p>To grant the Lambda function execution permissions, we define an IAM role named <em>ct-role</em> with a trust policy that allows AWS Lambda to assume this role. We also create a policy named <em>lambda-execution-policy</em> that permits Lambda to invoke functions.</p><pre>resource &quot;aws_iam_role&quot; &quot;ct_role&quot; {<br>  name = &quot;ct-role&quot;<br>  assume_role_policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action = &quot;sts:AssumeRole&quot;,<br>        Effect = &quot;Allow&quot;,<br>        Principal = {<br>          Service = &quot;lambda.amazonaws.com&quot;<br>        }<br>      }<br>    ]<br>  })<br>}<br><br>resource &quot;aws_iam_policy&quot; &quot;lambda_execution_policy&quot; {<br>  name        = &quot;lambda-execution-policy&quot;<br>  description = &quot;IAM policy for Lambda execution&quot;<br><br>  policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action   = &quot;lambda:InvokeFunction&quot;,<br>        Effect   = &quot;Allow&quot;,<br>        Resource = aws_lambda_function.ct_function.arn<br>      }<br>    ]<br>  })<br>}</pre><p>4. Lambda Function Configuration:</p><p>We configure an AWS Lambda function named <em>ct-function</em> with specific attributes, including a container image from the ECR repository, timeout, memory size, and the IAM role created earlier.</p><pre>resource &quot;aws_lambda_function&quot; &quot;ct_function&quot; {<br> function_name = &quot;ct-function&quot;<br> timeout = 100 # seconds<br> image_uri = &quot;${data.aws_ecr_repository.ct_image_repo.repository_url}:latest&quot;<br> package_type = &quot;Image&quot;<br> memory_size = 200 # MB<br> role = aws_iam_role.ct_role.arn<br>}</pre><p>5. S3 Bucket Declarations and IAM Policy for S3 Access:</p><p>We declare two Amazon S3 buckets: <em>data_bucket</em> and <em>model_registry_bucket</em>. Additionally, we create an IAM policy named <em>s3-access-policy</em> that grants our Lambda function read and write access to these buckets.</p><pre>resource &quot;aws_s3_bucket&quot; &quot;data_bucket&quot; {<br>  bucket = &quot;data-bucket-simple-ct&quot;<br>}<br><br>resource &quot;aws_s3_bucket&quot; &quot;model_registry_bucket&quot; {<br>  bucket = &quot;registry-bucket-simple-ct&quot;<br>}<br><br>resource &quot;aws_iam_policy&quot; &quot;s3_access_policy&quot; {<br>  name        = &quot;s3-access-policy&quot;<br>  description = &quot;IAM policy for S3 access&quot;<br><br>  policy = jsonencode({<br>    Version = &quot;2012-10-17&quot;,<br>    Statement = [<br>      {<br>        Action   = [&quot;s3:GetObject&quot;, &quot;s3:PutObject&quot;],<br>        Effect   = &quot;Allow&quot;,<br>        Resource = [<br>          &quot;${aws_s3_bucket.data_bucket.arn}/*&quot;,<br>          &quot;${aws_s3_bucket.model_registry_bucket.arn}/*&quot;,<br>        ],<br>      },<br>    ],<br>  })<br>}</pre><p>6. IAM Role Policy Attachments:</p><p>We attach both the Lambda execution policy and the S3 access policy to the IAM role we defined earlier.</p><pre>resource &quot;aws_iam_role_policy_attachment&quot; &quot;lambda_execution_attachment&quot; {<br> policy_arn = aws_iam_policy.lambda_execution_policy.arn<br> role = aws_iam_role.ct_role.name<br>}<br>resource &quot;aws_iam_role_policy_attachment&quot; &quot;s3_access_attachment&quot; {<br> policy_arn = aws_iam_policy.s3_access_policy.arn<br> role = aws_iam_role.ct_role.name<br>}</pre><p>7. CloudWatch Event and Permission:</p><p>We set up a CloudWatch event rule to trigger our Lambda function on a schedule (in this case, every Sunday at midnight UTC). We also grant permission to CloudWatch Events to invoke the Lambda function.</p><pre>resource &quot;aws_cloudwatch_event_rule&quot; &quot;lambda_schedule&quot; {<br> name = &quot;lambda-schedule-rule&quot;<br> description = &quot;Scheduled rule to trigger Lambda function&quot;<br> schedule_expression = &quot;cron(0 0 ? * SUN *)&quot; # Adjust the cron expression for your desired schedule.<br>}<br>resource &quot;aws_lambda_permission&quot; &quot;lambda_cloudwatch_permission&quot; {<br> statement_id = &quot;AllowExecutionFromCloudWatch&quot;<br> action = &quot;lambda:InvokeFunction&quot;<br> function_name = aws_lambda_function.ct_function.function_name<br> principal = &quot;events.amazonaws.com&quot;<br> source_arn = aws_cloudwatch_event_rule.lambda_schedule.arn<br>}</pre><p>7. Plan and Deploy:</p><p>The final step consists in planning and applying the infrastructure changes. Just use the command below, and you’ll see the magic happening!</p><pre>terraform plan &amp;&amp; terraform apply</pre><h4>Checking on AWS</h4><p>Now you can go to AWS and see your Lambda function up and running! Don’t forget to put some data on the bucket and adapt the Python code to your use case!</p><h4>Conclusion</h4><p>Congratulations! You have just set up your continuous training pipeline and made a new step in your MLOps journey!</p><p>The code for this tutorial is in my <a href="https://github.com/talesmarra/simple-mlops/tree/master/simple-continuous-training">GitHub</a>.</p><p>Hit that follow button to stay updated on future explorations! 🔥🤖 Let’s continue this journey of coding, machine learning, and MLOps.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5e6ddbf4c398" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Create Your Own Data Analysis Assistant with ChatGPT]]></title>
            <link>https://medium.com/@talesmarra/create-your-own-data-analysis-assistant-with-chatgpt-14dc97f1371b?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/14dc97f1371b</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[mlops]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Sun, 03 Sep 2023 17:01:20 GMT</pubDate>
            <atom:updated>2023-09-03T17:01:20.760Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ApvUb3Vldkl_ZIyQEwPlJw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/fr/@bady?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">bady abbas</a> on <a href="https://unsplash.com/fr/photos/k0y7QTjMb3k?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Large Language Models (LLMs) are currently taking center stage in the AI realm. The versatility they offer in application development is unparalleled.</p><p>One intriguing use-case? Crafting a personal assistant tailored for data analysis. In this guide, we’ll explore how to build an application that lets you upload a CSV file and inquire about its content, using everyday language. Let’s dive in!</p><h4>Getting Started with Dependencies</h4><p><strong>Setting up Poetry<br></strong><a href="https://python-poetry.org/">Poetry</a> is our go-to for managing project dependencies. It allows you to install, remove, package your dependencies quite easily! If you haven’t got it on your system yet, simply refer to the official installation documentation.</p><p><strong>Integrating Required Libraries<br></strong>Once Poetry is installed, you’ll first need to initiate it on the repository. This will create a <em>.toml </em>file for your project where your dependencies will later on appear.</p><p>You can do it by:</p><pre>poetry init</pre><p>incorporate the necessary libraries with:</p><pre>poetry add openai pandas streamlit langchain python-dotenv tabulate</pre><p><strong>API Key Configuration</strong></p><p>To interact with OpenAI’s API, first sign up for an account on their platform. Once registered, navigate to your user profile and generate a new API key within the account settings. <br>For security, store your <em>OPENAI_API_KEY</em> in a <em>.env</em> file and retrieve it within your application. <br><strong><em>⚠️ Important: If you plan to commit your project to a repository, make sure to add your `.env` file to the `.gitignore` to keep your API key confidential.</em></strong></p><pre>from dotenv import load_dotenv, find_dotenv<br>import os<br>_ = load_dotenv(find_dotenv())<br>if not os.environ.get(&#39;OPENAI_API_KEY&#39;):<br> raise ValueError(&quot;Ensure your API key is set!&quot;)</pre><h4>An Overview of LangChain</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*nMyNZ7T3Ua4-z3xf.png" /><figcaption>LangChain Library logo. Source: LangChain</figcaption></figure><blockquote>What makes LangChain stand out? It furnishes developers with the flexibility to tap into the capabilities of LLMs.</blockquote><p>LangChain is a powerful library conceived for users to interact with LLMs. Combining prompt chaining, it allows you to built applications that are:</p><ul><li>data-aware: connecting the LLM with other sources of data such as APIs, datasets and many more;</li><li>agentic: allow a language model to interact with its environment, performing for instance data manipulation to achieve some result.</li></ul><p>For our project, we’ll exploit the <em>Agent</em> abstraction. Agents utilize language models as a cognitive mechanism, determining the sequence and nature of actions. They function in a cyclic mode across four phases until they hit upon a solution:</p><ul><li><em>Thought</em>: Articulate a goal.</li><li><em>Action/Input</em>: Execute an action aligned with the goal, in our scenario, it involves manipulating the data through Pandas to retrieve an answer.</li><li><em>Observation</em>: Evaluate the outcome and go through the loop again if unsatisfactory.</li></ul><p>You can engage with your agent by:</p><pre>from langchain.agents import create_pandas_dataframe_agent<br>from langchain.llms import OpenAI<br>pd_agent = create_pandas_dataframe_agent(OpenAI(temperature=0), df, verbose=True)<br>pd_agent.run(&quot;YOUR DATA QUERY&quot;)</pre><p>Here we leverage LangChain capabilities to import an external data source (the .csv file) into the LLM environment, making it available as the source of information.</p><p>If you execute that code, you’ll notice the cyclic phases we described earlier.</p><h4>Crafting the User Interface with Streamlit</h4><p>A seamless interface is a crucial factor in enhancing the user experience of any software application. Streamlit is a Python library specifically designed for creating interactive and data-driven web applications with minimal effort.</p><p>We’ll be mainly using the following components:</p><ul><li><em>file_uploader</em>: allows the user to input their CSV for analysis;</li><li><em>input_text</em>: allows the user to input the question;</li><li><em>write</em>: allows the system to show the output to the user;</li></ul><p>Here’s a snapshot of what our <em>app.py</em> will look like:</p><pre>import streamlit as st<br>import pandas as pd<br>from langchain.agents import create_pandas_dataframe_agent<br>from langchain.llms import OpenAI<br>from dotenv import load_dotenv, find_dotenv<br>import os<br>_ = load_dotenv(find_dotenv())<br>if not os.environ.get(&#39;OPENAI_API_KEY&#39;):<br> st.error(&quot;Add OPENAI_API_KEY to your .env file&quot;)<br> st.stop()<br>openai.api_key = os.environ[&#39;OPENAI_API_KEY&#39;]<br># Launching the application<br>st.title(&#39;Your AI-Powered Data Analyst&#39;)<br>uploaded_file = st.file_uploader(&quot;Upload your CSV&quot;)<br>if uploaded_file:<br> df = pd.read_csv(uploaded_file)<br> st.write(&quot;Preview of your dataset:&quot;)<br> st.write(df.head(2))<br>st.write(&quot;Pose your query:&quot;)<br> question = st.text_input(&quot;Query:&quot;)<br> if question:<br> pd_agent = create_pandas_dataframe_agent(OpenAI(temperature=0), df, verbose=True)<br> with st.spinner(&#39;Crunching the numbers…&#39;):<br> response = pd_agent.run(question)<br> st.write(response)</pre><h4>Automate with Makefile</h4><blockquote>What’s a Makefile? It’s a blueprint that details the sequence of instructions for compiling and constructing software projects.</blockquote><p>A Makefile is a text file used in software development to define a set of instructions, called rules, that describe how a program or a set of files should be built, compiled, and linked. The purpose of a Makefile is to automate the compilation and building process of software projects by specifying the dependencies and commands necessary to produce the final executable or output.</p><p>It really helps out summarizing commands and not having to remember large commands over and over again.</p><p>Here’s a basic Makefile for our application:</p><pre>run:<br> poetry install &amp; poetry run streamlit run app.py</pre><p>To kick things off, simply enter <em>make run</em> in your terminal and see the magic happening!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/703/1*AjNYOsHX_p5afDDE-bQDiA.png" /><figcaption>Here’s how the app looks like</figcaption></figure><p>Kudos! 🚀 You’ve now developed an application harnessing the might of large language models. The whole code for this app is available on <a href="https://github.com/talesmarra/llm-data-analyst">Github</a>.</p><p>Hit that follow button to stay updated on future explorations! 🔥🤖 Let’s continue this journey of coding, machine learning, and MLOps.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=14dc97f1371b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[So, what is actually MLOps?]]></title>
            <link>https://medium.com/@talesmarra/so-what-is-actually-mlops-25ca00422367?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/25ca00422367</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Thu, 22 Sep 2022 20:06:59 GMT</pubDate>
            <atom:updated>2022-09-22T20:06:59.410Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/713/1*_gUerzrljRseTPf4zRMigw.jpeg" /></figure><p>According to Introducing MLOps:</p><blockquote>“MLOps is the standardization and streamlining of machine learning life cycle management.”</blockquote><p>This is a particularly interesting definition, because breaking it apart allows us to find some key concepts in understanding what it implies in practice:</p><p>1. Standardization: Machine learning code should be tested automatically and frequently! Who says automated tests is saying of course CI!</p><p>2. Streamlining: Model deployment, monitoring and replaced should also be automated! In here we find the famous CD!</p><p>Those will be developed in further posts, so stay tuned!</p><p>Now let’s discuss the machine learning lifecycle.</p><p>The Machine Learning Lifecycle is composed mainly of the following steps:</p><p>1) Business 🧠:<br>The Machine learning lifecycle starts with a business problem, that we’ll try to solve using machine learning. This step has to usually convert the business problem to some metric, KPI, etc. that we’re able to optimize using an ML algorithm;</p><p>2) Data Preparation 📝:<br>Data is usually stored somewhere in the cloud (BigQuery, S3, Cloud Storage, …) but is often set in an unsuited manner to the problem in question. We should therefore be able to produce a pipeline (standard set of operations) that is capable of processing this “scrambled” data and output something containing the information to answer the business problem.</p><p>3) Research 🔍:<br>At the end of data preparation, we can start both analyzing the dataset and experimenting with models to solve the business problem. The interest here is to produce a model/prototype, not something ready to production.</p><p>4) Deployment 🚀:<br>If we’re satisfied with our model metrics, we can move on to the deployment. Here we can include clean code, automated testing and also automated deployment to production.</p><p>5) Monitoring 🚨:<br>Once model is at serving phase, we need to monitor it to ensure timing and performance quality to the users. It’s important to keep in mind that once model is in production, the job is NOT done. Ensuring proper functioning and performance quality is a continual job.</p><p>How is it for you?<br>What does MLOps means to you and to the company you are at?<br>Let me know in the comments! Don’ forget to like and share if you liked it!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=25ca00422367" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Let’s talk about tests!]]></title>
            <link>https://medium.com/@talesmarra/lets-talk-about-tests-2bf49214ed56?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/2bf49214ed56</guid>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Thu, 22 Sep 2022 20:02:37 GMT</pubDate>
            <atom:updated>2022-09-22T20:02:37.746Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*oF3qlfTsyxnVBsr8" /><figcaption>Testing workflow</figcaption></figure><p>Testing is one of the most important parts in software engineering. It ensures the general functioning of components, as well as the quality of the integration of new components and code to the existing parts.</p><h4>Different types of testing</h4><p>The main different types of testing are:</p><p><em>Unit tests</em>: those constitute the first level of testing, the closest one to the code itself. It ensures that a function is doing what it’s supposed to and the different cases where bugs can happen (for instance, wrong input types etc.)</p><p><em>Integration tests</em>: those test the integration between functions, modules etc. Here is where the interface between components is going to be first tested.</p><p><em>System testing / End to End testing</em>: Aims to test the system as a whole, mocking inputs and testing the general produced result is correct. This is usually done by deploying the application on a staging environment and checking that everything is working over the application.</p><p><em>User Acceptance Testing</em>: Those are the “user” performed tests. A user, or something emulating user behavior will validate many business use cases over the platform (still in a protected environment), and if everything is ok, the code is then deployed to production.</p><p>There are many different types of testing that have different purposes; while not mandatory, I’ll advise you to implement and automate all of them. They can (and will) be your inspectors, catching mistakes that can cost you, your team and your company a lot of time and money if shipped to production.</p><p>If you liked this reading, please like, comment and share!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2bf49214ed56" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Diving into CI]]></title>
            <link>https://medium.com/@talesmarra/diving-into-ci-769c61445e1e?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/769c61445e1e</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[mlops]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Thu, 22 Sep 2022 19:54:43 GMT</pubDate>
            <atom:updated>2022-09-22T19:54:43.924Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/966/1*lmYOVUjFfKklXfveN9-MiQ.gif" /></figure><p>Before we can start developing data processing pipelines, models and applications, we need the proper base to do it, otherwise it’s going to get VERY complicated VERY soon!</p><p>CI/CD are important software engineering concepts, and they are really at the base and core of any software development project, even more if scaling is an important factor! That’s why it’s important to understand and apply those concepts in everyday life as a software engineer.</p><p>Let’s begin with CI.</p><p>CI stands for<strong> continuous integration</strong>.</p><blockquote><em>Integration? To what?</em></blockquote><p>That’s a good question. If you are just starting to program, you probably have not done a lot of collaboration. Your local environment or Jupyter notebook is enough for you to go on.</p><p>However, when you start being one of the many engineers collaborating on a single project, things start to get tricky and many questions can appear like:</p><ul><li>How do I integrate my contribution to the common project?</li><li>How do I know if my contribution has conflicts with the ones from someone else? (I modified a function that someone else erased it)</li></ul><p>and many more.</p><p>That’s where the common code base comes in handy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/776/1*0Smy3qwzT9IpezTK3wY4LQ.png" /><figcaption>Common code base where devs can contribute together</figcaption></figure><p>It’s a place where the source of truth of the code is going to be stored and developers can contribute by branching over the main line. Contributions can be analyzed by peers and everyone can be up-to-date. Some examples of this are Github, Gitlab etc.</p><p>If you are not yet familiar with those, I recommend you start using them as soon as possible.</p><blockquote><em>And how do we integrate?</em></blockquote><blockquote><em>Using tests of course, and lots of it!</em></blockquote><p>I’ll write a dedicated post later only about tests, since it’s such an important subject that it deserves special treatment. But the idea is that the various types of tests (unit tests, integration tests, …) should be run at this common code base for each contribution and each merge to the main branch in all environments, to make sure that there are no errors or unexpected problems not caught by the team during the development process.</p><p>And of course all <strong>tests should run automatically</strong>!!</p><p>If you are wondering how, stay tuned! A practical tutorial is coming soon!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=769c61445e1e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The SQL Cheat Sheet]]></title>
            <link>https://medium.com/@talesmarra/the-sql-cheat-sheet-a7beb0ac8f32?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/a7beb0ac8f32</guid>
            <category><![CDATA[knowledge]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[sql]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Wed, 27 May 2020 12:09:45 GMT</pubDate>
            <atom:updated>2020-05-27T12:12:43.882Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/225/1*L99Wj0EprBf9dKcQMyzb8Q.png" /></figure><p>Nowadays, when larger and larger databases are being produced and used by companies, SQL becomes more needed than ever. And not all of us have the time to take on courses and courses to learn about that, even tough it’s the recommended path. So, to help you out with that, I have decided to launch this little guide so that you can know the basics and therefore can already start on using it.</p><p>This is a quick and brief summary of the main aspects of SQL, and how to use them in simple examples.</p><p><em>Note: In here I am using SQL Lite, so the keywords may differ a little but the ideas are the same.</em></p><h3>Part 1: Main Keywords</h3><h4>SELECT … FROM : The keywords for selections</h4><p>The main idea that you have to have in mind for this one is that you are literally selecting something from a table.</p><p>For instance, on this table named costumer:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/406/1*bsEE59j4tTRNq_4C6250ew.png" /><figcaption>Customer table</figcaption></figure><pre>SELECT name FROM customer;</pre><p>Will give:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/99/1*kkbKitGc_BSOIxDr0nHofw.png" /><figcaption>Selected names of costumers</figcaption></figure><p><em>Additional Comments</em>: the keyword distinct allows you to see only unique results.</p><h4>WHERE : How to specify conditions</h4><p>To specify a condition that a record must match in order to be selected, you can use the WHERE keyword followed by the condition to match.</p><p>For example:</p><pre>SELECT * FROM customer <br>WHERE name LIKE &#39;Bill%&#39;;</pre><p>This statement will select from my table only rows where Bill is in the name.</p><p><em>Additional comments</em>: The keyword LIKE is to search for patterns in your condition statement, and the % sign is basically an ignore what’s after as long as it has <em>Bill</em> in its beginning. If you want to select for example only some last name, you could have used … ‘ % last_name’.</p><h4>GROUP BY: How to aggregate data</h4><p>Let’s say that you have some sale table, like this one:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/387/1*60SrCsVvgT_-aByHV17o9Q.png" /><figcaption>Sale table</figcaption></figure><p>But you, as a manager, would like to know how many units were sold in total and how much was the revenue of that day. This is where the GROUP BY keyword comes in, as it allows you to aggregate your data.</p><p>By doing,</p><pre>SELECT date,sum(quantity) AS amount ,sum(price) AS total_amount <br>FROM sale <br>GROUP BY date;</pre><p>You’ll do exactly that. Gathering your table by the dates, summing the columns of price, and quantity, <strong><em>giving them new names with AS </em></strong>and returning the result that will look like this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/262/1*4efEjxH4NOmTLu5S_WkbaQ.png" /><figcaption>Result for group by statement</figcaption></figure><h4>HAVING : The WHERE for aggregated data</h4><p>The HAVING keyword will work in a similar way as the WHERE one, but for the aggregated data. It will filter the table based on some condition.</p><p>For example:</p><pre>SELECT date,sum(quantity) AS amount , sum(price) AS total_amount FROM sale <br>GROUP BY date <br>HAVING total_amount&gt;5000;</pre><p>The same statement as before but adding just a condition over the summed prices will return as result only the second record (row), where the condition is met.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/258/1*UjJcsmGvCGoiLz4vkDLghw.png" /></figure><p>There is also the concept of JOIN, an important one, but this one requires more explanation and if you are interested, let me know and I can write a cheat sheet only for that.</p><h4>ORDER BY: Ordering the results you get</h4><p>This keyword is a very simple one and allows you to basically order the results you got by some field, and in ASC (ascending) or DESC (descending) order.</p><p>For example, if I had a table of people, I could just run the following statement:</p><pre>SELECT * from people <br>ORDER BY first_name ASC ,last_name ASC;</pre><p>And as a result I would have the names of this table in alphabetical order.</p><h3>Part 2 : Creation and Destruction</h3><h4>Creating and Destroying a table</h4><p>The commands to do that are very simple and intuitive. The are basically:</p><pre>CREATE TABLE name ( id INTEGER, description TEXT );</pre><pre>DROP TABLE <strong>IF EXISTS</strong> name;</pre><p><em>Additional notes</em>: In the CREATE TABLE, you can specify that a column (field) is a PRIMARY KEY and this column will be automatically filled with sequential unique values. There are also some tricks such as UNIQUE, that you can put on your features to not accept repetition of values, or NOT NULL, to not accept missing data. In the DROP TABLE one, I recommend you always put IF EXISTS keyword, otherwise if there is no such table you will get an error.</p><h4>Inserting and Deleting data</h4><p>This is also very simple and intuitive. To do so:</p><pre>INSERT INTO &lt;table&gt; ( &lt;attributes&gt; )<br>VALUES ( &lt;values&gt;);</pre><p>The main trick here is that you are not obliged to fill in all data to insert a new row.</p><p>To delete,</p><pre>DELETE FROM customer <br>WHERE &lt;condition of the row you want to delete&gt;;</pre><p><em>Additional Note: You can also update your table using the UPDATE and SET keywords.</em></p><p>For instance,</p><pre>UPDATE people <br>SET first_name=&#39;Bob&#39; <br>WHERE first_name=&#39;Aaron&#39; AND last_name= &#39;Davis&#39;;</pre><p>This will change the first name of <em>Aaron Davis </em>to <em>Bob.</em></p><h3>Part 3 : Interesting Stuff</h3><h4>Transactions</h4><p>You should always try to execute your sequences of statements (commands) in transactions, there are basically an encapsulation of those. This will really enhance performance and allow a better management of eventual conflicts.</p><pre>BEGIN TRANSACTION;<br>SQL STATEMENTS<br>END TRANSACTION;</pre><h4>Triggers : Automatic Updates and Verification</h4><p>Triggers are a way to automatically do some statements before of after something is done on a table. Two interesting examples of that are updating related tables after some insertion has been done, or verifying that the operation can be executed and if not, <strong><em>ROLLBACK </em></strong>(return the database to its previous state).</p><pre>CREATE TRIGGER &lt;trigger_name&gt; <br>AFTER INSERT ON &lt;table&gt;<br>    UPDATES IN TABLES<br>END</pre><p>This is an example of a trigger being set after some insertion on a table happens, in order to update related tables.</p><h4>Views : Saving and reusing results of queries</h4><p>Views are a way to store manipulations that you did on your database to reuse in other statements without altering the original tables, which is something quite interesting to maintain the integrity of your database. To do so, you just put the following before your query and the result will be stored as a view.</p><pre>CREATE VIEW &lt;view_name&gt; <br>AS SQL STATEMENTS</pre><p>This is possible as the result of every SQL query is a table.</p><p>For now that is it, hope you all enjoy and make use of this when you need a quick reminder or as an initial step.</p><p><em>Hope you all have enjoyed, and if you have any comments or suggestions, I am happy to hear!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a7beb0ac8f32" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[About Success]]></title>
            <link>https://medium.com/@talesmarra/about-success-94ae4dc63f95?source=rss-770f787e930b------2</link>
            <guid isPermaLink="false">https://medium.com/p/94ae4dc63f95</guid>
            <category><![CDATA[decisions]]></category>
            <category><![CDATA[success]]></category>
            <category><![CDATA[life-lessons]]></category>
            <dc:creator><![CDATA[Tales Marra]]></dc:creator>
            <pubDate>Sat, 25 Apr 2020 09:50:35 GMT</pubDate>
            <atom:updated>2020-04-25T09:50:35.355Z</atom:updated>
            <content:encoded><![CDATA[<iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2F4uGeJzUSCKKeQ%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2F4uGeJzUSCKKeQ%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2F4uGeJzUSCKKeQ%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="331" frameborder="0" scrolling="no"><a href="https://medium.com/media/4137837f8a521af711a3a892bc9ed279/href">https://medium.com/media/4137837f8a521af711a3a892bc9ed279/href</a></iframe><p><em>“Would you tell me, please, which way I ought to go from here?”</em><br> <em>“That depends a good deal on where you want to get to,” said the Cat.</em><br> <em>“I don’t much care where — ” said Alice.</em><br> <em>“Then it doesn’t matter which way you go,” said the Cat.</em><br> <em>“ — so long as I get </em>somewhere<em>,” Alice added as an explanation.</em><br> <em>“Oh, you’re sure to do that,” said the Cat, “if you only walk long enough.”</em></p><p>The world nowadays is probably the one with the greatest number of possibilities for a human being to do as a career. From scientist to youtuber to digital influencer, the Internet opens up whole new paths to follow.</p><p>As much as this is exciting, it is also an issue. To my generation, the two main problems are summarized in that little extract above.</p><p>The number of paths is too great, the number of roads is too high, and the details and the potential of each choice are given and updated to us in seconds. We are a Google search away from discovering the richest and most influential people in whatever path we decide to follow. We can have the finest quality measurements about any path we are interested about. When you sum up to that the opinions of family, friends and loved ones… I think you can picture the situation.</p><p>And that makes us all in a sense like Alice, with no certain path to go. The famous <em>paradox of choice</em> is right in front of us, and we are like Buridan’s ass.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*yn0cDe5sY38Cubr-bIMqRA.jpeg" /><figcaption>Buridan’s ass</figcaption></figure><p><em>“A paradoxical situation wherein an ass, placed exactly in the middle between two stacks of hay of equal size and quality, will starve to death since it cannot make any rational decision to start eating one rather than the other. The paradox is named after the 14th century French philosopher Jean Buridan.”</em></p><p>So when we ask from life which is the best way to go, it answers us exactly like the cat:</p><blockquote><em>“That depends a good deal on where you want to get to”</em></blockquote><p>Therefore, as a young Alice making her path through the world, the first thing we should ask ourselves is <strong><em>what is success to me.</em></strong></p><p>And the answer may surprise you.</p><p>You might discover that success to you is being the CEO of a great multinational, or coming home at night and having your children waiting for you at the door. Or even traveling the world with nothing but a backpack on your back, deciding the next country the day before going.</p><p>And they can all be Wonderland to you as long as you are being true to yourself (another great lesson of the story of Alice, as she can only rescue Wonderland from the red queen once she figures out who she is).</p><p>I once met an old man in Paris. He had quit a great job as a doctor for an early retirement, sold everything he had and started traveling the world with nothing except his body outfit. Today he is already in his third world tour and his only regret is not having started it before;</p><p>So don’t get stuck with the definition of success of others.</p><p><strong><em>Define who you are and what that world means to you. And then the path will open up clearly.</em></strong></p><p>The second problem is seen in the second part of that extract. The anxious Alice rushes to say to the cat:</p><blockquote><em>so long as I get </em>somewhere.</blockquote><p>She wants to get somewhere and she wants it now. And that is us, most of the time wanting the destination, especially when we can see people who have already arrived there waving at us by videos, or by Instagram posts.</p><p>But as we look to the destination, we forget about the path. All the long nights, all the failure and frustration that those who are there now had to go through in order to arrive. So when we start to walk the road, and things seem no to go as well as expected we begin to doubt ourselves completely and the thought about quitting comes to mind.</p><p>The precious lesson of this second part is summarized in the answer she gets from the cat:</p><blockquote><em>“Oh, you’re sure to do that,” said the Cat, “if you only walk long enough.”</em></blockquote><p>If you only walk long enough. <strong><em>Don’t forget, great things take time. </em></strong>You can look at any great invention, anything that someone built and that you admire. The great composers, CEO’s, athletes and people who are at the top of their respective fields had to go though a long path of studies and apprenticeship in order to become who they are. Also, they were all lost Alice once.</p><p><strong><em>So don’t let the struggles of the path discourage you. Keep walking.</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*g3szlT4GXqa6P2W251AMuQ.jpeg" /><figcaption>The path</figcaption></figure><p>Once you have decided your path, have accepted the fact that great things take time and start walking the path, Wonderland will appear to you.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=94ae4dc63f95" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>