<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://farhan0167.github.io/feed.xml" rel="self" type="application/atom+xml"/><link href="https://farhan0167.github.io/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-07-08T03:56:33+00:00</updated><id>https://farhan0167.github.io/feed.xml</id><title type="html">blank</title><subtitle>A simple, whitespace theme for academics. Based on [*folio](https://github.com/bogoli/-folio) design. </subtitle><entry><title type="html">Building a minimal agent harness from scratch</title><link href="https://farhan0167.github.io/blog/2026/highlight-project/" rel="alternate" type="text/html" title="Building a minimal agent harness from scratch"/><published>2026-06-15T09:00:00+00:00</published><updated>2026-06-15T09:00:00+00:00</updated><id>https://farhan0167.github.io/blog/2026/highlight-project</id><content type="html" xml:base="https://farhan0167.github.io/blog/2026/highlight-project/"><![CDATA[<p>Replace this with the story of your highlight project. This post is marked <code class="language-plaintext highlighter-rouge">featured: true</code>, so it renders as the large hero at the top of the blog.</p> <p>Write a few paragraphs about what you built, why, and what you learned.</p>]]></content><author><name>Ahmad Farhan Ishraq</name></author><category term="projects"/><category term="agents"/><category term="llms"/><summary type="html"><![CDATA[What I learned wiring up tool-calling, memory, and a control loop into a tiny, hackable agent kit.]]></summary></entry><entry><title type="html">When machines begin to reason over knowledge</title><link href="https://farhan0167.github.io/blog/2026/second-highlight/" rel="alternate" type="text/html" title="When machines begin to reason over knowledge"/><published>2026-06-01T09:00:00+00:00</published><updated>2026-06-01T09:00:00+00:00</updated><id>https://farhan0167.github.io/blog/2026/second-highlight</id><content type="html" xml:base="https://farhan0167.github.io/blog/2026/second-highlight/"><![CDATA[<p>This post is also <code class="language-plaintext highlighter-rouge">featured: true</code>. The newest featured post becomes the big hero on the left; the next one (this one) becomes the secondary card on the right.</p> <p>Swap in your own content.</p>]]></content><author><name>Ahmad Farhan Ishraq</name></author><category term="essays"/><category term="llms"/><category term="research"/><summary type="html"><![CDATA[A shorter reflection piece — this is the secondary featured post shown beside the hero.]]></summary></entry><entry><title type="html">Notes on shipping small tools</title><link href="https://farhan0167.github.io/blog/2026/first-post/" rel="alternate" type="text/html" title="Notes on shipping small tools"/><published>2026-05-20T09:00:00+00:00</published><updated>2026-05-20T09:00:00+00:00</updated><id>https://farhan0167.github.io/blog/2026/first-post</id><content type="html" xml:base="https://farhan0167.github.io/blog/2026/first-post/"><![CDATA[<p>A normal post. Add <code class="language-plaintext highlighter-rouge">featured: true</code> to promote it into the hero row, or leave it out to keep it in the Latest list.</p>]]></content><author><name>Ahmad Farhan Ishraq</name></author><category term="engineering"/><category term="tools"/><summary type="html"><![CDATA[A regular (non-featured) post. It shows up in the "Latest" list below the featured row as an image-left card.]]></summary></entry><entry><title type="html">The weight of good defaults</title><link href="https://farhan0167.github.io/blog/2026/second-post/" rel="alternate" type="text/html" title="The weight of good defaults"/><published>2026-04-10T09:00:00+00:00</published><updated>2026-04-10T09:00:00+00:00</updated><id>https://farhan0167.github.io/blog/2026/second-post</id><content type="html" xml:base="https://farhan0167.github.io/blog/2026/second-post/"><![CDATA[<p>More filler. Delete these sample posts once you have your own.Test</p>]]></content><author><name>Ahmad Farhan Ishraq</name></author><category term="essays"/><category term="design"/><summary type="html"><![CDATA[Another post to fill out the Latest list so you can see the card layout with multiple entries.]]></summary></entry><entry><title type="html">Building a No Code Platform and the BFS Algorithm</title><link href="https://farhan0167.github.io/blog/2024/building-a-no-code-platform-and-the-bfs-algorithm/" rel="alternate" type="text/html" title="Building a No Code Platform and the BFS Algorithm"/><published>2024-12-22T19:58:37+00:00</published><updated>2024-12-22T19:58:37+00:00</updated><id>https://farhan0167.github.io/blog/2024/building-a-no-code-platform-and-the-bfs-algorithm</id><content type="html" xml:base="https://farhan0167.github.io/blog/2024/building-a-no-code-platform-and-the-bfs-algorithm/"><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/998/1*KTx39TBwScO65d_c_OYbjw.gif"/></figure> <p>For the past couple of months I’ve been building out a low code/no code AI/ML <a href="https://otto-m8.com/">Platform</a> that lets users deploy their ML models as an API. Imagine the following scenario: you’ve trained a deep learning model and pushed it to Huggingface. While the model is great for what you trained it for, it lives inside a jupyter notebook but you need a deployable API where users can directly interact with your model. Or even better, you want to hook your model up with one of the LLM’s out there but you don’t want to spend time coding up the API, think about integration code, etc. That’s essentially what I’m trying to solve.</p> <p>From the user point of view, you see a flowchart like tool, where you configure your blocks(in the case of Huggingface, you’d paste in your model card), connect them to their input blocks(they essentially dictate whether your model accepts a text or image input or both), and hit create, which then deploys a docker container running a FastAPI server for you to then query. Under the hood, there is a graph being created with each node in the graph loading up the resources needed to run your workload. And in this article, I want to talk about the breadth first search algorithm and how it powers my project.</p> <p>Now consider the following workflow that runs a Financial Bert model for Sentiment Analysis. You have 3 blocks — the input block which will take your input text, the ML block and the output block which will display the end result.</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/723/1*n8FuYtyzP7ylnw1ZwCRahg.png"/></figure> <p>The first step, would be to take this UI and translate it into format that would speak to the backend. This could look something like:</p> <pre>{<br />  &quot;input&quot;: [<br />      &quot;Input_Block&quot;: {<br />          &quot;run_config&quot;: &quot;All user based config&quot;,<br />          &quot;connections&quot;: [ &quot;process.Financial_BERT&quot; ],<br />          &quot;payload&quot;: &quot;&lt;Insert Positive news for financial BERT&gt;&quot;,<br />          &quot;implementation&quot;: Input_Implementation_Class()<br />      }<br />  ],<br />  &quot;process&quot;: [<br />      &quot;Financial_BERT&quot;: {<br />          &quot;run_config&quot;: &quot;All user based config&quot;,<br />          &quot;connections&quot;: [ &quot;output.Output_Block&quot; ],<br />          &quot;payload&quot;: &quot;&lt;Insert Positive news for financial BERT&gt;&quot;,<br />          &quot;implementation&quot;: HF_MODEL_Class()<br />      }<br />  ],<br />  &quot;output&quot;: [<br />      &quot;Output_Block&quot;: {<br />          &quot;run_config&quot;: &quot;All user based config&quot;,<br />          &quot;connections&quot;: []<br />      }<br />  ]<br />}</pre> <p>The next step would be taking the payload of one block, passing it into the implementation of another, and you’d know the next block via the connections list. Now, naively you could implement an iterative loop that starts at the input block, traverses its connection by passing the payload around. It would look something like this:</p> <pre>start_node = workflow[&#39;input&#39;][&#39;Input_Block&#39;]<br /><br />for connection in start_node[&#39;connection&#39;]:<br />    # pass payload to process.Financial_BERT.implementation</pre> <p>This approach would work only if we had a linear workflow, where 1 block connects to only one block. But in the real world, one could have N blocks connecting to 1 block, wherein the following block expects inputs from all N blocks before running itself.</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*2t4k4-4ptCYbi2QRKcsFaw.png"/><figcaption>The orange block needs inputs A,B and C as params so it can run.</figcaption></figure> <p>So how do we ensure inputs from block A,B and C is passed altogether in the orange block? This where the breadth first search comes to the rescue.</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*lViYs6Huba1Doz69"/><figcaption>Source: <a href="https://commons.wikimedia.org/wiki/File:Breadth-First-Search-Algorithm.gif">https://commons.wikimedia.org/wiki/File:Breadth-First-Search-Algorithm.gif</a></figcaption></figure> <p>The way the BFS algorithm works is by starting at some node, source, it first looks at all its neighbors and traverses the graph in a layer wise fashion. Here’s an excerpt from a Hackerearth article that sums it up best:</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/990/1*_4yHaiZPMX-X5mg3iXUEGQ.png"/><figcaption>Source: <a href="https://www.hackerearth.com/practice/algorithms/graphs/breadth-first-search/tutorial/">https://www.hackerearth.com/practice/algorithms/graphs/breadth-first-search/tutorial/</a></figcaption></figure> <p>So coming back to our use case, we can do something like this:</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MssGOen2MSgZUFd3WbwlEA.png"/></figure> <p>We can start at some dummy node, look at all it’s immediate neighbors (A,B, and C) and process them, and only when all 3 are processed is when we move on the next layer where the orange block is and pass the 3 block’s output as the orange block’s input. The way we implement this is through a queue that processes nodes in the order they arrived in. We’ll also keep track of all the nodes we already visited and processed so we don’t end up reprocessing them. Below is a step by step flow of how its implemented.</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KyJRr_0wHC6WaqKDv05QwA.png"/><figcaption>Step by step flow of how I used BFS to process nodes</figcaption></figure> <p>Here’s the code block that I used to incorporate BFS in my project:</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ITbjwzpKgpzL7hDq407y6Q.png"/><figcaption>Source: <a href="https://github.com/farhan0167/otto-m8">https://github.com/farhan0167/otto-m8</a></figcaption></figure> <p>And if you notice, it looks a lot like what you’d find on Wikipedia on the BFS Algorithm:</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BnPGZPjDo_PT7EQKS-g3zQ.png"/><figcaption>Source: <a href="https://en.wikipedia.org/wiki/Breadth-first_search">https://en.wikipedia.org/wiki/Breadth-first_search</a></figcaption></figure> <p>Now that we have a way to pass payloads from one block to another, there’s a whole world of possibilities of what can be implemented. At the moment otto-m8 (which translates to automate), aims to provide all these blocks which implement some form of Deep Learning model. It supports LLM’s(OpenAI and Ollama) and Hugging Face models. When you create a workflow, you get a deployable Docker container with an exposed REST endpoint. And at its core (obviously an oversimplification) the BFS algorithm paves the way for a user input to pass through all the chained models in your workflow.</p> <p>Thank you for reading, especially if you’ve followed along all the way. Please feel free to try out otto-m8 which can be found here on <strong>Github: </strong><a href="https://github.com/farhan0167/otto-m8"><strong>https://github.com/farhan0167/otto-m8</strong></a>, and let me know what you think. If you like what I’m doing, please share some feedback and support me with a <a href="https://github.com/farhan0167/otto-m8">Github star</a> ⭐️!</p> <p><img src="https://medium.com/_/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=6555f2bac3e5" width="1" height="1" alt=""/></p>]]></content><author><name></name></author><category term="external-posts"/><category term="medium"/></entry><entry><title type="html">Embeddings are Everywhere</title><link href="https://farhan0167.github.io/blog/2023/embeddings-are-everywhere/" rel="alternate" type="text/html" title="Embeddings are Everywhere"/><published>2023-09-13T18:53:33+00:00</published><updated>2023-09-13T18:53:33+00:00</updated><id>https://farhan0167.github.io/blog/2023/embeddings-are-everywhere</id><content type="html" xml:base="https://farhan0167.github.io/blog/2023/embeddings-are-everywhere/"><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/792/1*uSADgM80EmCQXUAzVbE4mA.png"/></figure> <p>Earlier in July, I demoed a PDF QnA Bot, which was able to answer user queries related to an uploaded PDF file by utilizing Word Embeddings. You can check out the application <a href="https://github.com/farhan0167/QnAChatBot">here</a>. Embeddings are everywhere, especially in the realm of natural language processing. But what exactly are embeddings, and why are they so vital in the realm of natural language processing? At its core, an embedding serves as a bridge, connecting the abstract world of human language to the mathematical realm of deep neural networks and language models. In doing so, it transforms words, phrases, or even entire documents into numerical forms that machines can comprehend and manipulate.</p> <p>As illustrated by the PDF QnA Bot project, embeddings wield substantial power when it comes to conducting semantic searches within vast repositories of organizational documents. They serve as the cornerstone for the development of chatbots capable of ingesting extensive volumes of textual data, enabling them to provide insightful answers to user queries.</p> <p>However, as organizations navigate the fast changing landscape of AI agents and services, there has been a growing concern of data privacy. There are various AI companies that are offering their own embeddings endpoints that organizations can simply integrate within their own software development pipelines to build chatbots like the one I made earlier. Although, OpenAI does not use data passed or processed within their API’s, there has been a growing trend of organizations trying to leverage open source models to benefit from the same level of performance but with more fine grained control of their proprietary data.</p> <p>One question that usually pops up is how good is an open source model compared to leading AI platforms like OpenAI and Cohere. Even if an open source model performs on par with these platforms, how can an organization host these models, and can organizations justify the costs associated with hosting these models?</p> <p>In this <a href="https://github.com/farhan0167/QnAChatBot/blob/59ba2020cc8509d3ce256958f523e8d9e95e4d35/Embeddings.ipynb">notebook</a>, I explore 3 different ways we can generate embeddings of textual data. We start with CohereAI, followed by OpenAI and then an open source model provided by HuggingFace. The objective is to use Clustering and Classification to measure how the three models perform, and also create a cost analysis of using each model.</p> <blockquote>Access my experiment <a href="https://github.com/farhan0167/QnAChatBot/blob/59ba2020cc8509d3ce256958f523e8d9e95e4d35/Embeddings.ipynb">here</a></blockquote> <h3>The Dataset and Setup</h3> <p>For this experiment, I’ll mostly refer to CohereAI’s amazing <a href="https://colab.research.google.com/github/cohere-ai/notebooks/blob/main/notebooks/Visualizing_Text_Embeddings.ipynb#scrollTo=gmxKlGS5oWH4">notebooks</a> on their embeddings endpoint. More specifically, their demo uses a dataset that I think would be a great resource to test across different embeddings algorithms.</p> <h4>Dataset</h4> <p>This dataset, ATIS Airline Travel Information System, is a standard benchmark dataset widely used as an intent classification, where intent can be defined as a airline customer’s intent when typing in a question or comment. You can learn more about the dataset <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fwww.kaggle.com%2Fdatasets%2Fhassanamin%2Fatis-airlinetravelinformationsystem%3Fselect%3Datis_intents_train.csv">here</a>.</p> <pre>df.head()<br />Output:<br />query<br />0 which airlines fly from boston to washington ...<br />1 show me the airlines that fly between toronto...<br />2 show me round trip first class tickets from n...<br />3 i&#39;d like the lowest fare from denver to pitts...<br />4 show me a list of ground transportation at bo...</pre> <h4>Model Choices</h4> <p>For this experiment, we will analyze 3 models:</p> <ol><li>OpenAI’s Ada v2 Embeddings model</li><li>CohereAI’s Embedding endpoint</li><li>Sentence Transformers (open source)</li></ol> <p>For the open source model we will be using the Sentence Transformers library provided by huggingface to generate our embeddings. We will go with sentence-transformers/all-MiniLM-L6-v2 model, which has about 2.4M downloads on the hub. Or, you can pick from the many other models available <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fhuggingface.co%2Fmodels%3Flibrary%3Dsentence-transformers%26sort%3Dtrending">here</a>. One thing to note about this is that by default, input text longer than 256 word pieces is truncated.</p> <h4>Experiment Overview</h4> <p>The experiment goes as follows:</p> <ol><li>Sample a fraction of the dataset, i.e, 25%.</li><li>Load the embeddings model from cohere-ai, openai, huggingface and embed the dataset.</li><li>Reduce the the dimensionality using PCA to 10, visualize, and then reduce it further to 2.</li><li>Perform clustering (2 regions) on a sample of 9 datapoints, visualize and report results across models</li><li>Perform classification using an SVM classifier over the whole 25% of the dataset, and report results across models.</li></ol> <h3>Results</h3> <h4>Clustering across Models</h4> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cH_Ccf7LYScyZ6TtBaHlWQ.png"/></figure> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*khSkPedzu0-jDutYhdpGOA.png"/><figcaption>From left to right: CohereAI, OpenAI</figcaption></figure> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*42YFHGZim0t78TxqnNUJBw.png"/><figcaption>HuggingFace Sentence Transformer</figcaption></figure> <p>When it comes to clustering, we can see from the above results, that the three models output similar clusters, with each model being successful in separating ground transportation to airline queries. However, OpenAI’s embedding model seems to have 3 clusters which seem to capture the data seperation between our 3 classes more perfectly compared to Cohere and the open source model. Nonetheless, it is quite evident that one can go with an open source model with on-par performance to the closed models in the market. There is also the added benefit that we can fine-tune these open source models on our own datasets to perform even better, all the while having full control of how you use your data.</p> <h4>Classification Results</h4> <pre>Cohere Report: <br />                     precision    recall  f1-score   support<br /><br />       atis_airfare       0.97      0.97      0.97        29<br />       atis_airline       1.00      0.90      0.95        10<br />atis_ground_service       0.95      1.00      0.98        21<br /><br />           accuracy                           0.97        60<br />          macro avg       0.97      0.96      0.96        60<br />       weighted avg       0.97      0.97      0.97        60<br /><br />------------------------------------------------------------------------------ <br /><br />OpenAI Report: <br />                     precision    recall  f1-score   support<br /><br />       atis_airfare       0.97      0.97      0.97        29<br />       atis_airline       1.00      0.90      0.95        10<br />atis_ground_service       0.95      1.00      0.98        21<br /><br />           accuracy                           0.97        60<br />          macro avg       0.97      0.96      0.96        60<br />       weighted avg       0.97      0.97      0.97        60<br /><br />------------------------------------------------------------------------------ <br /><br />Open Source Report:<br />                     precision    recall  f1-score   support<br /><br />       atis_airfare       0.97      1.00      0.98        29<br />       atis_airline       1.00      0.90      0.95        10<br />atis_ground_service       1.00      1.00      1.00        21<br /><br />           accuracy                           0.98        60<br />          macro avg       0.99      0.97      0.98        60<br />       weighted avg       0.98      0.98      0.98        60</pre> <p>In terms of Classification, all three models performed equally with accuracy around 97%, with the open source model showing a percentage point improvement across all metrics.</p> <p>What this report goes on to show us that we can achieve similar results when it comes to closed and open ended word embeddings models. On a baseline, all three models did well but one thing to note is that, in this experiment, we saw a decrease in accuracy from 100% to 97% when we changed the sample size. So, it is worthy to note that this experiment isn’t conclusive until we run our experiment on a larger dataset. These results nonetheless should be a great start to considering open source models for organizations that want more control over their data. But one question still remains: How much would it cost us to deploy our own open source embeddings model?</p> <h3>Cost Analysis</h3> <p>We can find the pricing of <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fopenai.com%2Fpricing%23%3A%7E%3Atext%3DEmbedding-%2Cmodels%2C-Build%2520advanced%2520search">OpenAI</a> and <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fcohere.com%2Fpricing">Cohere</a> which are charged based on the number of tokens embedded.</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/238/1*knLwOmP-B4amo_TXB5dBSA.png"/></figure> <p>So, how do we calculate how many tokens we are processing?</p> <p>This <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fhelp.openai.com%2Fen%2Farticles%2F4936856-what-are-tokens-and-how-to-count-them">article</a> from OpenAI gives us a general understanding of how to calculate the number of tokens. Here’s a summary:</p> <pre>• 1 token ~= 4 chars in English<br />• 1 token ~= ¾ words<br />• 100 tokens ~= 75 words<br /><br />Or, <br /><br />• 1-2 sentence ~= 30 tokens<br />• 1 paragraph ~= 100 tokens<br />• 1,500 words ~= 2048 tokens</pre> <p>Using this information, let’s plot the costs across these models:</p> <pre>def tokenCounter(words:int):<br />  conversion = 2048/1500<br />  return conversion*words<br /><br />def costOfEmbedding(model:str, words:int):<br />  models = {&#39;openai&#39;: 0.0001, &#39;cohere-default&#39;: 0.0004, &#39;cohere-custom&#39;: 0.0008}<br />  numberOfTokens = tokenCounter(words)<br />  perTokenCost = models[model]/1000<br />  return numberOfTokens*perTokenCost<br /><br />models = [&#39;openai&#39;, &#39;cohere-default&#39;, &#39;cohere-custom&#39;]<br />costs = []<br />for model in models:<br />  costs.append(costOfEmbedding(model, 256)*10000)<br />import matplotlib.pyplot as plt<br />import seaborn as sns<br /><br />plt.figure(figsize=(10,8))<br />sns.barplot(x=models, y=costs)<br />for i, cost in enumerate(costs):<br />    plt.annotate(f&#39; ${cost}&#39;, (i, cost), textcoords=&quot;offset points&quot;, xytext=(0,10), ha=&#39;center&#39;)<br />plt.title(&quot;Cost of Embedding 10,000 documents with 256 words in average&quot;)<br />plt.show()</pre> <figure><img alt="" src="https://cdn-images-1.medium.com/max/826/1*oAjK8l-45hggm5tX2zm_FA.png"/></figure> <h4>Measuring costs associated with Open Source Models</h4> <p>While closed form models have a pricing catalog, which details how we are charged for embedding per token, with our open source model we need to think about the cost of hosting these models on the cloud.</p> <p>There are two ways to think about this:</p> <ul><li>We embed 10,000 document once and store it in a vector database for retrieval. This is a one time process with the assumption we will not need to process future documents.</li><li>We not only embed 10,000 documents, but also build a pipeline to embed future documents as they come in. This process assumes that we will own our own embeddings endpoint as a service internally within the organization.</li></ul> <p>Hosting transformer models on the cloud comes with its fair share of challenges, with the major challenge being the size of these models. Recent transformer models such as Llama2, GPTJ, Falcon-180B, etc are measured in billions of parameters that occupy over 20GB+ memory at the very least. On top of size, these models require advanced GPUs to perform vector calculation. For instance, Google Colab provides us a Nvidia T4 GPU with about 16GB memory, and it is not even sufficient to load up Llama2’s smallest 7B parameter model without some form of quantization tricks. Therefore, when it comes to deploying your own open sourced AI agents internally it becomes paramount to consider whether the costs associated with running these models are worth it. To give you an example, consider this chart below based on AWS Sagemaker pricing:</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/573/1*0i1WxcjyxwBjrvc5S9mKIQ.png"/></figure> <p>You can find all the instance pricing <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Faws.amazon.com%2Fsagemaker%2Fpricing%2F">here</a>. For Llama2 according to Meta, “The largest model, however, will require very powerful hardware like an A100 80GB.” One thing is quite obvious- the cost of running these transformer models are pretty high compared to just using services from OpenAI or Cohere, where they bare these costs by enjoying economies of scale, or worse losing money (but that will be a discussion for another blog).</p> <p>Luckily for us though, our open source embedding model is a fairly small model that can be run on a bare metal CPU. To understand the memory utilization of this model, we can reference this great <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fhuggingface.co%2Fspaces%2Fhf-accelerate%2Fmodel-memory-usage">tool</a> by HuggingFace to get an approximation. According to their findings, he minimum recommended vRAM needed for a model is denoted as the size of the “largest layer”, and training of a model is roughly 4x its size (for Adam). When performing inference, expect to add up to an additional 20% to this as found by <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fblog.eleuther.ai%2Ftransformer-math%2F">EleutherAI</a>.</p> <p>To calculate our vRam requirements, we see that our model is backed by a BERT base model, which is known to have 413.18MB with the largest layer consisting of 84.95MB.</p> <pre>Min vRam Required:  84.95 MB<br />vRam required for inference:  101.94 MB<br />vRam required for training/finetuning:  339.8 MB</pre> <p>As mentioned earlier, luckily our sentence transformer is a small transformer model, so we can use the ml.t2.medium instance type to host our model, which is charged at $0.056 per hour. Assuming, we only embed the first 10,000 documents, we can approximate, in the worst case, that the whole process will take us 2 hours. The whole process could finish up much faster but I could not test this out since I do not 10,000 documents to embed (the dataset used in this example only contains 1000 queries); therefore, let’s just assume it takes us 2hours and plot our results.</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/826/1*qvsb2zEBnXdaVPpG9wcSTg.png"/></figure> <p>What’s interesting about the visualization above is the fact that, for our open source model, the cost is not directly proportional to the number of tokens. Even though the processing time will depend on the number of documents that need to be embedded, the point to be made about this example is that we could’ve embedded about 20,000 documents with the same cost. With 1000 examples or lower, we might not even need to run the embedding process for more than 10mins, which would mean we’ll end up paying close to nothing.</p> <p>Furthermore, with the cost of open source model already substantially below those of OpenAI and Cohere, we can take it a step further. Since we also want our embeddings model to embed future models, we can leverage AWS Sagemaker’s Serverless Inference. This <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Faws.amazon.com%2Fblogs%2Fmachine-learning%2Fhost-hugging-face-transformer-models-using-amazon-sagemaker-serverless-inference%2F">documentation</a> should be a great guide for the following assesment. With Serverless Inference, you only pay for the compute capacity used to process inference requests, billed by the millisecond, and the amount of data processed.</p> <p>You can choose a Serverless Inference endpoint memory size from 1024 MB (1 GB) up to 6144 MB (6 GB), of which we decided to use only 4GB. Although I am not calculating the costs associated with running our embedding model on serverless inference (we can do this for a future post), we can still get an understanding by closely following the example provided with the DistilBERT example, which is model half the size of the BERT model used in our embedding model.</p> <pre>Total request time - 243ms + 43ms = 286ms<br />Compute cost (4096 MB) - $0.000080 USD per second<br />1 request cost - 1 * 0.286 * $0.000080 = $0.00002288<br />1 thousand requests cost - 1,000 * 0.286 * $0.000080 = $0.02288<br />1 million requests cost - 1,000,000 * 0.286 * $0.000080 = $22.88</pre> <p>So we can implicitly make the conclusion that the cost of running a serverless endpoint will be cheaper compared the other closed source models out there. It is also important to note that the serverless inference will not work for transformer models such as the Llama2 as they require GPUs and much higher memory requirements, which the serverless solution doesn’t currently support.</p> <h3>Conclusion</h3> <p>To sum it all up, in this experiment, we have went from using closed source models from OpenAI and Cohere, and compared both performance and costs with its open sourced counterpart. For organizations that are considering having more control over their data, an open source model could be a great option.</p> <p>However, I do want to point out some limitations about the open source model:</p> <ol><li>The sentence transformer used here can only process input sentences of length 256 word, whereas the OpenAI and Cohere model is limited to the token limit of around 2000–4000 tokens. However, this can be mitigated by exploring this <a href="https://colab.research.google.com/corgiredirector?site=https%3A%2F%2Fhuggingface.co%2Fsentence-transformers%2Fall-MiniLM-L6-v2%23usage-huggingface-transformers">code block</a> to use models that can handle larger input sequences. However, this could also in fact increase the model size, which might not be suitable for Serverless Inference.</li></ol> <p>The transformative power of AI is poised to reshape the business landscape in unprecedented ways. With the continuous emergence of new AI models and resources at an unprecedented pace, organizations are facing both a wealth of opportunities and a challenging terrain to navigate. To thrive in this evolving landscape, businesses will require individuals who possess a deep understanding of the diverse options available, ranging from open source to closed source solutions, like we did today. As AI continues to advance, those who can adeptly harness its capabilities will not only ensure their success but also shape the future of their industries. The journey ahead demands adaptability, expertise, and a commitment to embracing the ever-changing world of AI, where innovation is the key to sustainable growth and competitiveness.</p> <p><img src="https://medium.com/_/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=f328d27412ee" width="1" height="1" alt=""/></p>]]></content><author><name></name></author><category term="external-posts"/><category term="medium"/></entry><entry><title type="html">Tracking Prices on Amazon: A Serverless Approach</title><link href="https://farhan0167.github.io/blog/2023/tracking-prices-on-amazon-a-serverless-approach/" rel="alternate" type="text/html" title="Tracking Prices on Amazon: A Serverless Approach"/><published>2023-06-15T00:11:04+00:00</published><updated>2023-06-15T00:11:04+00:00</updated><id>https://farhan0167.github.io/blog/2023/tracking-prices-on-amazon-a-serverless-approach</id><content type="html" xml:base="https://farhan0167.github.io/blog/2023/tracking-prices-on-amazon-a-serverless-approach/"><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PxYHM-_ifq4LQo4KjuMD1Q.png"/></figure> <p>So here’s the problem statement- you are on Amazon and notice this pair of AirPods Pro selling at a 12% discount from list price, and you wonder whether you could snatch a higher discount. You want to track the price change over time, and want to be notified when the price drops by a certain threshold. You also don’t just want to run a script manually everyday; instead you want a system that runs in the background and notifies you of these changes.</p> <p>I’ve been studying for the AWS Solutions Architect Associates exam for the past month, and I thought of solving this problem by picking up on the materials I’ve touched throughout that journey. This article is not about how to build a React application or about a walkthrough on scrapping. This article is about how I use different AWS resources and combine them together.</p> <h3>A Simple Architecture</h3> <p>To achieve our goal, we need 3 essential tools:</p> <ul><li>A Frontend for the clients to interact with the system</li><li>A compute engine or backend to scrape a given link from Amazon, and</li><li>A database to store all the tracking information</li></ul> <p>We can visualize this architecture to look as follows:</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rHefATqZNrZvOARftZP_xQ.png"/></figure> <p>The frontend is built using React, and I integrate AWS Amplify to utilize Amplify’s user authentication feature. The React application is then deployed on Amazon S3. Amazon S3 is AWS’s proprietary object storage platform, and while we are aware of using it as a place to store files, images, logs, etc. we can also leverage S3’s web hosting feature to host static built websites.</p> <p>With a frontend in place, we now need to interact with the backend. For this application, we want users to be able to track 3 items and be able to monitor price changes daily by logging into the frontend. To achieve this, we can utilize an EC2 instance, which hosts a Flask application that provides the client 2 endpoints- one to get items, and the other to post items.</p> <p>For the AirPods, I would post the link of the product to the Flask endpoint, and the Flask application will scrape the given link for the price, and store it in DynamoDB. Once stored in the database, users can simply use the get-items endpoint to see their tracked items. And then for every day after an item was posted, the Flask application will run a process to re-scrape price information on a daily interval, and match price changes against the target price users have set- if the price drops to target, the Flask application will notify the users.</p> <p>This architecture would serve us well but this can become quite expensive to run. EC2 instances are charged based on the instance type, RAM, storage, etc, per hour. For instance, if we run this on a an instance type t3.medium it will cost us $ 0.052/Hour, and could cost us an upward of $ 37.96/Month. This is expensive, and the costs could balloon up as we add more users and possibly more instance to distribute load. It’s not sustainable to pay this much for a service that will perform functions like get/store items, and run a 1 time scraping job at 9am in the morning. We can do better.</p> <h3>A Cost Optimized Serverless Architecture</h3> <figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kN9d9wOjBCJvD-LuALKFJw.png"/></figure> <p>The main idea here is to leverage the AWS Serverless approach. AWS Serverless is a cloud computing model that allows us to build and deploy applications without worrying about server management. It offers scalability, cost-effectiveness, and rapid deployment, making it an ideal choice for our use case. And most importantly, we will only be charged for every time the system is used, as opposed to on a per hour basis.</p> <h4>System Breakdown</h4> <p>The system is broken into 4 different Lambda functions, with each of these functions doing a specific task. The client interacts with AWS API Gateway, which replaces the Flask endpoints- store and get items. At the very basic level, the get-items endpoint queries Lambda function-3 that queries the DynamoDB table for all the tracking items that belong to the user.</p> <p><strong>The </strong><strong>/store-items endpoint:</strong></p> <p>The client makes the following POST request:</p> <pre>{<br />    &quot;url&quot;: &quot;https://www.amazon.com/product-to-track&quot;,<br />    &quot;username&quot;: &quot;amplify-provided-cognito-username&quot;,<br />    &quot;custom_name&quot;: &quot;custom-name-set-by-user&quot;,<br />    &quot;target&quot;: 0.25,<br />    &quot;price&quot;: 129.00<br />}</pre> <p>Initially, I only had one Lambda function, the Lambda function-1, in place to handle this endpoint. This function takes in the url and scrapes that particular link using the ScrapingBee API, to get the price and product name and store it in DynamoDB. However, I ran into a timeout issue. It turned out that the API Gateway has a 29s timeout window whereas the Lambda function would take about a minute to to finish scraping. So in 29s the API Gateway would timeout and send an error code back to the client, while the Lambda function would successfully execute in 1 minute and store the item in the database.</p> <p>And that’s why I introduce the SNS module, a service that provides message delivery from publishers to subscribers. So we decouple the application by moving the Lambda function-1 to Lambda function-2, and have Lambda function-1, process the API request and publish the scraping job to SNS. Lambda-function-1 can now simply return the same message it received back to the client, so that the client is able to see that the items to track is there.</p> <p>This implementation introduced a new challenge. With the decoupling in place, whenever a client puts in a request to store an item, the first lambda function would respond with the tracking details of the product which the client could render. However, since that item takes about 2minutes-5minutes to process by the other lambda function, the database still isn’t aware of this new item. Therefore, the minute the client refreshes their browser, the new item disappears. To solve this issue, I leverage caching. When the first lambda responds, I immediately store all the items data on the client’s local storage with a timeout of 5–15 minutes. This would allow the client to see their newly put item and after 15minutes, they would start seeing the item from the database all the while the idea of database store is abstracted away. This also enables us to reduce the load on the AWS services in the backend with caching.</p> <p><strong>The EventBridge Scheduler</strong></p> <p>With items readily available in DynamoDB, we can now implement an EventBridge scheduler to trigger an event daily to invoke Lambda function-4 to: extract all the urls available in the table, scrape the price for that day, and compare it against the original price. Currently, the function determines whether the price extracted on a given day the scheduler runs is the target price the customer has set. If there’s a match, we can utilize another SNS module to utilize Amazon Simple Email Service to email users to notify them of it.</p> <p>The new prices are appended in the following way in the priceCh` array:</p> <pre>{<br />        &quot;product&quot;: &quot;Screen Cleaner Spray (16oz)..&quot;,<br />        &quot;net_change&quot;: 0.0,<br />        &quot;custom_name&quot;: &quot;Spray&quot;,<br />        &quot;priceCh&quot;: [<br />            19.97, 19.50, 19.00<br />        ],<br />        &quot;target&quot;: -87.5,<br />        &quot;uuid&quot;: &quot;db-unique-key&quot;,<br />        &quot;username&quot;: &quot;amplify-provided-cognito-username&quot;,<br />        &quot;price&quot;: 19.97,<br />        &quot;url&quot;: &quot;https://www.amazon.com/product-to-track&quot;,<br />        &quot;change_since_yesterday&quot;: 0.0<br />}</pre> <p>With this priceCh array, the frontend can now visualize price change over time(last item in array is the current day price)that looks like this:</p> <figure><img alt="" src="https://cdn-images-1.medium.com/max/870/1*lZy_1-9tUaMgvgLY2JuAMw.png"/></figure> <h4>Closing Remarks</h4> <p>I’m still working on this project to finish up a few issues and future directions this can take, which could be summarized as:</p> <ol><li>Instead of checking whether current price equals target price, we can implement a target window, where users are notified when the price drops to within a 5% range of the target price.</li><li>We can enable a feature that customers can select when posting an item to track, wherein when a price drops to target range, we authorize Stripe to make payments towards buying it directly instead of having to do it manually.</li></ol> <p>Thanks for sticking it out till the end. If you enjoyed reading about this system design walkthrough please drop in a like to show your support. And I’m also open to receiving feedback on how this could have been done differently.</p> <p><img src="https://medium.com/_/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=3877d1a5403" width="1" height="1" alt=""/>&lt;hr&gt;&lt;p&gt;<a href="https://awstip.com/tracking-prices-on-amazon-a-serverless-approach-3877d1a5403">Tracking Prices on Amazon: A Serverless Approach</a> was originally published in <a href="https://awstip.com">AWS Tip</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.&lt;/p&gt;</p>]]></content><author><name></name></author><category term="external-posts"/><category term="medium"/></entry><entry><title type="html">Adversarial Attacks on CNN</title><link href="https://farhan0167.github.io/blog/2023/adversarial-attacks-on-cnn/" rel="alternate" type="text/html" title="Adversarial Attacks on CNN"/><published>2023-06-14T14:21:06+00:00</published><updated>2023-06-14T14:21:06+00:00</updated><id>https://farhan0167.github.io/blog/2023/adversarial-attacks-on-cnn</id><content type="html" xml:base="https://farhan0167.github.io/blog/2023/adversarial-attacks-on-cnn/"><![CDATA[<h3>Can Deep Neural Networks misclassify? How this simple idea of adversarial attack on CNN is now being used as a Defense against generative AI</h3> <p>I recently came across this <a href="https://www.nytimes.com/2023/02/13/technology/ai-art-generator-lensa-stable-diffusion.html">article</a>, where a group of University of Chicago researchers are creating <a href="http://glaze.cs.uchicago.edu/">The Glaze Project</a> which aims to prevent the use of artist’s work to train generative AI models like Stable Diffusion. Generative AI has exploded in popularity over the last year, especially since the launch of LensaAI, Dall-E and other generative AI models that produce art from text prompts. Concerns over these apps started appearing in the news following their rise in popularity, and a divide emerged between one party arguing why it was not a copyrights issue and the other arguing why it was.</p> <p>I don’t wan’t to talk about any of that but about the Glaze Project. Last semester, I took a Cybersecurity class in Machine Learning, where we were introduced to the idea of Sign based gradient descent attacks. Put simply, given an image, attackers can modify the image using gradient methods to perturb the image such that a AI algorithm would misclassify. The catch is, to the human eye, you would see no reason to believe the model’s prediction because to the human eye the picture looks just fine.</p> <p>In a more technical sense, here is an example of what I mean by a gradient based attack:</p> <figure><img alt="Adversarial Example" src="https://cdn-images-1.medium.com/proxy/0*jQkkJdX7LBPpHGrU"/></figure> <p>Here, starting with the image of a panda, the attacker adds small perturbations (distortions) to the original image, which results in the model labelling this image as a gibbon, with high confidence.</p> <p>You can read more about this from where I adapted my notebook. <a href="https://www.tensorflow.org/tutorials/generative/adversarial_fgsm">Link to example notebook</a>.</p> <h4>So how does this work?</h4> <p>For those of us who’s worked with Deep Neural Networks aka AI models, what we are really trying to do is minimizing some loss function with respect to an input. In a gradient based attack, what we want to do is maximize that loss. We can do this by finding how much each pixel in the image is contributing to the loss function and compute the sign of the gradient. And then we’ll take the image and add a small epsilon to the gradient, resulting in a image that is perturbed.</p> <h4>So how does it effect Generative AI models?</h4> <p>Since generative models rely on advances in convolutional neural networks, on a very high level your text prompt of “generate an image of a panda” will be fed into some CNN model that knows what a panda looks like. But if we apply the gradient based attack on our images, what supposedly looks like panda to us, looks like a gibbon to AI. Therefore when an outsider will scrape this image of what looks like a panda, they’ll in fact train their models to construct a gibbon. While this is a over simplification, the idea of this gradient based attack has seen many iterations over the past years and there are better attacks to fool neural networks. You can read more about the technical details of the UChicago work <a href="https://arxiv.org/pdf/2302.04222.pdf">here</a></p> <p>And without further talk, I want to demonstrate the idea of a gradient based attack we learnt in class so you can get a hands on for what I just discussed.</p> <pre>import tensorflow as tf<br />import matplotlib as mpl<br />import matplotlib.pyplot as plt<br /><br />mpl.rcParams[&#39;figure.figsize&#39;] = (8, 8)<br />mpl.rcParams[&#39;axes.grid&#39;] = False</pre> <pre>import requests<br />from io import BytesIO<br />from PIL import Image</pre> <p>Let’s load the pretrained Xception model and the ImageNet class names.</p> <pre>pretrained_model = tf.keras.applications.Xception(include_top=True,<br />                                                     weights=&#39;imagenet&#39;)<br />pretrained_model.trainable = False<br /><br /># ImageNet labels<br />decode_predictions = tf.keras.applications.mobilenet_v2.decode_predictions</pre> <pre># Helper function to preprocess the image so that it can be inputted in model<br />def preprocess(image):<br />  image = tf.cast(image, tf.float32)<br />  image = tf.image.resize(image, (299, 299))<br />  image = tf.keras.applications.mobilenet_v2.preprocess_input(image)<br />  image = image[None, ...]<br />  return image<br /><br /># Helper function to extract labels from probability vector<br />def get_imagenet_label(probs):<br />  return decode_predictions(probs, top=1)[0][0]</pre> <h4>Original image</h4> <pre>#you can insert any image from the web to play around:<br />url = &quot;https://www.ontheblufflabradors.com/wp-content/uploads/2021/02/25B182D2-3801-4E6E-8EB0-51D8B3B0C59D-1000x1000.jpeg&quot;<br />response = requests.get(url)<br />img = Image.open(BytesIO(response.content)).convert(&#39;RGB&#39;)</pre> <pre>image = preprocess(img)<br />image_probs = pretrained_model.predict(image)</pre> <pre>1/1 [==============================] - 2s 2s/step</pre> <p>Let’s have a look at the image.</p> <pre>plt.figure()<br />plt.imshow(image[0] * 0.5 + 0.5)  # To change [-1, 1] to [0,1]<br />_, image_class, class_confidence = get_imagenet_label(image_probs)<br />plt.title(&#39;{} : {:.2f}% Confidence&#39;.format(image_class, class_confidence*100))<br />plt.show()</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*cv1w_GPKlTPLGZrbR_f6QQ.png"/></figure> <h3>Create the adversarial image</h3> <h4>Implementing fast gradient sign method</h4> <p>The first step is to create perturbations which will be used to distort the original image resulting in an adversarial image. As mentioned, for this task, the gradients are taken with respect to the image.</p> <pre>loss_object = tf.keras.losses.CategoricalCrossentropy()<br /><br />def create_adversarial_pattern(input_image, input_label):<br />  with tf.GradientTape() as tape:<br />    tape.watch(input_image)<br />    prediction = pretrained_model(input_image)<br />    loss = loss_object(input_label, prediction)<br /><br />  # Get the gradients of the loss w.r.t to the input image.<br />  gradient = tape.gradient(loss, input_image)<br />  # Get the sign of the gradients to create the perturbation<br />  signed_grad = tf.sign(gradient)<br />  return signed_grad</pre> <p>The resulting perturbations can also be visualised.</p> <pre># Get the input label of the image. You can find them here: https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a<br />target_index = 270 #270 is a &#39;white wolf, Arctic wolf, Canis lupus tundrarum&#39;<br />label = tf.one_hot(target_index, image_probs.shape[-1])<br />label = tf.reshape(label, (1, image_probs.shape[-1]))<br /><br />perturbations = create_adversarial_pattern(image, label)<br />plt.imshow(perturbations[0] * 0.5 + 0.5);  # To change [-1, 1] to [0,1]</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*Ajo8y0inAE2OcYyOUvLlAg.png"/></figure> <p>Let’s try this out for different values of epsilon and observe the resultant image. You’ll notice that as the value of epsilon is increased, it becomes easier to fool the network. However, this comes as a trade-off which results in the perturbations becoming more identifiable.</p> <pre>def display_images(image, description):<br />  _, label, confidence = get_imagenet_label(pretrained_model.predict(image))<br />  plt.figure()<br />  plt.imshow(image[0]*0.5+0.5)<br />  plt.title(&#39;{} \n {} : {:.2f}% Confidence&#39;.format(description,<br />                                                   label, confidence*100))<br />  plt.show()</pre> <pre>epsilons = [0,0.44, 0.6]<br />descriptions = [(&#39;Epsilon = {:0.3f}&#39;.format(eps) if eps else &#39;Input&#39;)<br />                for eps in epsilons]<br /><br />for i, eps in enumerate(epsilons):<br />  adv_x = image + eps*perturbations<br />  adv_x = tf.clip_by_value(adv_x, -1, 1)<br />  display_images(adv_x, descriptions[i])</pre> <pre>1/1 [==============================] - 0s 36ms/step</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*-2clSBNBEoaPkdUg9VCPsA.png"/></figure> <pre>1/1 [==============================] - 0s 44ms/step</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*oUrDABuTb9QYuQYn3_EN4w.png"/></figure> <pre>1/1 [==============================] - 0s 59ms/step</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*cxgiGpmS6zSftz-gmYttTA.png"/></figure> <p>As you can see, by adding the perturbation, and image which still looks like a Labrador is being classified as ice bear and star fish depending on the value of epsilon. While in this example, one can visibly note that the image has been altered, recent progress in this space has produced perturbation that is invisible to the naked eye.</p> <h4>Iterative Fast Gradient Sign Method</h4> <p>We can take our fast gradient sign method and extend it a bit further by mounting an iterative fast gradient sign attack. The idea is simple, we do exactly what we did previously but this time we take small values of epsilon and repeat the process some n number of times. This allows us to use small epsilon values instead of large values used in the previous method, i.e epsilons = [0,0.44, 0.6]</p> <pre>def IFGSM(img,label, alph, step_size):<br />  #convert input image dtype to tensor<br /><br />  adv_x = img<br />  #repeat the create_adversarial_pattern step_size amount of times<br />  for step in range(step_size):<br />    signed_grad = create_adversarial_pattern(adv_x, label)<br />    adv_x = adv_x + alph*signed_grad<br />    adv_x = tf.clip_by_value(adv_x,-1,1)<br />  return adv_x</pre> <pre>#lets use smaller values of epsilon to see how we are doing<br />epsilons = [ 0.345, 0.358,0.369]<br />descriptions = [(&#39;Alpha = {:0.3f}&#39;.format(eps))<br />                for eps in epsilons]<br /><br />for i, eps in enumerate(epsilons):<br />  adv_x_ifgsm = IFGSM(image,label, eps,2)<br />  display_images(adv_x_ifgsm, descriptions[i])</pre> <pre>1/1 [==============================] - 0s 36ms/step</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*jwhch1bjJ9fhCpekidFMzQ.png"/></figure> <pre>1/1 [==============================] - 0s 28ms/step</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*bjq2qmDj8vd5AgHSD2EBTA.png"/></figure> <pre>1/1 [==============================] - 0s 32ms/step</pre> <figure><img alt="png" src="https://cdn-images-1.medium.com/proxy/1*gS424YXUurMGmMHslAJOqA.png"/></figure> <p>It’s funny to see how the model see’s a football helmet and shower cap because as far as I see, I see a dog.</p> <p>To conclude, when we came across this in class, this was introduced to us as an attack on AI models, and we learnt about ways we can defend from these attacks. The field has evolved a lot since the fast gradient method was introduced but it was interesting to see that methodologies like these are being used to defend.</p> <p><img src="https://medium.com/_/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=26502dc0f2e1" width="1" height="1" alt=""/></p>]]></content><author><name></name></author><category term="external-posts"/><category term="medium"/></entry></feed>