<?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 Kartik Chaudhary on Medium]]></title>
        <description><![CDATA[Stories by Kartik Chaudhary on Medium]]></description>
        <link>https://medium.com/@kartikgill96?source=rss-3fd5a49d1e91------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*d-lL1PrJm0ySO-ZgIHht0g.jpeg</url>
            <title>Stories by Kartik Chaudhary on Medium</title>
            <link>https://medium.com/@kartikgill96?source=rss-3fd5a49d1e91------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 13:30:57 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@kartikgill96/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[Turbocharge Large Language Model Training with Parallelization]]></title>
            <link>https://medium.com/google-cloud/turbocharge-large-language-model-training-with-parallelization-da8f22e294f6?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/da8f22e294f6</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[large-language-models]]></category>
            <category><![CDATA[llm-training]]></category>
            <category><![CDATA[llm-optimization]]></category>
            <category><![CDATA[gpu-computing]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Thu, 28 Nov 2024 04:37:00 GMT</pubDate>
            <atom:updated>2024-11-28T04:37:00.975Z</atom:updated>
            <content:encoded><![CDATA[<h4>Parallelization techniques for efficient distributed training of large deep learning models.</h4><h3>Introduction</h3><p>The story began in 2017 when researchers from Google introduced the famous <a href="https://arxiv.org/pdf/1706.03762">Transformer</a> architecture in their paper <em>“Attention Is All You Need!”</em>. Transformers turned out to be highly effective for tasks such as language translation, question-answering, and other similar sequence-to-sequence problems. Key features that make the Transformer architecture unique and effective, are — <a href="https://d2l.ai/chapter_attention-mechanisms-and-transformers/self-attention-and-positional-encoding.html">positional encoding and self-attention</a>.</p><p>Large Language Models, or LLMs, also implement a Transformer architecture. These models are usually very large and need a huge amount of text data to train. Their size plays a big role in their success, but it also makes them difficult to train.</p><p>LLMs typically have an enormous number of trainable parameters, sometimes reaching hundreds of billions. This makes it challenging to fit them onto a single accelerator chip for training.</p><p>In this article, you will explore the techniques that help speed up these models through effective parallelization. Following are the key topics covered in this article —</p><ol><li><strong><em>What is Parallelism</em></strong></li><li><strong><em>Speeding Up LLM Training with Parallelization</em></strong></li><li><strong><em>Which parallelism is suitable for you?</em></strong></li><li><strong><em>References</em></strong></li></ol><p>Let’s get started.</p><h3>What is Parallelism?</h3><p>In computer programming, a large task can be broken down into smaller tasks that can run at the same time, speeding up the overall process. This approach is called parallel programming.</p><p>Similarly, in Deep Learning (DL), you can speed up the training of large models by splitting the work across multiple machines or accelerators like GPUs and TPUs. Parallelism in DL is mainly achieved through the follwoing two key methods:</p><ol><li><strong>Data Parallelism</strong></li><li><strong>Model Parallelism</strong></li></ol><p>Let’s explore these concepts further.</p><h4>Data Parallelism</h4><p>In this approach, the training data is split into smaller parts and distributed across multiple machines or processors. Each machine trains an identical copy of the deep learning model using its portion of the data. The parameters learned by all machines are regularly combined to update the final model.</p><h4>Model Parallelism</h4><p>Here, the model itself is divided into smaller sections, with each part assigned to a different machine or processor. Each machine trains only its specific part of the model. The outputs from all parts are then combined to form the complete, final model.</p><blockquote><strong><em>Which technique should I use for training LLMs?</em></strong></blockquote><p>→ As LLMs are really large models and do not always fit on a single accelerator chip, <strong>model parallelism</strong> can help!!</p><p>→ Data parallelism and model parallelism can also be combined together to make training even faster.</p><h4>Don’t Overlook the Challenge of “Combining Results”</h4><p>When training a model using any parallelism technique, you’ll need to merge the learnings (or parameters) from different machines or processors to create the final trained model. This merging process often involves summing up or averaging the results from each machine. To do this, you must establish a way for machines to share information, which can slow down the process and become a bottleneck in training. The frequency of this communication depends on how the parallelism is implemented. Therefore, it’s crucial to account for this communication overhead when designing your parallel training strategy.</p><p>Now that you have got the basic idea of parallelizing DL models, lets jump into some technical aspects of parallelizing the training of Large Language Models (LLMs).</p><h3>Speeding Up LLM Training with Parallelization</h3><p>Training large language models (LLMs) can take an extremely long time because of their huge size and the vast amount of data they require for pre-training. If done on a single processor, it could take weeks or even months, which is highly impractical. To save time, it’s essential to use parallelization techniques to speed up the training process.</p><p>Here are some effective methods to train LLMs more efficiently:</p><ul><li><em>Using Data Parallelism (DP)</em></li><li><em>Using Tensor Parallelism (TP)</em></li><li><em>Applying Pipeline Parallelism (PP)</em></li><li><em>Using Zero Redundancy Optimizer (ZeRO)</em></li></ul><p>Let’s understand these techniques one-by-one with examples.</p><h4>Using Data Parallelism (DP)</h4><p>In this approach, the training data is divided and distributed among multiple processors or machines. Each processor runs its own copy of the same model in parallel. After completing a training step, all processors share and synchronize their results to ensure the learning is updated collectively. This method works best when the entire model can fit into the memory of a single processor.</p><p>Take a look at Figure 1. There are three processors, each with a GPU accelerator and a copy of the same model. The training dataset is also divided into three parts. Each processor takes one batch from it’s partition of the dataset and trains its own model copy for one step. At the same time, the other two processors also do the same.</p><p>After completing their individual training step, all processors send their gradients to a central parameter server. The parameter server calculates the average gradient, updates the final model weights, and shares the updated weights with all processors. This completes one training step.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*w3EUAfTKWnG1kBzq5WWYcg.png" /><figcaption><strong>Figure 1: Data parallelism technique for training deep learning models | Image by Author</strong></figcaption></figure><p>Now lets understand pipeline parallelism.</p><h4>Using Pipeline Parallelism</h4><p>Pipeline parallelism (PP) is essentially a type of model parallelism, where we distribute the layers of the neural network across processing devices (such as GPUs or TPUs). For example, a large model consisting of 100 layers can be distributed across 4 GPUs where each GPU handles about 25 consecutive layers. See the following illustration (Figure 2).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HqRULi5nrZqBGeAYAQnihg.png" /><figcaption><strong>Figure 2: Pipeline Parallelism | A 100 layer neural network on 4 GPUs | Image by Author</strong></figcaption></figure><p>As per the Figure 2, the data moves from layer-1 to layer-25 on GPU-0. However, when it reaches layer-25 and needs to move to layer-26, it will travel from GPU-0 to GPU-1 through a communication channel. If both GPUs are on the same machine, the data transfer will be faster. But if GPU-0 and GPU-1 are on different machines, the data transfer cost can increase significantly. In such cases, the communication channel could become a bottleneck in pipeline parallelism.</p><p>Now, let’s explore Tensor parallelism.</p><h4>Applying Tensor Parallelism</h4><p>Tensor parallelism (TP) can also be used for fitting a large DL model in multiple GPUs. In this method, each GPU handles only a part of the tensor. Essentially, the large matrix calculations are divided among the GPUs, and the results are then combined to form the final tensor. The following paragraph explains TP with an example.</p><p>Take a look at Figure 3 and assume that<strong> A is the input tensor</strong> and <strong>B is the model weights tensor</strong>. The matrix multiplication can be broken down as shown in the figure. Specifically, the weights tensor B can be divided into two parts, B1 and B2, which can be stored on separate processors.</p><p>Each processor will then perform matrix multiplication on their slice of the tensor and calculate the results at the same time. Basically, <strong>processor 1 will give C1</strong>, and <strong>processor 2 will give C2</strong>. These results, <strong>C1 and C2</strong>, can be transferred from the processors and combined to form the final output <strong>tensor C</strong> when needed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s61dylIZMpuvcq53GmQhdA.png" /><figcaption><strong>Figure 3: Tensor Parallelism — splitting matrix multiplications using Tensor slices | Image by Author</strong></figcaption></figure><p>This technique allows you to spread your large model across multiple GPUs. Now, let’s move on to the next approach.</p><h4>Using Zero Redundancy Optimizer (ZeRO)</h4><p>Data parallelism and Model parallelism approaches have some known limitations such as —</p><ul><li>Data Parallelism doesn’t reduce the memory footprint of the models. Large DL models with billions of parameters are difficult to into single GPUs with limited memory.</li><li>Model parallelism doesn’t scale well beyond a single node because the communication becomes an overhead.</li></ul><p>ZeRO was developed by a Microsoft Research team to overcome the limitations of data parallelism and model parallelism. Unlike vanilla data parallel training, ZeRO doesn’t run exact replicas of the model across processors, It actually optimizes the data parallelism approach by partitioning the model states (parameters, gradients and optimizer states) across different data parallel processors. As ZeRO reduces per device memory usage, it allows you to fit very big models into multiple data parallel processors having smaller memories.</p><p>Following are three common ways of implementing ZeRO —</p><ol><li><strong>Optimizer State Partitioning (OS): </strong>OS reduces memory consumption by <strong>4x, </strong>and doesn’t add any extra communication overhead to the existing data parallel setup.</li><li><strong>OS + Gradient Partitioning (GP): </strong>If you combine OS with GP, it reduces the memory requirements by <strong>8x, </strong>It also doesn’t add any communication overhead over the previous setup.</li><li><strong>OS + GP + Parameter partitioning: </strong>This setup can achieve memory reduction linear with the degree of data parallelism. For example, if your data parallel setup is using 32 GPUs, you can get a <strong>32x</strong> reduction in the memory of each processor. This setup however increases the communication volume by about 50%.</li></ol><p>The distribution of memory consumption of aforementioned three approaches can be seen in Figure 4. This illustration has been taken from the original research paper titled “<a href="https://arxiv.org/pdf/1910.02054"><strong><em>ZeRO: Memory Optimizations Toward Training Trillion Parameter Models</em></strong></a>” published in 2020 by Microsoft Research Team.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sG9km_ZwPfiibo7mUq5VOA.png" /><figcaption><strong>Figure 4: ZeRO memory consumption illustration as per the original research paper.</strong></figcaption></figure><h4><strong>BTW — What is DeepSpeed?</strong></h4><p><a href="https://github.com/microsoft/DeepSpeed">DeepSpeed</a> is a deep learning optimization library developed by Microsoft that makes training of the large deep learning models faster and more efficient. It allows you to train 10x larger models, 10x faster with minimal code changes.</p><h3>Which parallelism is suitable for you?</h3><p>The best parallelism strategy for your unique use case can depend upon various factors such as — model size, number of available machines, number of accelerators (or GPUs) per machine etc. Let’s look at a few scenarios to understand the possibilities.</p><h4>Single Machine — Single GPU</h4><ul><li><strong>Model fits in the GPU</strong>: In this case, you can just go ahead and train your model normally.</li><li><strong>Model doesn’t fit in the GPU</strong>: You can use ZeRO + CPU offloading.</li></ul><h4>Single Machine — Multiple GPUs</h4><ul><li><strong>Model fits in a single GPU</strong>: You can use data parallelism. Optionally, you can augment it with ZeRO, but it may or may not provide any speedups given the situation and configurations.</li><li><strong>Model doesn’t fit in a single GPU</strong>: You have multiple options: pipeline parallelism (PP), ZeRO augmented data parallelism and Tensor parallelism (TP). If the largest layer of the model is not fitting in a single GPU, you can combine PP with TP or implement ZeRO.</li></ul><h4>Multiple Machines — Multiple GPUs</h4><ul><li><strong>If inter-node connectivity is fast</strong>: ZeRO would be easiest option to implement as it doesn’t require much code changes. Otherwise, you can implement <strong>PP+DP+TP, </strong>but this setup would require significant changes to the model.</li><li><strong>If inter-node connectivity is slow</strong>: If you are low on GPU memory and have to utilize multi-node setup. You can implement <strong>DP+PP+TP+ZeRO</strong> all together.</li></ul><p>Thanks for reading this article. I hope it was helpful. Please do share your feedback. See you in the next article!!</p><p>Let’s connect over <a href="https://www.linkedin.com/in/chaudharykartik/">LinkedIn</a>.</p><h4>References</h4><ul><li><a href="https://pypi.org/project/deepspeed/0.3.7/">https://pypi.org/project/deepspeed/0.3.7/</a></li><li><a href="https://github.com/microsoft/DeepSpeed">https://github.com/microsoft/DeepSpeed</a></li><li><a href="https://huggingface.co/docs/text-generation-inference/conceptual/tensor_parallelism">https://huggingface.co/docs/text-generation-inference/conceptual/tensor_parallelism</a></li><li><a href="https://huggingface.co/docs/transformers/v4.13.0/en/parallelism">https://huggingface.co/docs/transformers/v4.13.0/en/parallelism</a></li><li><a href="https://www.microsoft.com/en-us/research/blog/zero-deepspeed-new-system-optimizations-enable-training-models-with-over-100-billion-parameters/">https://www.microsoft.com/en-us/research/blog/zero-deepspeed-new-system-optimizations-enable-training-models-with-over-100-billion-parameters/</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=da8f22e294f6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/turbocharge-large-language-model-training-with-parallelization-da8f22e294f6">Turbocharge Large Language Model Training with Parallelization</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Understanding Key Evaluation Techniques for LLMs]]></title>
            <link>https://medium.com/game-of-bits/understanding-key-evaluation-techniques-for-llms-af902469537e?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/af902469537e</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[llm-evaluation]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[evaluation]]></category>
            <category><![CDATA[large-language-models]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Wed, 23 Oct 2024 15:52:04 GMT</pubDate>
            <atom:updated>2024-10-23T15:52:04.906Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NqKnwz6g2lkDjnW_.jpg" /><figcaption><strong><em>Key Evaluation Techniques for LLMs</em></strong> | Image by Author</figcaption></figure><p>Large Language Models, or LLMs for short, have attracted a lot of attention in past few years due to their amazing capabilities. As a result, there is a growing demand to integrate LLMs in production applications. Before putting them into production, it is critical to design proper evaluation strategies to ensure their positive business impact. This article “<strong><em>Key Evaluation Techniques for LLMs</em></strong>”, highlights some important evaluation techniques for LLMs.</p><p>Evaluating LLMs is a challenging task due to their complex nature. The way they generate outputs, is quite unintuitive, and it is almost impossible to tell whether the generated outputs are factually correct or not (they are grammatically correct most of the times though). As their output can’t be trusted, we can’t just integrate them into our production applications or products.</p><p>So, it is really important to understand the key evaluation techniques for LLMs. Also, it is critical to design the best suited evaluation strategy that meets your goals (for your unique business use case). Keeping this in mind, lets dive into the world of LLM evaluation.</p><p>This article covers the following key topics about LLM Evaluation techniques:</p><ol><li>History of Large Language Models</li><li>Key Evaluation Techniques for LLMs</li><li>Human Evaluation</li><li>Programmatic Evaluation</li><li>AutoRater Evaluation Tool</li><li>Key Metrics for LLM Evaluation</li><li>Summary</li></ol><p>Let’s get started.</p><h3>1. History of Large Language Models</h3><h3>1.1 Language Models Before 2017</h3><p>Before 2017, language models were relatively small and their capabilities were limited. It was a common practice to develop a single model to solve a single unique problem such as sentiment analysis, text classification, named entity recognition (NER) and so on. ML practitioners were focused on keeping the models small and simple, and often a number of task specific feature engineering techniques were applied to get the best results on that particular task.</p><p>Evaluating such small language models was not very difficult as the task that they were trained to solve, was well defined (or already known). And, often a holdout test dataset was present to check if the model is giving expected results or not. If the model is not working as expected, the ML practitioners could always tweak their feature engineering technique, or model architectures, or both to get the best results on holdout dataset.</p><p><strong><em>Things changed significantly after 2017.</em></strong></p><h3>1.2 Language Models After 2017</h3><p>In 2017, a research paper from Google, titled ‘’<a href="https://arxiv.org/pdf/1706.03762"><strong>Attention Is All You Need</strong></a>”, introduced the popular “<a href="https://machinelearningmastery.com/the-transformer-model/">Transformer</a>s” architecture, and the things changed drastically (Figure below depicts the core Transformer architecture, as shown in the original research paper). If you are interested in going into low level details of this architecture, you can read the research paper, it is really well written.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/672/0*nPc_xKK5Tw1rnlOq.png" /><figcaption>Transformer Architecture | Taken from original paper ‘Attention is all you need’ | <strong><em>Key Evaluation Techniques for LLMs</em></strong></figcaption></figure><p>The advent of <strong><em>Transformers</em></strong>, led to the development of <strong>Large Language Models</strong> (<strong>LLMs</strong>). Today, we have models with billions of parameters capable of solving complex language tasks, and almost all of them utilize <em>Transformer</em> architecture as their key building block.</p><blockquote><em>Also, check out my introductory articles on GenAI:<br>1. </em><a href="https://dropsofai.com/a-gentle-introduction-to-large-language-models/"><em>A Gentle Introduction to Large Language Models</em></a><em> <br>2. </em><a href="https://dropsofai.com/beginner-friendly-introduction-to-genai-and-its-applications/"><em>Beginner Friendly Introduction to GenAI and Its Applications</em></a></blockquote><p>Today, we have <a href="https://www.ibm.com/topics/instruction-tuning">Instruction Tuned (IT) Large Language Models</a>. These models are very advanced generative LLMs and have the following key capabilities:</p><ul><li>Ability to accept Super long inputs</li><li>Ability to solve tons of language tasks</li><li>Multiple language support</li><li>Muti-modality</li><li>Performance surpassing even humans</li></ul><p>Now, let’s understand some key things about these models.</p><h3>1.3 Latest LLMs are Mysterious</h3><p>When it comes to integrating AI models into business applications or products, the key considerations usually are: safety, security and performance. Given that the current LLMs are black box models (due to their training and generation process), their behavior can be quite surprising sometimes. Additionally, these LLMs are extremely sensitive to <a href="https://huggingface.co/docs/transformers/en/tasks/prompting">prompting</a> and other input changes.</p><p>Given the surprising behaviors of current LLMs, we must be really careful while deploying these models in production. As their true capabilities and performance is not already known. Thus, it becomes extremely important to design and consider the correct evaluation strategies based on the problem you are solving.</p><p>The next section describes the key evaluation techniques for LLMs.</p><h3>2. Key Evaluation Techniques for LLMs</h3><p>LLM evaluation techniques are a set of metrics and benchmarks that are used to assess the performance of LLMs on a variety of tasks. Some key benefits of evaluating LLMs are as follows:</p><ul><li>Ensures that LLMs are secure, safe and performant</li><li>Helps in comparing two LLMs, based on their performance on various tasks</li><li>Helpful for the developers in identifying areas of improvement for LLMs</li><li>Helps in understanding the business impact of LLMs in applications and products</li></ul><p>LLM evaluation techniques can be broadly categorized into the following three categories:</p><ol><li>Human Evaluation</li><li>Programmatic Evaluation</li><li>AutoRater Evaluation Tool</li></ol><p>Each of these types of evaluation techniques, have their own pros and cons. Together they make an overall LLM evaluation toolkit. In the next sections, we will learn about these methods in more details.</p><h3>3. Human Evaluation</h3><p>In this technique, human evaluators judge the outputs of a LLM against some rubric or against another LLM. This technique is quite popularly used and can be applied for the evaluation of almost any tasks. But, human evaluation is quite slow, expensive and often requires skilled human evaluators.</p><h3>3.1 How does human evaluation work?</h3><p>The idea is to generate a bunch of model outputs and show them to a human for evaluation. Despite it’s drawbacks (slow and costly), this evaluation technique is still considered the gold standard for evaluating LLMs. This is especially useful in case of generative models, as programmatic evaluation may not be reliable every time (for every task).</p><p>There are different platforms available out there for human evaluation, and there are quite a few third-party companies that sell human evaluation as a service.</p><p>Human evaluation is not always perfect. It comes with it’s own challenges. Following are some of the key challenges with human evaluation:</p><ul><li>Quality of human evaluation depends upon the judgement and skills of the evaluator. It is difficult to find (or test) the perfect human evaluator for a given task.</li><li>Even if your evaluation quality is good, you might not get statistically significant pointers for improving the performance. So, it is really important to design the evaluation criteria very carefully.</li></ul><p>Let’s learn about the programmatic evaluation techniques now.</p><h3>4. Programmatic Evaluation</h3><p>In this technique, as the name also suggests, the model output is evaluated using an automated script. Programmatic evaluation requires a golden testing dataset with expected outputs. As this evaluation is done using a script, it is quite fast, but the curation of the golden dataset might take a lot of time and efforts.</p><p>Programmatic evaluation is a good choice when the structure of the output is well defined and the expected outcome is already known. These methods often use known metrics (old ML evaluation metrics such as F1 score, Precision and Recall) for calculating model performance. Some example scenarios where programmatic evaluation can be applied are as follows:</p><ol><li><strong>Sentiment Analysis</strong>: As the sentiment classes are already known (positive, negative, neutral, etc), model can be evaluated using a script.</li><li><strong>Entity Recognition</strong>: An already labelled dataset with known entities can be used for evaluation programmatically.</li><li><strong>Language Identification</strong>: There is a single correct answer.</li><li><strong>Image Classification</strong>: A known labelled data can be used for comparing the model outputs.</li><li><strong>Object Detection:</strong> Already labelled test set can be used for script based evaluation.</li></ol><p>You need to be really careful while curating the golden dataset ensuring that the labels are absolutely correct, and there is no leakage of data between the training and the testing set. The test dataset should cover almost all different scenarios (types of inputs).</p><p>Next, let’s learn about the AutoRater technique.</p><blockquote><em>If you are interested in learning more about the generative learning and Generative Adversarial Networks, Do check out my book:</em></blockquote><blockquote><a href="https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C"><em>https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C</em></a></blockquote><h3>5. AutoRater Evaluation Tool</h3><p>AutoRaters are automated systems or algorithms to assess the performance of models (Note that these are different from programmatic evaluations where the evaluation script is very simple and just compares the model results with known results).</p><p>AutoRater technique is very frequently used for evaluating LLMs. AutoRater can be an AI model itself that was trained to mimic human raters on tasks such translation, creativity analysis or safety analysis.</p><p>As AutoRaters are sometimes LLMs, it is critical to make sure that AutoRater reflects the human raters correctly that it is trying to mimic.</p><p>AutoRaters are a good option for evaluating performance of the LLM on the situations where we want to assess the model for following:</p><ul><li>Quality Assessment</li><li>Semantic Similarity</li><li>Content Relevance</li><li>Diversity and Creativity</li><li>Human Like Characteristics</li></ul><p>In summary, while AutoRater evaluations offer efficient and scalable methods for assessing large language models, they are often complemented by human evaluations to ensure a comprehensive understanding of the model performance.</p><p>In the next section, we will lean about some frequently use key metrics for LLM evaluation.</p><h3>6. Key Metrics for LLM Evaluation</h3><p>In this section, we will learn about some frequently used evaluation metrics for LLMs along with their task specific use cases.</p><h3>6.1 Accuracy, AUC, F1, Precision, Recall</h3><p>Metrics such as accuracy, f1-score, precision and recall are often used for evaluating classification tasks. Where, the top ranked predictions of the model are compared against the already known outputs. These metrics are often used for classification tasks such as Sentiment Analysis, Image Classification and so on.</p><h3>6.2 Toxicity</h3><p>Measures the toxicity of the text. Toxicity of a LLM is usually evaluated using another LLM (an AutoRater) that is specifically trained for identifying toxicity in other models. Common toxicity evaluation tools are — <a href="https://perspectiveapi.com/">Perspective API</a> and Detoxify.</p><h3>3. BLEU</h3><p>Bilingual Evaluation Understudy, or <a href="https://en.wikipedia.org/wiki/BLEU">BLEU</a>, measures the similarity between the model translation and reference translation. BLEU provides sentence level scores, and then the overall score is usually calculated by averaging the scores over full evaluation dataset. Now-a-days, BLEURT is often preferred over BLEU. Next, let’s learn about BLEURT.</p><h3>4. BLEURT</h3><p>Measures if the text generated by model conveys the same meaning as the reference text. <a href="https://arxiv.org/pdf/2004.04696">BLEURT</a> scores are calculated using a regression model trained on ratings data. It is a good metric for evaluating language translations.</p><h3>5. SQuAD</h3><p>Stanford Question Answering Dataset, or <a href="https://huggingface.co/spaces/evaluate-metric/squad">SQuAD</a> for short, is a reading comprehension dataset. This dataset has questions on a set of wikipedia articles, such that the answers to those questions are present as a segment within those articles, or the answer may not be present at all. SQuAD is a very popular metric for evaluating LLMs for question answering use cases, where the answer is present in a already known knowledge base.</p><h3>6. ROUGE</h3><p>Recall-Oriented Understudy for Gisting Evaluation, or <a href="https://en.wikipedia.org/wiki/ROUGE_(metric)">ROUGE</a>, is useful for evaluating text generation tasks like <strong><em>Text-summarization</em></strong>. ROUGE has multiple different versions but the basic idea is to measure the overlap between the text generated by the model and the reference text.</p><p>Some popular variants of ROUGE are:</p><ul><li><strong>ROUGE-N</strong>: Checks the common n-grams between the model generated text and the reference text. ROUGE-1 counts the number of shared unigrams, ROUGE-2 counts the number of shared bigrams and so on. ROUGE-2 is a good metric for evaluating summarization.</li><li><strong>SP-ROUGE-N</strong>: It is ROUGE-N applied to the text that is tokenized using <a href="https://github.com/google/sentencepiece">Sentence Piece (SP) tokenizer</a>.</li><li><strong>ROUGE-L</strong>: Considers the Longest Common Subsequence (LCS), between the model output and the reference text for measuring similarity.</li></ul><p>ROUGE is a popular metric for evaluating summarization and machine translation tasks.</p><h3>Conclusion</h3><p>In this article, we discussed the brief history of evolution of LLMs and the importance of right evaluation strategies before putting them into production.</p><p>We learned about three key evaluation techniques for LLMs: <strong><em>Human Evaluation, Programmatic Evaluation </em></strong>and <strong><em>AutoRater Evaluation</em></strong>. Finally, we listed down some key evaluation metrics for LLMs along with their key use cases.</p><p>I hope this article, <strong><em>Key Evaluation Techniques for LLMs</em></strong>, was helpful for the readers, in understanding the evaluation of LLMs. Please let me know your thoughts by commenting below.</p><p>See you in the next article!</p><h3>Read Next&gt;&gt;&gt;</h3><ol><li><a href="https://dropsofai.com/a-gentle-introduction-to-large-language-models/">A Gentle Introduction to Large Language Models</a></li><li><a href="https://dropsofai.com/beginner-friendly-introduction-to-genai-and-its-applications/">Beginner Friendly Introduction to GenAI and Its Applications</a></li><li><a href="https://dropsofai.com/how-does-a-generative-learning-model-work/">How Does a Generative Learning Model Work?</a></li><li><a href="https://dropsofai.com/building-blocks-of-deep-generative-models/">Building Blocks of Deep Generative Models</a></li><li><a href="https://dropsofai.com/generative-learning-and-its-differences-from-the-discriminative-learning/">Generative Learning and its Differences from the Discriminative Learning</a></li><li><a href="https://dropsofai.com/image-synthesis-using-pixel-cnn-based-autoregressive-generative-model/">Image Synthesis using Pixel CNN based Autoregressive Generative Models</a></li><li><a href="https://dropsofai.com/what-are-autoregressive-generative-models/">What are Autoregressive Generative Models?</a></li><li><a href="https://dropsofai.com/best-practices-for-training-stable-gans/">Best Practices for training stable GANs</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=af902469537e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/understanding-key-evaluation-techniques-for-llms-af902469537e">Understanding Key Evaluation Techniques for LLMs</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Unlocking Video Insights: Extract Thumbnails with Captions using Gemini 1.5 Pro]]></title>
            <link>https://medium.com/google-cloud/extracting-thumbnails-for-a-video-along-with-captions-using-gemini-1-5-pro-3279f5e73c37?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/3279f5e73c37</guid>
            <category><![CDATA[generative-ai]]></category>
            <category><![CDATA[video-analytics]]></category>
            <category><![CDATA[google-gemini-pro]]></category>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[multimodal]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Mon, 23 Sep 2024 02:48:11 GMT</pubDate>
            <atom:updated>2024-09-23T06:49:10.935Z</atom:updated>
            <content:encoded><![CDATA[<h4>A step-by-step tutorial for extracting thumbnails and meaningful captions from videos using the multimodal capabilities of Gemini</h4><p>Video content creation has become very popular, with creators spending a lot of time on eye-catching thumbnails and engaging captions. A great thumbnail and a meaningful caption can really grab viewers’ attention. In this tutorial, we’ll show you how to use Google’s Gemini model to extract interesting thumbnails and captions from a video.</p><p>This article walks you through the step-by-step process of extracting thumbnails, with Python code examples. We’ll also highlight how using better prompts can improve your results.</p><p>Let’s get started.</p><h3>Step 1: Installing Libraries</h3><p>In this tutorial, we will work with the following two python libraries.</p><ol><li><a href="https://cloud.google.com/vertex-ai/docs/python-sdk/use-vertex-ai-python-sdk"><strong>Vertex AI SDK for Python</strong></a>: useful for calling Vertex AI Gemini API.</li><li><a href="https://zulko.github.io/moviepy/"><strong>MoviePy</strong></a>: A module for video editing, we will use it to extract thumbnail images from the source video for a given timestamp.</li></ol><p>Let’s open a terminal and install these two libraries.</p><pre>pip3 install --upgrade --user google-cloud-aiplatform<br>pip3 install --upgrade --user moviepy</pre><h3>Step 2: Import useful libraries</h3><p>Open a <a href="https://www.dataquest.io/blog/jupyter-notebook-tutorial/">Jupyter Notebook</a> (or a <a href="https://colab.research.google.com/">colab</a> notebook) and import the following useful python libraries for our experiment.</p><pre>import json<br>import matplotlib.pyplot as plt<br>import moviepy<br>from moviepy.editor import VideoFileClip<br>from vertexai.generative_models import GenerationConfig, GenerativeModel, Part</pre><h3>Step 3: Setting up the Google Cloud Project</h3><p>To get started using Vertex AI, you must have an existing Google Cloud project and <a href="https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com">enable the Vertex AI API</a>.</p><p>The following python script will set the project information and initialize Vertex AI SDK for the experiment.</p><pre>PROJECT_ID = &quot;your-project-id&quot;  # @param {type:&quot;string&quot;}<br>LOCATION = &quot;us-central1&quot;  # @param {type:&quot;string&quot;}<br><br># Initialize Vertex AI<br>import vertexai<br><br>vertexai.init(project=PROJECT_ID, location=LOCATION)</pre><h3>Step 4: Download a Sample Video</h3><p>In this tutorial, we will use the ‘<em>Google Trips’</em> video as input for thumbnail extraction. This video can be <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/prompt-gallery/samples/video_video_q_and_a_89?hl=en">watched/downloaded from this page.</a></p><p>Download the video and upload it to a Google Cloud Storage (GCS) bucket in the same project. Also, create a local copy of the video in your Python environment. The local copy of the video will help in faster frame extraction with the help of <strong><em>MoviePy</em></strong> package.</p><p>The following python script, copies the video file from GCS bucket to local file storage and creates a <em>MoviePy-Clip</em> object.</p><pre>video_uri = &quot;gs://sample-videofile/sample_video_google_trips.webm&quot;<br>!gsutil cp {video_uri} sample_video.webm<br><br># Creating a MoviePy Clip Object<br>clip = VideoFileClip(&quot;sample_video.webm&quot;)</pre><h3>Step 5: Load Gemini 1.5 Pro model</h3><p>The Gemini 1.5 Pro (gemini-1.5-pro) model is a foundation model that performs well at a variety of multimodal tasks such as visual understanding, classification, summarization, and creating content from image, audio and video. Let’s load this model for our multimodal experiment.</p><p>The following python code creates a model object:</p><pre>model = GenerativeModel(&quot;gemini-1.5-pro&quot;)</pre><h3>Step 6: Define a Function to Call Gemini API</h3><p>In our experiment, we will provide the video file to Gemini model and ask it to extract few good thumbnails with meaningful captions (using a text prompt). Remember, Gemini 1.5 Pro is multimodal and thus it can accept the text and video (with audio) inputs together.</p><p>We will now write a python function for calling the Gemini API. In this function, we first set up the configurations for the model with <a href="https://cloud.google.com/vertex-ai/docs/reference/rest/v1/GenerationConfig">generation parameters</a> and <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/control-generated-output">response schema</a>.</p><p>Response schema will help us in setting up a fixed output format beforehand as we want Gemini to provide us the output in a fixed JSON format. A fixed JSON output would be really easy to parse and interpret. Check out the following python code.</p><pre>def call_gemini(<br>    prompt: str,<br>    gcs_video_path: str,<br>    model: vertexai.generative_models.GenerativeModel,<br>) -&gt; str:<br>    &quot;&quot;&quot;Call Gemini 1.5 Pro API with video and prompt.&quot;&quot;&quot;<br>    # define fixed schema for Gemini outputs<br>    response_schema = {<br>        &quot;type&quot;: &quot;array&quot;,<br>        &quot;items&quot;: {<br>            &quot;type&quot;: &quot;object&quot;,<br>            &quot;properties&quot;: {<br>                &quot;timestamp&quot;: {<br>                    &quot;type&quot;: &quot;string&quot;,<br>                },<br>                &quot;caption&quot;: {<br>                    &quot;type&quot;: &quot;string&quot;,<br>                },<br>            },<br>            &quot;required&quot;: [&quot;timestamp&quot;, &quot;caption&quot;],<br>        },<br>    }<br>    # model configurations<br>    generation_config = GenerationConfig(<br>        temperature=1,<br>        top_p=0.8,<br>        max_output_tokens=8192,<br>        response_schema=response_schema,<br>        response_mime_type=&quot;application/json&quot;,<br>    )<br>    # creating video input for API call<br>    video_input = Part.from_uri(<br>        mime_type=&quot;video/webm&quot;,<br>        uri=gcs_video_path,<br>    )<br>    # calling Gemini API<br>    responses = model.generate_content(<br>        [video_input, prompt],<br>        generation_config=generation_config,<br>        stream=False,<br>    )<br>    return responses.text</pre><p>In this function, we have defined the response schema in such a way that the model would return the “<strong><em>timestamps</em></strong>” of the thumbnails from the videos, along with the <strong><em>captions</em></strong>.</p><h3>Step 7: Parse the model response and display results</h3><p>We now have the model’s response text with us, which returns a JSON output consisting of the <strong><em>timestamps</em></strong> and <strong><em>captions </em></strong>of the resulting thumbnails. We will use the <strong><em>MoviePy</em></strong> library to extract the frame images from the video using these timestamps.</p><p>The following python function, extracts the thumbnails from the video and displays them along with their captions (caption as the title of the image).</p><pre>def display_results(<br>    response_text: str,<br>    clip: moviepy.video.io.VideoFileClip.VideoFileClip,<br>) -&gt; None:<br>    &quot;&quot;&quot;Parse json output, extract thumbnail frames and display.&quot;&quot;&quot;<br>    # loading json output object<br>    json_response = json.loads(response_text)<br><br>    # Image plotting settings<br>    fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(12, 9))<br><br>    # extract frame for each timestamp and plot the images<br>    counter = 0<br>    for item in json_response:<br>        timestamp = item[&quot;timestamp&quot;]<br>        caption = item[&quot;caption&quot;]<br>        frame = clip.get_frame(timestamp)<br>        row, col = counter // 2, counter % 2<br>        ax[row, col].imshow(frame)<br>        ax[row, col].set_title(caption, fontdict={&quot;fontsize&quot;: 9})<br>        counter += 1<br><br>    fig.show()</pre><p>Our utility functions are all set, let’s start experimenting now.</p><h3>Experiment 1: Basic Prompting</h3><p>In our first experiment, we will use a very basic prompt for thumbnail generation, and in the next experiment we will use a more detailed prompt.</p><pre>basic_prompt = (<br>    &quot;&quot;&quot;Generate 4 thumbnail images from the given video file with short captions.&quot;&quot;&quot;<br>)</pre><p>Let’s call the Gemini API, and get the results:</p><pre>response_text = call_gemini(<br>    prompt=basic_prompt,<br>    gcs_video_path=video_uri,<br>    model=model,<br>)</pre><p>Gemini API call will take a few seconds to generate the results. Let’s display the results.</p><pre>display_results(response_text, clip)</pre><p>The following image shows the results of our first experiment with basic prompting. We can see that the model is able to generate some thumbnail candidates but the candidates are not great, also the captions are not telling a good story.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s_NLMhtlHT8lUmaBCSEmUg.png" /><figcaption>Thumbnail Results with basic prompting</figcaption></figure><p>Can we do better with a detailed prompt?</p><h3>Experiment 2: Advanced Prompting</h3><p>Let’s write a more detailed prompt explaining what a good thumbnail actually means. This will help the model in understanding what kind of outputs are expected. Let’s try this.</p><p>Let’s try out the following prompt (a more detailed one).</p><pre>advanced_prompt = &quot;&quot;&quot;You are an expert in video content creation and content marketing.<br>You have the ability to find best thumbnails from a video and provide meaningful and short and catchy captions for them.<br>Your task is to find the best 4 thumbnails from a given video along with short, and meaningful captions that is good for marketing.<br>Consider the following rules while generating thubmnails:<br><br>- Thumbnail should have clear focus on the key objects and people, less focus on background<br>- Thumbnail image should be high quality and bright, avoid blurry images<br>- Thumbnail image and caption together tell a story<br>- Thumbnail caption is good for marketing<br>&quot;&quot;&quot;</pre><p>The following image shows the results after the advanced prompting. We can see that the thumbnail frames are much better this time and even the captions seem really good and meaningful.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KgUP2YiltyB9_4mfOVxqFA.png" /><figcaption>Thumbnail Results with advanced prompting.</figcaption></figure><p>We can see that the results have improved significantly with better prompting.</p><h3>Conclusion</h3><p>In this tutorial, we experimented with the multimodal capabilities of <em>Gemini 1.5 Pro</em> model to extract meaningful thumbnails from an example video, and also generated meaningful captions for them. We noticed that the model is able to understand the video, audio and text simultaneously to answer our question wisely.</p><p>We also noticed that — better prompting can improve the results significantly. A detailed and well-written prompt is really useful for the model to understand the objectives of the experiment, and to generate great results.</p><p>I would recommend the readers to try this experiment out on more sample videos, and also play around with the prompt. Do share your unique prompts and results by commenting below.</p><p>I hope this article was helpful for the readers. Please let me know your feedback!!</p><p>Find the python code here: <a href="https://github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/video-thumbnail-generation/video_thumbnail_generation.ipynb">Github code</a>.</p><p>Connect with me on <a href="https://www.linkedin.com/in/chaudharykartik/">LinkedIn</a>.</p><p>Thanks for reading.</p><p>See you in the next article!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3279f5e73c37" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/extracting-thumbnails-for-a-video-along-with-captions-using-gemini-1-5-pro-3279f5e73c37">Unlocking Video Insights: Extract Thumbnails with Captions using Gemini 1.5 Pro</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Adversarial Examples and Defence Mechanisms against them]]></title>
            <link>https://medium.com/game-of-bits/adversarial-examples-and-defence-mechanisms-against-them-e71892e87b33?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/e71892e87b33</guid>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[adversarial-example]]></category>
            <category><![CDATA[gans]]></category>
            <category><![CDATA[adversarial-attack]]></category>
            <category><![CDATA[generative-adversarial]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Tue, 16 Apr 2024 16:40:04 GMT</pubDate>
            <atom:updated>2024-04-16T16:40:04.718Z</atom:updated>
            <content:encoded><![CDATA[<h4>Understanding Adversarial Examples and Defence Mechanisms</h4><p>Adversarial examples are inputs to Machine Learning (ML) models that are intentionally designed to fool the model. These examples are quite easy to generate and can be created by performing intentional feature perturbation on the inputs. And, as a result they can make the ML models do false predictions. In this article, we will cover adversarial examples and defence mechanisms against them.</p><p>Adversarial examples are often indistinguishable to the human eye. It is really important to study such inputs because they make ML models vulnerable to attacks. These attacks may cause serious security violations in some scenarios. Thus, it is really important to study them and make ML models robust to such adversarial attacks.</p><p>This article covers the following key topics:</p><ul><li>What is Adversarial Machine Learning?</li><li>What are common types of Adversarial Attacks?</li><li>How to defend against Adversarial Attacks?</li><li>Why it is hard to defend against Adversarial Attacks?</li><li>Conclusion</li></ul><blockquote>If you are interested in learning more about the generative learning and Generative Adversarial Networks, Do check out my book:</blockquote><blockquote><a href="https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C"><em>https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C</em></a></blockquote><p>Let’s get started.</p><h3>What is Adversarial Machine Learning?</h3><p>Adversarial Machine Learning is the study of adversarial examples and defence mechanisms against them. Adversarial examples are intentionally generated in order to trick the ML models by using deceptive inputs. Now a days, ML models are extensively used in many security and safety departments and the adversarial attacks are seriously dangerous for such scenarios. Thus, it is important to study such attacks and prepare the defence mechanisms against them.</p><p>Based on the <strong>intentions of the attacker</strong>, the adversarial attacks can be classified into following two categories: <strong>the targeted attacks and the un-targeted attacks.</strong></p><h3>Targeted and Un-Targeted Adversarial Attacks</h3><p>In case of an un-targeted adversarial attack, the only intention of the attacker is to make the ML model do a wrong prediction (irrespective of the outcome). On the other hand, a targeted attack has a target class and the intention of the attacker is not just to make the model do a mistake but also to make the model do a desired mistake and get a wrong prediction that belongs to the desired output class.</p><p>Based on the information that attacker has, the adversarial attacks can be classified into the following two categories: <strong>a white-box attack and a black-box attack.</strong></p><h3>White Box and Black Box Adversarial Attacks</h3><p><strong>A white-box attack</strong> is a scenario where the attacker has full access to the ML model. The<br>attacker is already aware of the model’s architecture and its parameters.</p><p><strong>In a black-box attack</strong>, the attacker can only see the output of the ML model and doesn’t<br>have any other information about it.</p><p>ML has become an essential part of almost every organisation and their key business decisions. Many critical tools built for security and safety purposes are developed using ML algorithms today. Thus, the need to protect these ML systems is also growing really fast.</p><p>In the next sections, we will learn about some common methods of generating adversarial<br>examples and defence mechanisms against them.</p><h3>What are common methods of Adversarial Attacks?</h3><p>As discussed earlier, the adversarial examples are intentionally prepared to make the ML model do a wrong prediction. These examples appear normal to humans but they can cause misclassifications for the target ML models. Many different methods of generating the adversarial examples have been studied.</p><p>Following are some common methods of generating adversarial examples:</p><ul><li>Fast Gradient Sign Method (FGSM)</li><li>Limited-Memory BFGS (L-BFGS)</li><li>Jacobian-based Saliency Map Attack (JSMA)</li><li>Deep Fool Attack</li><li>Carlini &amp; Wagner Attack</li><li>Generative Adversarial Networks (GANs)</li><li>Zeroth-Order Optimisation Attack (ZOO)</li></ul><p>Let’s learn about these methods.</p><h3>Fast Gradient Sign Method (FGSM)</h3><p>Fast Gradient Sign Method, of FGSM, works by using the gradients of the neural network. Because FGSM has access to the model, it comes under the white-box attacking mechanisms. In this method, the input image pixels are perturbed using the information of the gradient of the loss function, such that the model loss is increased. This newly generated input image is called the adversarial image.</p><p>The panda image shown in the following Figure, is a very popular adversarial example generated using FGSM method. This image was taken from the research paper titled “<a href="https://arxiv.org/pdf/1412.6572.pdf">Explaining and Harnessing Adversarial Examples-2015</a>” by <em>Ian J. Goodfellow</em> and fellow researchers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/918/0*AgrEwLak9WqTnrET.png" /><figcaption>Generating an adversarial example using FGSM, taken from the <a href="http://generating%20an%20adversarial%20example%20using%20fgsm%20taken%20from%20the%202015%20paper%20of%20ian%20goodfellow%20et.al./">2015 paper</a> of <em>Ian<br>Goodfellow et.al</em>.</figcaption></figure><p>Let’s learn about L-BFGS now.</p><h3>Limited-Memory BFGS (L-BFGS)</h3><p>Limited memory BFGS, or L-BFGS, is an optimisation algorithm to minimise the number of perturbations added to an image. It is a non-linear gradient-based method. It is quite effective in generating adversarial examples. But it is very computationally expensive.</p><p>Next, let’s learn about JSMA.</p><h3>Jacobian-based Saliency Map Attack (JSMA)</h3><p>JSMA method uses feature selection method to minimise the number of feature perturbations needed to cause the model make a classification mistake. This method is also very computationally intensive.</p><p>Let’s now learn about deep fool attack.</p><h3>Deep Fool Attack</h3><p>Deep Fool attack technique works by minimising the Euclidean distance between the perturbed inputs and the original inputs. In this method, the perturbations are added iteratively based on the decision boundaries. This method of generating adversarial examples is also computationally expensive.</p><p>Let’s move to the next method.</p><h3>Carlini &amp; Wagner Attack</h3><p>This method is based on the L-BFGS algorithm and is more efficient at generating the adversarial examples. This method was able to defeat certain defence mechanisms. Again, this attack is also very computationally expensive.</p><p>Let’s learn about GAN based attack now.</p><h3>Generative Adversarial Networks (GANs)</h3><p>Generative Adversarial Networks, or GANs for short, have also been used for generating adversarial examples. GANs are capable of generating desired number of plausible examples that are similar to the training dataset. Training a GAN is also computationally intensive and highly unstable.</p><p>Let’s now learn about ZOO attack now.</p><h3>Zeroth-Order Optimisation Attack (ZOO)</h3><p>ZOO attack is a black-box adversarial attack that works without even the knowledge of the ML algorithm. This method collects gradient information of the ML model indirectly, by querying the model with modified individual features. One common dis-advantage of ZOO technique is that it requires large number of queries to the underlying ML model.</p><p>Now that we have learned about some common adversarial attack methodologies. Let’s learn about some of the defence mechanism against them.</p><h3>How to defend against Adversarial Attacks?</h3><p>Traditional optimisation techniques such as weight decay, dropouts and so on, generally<br>don’t provide defence against the adversarial attacks. The paper “<a href="https://arxiv.org/pdf/1810.00069.pdf">Adversarial Attacks and Defences: A Survey-2018</a>” by <em>Anirban chakraborty</em> and team describes some common adversarial attacks and defence mechanisms.</p><p>Following are some of the common defence mechanisms against the adversarial attacks,<br>as per their paper:</p><ul><li>Adversarial Training</li><li>Defensive Distillation</li><li>Gradient Hiding</li><li>Feature Squeezing</li><li>Blocking the Transferability</li><li>Defense GAN</li><li>Mag Net</li></ul><p>Let’s discuss these mechanisms.</p><h3>Adversarial Training</h3><p>The adversarial training is a simple brute-force solution to defend the ML models against the adversarial attacks. In this method, a large number of adversarial examples are generated and then the ML model is explicitly trained on them, to make sure that it is not fooled by them.</p><p>In this way, the ML models become robust to such known types of the adversarial examples. However, the attacker might still break this defence using a new attacking mechanism that the model has not seen during the training process.</p><p>Let’s move to the second technique now.</p><h3>Defensive Distillation</h3><p>This method is based on the concept of knowledge distillation of the Neural Networks where, a small ML model is trained to imitate a very large ML model, in order to obtain the computational savings. This small ML model, trained using the probabilistic outputs of the larger ML model, is robust to the adversarial attacks as its loss surface is smoothed in the directions that an adversary will try to exploit. This mechanism makes it hard for the attacker to tweak the adversarial examples for getting a wrong prediction from the ML model.</p><p>Let’s now learn about Gradient Hiding method.</p><h3>Gradient Hiding</h3><p>As discussed earlier, some of the attacking mechanisms such as FGSM, rely on the gradient information from the ML model. Gradient hiding is one way to make those attacks ineffective by using non-differentiable models such as Decision Trees, KNN, Random Forests and so on.</p><p>Let’s now move to the next defence mechanism.</p><h3>Feature Squeezing</h3><p>Feature squeezing is a method of model hardening. In this method, the ML models are made less complex by reducing or squeezing the input features. Simpler ML models are more robust to the small feature perturbations and noise. One dis-advantage with this method is that these ML models are often less accurate because of their simpler nature.</p><p>Let’s now learn about Blocking and Transferability method.</p><h3>Blocking and Transferability</h3><p>The main reason behind the defeat of most of the well-known defence mechanisms; is due to the strong transferability property of the neural networks. For example, the adversarial examples generated on one classifier are expected to cause another classifier to perform the same mistake. The transferability property holds true even if the classifiers have different architectures or have been trained on disjoint datasets.</p><p>Hence, the key for protecting against a black-box attack is to block the transferability of the adversarial examples. Let’s now learn about the next mechanism.</p><h3>Defense-GAN</h3><p>The Defense-GAN mechanism leverages the power of Generative Adversarial Networks to reduce the efficiency of the adversarial perturbations. The central idea of this method is to project the input images onto the range of the generator by minimising the reconstruction error, prior to feeding the image to the classifier. Due to this extra step, the legitimate samples will be closer to the range of the generator than the adversarial samples, resulting in substantial reduction of the potential adversarial perturbations.</p><p>Let’s now learn about MagNet.</p><h3>MagNet</h3><p>MagNet is an adversarial defence framework that uses the classifier as a black box, to read the outputs of the classifier’s last layer without reading the data on any internal layer or modifying the classifier. It uses detectors to distinguish the normal samples from the adversarial examples. The detector measures the distance between the given test example and the manifold and, rejects the sample if the distance exceeds a threshold. It also uses a reformer to reform the adversarial example to a similar legitimate example using the auto-encoders.</p><p>Although MagNet is quite successful in thwarting a range of the black-box attacks, its performance degrades significantly in the case of the white-box attacks where, the attackers are supposed to be aware of the parameters of the MagNet. So, the authors came up with an idea of using varieties of auto-encoders and randomly picking one at a time to make it difficult for the adversary to predict which auto-encoder is actually sitting behind the defence.</p><p>We now have learned about quite a few defence mechanisms against the adversarial attacks. Although these mechanisms are really good at catching the adversarial attacks, still, they can be defeated if the attacker has significantly large number of computational resources. So, an absolute defence against the adversarial attacks, remains a challenge.</p><p>Let’s now learn about the common challenges of defending against the adversarial attacks.</p><h3>Why it is hard to defend against Adversarial Attacks?</h3><p>The adversarial examples are hard to defend against because: it is difficult to build a model of the process of creating an adversarial example. The adversarial examples are the solutions to an optimisation problem (or results of an optimisation algorithm) that is non-linear and non-convex for many neural networks.</p><p>ML models need to provide the good outputs for every possible input. A considerable modification of the model to incorporate the robustness against the adversarial examples, may also change the elementary objective of the model. And, it may result in a bad performing model.</p><p>The defence strategies discussed earlier, work really well against only a certain type of attacks but fail for new kind of attacks because they are not adaptive. If an attacker knows the defence strategies used in a system, then it’s a major vulnerability. Moreover, the implementation of such defence strategies may cause performance overhead as well as the degradation in model accuracy for the actual or intended inputs.</p><p>Thus, it is important to design powerful defence mechanism which are adaptive, to protect ML systems from the adversarial attacks. It is also a growing area of research and let’s see what the future holds.</p><h3>Conclusion</h3><p>In this article, we learned about the adversarial examples, common types of adversarial attacks, common defence mechanisms against them and the importance of designing the appropriate defence mechanisms against them to protect the ML based intelligent systems.</p><p>Specifically, we learned:</p><ul><li>What is adversarial Machine Learning? And, what are adversarial examples?Why they are dangerous to ML systems and how to create them?</li><li>What are some of the known types of adversarial attacks and why it is hard to defend against them?</li><li>How can we make our ML systems robust against the various adversarial attacking mechanisms?</li></ul><p>Originally posted on <a href="https://dropsofai.com/understanding-adversarial-examples-and-defence-mechanisms/">Drops of AI</a>!</p><p>I hope this article was helpful, do share your feedback by commenting below. See you in the next article!</p><h3>Read Next&gt;&gt;&gt;</h3><ol><li><a href="https://dropsofai.com/how-does-a-generative-learning-model-work/">How Does a Generative Learning Model Work?</a></li><li><a href="https://dropsofai.com/building-blocks-of-deep-generative-models/">Building Blocks of Deep Generative Models</a></li><li><a href="https://dropsofai.com/generative-learning-and-its-differences-from-the-discriminative-learning/">Generative Learning and its Differences from the Discriminative Learning</a></li><li><a href="https://dropsofai.com/image-synthesis-using-pixel-cnn-based-autoregressive-generative-model/">Image Synthesis using Pixel CNN based Autoregressive Generative Models</a></li><li><a href="https://dropsofai.com/what-are-autoregressive-generative-models/">What are Autoregressive Generative Models?</a></li><li><a href="https://dropsofai.com/best-practices-for-training-stable-gans/">Best Practices for training stable GANs</a></li><li><a href="https://dropsofai.com/understanding-failure-modes-of-gan-training/">Understanding Failure Modes of GAN Training</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e71892e87b33" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/adversarial-examples-and-defence-mechanisms-against-them-e71892e87b33">Adversarial Examples and Defence Mechanisms against them</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Understanding Failure Modes of GAN Training]]></title>
            <link>https://medium.com/game-of-bits/understanding-failure-modes-of-gan-training-eae62dbcf1dd?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/eae62dbcf1dd</guid>
            <category><![CDATA[genai]]></category>
            <category><![CDATA[generative-adversarial]]></category>
            <category><![CDATA[computer-vision]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[gans]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Mon, 08 Apr 2024 14:45:44 GMT</pubDate>
            <atom:updated>2024-04-08T14:45:44.633Z</atom:updated>
            <content:encoded><![CDATA[<h4>Mode Collapse and Convergence Failure of Generative Adversarial Networks</h4><h3>Failure Modes of GAN Training</h3><p>The idea of two competing neural networks is no doubt interesting; where, at each step one of them attempts to defeat the other one and in the process, both networks keep getting better at their job. But building such a dynamic training system is not always feasible. Generative Adversarial Networks, or GANs, are really difficult to train in practice. GANs usually suffer from two common types of failure modes during training. It is really important to understand these failure modes before training a GAN based model otherwise, we might not be able to develop and train a stable GAN based model. This article will mainly focus on explaining those two common failure modes in details, along with python examples. Once we are able to understand these failure modes, it will be easier for us to start developing and training our own stable GAN based models to generate the data of our choosing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dpvLTNZX0f6vA4KW.jpeg" /><figcaption>An image generated using Google Gemini model | Mode Collapse and Convergence Failure of Generative Adversarial Networks</figcaption></figure><p>This article covers the following topics:</p><ul><li><em>Why GAN training is unstable?</em></li><li><em>What are GAN failure modes?</em></li><li><em>What is mode collapse in GAN training?</em></li><li><em>What is convergence failure in GAN training?</em></li><li><em>Summary</em></li></ul><p>Let’s get started.</p><h3>1. Why GAN training is unstable?</h3><p>Generative Adversarial Networks, or GANs for short, are quite difficult to train in practice. GAN training can be visualised as a two-player zero sum game. The game between the generator and the discriminator is non-cooperative which means that improvements in one model come at the expense of the other model. This kind of setup is only meaningful (or stable) when both players are capacity-wise balanced. For example: If one of the players is very strong, it will dominate the game and will not let the weaker player gain anything. So, basically the weaker model might not be able to learn anything useful. And thus, the balance between two competing models is very important.</p><p>Finding this kind of balance between the generator and the discriminator model can be related to the problem of finding <a href="https://en.wikipedia.org/wiki/Nash_equilibrium">Nash Equilibrium</a> (a game theory concept that determines the optimal solution in a non-cooperative game). A Nash Equilibrium occurs when each player has the minimal cost. Both the players in a GAN setup are neural networks (functions of high-dimensional parameter space), parameters are continuous variables, and the cost functions are non-convex. Finding the Nash Equilibrium in such a setup is not trivial. Also, there is no known algorithm for the same.</p><p>The key idea of keeping each player at minimum cost (Nash Equilibrium) motivates the use of traditional gradient descent-based learning methods. These learning methods can be leveraged for minimising the cost of both players simultaneously. But in our GAN setup, modification in one player’s cost using gradient descent, might influence the other player in a wrong way as well. This is the key reason that leads to the convergence failure of GANs very frequently</p><blockquote>If you are interested in learning more about the generative learning and Generative Adversarial Networks, Do check out my book:</blockquote><blockquote><a href="https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C"><em>https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C</em></a></blockquote><p>As we can see that GANs are very unstable and difficult to train. Thus, it is important to study these common failure modes before developing GANs. Let’s learn about the common GAN failure modes.</p><h3>2. GAN failure modes</h3><p>The best way to check whether the GAN training is successful or not, is to monitor the generated samples very carefully and frequently (along with model loss). After looking at the generated content for a few iterations of training, an experienced AI practitioner will know whether the training is going in the right direction or not. If the training is not going in the right direction, one should stop the training and make required changes to the model and start training again.</p><h4>Understanding Failure Modes of GAN Training</h4><p>Before starting to develop or train GANs, it is important to understand the common failure modes of GAN training. Although, there can be lot many reasons behind the training failure of a GAN like setup, and sometimes they may even be related to the training dataset as well. It is really difficult to identify the exact reason of failure every time. However, the researchers have observed the following two failure modes to be occurring very frequently in case of GANs.</p><ul><li><em>Mode Collapse</em></li><li><em>Convergence Failure</em></li></ul><p>Let’s learn more about these failure modes.</p><h3>3. Mode Collapse in GANs</h3><p>Whenever we train a GAN based generative model, we expect it to generate wide variety of realistic samples. But it’s not always the case. Sometimes, due to an unbalanced training setup, the generator network fails to learn the correct representations and thus, fails to generate large variety of content. This problem with the training of GANs is known as ‘mode collapse’. Mode collapse is quite easy to detect but very difficult to solve. Basically, mode collapse means that the generator model collapses to generate only a limited variety of samples. This failure can be easily detected by inspecting the generated samples during the training phase. If there is very little diversity in the generated samples and some of the generated samples are exactly similar, then there are high chances of mode collapse.</p><p>Sometimes, all of the generated images are exactly same. Such scenario is known as a complete collapse. And the case when the generator collapses to a small variety of samples is termed as a partial collapse of GAN. Partial collapse is quite common whereas we don’t get to see a complete collapse very often. Let’s learn about the reasons behind a mode collapse.</p><h3>3.1 Reasons behind Mode Collapse</h3><p>Mode Collapse happens when the generator network fails to generate a wide variety of content. If the generator network is having a mode collapse and as a result it is producing similar kind of samples again and again, Then, the duty of an ideal discriminator network is to learn to reject those repeated samples as fake. And thus, it should make the generator put some more work into generating samples. But it is not always the case. Sometimes, the discriminator network gets stuck in a local minimum and fails to get out of it in future training steps, the generator takes advantage of this situation and learns to generate only a few variations of images which are good enough to fool the discriminator. In other words, both the players keep optimising to exploit the short-term weakness of the opponent.</p><p>A generator network collapsing for a small variety of samples, even when the input noise vector (<em>z</em>) is always different, indicates that the generator output is independent of <em>z </em>(in simple words, the gradient associated with <em>z </em>approaches to zero). Now that we have built an intuition behind the most probable reasons of model collapse, let’s see how can we solve it.</p><h3>3.2 Solving Mode Collapse</h3><p>Mode collapse, a very common problem leading to the failure of GANs, has led the researchers to find out multiple different ways to solve it. However, we can’t confidently claim that a particular hack would work in a given situation. Following is a list of some of the common hacks (or best practices) to solve mode collapse and make the GANs output wide variety of samples:</p><ul><li><a href="https://en.wikipedia.org/wiki/Wasserstein_GAN">Wasserstein GAN</a> solves this problem with the help of a new loss function that gives the flexibility of training the discriminator to optimality without worrying about the vanishing gradients problem. We will learn about Wasserstein GANs later in this book.</li><li>Unrolled GANs use a different loss function for the generator that doesn’t let it over-optimize for a particular discriminator state. This setup takes feedback from multiple discriminators while updating the generator parameters.</li><li>Increasing the dimensions of the input vector (z) can introduce more variety to the generated content.</li><li>Making the generator more complex (or deeper), such that it is capable of learning the complex representations/features.</li><li>Impairing the discriminator by randomly giving some false labels.</li></ul><p>The hacks listed above have proved to be useful in solving many mode collapse cases as per the study conducted by researchers. We may not be able to tell which hack might solve a given mode collapse problem, but with these hacks, our we should be able to solve most of our mode collapse related issues. Next, let’s learn about another common failure mode of GANs: Convergence Failure.</p><h3>4. Convergence Failure in GANs</h3><p>Convergence failure is a scenario when GAN training fails to converge without even producing any meaningful content. GAN training is a two-player zero sum game where each player learns at the cost of the other one (at each iteration), such a setup needs both players to be chosen carefully in order to establish an equilibrium. If one of the players dominates, the whole GAN setup fails to converge. This kind of problem with the training of GANs is known as <em>Convergence Failure. </em>And in case of a convergence failure, GANs don’t produce any meaningful output.</p><p>Convergence failure is quite frequently observed during the training of GANs. Following are the ways to identify convergence failure:</p><ul><li>The loss of the discriminator network rapidly decreases to a value very close to zero and stays there during the remaining training iterations.</li><li>The samples generated by the generator network are very bad quality and it’s a trivial job for the discriminator to flag them as fake.</li><li>The loss of the generator network either reaches zero or keeps continuously increasing during the entire training phase.</li></ul><p>If our GAN training fails and shows the behavior related to any of the above-described scenarios, our model is most probably having a convergence failure situation. Next, let’s learn about the main reasons behind the convergence failure of GAN training.</p><h3>4.1 Reasons behind Convergence Failure</h3><p>Convergence failure happens when there is no balance between the generator and the discriminator networks. There can be two possible reasons behind this imbalance between the two networks. Following are those two possible scenarios:</p><ul><li>The first scenario is observed when the discriminator is weak, and the generator dominates. In this case, the discriminator is incapable of distinguishing real samples from the fake ones and thus it is not able to provide useful feedbacks to the generator. The generator loss reaches close to zero despite the bad quality of samples generated by it.</li><li>Another possible scenario is when the discriminator is too good at its job. It means that the samples generated by the generator are always rejected and the generator is never able to fool the discriminator during the entire training process. The generator loss in such cases, keeps increasing during training and it produces garbage outputs.</li></ul><p>We now understand the key reasons behind the convergence failure of a GAN training setup. Let’s learn about some ways of solving it.</p><h3>4.2 Solving Convergence Failure</h3><p>There are quite a few tricks to solve the convergence failure problem of GANs. All we have to do is: make the generator and discriminator networks balanced, such that neither of them dominates during the training. Let’s learn about some ways of balancing the two networks.</p><p>Solving for the first scenario where the Generator dominates:</p><ul><li>Make the discriminator deeper, thus better at rejecting the fake samples and making the generator put more work.</li><li>Impairing the generator by adding dropout layers, thus it learns slower and in sync with the discriminator network.</li><li>Making the generator weaker by removing some layers.</li></ul><p>Solving for the second scenario where the Discriminator dominates:</p><ul><li>Impairing the discriminator by randomly giving some false labels to real images.</li><li>Impairing the discriminator by adding dropouts (or other regularization techniques).</li><li>Making the generator deeper, thus better at learning representations/features and producing realistic samples.</li><li>Making the discriminator weaker by removing few layers, thus it learns slowly and in sync with the generator.</li></ul><p>We have just learned about multiple tricks to balance the models for each scenario of convergence failure. All we have to do here is to balance the learning process of both models so that they learn in sync and keep improving each other. Now let’s jump into some hands-on experiments.</p><h3>Conclusion</h3><p>This article highlights the fact that GANs are quite difficult to train. GANs usually suffer from two common training failure scenarios: model collapse and convergence failure. It is quite important to learn to identify and overcome these failure modes before starting to work on GANs. After reading this article, the readers should be confident about answering the following questions about GAN failure modes:</p><ul><li>Why GANs are hard to train? What are the common problems they suffer from during training?</li><li>How to identify the mode collapse failure during the GAN training? What are the different tricks to solve it?</li><li>What are the common reasons behind the convergence failure of a GAN? How can we identify it during the training process? What are the tips and tricks to avoid and solve this issue?</li></ul><h3>Read Next&gt;&gt;&gt;</h3><ol><li><a href="https://dropsofai.com/what-are-autoregressive-generative-models/">What are Autoregressive Generative Models?</a></li><li><a href="https://dropsofai.com/building-blocks-of-deep-generative-models/">Building Blocks of Deep Generative Models</a></li><li><a href="https://dropsofai.com/generative-learning-and-its-differences-from-the-discriminative-learning/">Generative Learning and its Differences from the Discriminative Learning</a></li><li><a href="https://dropsofai.com/how-does-a-generative-learning-model-work/">How Does a Generative Learning Model Work?</a></li><li><a href="https://dropsofai.com/image-synthesis-using-pixel-cnn-based-autoregressive-generative-model/">Image Synthesis using Pixel CNN based Autoregressive Generative Models</a></li><li><a href="https://dropsofai.com/autoencoders-in-keras-and-deep-learning/">AutoEncoders in Keras and Deep Learning</a></li><li><a href="https://dropsofai.com/optimizers-explained-for-training-neural-networks/">Optimizers explained for training Neural Networks</a></li><li><a href="https://dropsofai.com/optimizing-tensorflow-models-with-quantization-techniques/">Optimizing TensorFlow models with Quantization Techniques</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eae62dbcf1dd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/understanding-failure-modes-of-gan-training-eae62dbcf1dd">Understanding Failure Modes of GAN Training</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Image Synthesis using Pixel CNN based Autoregressive Generative Model]]></title>
            <link>https://medium.com/game-of-bits/image-synthesis-using-pixel-cnn-based-autoregressive-generative-model-05179bf662ff?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/05179bf662ff</guid>
            <category><![CDATA[image-generation]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[image-synthesis]]></category>
            <category><![CDATA[generative-learning]]></category>
            <category><![CDATA[computer-vision]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Sat, 17 Feb 2024 16:32:26 GMT</pubDate>
            <atom:updated>2024-02-17T16:32:26.734Z</atom:updated>
            <content:encoded><![CDATA[<h4>Implementing Pixel CNN for Handwritten Digit Image Generation</h4><h3>Introduction</h3><p>Recent advances in the field of deep learning have led to the development of complex generative models that are capable of generating high quality content in the form of text, audio, pictures, videos and so on. Generative models that make use of deep learning architectures to tackle the task of learning distributions, are known as deep generative models. Due to the flexibility and scalability of neural networks, deep generative models have become the most exciting and swiftly evolving field of ML and AI. Deep generative modeling techniques have helped in developing modern AI agents that are constantly generating and processing vast amounts of data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6rPZcnuSvJINI8rT.jpeg" /><figcaption><strong>A beautiful Sunset | Image by Author</strong></figcaption></figure><p>Generative learning with deep neural networks is creating wonders today. There are quite a few popular deep generative learning frameworks that are an active area of research. In this article we will learn about one such generative learning framework — Autoregressive Generative Models. We will also develop a Pixel CNN based autoregressive generative model from scratch.</p><p>This article has the following four parts.</p><ol><li><strong>Autoregresssive Generative Models</strong></li><li><strong>Pros and Cons of Autoregresssive Generative Models</strong></li><li><strong>Image Synthesis using Pixel CNN</strong></li><li><strong>Conclusion</strong></li></ol><p>Let’s get started.</p><h3>1. Autoregressive Generative Models</h3><p>The term ‘<em>autoregressive</em>’ is taken from the field of time-series forecasting where a model considers the past observations in an ordered or timely manner, to make predictions about the future. Autoregressive generative models are also quite similar in nature, as they also take help from all of their past predictions for deciding the subsequent prediction.</p><p>For example: an autoregressive model may generate an image by predicting one pixel at a time. Here each new pixel value is estimated based on the previously predicted or observed pixel values. In statistical terms, an autoregressive model is trained to learn the conditional distribution of each individual pixel given the surrounding pixels that are already known (or have already been estimated by the same model in earlier iterations).</p><p>Pixel CNN, Pixel RNN, Character CNN, Character RNN and Wave-Net are some popular examples of the Deep Autoregressive Generative models. Some of these models have also been successfully applied in the field of anomaly detection and adversarial attacks detection.</p><h3>2. Pros and Cons of Autoregressive Generative Models</h3><p>Following is a list of some pros of autoregressive generative models:</p><ul><li><em>Easy to understand and calculate likelihoods</em></li><li><em>Training process is supervised and very straight-forward</em></li></ul><blockquote><em>To get a deeper and intuitive understanding of the autoregressive generative modeling framework, check out my article on :</em></blockquote><blockquote><a href="https://dropsofai.com/what-are-autoregressive-generative-models/"><em>What are Autoregressive Generative Models?</em></a></blockquote><p>Let’s now look at some of the cons of autoregressive approach:</p><ul><li><em>Requires an ordering of random variables</em></li><li><em>Generation process is sequential, hence very slow</em></li><li><em>High likelihood does not guarantee better looking samples in practice</em></li><li><em>Does not learn unsupervised features (or representations)</em></li></ul><p>Now that we know the basic idea behind autoregressive generative models, let’s develop a Pixel CNN model from scratch for image synthesis.</p><h3>3. Image Synthesis using Pixel CNN</h3><p>In this example, we will implement and train an autoregressive generative model called ‘Pixel CNN’ on MNIST handwritten digits dataset and verify its generative capabilities.</p><p>The code related to this experiment can be found <a href="https://github.com/kartikgill/The-GAN-Book/blob/main/Skill-01/Pixel-CNN-for-MNIST.ipynb">here on Github</a>.</p><p>This example has the following steps:</p><ul><li><em>Download and show data</em></li><li><em>Data Preparation</em></li><li><em>Define Masked CNN layers</em></li><li><em>Define Pixel-CNN</em></li><li><em>Training Pixel-CNN Model</em></li><li><em>Results</em></li></ul><p>Let’s get started.</p><h4>Step 1: Importing Libraries</h4><p>As a first step, we will import some useful python libraries in a Jupyter Notebook cell. See the following snippet.</p><pre>import numpy as np<br>import matplotlib.pyplot as plt  <br>import pandas as pd  <br>import seaborn as sns  <br>import warnings  <br>warnings.filterwarnings(&#39;ignore&#39;)  <br>%matplotlib inline  <br>import tensorflow  <br>print (tensorflow.__version__)</pre><p>We will be using TensorFlow library with version 2.4.1 for our experiments.</p><pre>Out[1]: 2.4.1</pre><p>Now, let’s download the dataset.</p><h4>Step 2: Download and show data</h4><p>In this step, we will download the MNIST Handwritten Digits dataset. This is a very common dataset and thus it is also available in keras datasets. The following python code downloads the data and plot’s some handwritten digit images to verify the samples.</p><pre>from tensorflow.keras.datasets import mnist<br><br>(trainX, trainy), (testX, testy) = mnist.load_data()  <br>print(&#39;Training data shapes: X=%s, y=%s&#39; % (trainX.shape, trainy.shape))  <br>print(&#39;Testing data shapes: X=%s, y=%s&#39; % (testX.shape, testy.shape))  <br>for k in range(9):  <br>    plt.figure(figsize=(9,6))  <br>    for j in range(9):  <br>        i = np.random.randint(0, 10000)  <br>        plt.subplot(990 + 1 + j)  <br>        plt.imshow(trainX[i], cmap=&#39;gray_r&#39;)  <br>        plt.axis(&#39;off&#39;)  <br>        #plt.title(trainy[i])  <br>    plt.show()</pre><p>Here is the output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/0*0-so9NnvOX2d2n2x.png" /><figcaption>Figure 1 : A glimpse of MNIST Handwritten Digits dataset.</figcaption></figure><p>Figure 1 gives a basic idea about the MNIST handwritten digits dataset. It has around 60k training images and 10k test images each with dimensions: 28 x 28.</p><p>Now, let’s prepare the dataset for the model.</p><h4>Step 3: Data Preparation</h4><p>In this step, we will prepare our dataset for the model training purpose. Firstly, we will convert these images into binary format (as expected by our basic Pixel CNN). Secondly, we will add a channel dimension to all the images, as expected by the Convolutional layers in our Pixel CNN.</p><pre>trainX = np.where(trainX &lt; (0.33 * 256), 0, 1)<br>train_data = trainX.astype(np.float32)  <br>testX = np.where(testX &lt; (0.33 * 256), 0, 1)  <br>test_data = testX.astype(np.float32)  <br>train_data = np.reshape(train_data, (60000, 28, 28, 1))  <br>test_data = np.reshape(test_data, (10000, 28, 28, 1)) <br>print (train_data.shape, test_data.shape)</pre><p>Following is the final shape of our dataset after pre-processing:</p><pre>Out[3]: (60000, 28, 28, 1) (10000, 28, 28, 1)</pre><p>Our data is now ready. We can now define the Pixel CNN architecture.</p><h4><strong>Step 4: Define Masked CNN layers</strong></h4><p>In this step, we will define some building blocks of our Pixel CNN framework. First, we will define a <em>PixelConvLayer</em> class. A Pixel CNN layer is simply built on top of 2D Convolutional layers. Only difference is that it includes masking in order to accommodate the autoregressive training of the network. In simple words, autoregressive models generate output one pixel at a time, so, masking is a clever way to train Pixel CNN with regular CNN layers.</p><p>See the python code below for Pixel CNN layer implementation:</p><pre>class PixelConvLayer(tensorflow.keras.layers.Layer):<br>    def __init__(self, mask_type, **kwargs):  <br>            super(PixelConvLayer, self).__init__()  <br>            self.mask_type = mask_type  <br>            self.conv = tensorflow.keras.layers.Conv2D(**kwargs)  <br>        def build(self, input_shape):  <br>            # Build the conv2d layer to initialize kernel variables  <br>            self.conv.build(input_shape)  <br>            # Use the initialized kernel to create the mask  <br>            kernel_shape = self.conv.kernel.get_shape()  <br>            self.mask = np.zeros(shape=kernel_shape)  <br>            self.mask[: kernel_shape[0] // 2, ...] = 1.0  <br>            self.mask[kernel_shape[0] // 2, : kernel_shape[1] // 2, ...] = 1.0  <br>            if self.mask_type == &quot;B&quot;:  <br>                self.mask[kernel_shape[0] // 2, kernel_shape[1] // 2, ...] = 1.0  <br>        def call(self, inputs):  <br>            self.conv.kernel.assign(self.conv.kernel * self.mask)  <br>            return self.conv(inputs)</pre><p>Secondly, we will define a residual block layer. It is also a normal residual block, which is based on the Pixel CNN layer. See the following code:</p><pre>class ResidualBlock(tensorflow.keras.layers.Layer):<br>    def __init__(self, filters, **kwargs):  <br>            super(ResidualBlock, self).__init__(**kwargs)  <br>            self.conv1 = tensorflow.keras.layers.Conv2D(  <br>                filters=filters, kernel_size=1, activation=&quot;relu&quot;  <br>            )  <br>            self.pixel_conv = PixelConvLayer(  <br>                mask_type=&quot;B&quot;,  <br>                filters=filters // 2,  <br>                kernel_size=3,  <br>                activation=&quot;relu&quot;,  <br>                padding=&quot;same&quot;,  <br>            )  <br>            self.conv2 = tensorflow.keras.layers.Conv2D(  <br>                filters=filters, kernel_size=1, activation=&quot;relu&quot;  <br>            )  <br>        def call(self, inputs):  <br>            x = self.conv1(inputs)  <br>            x = self.pixel_conv(x)  <br>            x = self.conv2(x)  <br>            return tensorflow.keras.layers.add([inputs, x])</pre><p>We now have the building blocks ready for our Pixel CNN. We can now go ahead and define the final Pixel CNN architecture.</p><h4>Step 5: Define Pixel CNN</h4><p>In this step, we will define the final Pixel CNN model architecture. This architecture is very similar to the one shown in <a href="https://arxiv.org/pdf/1601.06759.pdf">original Pixel CNN paper</a>. It combines Pixel CNN layers with residual blocks as shown in the following python code:</p><pre>inputs = tensorflow.keras.Input(shape=(28,28,1))<br>x = PixelConvLayer(  <br>    mask_type=&quot;A&quot;, filters=128, kernel_size=7, activation=&quot;relu&quot;, padding=&quot;same&quot;  <br>)(inputs)  <br>for _ in range(5):  <br>    x = ResidualBlock(filters=128)(x)  <br>for _ in range(2):  <br>    x = PixelConvLayer(  <br>        mask_type=&quot;B&quot;,  <br>        filters=128,  <br>        kernel_size=1,  <br>        strides=1,  <br>        activation=&quot;relu&quot;,  <br>        padding=&quot;valid&quot;,  <br>    )(x)  <br>out = tensorflow.keras.layers.Conv2D(  <br>    filters=1, kernel_size=1, strides=1, activation=&quot;sigmoid&quot;, padding=&quot;valid&quot;  <br>)(x)  <br>pixel_cnn = tensorflow.keras.Model(inputs, out)  <br>pixel_cnn.summary()</pre><p>Following is the final summary of our Pixel CNN model. It has roughly 500k trainable parameters.</p><pre>_________________________________________________________________<br>Layer (type)                 Output Shape              Param #   <br>=================================================================<br>input_1 (InputLayer)         [(None, 28, 28, 1)]       0         <br>_________________________________________________________________<br>pixel_conv_layer (PixelConvL (None, 28, 28, 128)       6400      <br>_________________________________________________________________<br>residual_block (ResidualBloc (None, 28, 28, 128)       98624     <br>_________________________________________________________________<br>residual_block_1 (ResidualBl (None, 28, 28, 128)       98624     <br>_________________________________________________________________<br>residual_block_2 (ResidualBl (None, 28, 28, 128)       98624     <br>_________________________________________________________________<br>residual_block_3 (ResidualBl (None, 28, 28, 128)       98624     <br>_________________________________________________________________<br>residual_block_4 (ResidualBl (None, 28, 28, 128)       98624     <br>_________________________________________________________________<br>pixel_conv_layer_6 (PixelCon (None, 28, 28, 128)       16512     <br>_________________________________________________________________<br>pixel_conv_layer_7 (PixelCon (None, 28, 28, 128)       16512     <br>_________________________________________________________________<br>conv2d_18 (Conv2D)           (None, 28, 28, 1)         129       <br>=================================================================<br>Total params: 532,673<br>Trainable params: 532,673<br>Non-trainable params: 0<br>_________________________________________________________________</pre><p>Our Pixel CNN architecture is now ready. We will utilize <a href="https://dropsofai.com/optimizers-explained-for-training-neural-networks/"><em>Adam</em> optimizer</a> with a learning rate of 0.0005 for updating the weights of our model during training. Also, we will utilize ‘<a href="https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html"><em>binary_crossentropy</em>’</a> as a loss function for our model.</p><p>Remember, Pixel CNN generates image one pixel at a time, and our setup considers binary images with values 0 and 1. Thus, ‘<em>binary_crossentropy’</em> loss makes sense here.</p><h4>Compiling Pixel CNN:</h4><pre>adam = tensorflow.keras.optimizers.Adam(learning_rate=0.0005)<br>pixel_cnn.compile(optimizer=adam, loss=&quot;binary_crossentropy&quot;)</pre><p>Our Pixel CNN is now ready for training.</p><h4>Step 6: Training Pixel-CNN Model</h4><p>In this step, we will train the Pixel CNN model on MNIST Handwritten Digits dataset. We will train our model for 50 epochs with a batch size of 128.</p><pre>pixel_cnn.fit(  <br>    x=train_data,<br>    y=train_data,<br>    batch_size=128,<br>    epochs=50,<br>    validation_data=(test_data, test_data),<br>    verbose=1,<br>)</pre><p>Following are the training logs. We can see that the validation loss is decreasing consistently, which proves that the model is learning:</p><pre>Epoch 1/50<br>469/469 [==============================] - 57s 116ms/step - loss: 0.1748 - val_loss: 0.0923<br>Epoch 2/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0918 - val_loss: 0.0892<br>Epoch 3/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0894 - val_loss: 0.0882<br>Epoch 4/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0881 - val_loss: 0.0873<br>.  .  .  .  .<br>.  .  .  .  .<br>.  .  .  .  .<br>.  .  .  .  .<br>Epoch 45/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0815 - val_loss: 0.0829<br>Epoch 46/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0815 - val_loss: 0.0827<br>Epoch 47/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0813 - val_loss: 0.0829<br>Epoch 48/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0812 - val_loss: 0.0829<br>Epoch 49/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0813 - val_loss: 0.0830<br>Epoch 50/50<br>469/469 [==============================] - 53s 113ms/step - loss: 0.0812 - val_loss: 0.0828</pre><p>As our model training is complete now, we can now check the results.</p><h4>Step 7: Results (Image Synthesis using Pixel CNN)</h4><p>The following python code utilizes our Pixel CNN model for generating handwritten digit images. It also plots some of the generated results.</p><pre>from IPython.display import Image, display<br>from tqdm import tqdm_notebook  <br># Create an empty array of pixels.  <br>batch = 81  <br>pixels = np.zeros(shape=(batch,) + (pixel_cnn.input_shape)[1:])  <br>batch, rows, cols, channels = pixels.shape  <br># Iterate over the pixels because generation has to be done sequentially pixel by pixel.  <br>for row in tqdm_notebook(range(rows)):  <br>    for col in range(cols):  <br>        for channel in range(channels):  <br>            # Feed the whole array and retrieving the pixel value probabilities for the next  <br>            # pixel.  <br>            probs = pixel_cnn.predict(pixels)[:, row, col, channel]  <br>            # Use the probabilities to pick pixel values and append the values to the image  <br>            # frame.  <br>            pixels[:, row, col, channel] = tensorflow.math.ceil(  <br>              probs - tensorflow.random.uniform(probs.shape)  <br>            )  <br>counter = 0  <br>for i in range(9):  <br>    plt.figure(figsize=(9,6))  <br>    for j in range(9):  <br>        plt.subplot(990 + 1 + j)  <br>        plt.imshow(pixels[counter,:,:,0], cmap=&#39;gray_r&#39;)  <br>        counter += 1  <br>        plt.axis(&#39;off&#39;)  <br>    plt.show()</pre><p>Figure 2 shows the output of our Pixel CNN model. We can see that the output images look very close to the actual handwritten digits. They are not perfect though, due to the limitations of the framework, model capacity and dataset.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/456/0*fBQh5pd11pfxxNE1.png" /><figcaption>Figure 2: Handwritten Digit Images generated using the Pixel CNN model.</figcaption></figure><p>Yay! We have now successfully implemented, trained and validated the Pixel CNN model.</p><h3>4. Conclusion</h3><p>In this article, we discussed about a popular generative learning framework: Autoregressive Generative Models. We have also implemented a Pixel CNN based autoregressive generative model for image synthesis from scratch in python. Our results prove that Pixel CNN framework is capable of generating images one pixel at a time. Although the results are not perfect. These results can be improved by increasing the capacity of the model, increasing the size of the dataset, and also by using a better generative learning modeling framework such as — Generative Adversarial Networks (GANs), Variational AutoEncoders (VAEs), Diffusion based models and so on.</p><blockquote>If you are interested in learning more about the generative learning and Generative Adversarial Networks, Do check out my book:</blockquote><blockquote><a href="https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C"><em>https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C</em></a></blockquote><p>I hope this article was helpful. Please let me know your feedback/suggestions by commenting below.</p><p>See you in the next article!</p><h3>Read Next&gt;&gt;&gt;</h3><ol><li><a href="https://dropsofai.com/what-are-autoregressive-generative-models/">What are Autoregressive Generative Models?</a></li><li><a href="https://dropsofai.com/building-blocks-of-deep-generative-models/">Building Blocks of Deep Generative Models</a></li><li><a href="https://dropsofai.com/generative-learning-and-its-differences-from-the-discriminative-learning/">Generative Learning and its Differences from the Discriminative Learning</a></li><li><a href="https://dropsofai.com/how-does-a-generative-learning-model-work/">How Does a Generative Learning Model Work?</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-introduction/">Deep Learning with PyTorch: Introduction</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-first-neural-network/">Deep Learning with PyTorch: First Neural Network</a></li><li><a href="https://dropsofai.com/autoencoders-in-keras-and-deep-learning/">AutoEncoders in Keras and Deep Learning</a> (Introduction)</li><li><a href="https://dropsofai.com/optimizers-explained-for-training-neural-networks/">Optimizers explained for training Neural Networks</a></li><li><a href="https://dropsofai.com/optimizing-tensorflow-models-with-quantization-techniques/">Optimizing TensorFlow models with Quantization Techniques</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=05179bf662ff" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/image-synthesis-using-pixel-cnn-based-autoregressive-generative-model-05179bf662ff">Image Synthesis using Pixel CNN based Autoregressive Generative Model</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Understanding Generative Learning for Computer Vision]]></title>
            <link>https://medium.com/game-of-bits/how-does-a-generative-learning-model-work-cb51e52d3f4a?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/cb51e52d3f4a</guid>
            <category><![CDATA[probability-distributions]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[generative-learning]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Wed, 07 Feb 2024 15:40:23 GMT</pubDate>
            <atom:updated>2024-02-07T15:58:07.623Z</atom:updated>
            <content:encoded><![CDATA[<h4>A Gentle Introduction to Generative Learning Models!</h4><p>Generative Learning refers to a special class of statistical models that are capable of generating content that is very hard to distinguish from the reality (or fake content that looks real). The generated content could be poems, images, music, songs, videos, 3D objects or content from some other domain we could imagine. A domain is nothing but a fancy word for a bunch of examples that follow some common pattern. In this article, we will learn: how does a generative learning model work?</p><p>Interesting part about the generative models is that, sometimes, the content generated by them is not just realistic, its completely new as well (or unseen in the training examples). Everyone must have seen or heard about the modern technologies that can generate very realistic faces of the people that do not even exist in the world. Projects such as Face aging apps, Virtual try-on, Photos to paintings and a lot more advancements with similar technologies are examples of the generative models.</p><p>Let’s now learn how exactly does a generative learning model work.</p><blockquote><em>Check out my introductory article on “</em><a href="https://dropsofai.com/generative-learning-and-its-differences-from-the-discriminative-learning/"><em>Generative Learning and its Differences from the Discriminative Learning</em></a><em>”</em></blockquote><h3>How does a Generative Learning Model work?</h3><p>To understand how does the generative learning work: lets first define an example problem and then we will discuss how a generative model will solve it. Let’s assume that we have a dataset (D) of 1 million cat images representing multiple breeds of cats across the world and the photographs have been taken from almost all possible angles. Note that the number 1 million is significant here, as generative models generally require larger datasets to estimate the target distribution more accurately.</p><p>Because a generative learning approach estimates the data distribution to solve a problem, our focus is to define a generative model that is capable of learning the distribution (𝑷𝒄𝒂𝒕𝒔) that these cat images represent. Every dataset represents some data distribution that it is originally sampled from, and that data distribution is known as the true distribution of that particular dataset. Here 𝑷𝒄𝒂𝒕𝒔 is the distribution of all possible cat images in the universe and this dataset is sampled from it as a representative of the true data distribution.</p><p>If somehow, our model (<strong><em>p</em></strong>) is able to learn the distribution 𝑷𝒄𝒂𝒕𝒔, It will be able to answer all possible questions about cats present in this universe. For example:</p><ul><li><em>It will be able to tell whether a given image x represents a cat or not. If the<br>likelihood value 𝒑(𝒙) is high, then x is definitely a cat or vice-versa.</em></li><li><em>Secondly, if you go ahead and sample an image from 𝒑(𝒙), it will always be a cat image. In this way, it will be able to generate cat images infinitely.</em></li></ul><p>This example gave us a much better understanding of generative models. We now understand that a generative model first learns the underlying data distribution so that later it could answer any questions about that data. But in reality, learning a data distribution is not trivial. To understand how complex, it can be to learn a joint distribution, we first need to understand what does a joint distribution actually mean?<br>The following subsection explains the joint distributions.</p><h3>1. Joint Distribution</h3><p>As we all are aware, the digital images are made up of pixels. Each pixel inside an image, represents a colour and a group of such colour pixels, may represent the objects inside that image. In digital computers and smartphones, each pixel is represented using three discrete random variables R, G and B representing the intensity of three colours — Red, Green and Blue.</p><p>In a given digital image, <a href="https://en.wikipedia.org/wiki/Pixel">each colour pixel</a> represented by these three random discrete variables, can choose any random discrete integer value from the range [0, 255] for each variable R, G and B. We can represent the joint distribution of a single-coloured pixel by 𝒑(𝑹, 𝑮, 𝑩) such that sampling from this distribution (𝒓,𝒈, 𝒃)~𝒑(𝑹, 𝑮, 𝑩) always generates a colourful pixel. In this case, the total number of parameters required to<br>specify the joint distribution 𝒑(𝑹, 𝑮, 𝑩) would be:</p><p><strong>= 256 x 256 x 256–1 = 256^3–1</strong></p><p>Here, as each random variable has 256 possible values, so total parameters required to specify this true distribution would be on less than the total possible combinations, as shown in the calculation above.</p><p>This was just a single pixel, now think about an image with 100x100 dimensions (though it’s a pretty low-resolution image) that is made up of 10,000 such colourful pixels. Now, can you imagine the number of parameters required to represent a true joint distribution of all such possible 100x100 dimension colour images? Pretty huge right. Let’s calculate it. We just need to multiply the number of possible combinations of one coloured pixel ten thousand time. Check the following calculation.</p><p><strong>= (256^3–1) x (256^3–1) x …… 10,000 times</strong><br><strong>= 256^30,000 (approximately)</strong></p><p>This number is pretty huge. Now if I ask you, can you prepare a dataset that can efficiently represent the above-described distribution of color images with 100 x 100 resolution? The answer is pretty obvious:</p><p><strong>“Never”.</strong></p><p>It is impossible to practically represent the true data distribution in this case, no matter how big dataset you have, it’s never enough. Any given dataset, representing a distribution 𝑷𝑫𝒂𝒕𝒂𝒔𝒆𝒕 , is a “not very efficient” representative of the true data distribution. Now, one question that pops up in our mind is: Do we really need to model the true joint distribution? Can we settle for less (something like 𝑷𝑫𝒂𝒕𝒂𝒔𝒆𝒕)?</p><p>Actually, modelling the true distributions is pointless as they are deterministic in nature. In other words, if we already have the required information about the true distribution, we don’t really need to model it. For example: the distribution of all the possible colorful images of dimensions 100x100, we don’t actually need to model it.</p><p>Because we already know that any random color image of 100x100 dimensions will always belong to the aforementioned distribution with 100% confidence. Thus, there is no point in learning such distributions.</p><p>The aforementioned data distribution is deterministic in nature, because we assumed the pixels to be independent from each other. What if the pixels are somehow related? This relation between pixels can restrict the given true distribution to represent only a particular class of colour images, such as the dataset of 1 million cats where pixels are not independent.</p><p>The dataset of 1 million cat images can be considered as a restricted distribution due to the pixel relationships. Learning this kind of restricted distribution, instead of the true joint distribution described above, can be helpful. To understand this, let’s get into more details about the restricted distributions next.</p><h3>2. Restricted Distribution</h3><p>Now, let’s get back to our dataset of 1 million cat images. Let’s assume that our dataset has the distribution 𝑷𝒄𝒂𝒕𝒔 which is supposed to be close to the real distribution of all the possible cats in this universe. Imagine, we are able to learn a generative model 𝑷𝑴𝒐𝒅𝒆𝒍 (model distribution) such that 𝑷𝑴𝒐𝒅𝒆𝒍 is very close to 𝑷𝒄𝒂𝒕𝒔 (from our dataset).</p><p>Using this model distribution (𝑷𝑴𝒐𝒅𝒆𝒍), we should be able to perform the following tasks such as –</p><ul><li><strong>Generation:</strong> <em>Sampling from the model (𝒙𝒏𝒆𝒘 ~𝑷𝑴𝒐𝒅𝒆𝒍) will always generate a cat image and it will give us the flexibility of generating infinite number of cat images if required. (See example in Figure below).</em></li><li><strong>Prediction:</strong> <em>It will be able to tell whether a given image x, represents a cat or<br>not. If the likelihood value 𝑷𝑴𝒐𝒅𝒆𝒍(x) is high, x is a cat or vice-versa.</em></li><li><strong>Representation Learning:</strong> <em>The model will be capable of learning the<br>unsupervised features related to cats such as breed, colour, eyes, tail and so on<br>without explicitly providing labels for these attributes.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/934/0*kV6Dwkh3mb9C1s8Y.png" /><figcaption>Generated sample x, sampled from probability distribution p(x)</figcaption></figure><p>Given the above notion, a conditional generative model is also possible. Suppose that we want to generate a set of variables: Y, given some other set of variables: X, we can directly train a generative model to learn the conditional distribution 𝑷(𝒀|𝑿) without worrying about the joint distribution. This is very similar to the sequence generation<br>tasks where the next candidate of the sequence is predicted given some already existing candidates. Another popular example of conditional generative models is: Latent variable based generative models. Let’s discuss how latent variable based generative models actually work.</p><h3>3. Latent variable based Generative Models</h3><p>To understand the latent variable based generative models, let’s get back to our dataset of 1 million cat images. This dataset is not annotated and it means that there is no information about the kind of cat, that is present in a given picture. Now suppose that we want to train a generative model on this dataset, so that later we can use it to generate some cat images. But this time we would like our model to generate the images of desired type of cats, instead of generating random cat images. This time, we are asking the model to learn unsupervised features as well, along with the data<br>distribution so that it is able to answer questions like: Generate an orange long-haired cat image! The term ‘unsupervised features’ makes sense here because we are not providing the model with any labelled information for learning these features.</p><blockquote><strong><em>Latent Variable: </em></strong><em>A Latent variable is a variable that is hidden or that is not directly observed but is actually inferred from other variables that are observed.</em></blockquote><p>The idea is to learn these unsupervised features, such as colours, hair-length, poses and so on, with the help of a latent vector (z). Here, the latent vector z is expected to represent these high-level features of cat images. In this case, a cat image of desired type can be sampled from the conditional distribution 𝒑(𝒙|𝒛), if we are able to provide the correct value of z here. Now, our objective has changed and our new goal is to learn the conditional distribution 𝒑(𝒙|𝒛), instead of the joint distribution P(x) which was<br>more complex. Figure below shows the high-level idea of sampling from this new model, this time sampling is conditioned on the latent input.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*OXOkSsY3GQmi013C.png" /><figcaption>Generated Sample x, sampled from conditional distribution p(x | z)</figcaption></figure><p>Now the real question is: How do we know what value of z generates which type of cat images? Because the training is also completely unsupervised (or unlabelled), we can’t really have control over the latent variables.</p><p>But here the trick, we will let our model learn the conditional distribution 𝒑(𝒙|𝒛) and then, we can simply reverse the equation and learn the reverse conditional distribution 𝒑(𝒛|𝒙). Using this simple trick, we will be able to map the generated cats back to their input latent vector z, and hence, we will be able to find out what value of z generates which type of cat image.</p><blockquote>If you are interested in learning more about the generative learning and Generative Adversarial Networks, Do check out my book:</blockquote><blockquote><a href="https://www.amazon.com/GAN-Book-Generative-Adversarial-TensorFlow2-ebook/dp/B0CR8C725C?ref_=ast_author_dp">The GAN Book: Train stable Generative Adversarial Networks using Tensorflow2, Keras and Python</a></blockquote><p>Our plan seems simple, but again, learning this conditional distribution 𝒑(𝒙|𝒛) is a challenging task and we cannot be 100% sure that it will learn the desired features corresponding to different values of the latent vector z (so that we could map them back by reversing the process), as the training is completely unsupervised (or uncontrollable).</p><p>Another important thing to consider is that we are talking about training models to learn the distributions here. To accomplish that –</p><p><strong>“We need a way to compare distributions”!</strong></p><p>As we have discussed earlier as well, the real job of a generative model is to learn the distribution 𝑷𝑴𝒐𝒅𝒆𝒍 which is really close to the true data distribution 𝑷𝑻𝑹𝑼𝑬 (here, 𝑷𝑫𝒂𝒕𝒂𝒔𝒆𝒕 can be a good proxy for the true distribution). During the learning phase, a generative model may request to know how close the model distribution (𝑷𝑴𝒐𝒅𝒆𝒍) is to the expected distribution (𝑷𝑫𝒂𝒕𝒂𝒔𝒆𝒕). For this reason, we need a function that is capable of efficiently comparing and quantifying the closeness of two distributions (e.g., 𝑷𝑴𝒐𝒅𝒆𝒍 and 𝑷𝑫𝒂𝒕𝒂𝒔𝒆𝒕).</p><p>We will cover the different ways of learning or comparing distributions in my subsequent articles.</p><h3>Conclusion</h3><p>In this article, we learned about some basics related to the generative models. We have also understood how does a generative learning model work, with the help of some examples. We also learned about the the joint distributions, restricted distributions and the latent variable based generative models on a very high level. Next important thing is: finding ways to learn or compare distributions in practice. We will cover this topic in my subsequent articles on generative learning.</p><p>I hope this article was helpful and gave you a good basic understanding of the generative models. If you find this useful kindly share, if you find any mistakes please let me know your valuable feedback by commenting below.</p><p>See you in my next articles on generative learning!!</p><p>Originally published on <a href="https://dropsofai.com/how-does-a-generative-learning-model-work/">Drops of AI</a> !</p><h3>Read Next&gt;&gt;&gt;</h3><ol><li><a href="https://dropsofai.com/generative-learning-and-its-differences-from-the-discriminative-learning/">Generative Learning and its Differences from the Discriminative Learning</a></li><li><a href="https://dropsofai.com/building-blocks-of-deep-generative-models/">Building Blocks of Deep Generative Models</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-introduction/">Deep Learning with PyTorch: Introduction</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-first-neural-network/">Deep Learning with PyTorch: First Neural Network</a></li><li><a href="https://dropsofai.com/autoencoders-in-keras-and-deep-learning/">Autoencoders in Keras and Deep Learning</a> (Introduction)</li><li><a href="https://dropsofai.com/optimizers-explained-for-training-neural-networks/">Optimizers explained for training Neural Networks</a></li><li><a href="https://dropsofai.com/optimizing-tensorflow-models-with-quantization-techniques/">Optimizing TensorFlow models with Quantization Techniques</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cb51e52d3f4a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/how-does-a-generative-learning-model-work-cb51e52d3f4a">Understanding Generative Learning for Computer Vision</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Denoising AutoEncoders can reduce noise in images]]></title>
            <link>https://medium.com/game-of-bits/denoising-autoencoders-can-reduce-noise-in-images-5b74753eaf97?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/5b74753eaf97</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[autoencoder]]></category>
            <category><![CDATA[denoising-autoencoder]]></category>
            <category><![CDATA[computer-vision]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Wed, 22 Nov 2023 13:06:02 GMT</pubDate>
            <atom:updated>2023-11-22T13:06:02.212Z</atom:updated>
            <content:encoded><![CDATA[<h4>Developing denoising autoencoders with keras and TensorFlow</h4><p>Autoencoders are unsupervised Deep Learning techniques that are extensively used for dimensionality reduction, latent feature learning (Learning Representations), and also as generative models (Generative Adversarial Networks: GANs). Denoising Autoencoders are slight modifications to the vanilla autoencoders that can be used for reducing noise from real-world noisy datasets. In this tutorial, we will investigate Convolutional Denoising Autoencoders to reduce noise from the images.</p><p>Autoencoders have proved to be very useful in learning complex representations of data and are utilized to solve many complex real-world problems. In my previous article on ‘<a href="https://dropsofai.com/autoencoders-in-keras-and-deep-learning/">Autoencoders in Keras and Deep Learning</a>’, I have given a basic overview of autoencoders using Keras in python.</p><p>This tutorial will focus on Convolutional Denoising Autoencoders where we will train a denoising autoencoder from scratch using Keras and TensorFlow. Here is a quick peek into the content-</p><ol><li>Convolutional Denoising Autoencoders</li><li>Data Preparation</li><li>Training Convolutional Denoising Autoencoder</li><li>Results</li><li>Summary</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/822/0*cFA1FkU_yhN2fzhc.png" /></figure><h3>1. Convolutional Denoising Autoencoders</h3><h3>Background</h3><p>Autoencoders are typically used for representing data in lower-dimensional space(latent feature space), usually for dimensionality reduction tasks. They achieve this task by first converting input data into a lower-dimensional encoding (bottle-neck) and then take that encoding to reconstruct the original data as an output. In this way, the model learns the important aspects of input data as latent features(ignoring non-important information) such that it is able to recreate it efficiently.</p><p>Denoising Autoencoders are slightly different in working. They learn to capture only useful information from input data (ignoring noise) by changing the reconstruction criterion. Denoising Autoencoders are used for reducing noise from noisy datasets. They take noisy data points as input and reconstruct the clean version as output thus the input data and output data are not the same in the case of the Denoising Autoencoders.</p><p>This kind of training (<strong><em>noisy data -&gt; clean data</em></strong>), helps the model to learn only valuable features(ignoring the noise) in latent space, and thus it re-constructs the clean version. This kind of setup is utilized in multiple applications for cleaning real-world noisy datasets.</p><p>Denoising Autoencoder will only be able to remove noise from the dataset when the following two conditions are true-</p><ol><li>Original Features of data are stable and robust to noise.</li><li>The model should be able to learn the useful structure from the distribution of the dataset.</li></ol><h3>Convolutional Denoising Autoencoders</h3><p>Denoising autoencoders work well in multiple different domains(or application areas) with slight modifications depending upon the kind of dataset is being fed. In this tutorial, we will learn about one such variant called <strong><em>convolutional denoising autoencoders</em></strong> which are utilized for denoising image data.</p><p>These models take a noisy image as input and extract important features using multiple convolutional operations, these latent features are then passed to a set of de-convolutional layers in order to reconstruct the cleaner version of this image with the same height and width. Deconvolution operations can be performed with something like <strong><em>Conv2DTransponse</em></strong> implementations from TensorFlow and Keras.</p><p><strong>Note:</strong> Latent feature dimensions needn’t be smaller in the case of denoising autoencoders as inputs and outputs are different. Thus there is no risk of learning identity function (An identity function basically copies the input into output without learning important aspects of data).</p><h3>2. Data Preparation</h3><p>We will train a denoising autoencoder on MNIST handwritten digits dataset available through Keras. Here is how we can download and load the dataset in our Python notebook-</p><pre>import numpy as np<br>import matplotlib.pyplot as plt<br>import pandas as pd<br>import seaborn as sns<br>import warnings<br>warnings.filterwarnings(&#39;ignore&#39;)<br>%matplotlib inline</pre><pre>from tensorflow.keras.datasets import mnist</pre><pre>(trainX, trainy), (testX, testy) = mnist.load_data()</pre><pre>print(&#39;Training data shapes: X=%s, y=%s&#39; % (trainX.shape, trainy.shape))<br>print(&#39;Testing data shapes: X=%s, y=%s&#39; % (testX.shape, testy.shape))</pre><pre>for j in range(5):<br>    i = np.random.randint(0, 10000)<br>    plt.subplot(550 + 1 + j)<br>    plt.imshow(trainX[i], cmap=&#39;gray&#39;)<br>    plt.title(trainy[i])<br>plt.show()</pre><p>MNIST handwritten digits dataset comes with 60K labeled handwritten digit images in the training partition and 10K images in the test partition. Here is a glimpse of 5 images from the dataset. Each image is of 28 * 28 dimensions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/892/0*ZtjGxQmVIWSKRD3h.png" /></figure><h3>Creating Noisy Data</h3><p>As our task is to learn a denoising autoencoder, we will need noisy images (for corresponding clean images) for training the network. We will manually add four different kinds of noise into our training and test images.</p><p>Here are the python scripts capable of adding following four different kinds of noise to the input images-</p><ol><li><em>Gaussian Noise</em></li><li><em>Salt and Pepper Noise</em></li><li><em>Poisson Noise</em></li><li><em>Speckle Noise</em></li></ol><pre># Adding Noise to the dataset<br>def guassian_noise(image):<br>    r,c= image.shape<br>    mean = 0<br>    var = 0.1<br>    sigma = var**0.5<br>    gaussian = np.random.normal(mean,sigma,(r,c))<br>    gaussian = gaussian.reshape(r,c)<br>    noisy = image + gaussian<br>    return noisy</pre><pre>def salt_and_pepper_noise(image):<br>    ratio = 0.9<br>    amount = 0.1<br>    noisy = np.copy(image)<br>    <br>    salt_count = np.ceil(amount * image.size * ratio)<br>    coords = [np.random.randint(0, i - 1, int(salt_count)) for i in image.shape]<br>    noisy[coords] = 1</pre><pre>    pepper_count = np.ceil(amount* image.size * (1. - ratio))<br>    coords = [np.random.randint(0, i - 1, int(pepper_count)) for i in image.shape]<br>    noisy[coords] = 0<br>    return noisy</pre><pre>def poisson_noise(image):<br>    vals = len(np.unique(image))<br>    vals = 2 ** np.ceil(np.log2(vals))<br>    noisy = np.random.poisson(image * vals) / float(vals)<br>    return noisy</pre><pre>def speckle_noise(image):<br>    r,c = image.shape<br>    speckle = np.random.randn(r,c)<br>    speckle = speckle.reshape(r,c)        <br>    noisy = image + image * speckle<br>    return noisy    </pre><pre>def add_noise(image):<br>    p = np.random.random()<br>    if p &lt;= 0.25:<br>        #print(&quot;Guassian&quot;)<br>        noisy = guassian_noise(image)<br>    elif p &lt;= 0.5:<br>        #print(&quot;SnP&quot;)<br>        noisy = salt_and_pepper_noise(image)<br>    elif p &lt;= 0.75:<br>        #print(&quot;Poison&quot;)<br>        noisy = poisson_noise(image)<br>    else:<br>        #print(&quot;speckle&quot;)<br>        noisy = speckle_noise(image)<br>    return noisy</pre><p>Let’s checkout some corrupted samples with randomly chosen noise as per above python functions-</p><pre>print (&quot;Corrupted Example Samples&quot;)<br>for j in range(9):<br>    i = np.random.randint(0, 10000)<br>    plt.subplot(330 + 1 + j)<br>    noisy = add_noise(trainX[i]/255)<br>    plt.imshow(noisy, cmap=&#39;gray&#39;)<br>plt.show()</pre><p>We can see that the images have been fairly corrupted with multiple different types of corruption. This kind of corruption is often observed in real-world images. We will focus on removing this noise and obtaining a cleaner version of each image.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/754/0*oC9eMwJYQsI_jLZg.png" /></figure><h3>Data Preparation</h3><p>We will prepare training and test datasets separately for clean and noisy versions of images. Noisy images will be fed as input and the reconstructed images would be compared with the cleaner versions of the corresponding images. Images are reshaped to add an extra dimension for channels (as per the Convolutional layers input format defined in Keras and TensorFlow).</p><pre>train_clean = [image/255 for image in trainX]<br>test_clean = [image/255 for image in testX]</pre><pre>train_noisy = [add_noise(image/255) for image in trainX]<br>test_noisy = [add_noise(image/255) for image in testX]</pre><pre>train_clean = np.reshape(train_clean, (60000, 28, 28, 1))<br>test_clean = np.reshape(test_clean, (10000, 28, 28, 1))</pre><pre>train_noisy = np.reshape(train_noisy, (60000, 28, 28, 1))<br>test_noisy = np.reshape(test_noisy, (10000, 28, 28, 1))</pre><pre>print (train_clean.shape, train_noisy.shape, test_clean.shape, test_noisy.shape)</pre><pre>(60000, 28, 28, 1) (60000, 28, 28, 1) (10000, 28, 28, 1) (10000, 28, 28, 1)</pre><h3>3. Training Convolutional Denoising Autoencoder</h3><p>In this section, we will define the architecture and train it on the prepared dataset.</p><h3>Architecture</h3><p>The model starts with an input layer that takes a batch of images as input with each image having dimensions=(28 * 28 * 1). The first few layers(encoder part) are composed of Convolutional layers followed by MaxPooling layers. The encoder part of the model downsamples the image across width and height and extracts features.</p><p>These extracted features from the encoder part are passed into the decoder part as input where the decoder reconstructs the image of the original dimensions. The decoder part is consists of multiple De-convolution layers, each followed by an upsampling layer.</p><p>Here is the python implementation of the model-</p><pre>import tensorflow</pre><pre>input_data = tensorflow.keras.layers.Input(shape=(28, 28, 1))</pre><pre>#Encoder part<br>encoder = tensorflow.keras.layers.Conv2D(64, (5,5), activation=&#39;relu&#39;)(input_data)<br>encoder = tensorflow.keras.layers.MaxPooling2D((2,2))(encoder)</pre><pre>encoder = tensorflow.keras.layers.Conv2D(128, (3,3), activation=&#39;relu&#39;)(encoder)<br>encoder = tensorflow.keras.layers.MaxPooling2D((2,2))(encoder)</pre><pre>encoder = tensorflow.keras.layers.Conv2D(256, (3,3), activation=&#39;relu&#39;)(encoder)<br>encoder = tensorflow.keras.layers.MaxPooling2D((2,2))(encoder)</pre><pre>#Decoder Part<br>decoder = tensorflow.keras.layers.Conv2DTranspose(256, (3,3), activation=&#39;relu&#39;)(encoder)</pre><pre>decoder = tensorflow.keras.layers.Conv2DTranspose(128, (3,3), activation=&#39;relu&#39;)(decoder)<br>decoder = tensorflow.keras.layers.UpSampling2D((2,2))(decoder)</pre><pre>decoder = tensorflow.keras.layers.Conv2DTranspose(64, (3,3), activation=&#39;relu&#39;)(decoder)<br>decoder = tensorflow.keras.layers.UpSampling2D((2,2))(decoder)</pre><pre>decoded = tensorflow.keras.layers.Conv2DTranspose(1, (5,5), activation=&#39;relu&#39;)(decoder)</pre><h3>Loss</h3><p>The final task is to compare the reconstructed image with the cleaner version of the input image. As these images are represented with pixel values, we can use <strong><em>mean squared error</em></strong>(MSE) to quantify the goodness of the autoencoder. We will use the Adam optimizer that will tune the model weights such that MSE is reduced.</p><pre>autoencoder = tensorflow.keras.models.Model(inputs=input_data, outputs=decoded)<br>autoencoder.compile(loss=&#39;mse&#39;, optimizer=&#39;adam&#39;)<br>autoencoder.summary()</pre><p>Here is the model summary-</p><pre>Model: &quot;functional_1&quot;<br>_________________________________________________________________<br>Layer (type)                 Output Shape              Param #   <br>=================================================================<br>input_1 (InputLayer)         [(None, 28, 28, 1)]       0         <br>_________________________________________________________________<br>conv2d (Conv2D)              (None, 24, 24, 64)        1664      <br>_________________________________________________________________<br>max_pooling2d (MaxPooling2D) (None, 12, 12, 64)        0         <br>_________________________________________________________________<br>conv2d_1 (Conv2D)            (None, 10, 10, 128)       73856     <br>_________________________________________________________________<br>max_pooling2d_1 (MaxPooling2 (None, 5, 5, 128)         0         <br>_________________________________________________________________<br>conv2d_2 (Conv2D)            (None, 3, 3, 256)         295168    <br>_________________________________________________________________<br>max_pooling2d_2 (MaxPooling2 (None, 1, 1, 256)         0         <br>_________________________________________________________________<br>conv2d_transpose (Conv2DTran (None, 3, 3, 256)         590080    <br>_________________________________________________________________<br>conv2d_transpose_1 (Conv2DTr (None, 5, 5, 128)         295040    <br>_________________________________________________________________<br>up_sampling2d (UpSampling2D) (None, 10, 10, 128)       0         <br>_________________________________________________________________<br>conv2d_transpose_2 (Conv2DTr (None, 12, 12, 64)        73792     <br>_________________________________________________________________<br>up_sampling2d_1 (UpSampling2 (None, 24, 24, 64)        0         <br>_________________________________________________________________<br>conv2d_transpose_3 (Conv2DTr (None, 28, 28, 1)         1601      <br>=================================================================<br>Total params: 1,331,201<br>Trainable params: 1,331,201<br>Non-trainable params: 0</pre><h3>Training</h3><p>We will train the model on training data where noisy images are passed as input and clean images are passed as the output of the model. The test dataset is kept as validation data in order to check the MSE on test batches. The model is trained for 30 epochs with a batch of 64 images and validated on the complete test dataset. After 30 epochs of training, the validation loss comes down to 0.0069.</p><pre>autoencoder.fit(train_noisy, train_clean, epochs=30, batch_size=64, validation_data=(test_noisy, test_clean))</pre><pre>Epoch 1/30<br>938/938 [==============================] - 84s 90ms/step - loss: 0.0244 - val_loss: 0.0135<br>Epoch 2/30<br>938/938 [==============================] - 75s 80ms/step - loss: 0.0119 - val_loss: 0.0107<br>Epoch 3/30<br>938/938 [==============================] - 78s 84ms/step - loss: 0.0100 - val_loss: 0.0095<br>Epoch 4/30<br>938/938 [==============================] - 80s 85ms/step - loss: 0.0090 - val_loss: 0.0088<br>Epoch 5/30<br>938/938 [==============================] - 80s 85ms/step - loss: 0.0084 - val_loss: 0.0087<br>Epoch 6/30<br>938/938 [==============================] - 80s 85ms/step - loss: 0.0080 - val_loss: 0.0083<br>Epoch 7/30<br>938/938 [==============================] - 80s 85ms/step - loss: 0.0076 - val_loss: 0.0078<br>Epoch 8/30<br>938/938 [==============================] - 80s 85ms/step - loss: 0.0073 - val_loss: 0.0078<br>Epoch 9/30<br>938/938 [==============================] - 78s 84ms/step - loss: 0.0071 - val_loss: 0.0079<br>Epoch 10/30<br>938/938 [==============================] - 79s 84ms/step - loss: 0.0069 - val_loss: 0.0076<br>Epoch 11/30<br>938/938 [==============================] - 79s 84ms/step - loss: 0.0068 - val_loss: 0.0073<br>Epoch 12/30<br>938/938 [==============================] - 79s 84ms/step - loss: 0.0066 - val_loss: 0.0074<br>Epoch 13/30<br>938/938 [==============================] - 78s 84ms/step - loss: 0.0065 - val_loss: 0.0074<br>Epoch 14/30<br>938/938 [==============================] - 79s 84ms/step - loss: 0.0064 - val_loss: 0.0074<br>Epoch 15/30<br>938/938 [==============================] - 79s 84ms/step - loss: 0.0063 - val_loss: 0.0070<br>Epoch 16/30<br>938/938 [==============================] - 79s 85ms/step - loss: 0.0062 - val_loss: 0.0072<br>Epoch 17/30<br>938/938 [==============================] - 79s 85ms/step - loss: 0.0061 - val_loss: 0.0071<br>Epoch 18/30<br>938/938 [==============================] - 79s 84ms/step - loss: 0.0060 - val_loss: 0.0071<br>Epoch 19/30<br>938/938 [==============================] - 79s 84ms/step - loss: 0.0059 - val_loss: 0.0071<br>Epoch 20/30<br>938/938 [==============================] - 78s 84ms/step - loss: 0.0059 - val_loss: 0.0069<br>Epoch 21/30<br>938/938 [==============================] - 75s 80ms/step - loss: 0.0058 - val_loss: 0.0070<br>Epoch 22/30<br>938/938 [==============================] - 76s 81ms/step - loss: 0.0057 - val_loss: 0.0070<br>Epoch 23/30<br>938/938 [==============================] - 77s 83ms/step - loss: 0.0057 - val_loss: 0.0069<br>Epoch 24/30<br>938/938 [==============================] - 84s 90ms/step - loss: 0.0056 - val_loss: 0.0071<br>Epoch 25/30<br>938/938 [==============================] - 78s 83ms/step - loss: 0.0056 - val_loss: 0.0069<br>Epoch 26/30<br>938/938 [==============================] - 76s 81ms/step - loss: 0.0056 - val_loss: 0.0072<br>Epoch 27/30<br>938/938 [==============================] - 75s 80ms/step - loss: 0.0055 - val_loss: 0.0068<br>Epoch 28/30<br>938/938 [==============================] - 76s 81ms/step - loss: 0.0055 - val_loss: 0.0070<br>Epoch 29/30<br>938/938 [==============================] - 80s 85ms/step - loss: 0.0054 - val_loss: 0.0071<br>Epoch 30/30<br>938/938 [==============================] - 80s 86ms/step - loss: 0.0054 - val_loss: 0.0069</pre><h3>4. Results</h3><p>In the last section, we have trained our denoising autoencoder reasonably. In this section, we will check how it performs. We will pass a set of noisy images from the test dataset for prediction and plot the results (model output) for them.</p><p>Here is the python code for inference on test dataset-</p><pre>offset=92<br># print (&quot;Real Test Images&quot;)<br># # Real Images<br># for i in range(9):<br>#     plt.subplot(330 + 1 + i)<br>#     plt.imshow(test_clean[i+offset,:,:, -1], cmap=&#39;gray&#39;)<br># plt.show()</pre><pre>print(&quot;Noisy test images&quot;)<br>for i in range(9):<br>    plt.subplot(330 + 1 + i)<br>    plt.imshow(test_noisy[i+offset,:,:, -1], cmap=&#39;gray&#39;)<br>plt.show()</pre><pre># Reconstructed Images<br>print (&quot;Cleaned Version(Denoising Autoencoder):) &quot;)<br>for i in range(9):<br>    plt.subplot(330 + 1 + i)<br>    output = autoencoder.predict(np.array([test_noisy[i+offset]]))<br>    op_image = np.reshape(output[0]*255, (28, 28))<br>    plt.imshow(op_image, cmap=&#39;gray&#39;)<br>plt.show()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/982/0*cGnommedFxC2WoGy.png" /></figure><p>The above output shows that our Convolutional Denoising autoencoder is doing a good job at learning important features and ignoring the noise from the corrupted images. The input images were fairly corrupted and the model was able to reconstruct the cleaner version of them.</p><h3>5. Summary</h3><p>This tutorial gives a background of Convolution based denoising autoencoders adopted for noise reduction in image datasets. With a little background on how it works, it explains how to prepare the training dataset for it. It further explains how to write a simple convolution-based denoising autoencoder in Keras and TensorFlow.</p><p>The study is finally concluded with model training and displaying results. The results were quite good for our toy dataset. This kind of image denoising autoencoder can be utilized in multiple applications as a denoising utility to boost the overall performance. Some of the relevant application areas are listed below-</p><ol><li><em>Optical character recognition tasks (OCR)</em></li><li><em>Handwritten text recognition engine(HTR)</em></li><li><em>Traffic sign classification</em></li><li><em>Photo editing tools</em> and many more similar areas</li></ol><p><strong>Github Link:</strong> <a href="https://github.com/kartikgill/Autoencoders">https://github.com/kartikgill/Autoencoders</a></p><p>With this i would like to end this article here.</p><p>Thanks for reading, I hope it was helpful! Do let me know your thoughts and suggestions by commenting below. See you in the next article.</p><h3>Read Next &gt;&gt;&gt;</h3><ol><li><a href="https://dropsofai.com/autoencoders-in-keras-and-deep-learning/">Autoencoders in Keras and Deep Learning</a> (Introduction)</li><li><a href="https://dropsofai.com/variational-autoencoders-and-image-generation-with-keras/">Variational AutoEncoders and Image Generation with Keras</a></li><li><a href="https://dropsofai.com/optimizers-explained-for-training-neural-networks/">Optimizers explained for training Neural Networks</a></li><li><a href="https://dropsofai.com/optimizing-tensorflow-models-with-quantization-techniques/">Optimizing TensorFlow models with Quantization Techniques</a></li><li><a href="https://dropsofai.com/1d-cnn-based-fully-convolutional-model-for-handwriting-recognition/">1D-CNN based Fully Convolutional Model for Handwriting Recognition</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-introduction/">Deep Learning with PyTorch: Introduction</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-first-neural-network/">Deep Learning with PyTorch: First Neural Network</a></li></ol><h3>Related Papers</h3><ol><li><a href="https://www.cs.toronto.edu/~larocheh/publications/icml-2008-denoising-autoencoders.pdf">Extracting and Composing Robust Features with Denoising<br>Autoencoders</a></li><li><a href="https://bio-asplab.citi.sinica.edu.tw/paper/conference/lu2013speech.pdf">Speech Enhancement Based on Deep Denoising Autoencoder</a></li><li><a href="https://dl.acm.org/doi/abs/10.1145/2806416.2806527">Deep Collaborative Filtering via Marginalized Denoising Auto-encoder</a></li><li><a href="https://ieeexplore.ieee.org/abstract/document/7836672">Medical Image Denoising Using Convolutional Denoising Autoencoders</a></li><li><a href="https://dl.acm.org/doi/abs/10.1145/3072959.3073601">Interactive reconstruction of Monte Carlo image sequences using a recurrent denoising autoencoder</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5b74753eaf97" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/denoising-autoencoders-can-reduce-noise-in-images-5b74753eaf97">Denoising AutoEncoders can reduce noise in images</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What are AutoEncoders in Deep Learning]]></title>
            <link>https://medium.com/game-of-bits/what-are-autoencoders-in-deep-learning-ba802298bc70?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/ba802298bc70</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[keras]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[autoencoder]]></category>
            <category><![CDATA[tensorflow]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Sat, 18 Nov 2023 13:06:01 GMT</pubDate>
            <atom:updated>2023-11-18T13:06:01.505Z</atom:updated>
            <content:encoded><![CDATA[<h4>Develop AutoEncoders with Keras and TensorFlow</h4><p>We all are well aware of the Supervised Machine Learning algorithms where ML algorithm tries to understand the relationship between input features and labels from the training data and is expected to automatically generate a similar kind of relationship between test data features and set of possible output labels. Although we solve lots of problems with supervised learning algorithms, not all problems are supervised in nature. There are problems where we just need the algorithm to learn representation (encoding) from the dataset without requiring labels. These algorithms are known as unsupervised learning ML algorithms. Autoencoders also come under unsupervised learning techniques. In this tutorial, we will learn about Autoencoders in Keras and Deep Learning.</p><p>Clustering algorithms (for example- KNN, KMeans, DBSCAN, etc.) are also examples of unsupervised learning techniques as they do not require labeled data to learn relationships/representations in data. Autoencoders are deep learning-based(Neural Networks) algorithms that are widely used to solve many complex tasks.</p><p>Here is a list of some of the popular tasks that are solved efficiently using autoencoder based deep learning models-</p><ul><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Dimensionality_Reduction">Dimensionality Reduction</a></li><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Information_Retrieval">Information Retrieval</a></li><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Anomaly_Detection">Anomaly Detection</a></li><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Image_Processing">Image Processing</a></li><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Drug_discovery">Drug discovery</a></li><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Population_synthesis">Population synthesis</a></li><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Popularity_prediction">Popularity prediction</a></li><li><a href="https://en.wikipedia.org/wiki/Autoencoder#Machine_Translation">Machine Translation</a></li></ul><p>In this article, we will learn about how to write autoencoders in Keras and deep learning. The rest of the article is divided into the following sub-sections-</p><ol><li>Autoencoders in Keras and Deep Learning</li><li>Python Implementation</li><li>Types of Autoencoders</li><li>Summary</li><li>References</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9Okqu_m_-H4-ZFg_.jpeg" /></figure><h3>1. AutoEncoders in Keras and Deep Learning</h3><p>I hope everyone is aware of <a href="https://www.google.com/search?q=sponge+balls&amp;tbm=isch&amp;chips=q:sponge+balls,g_1:smiley:EQ7EZrhhti4%3D&amp;hl=en&amp;sa=X&amp;ved=2ahUKEwjQ8Z6kltTsAhXIVawKHTbUAqcQ4lYoBXoECAEQIw&amp;biw=1680&amp;bih=971">sponge balls</a> that are extensively used as stress balls. <a href="https://en.wikipedia.org/wiki/Stress_ball">Stress balls</a> (or hand exercise balls) are squeezed in hand and manipulated by fingers to relieve muscle tension and stress as prescribed in physical therapy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/275/0*y5SwpXn6h_mxUs_H.jpeg" /></figure><p>Sponge balls are known for their elastic property which brings them into their original shape when squeezed forcefully. Due to this property, you can actually keep these balls in smaller boxes(in size) with force and they will acquire their original shape back (approximately) once the box is opened.</p><p>The idea behind autoencoders is very similar. An autoencoder will take a data point, squeeze to fit it in a smaller box(smaller data shape), and will be able to convert it back(to its original form) when required. As our data is not elastic like the stress balls, It will not get back to its original form perfectly which means that we will be losing some information in the process. An autoencoder is made up of two parts-Encoder and Decoder.</p><p>The Encoder part of an autoencoder is a neural network (non-recurrent generally) that takes the input data point and squeezes it into a lower dimension state (h: as shown in the below figure). This code(h) is expected to learn important information from the input data point. The Decoder part of the autoencoder is again a neural network that is supposed to take this hidden-code representation(h) of the data as input and reconstruct the original data point as output. Thus the inputs and outputs of an autoencoder are the same, and the most important thing is the hidden state(compressed representation of data) that learns important features from the data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/841/0*9FDzLOp0FxC7VSle.png" /></figure><p>Autoencoders were primarily used for dimensionality reduction and feature learning in the past decades. But recently this technique is quite popular and is widely used in developing <a href="https://en.wikipedia.org/wiki/Generative_model">generative models</a> (like-Generative Adversarial Networks (GANs)).</p><p><a href="https://en.wikipedia.org/wiki/Dimensionality_reduction">Dimensionality reduction</a> is the task of representing high dimensional data points in lower dimensions without losing much information. In this manner, autoencoders are significantly related to the Principal Component Analysis(PCA) when used with linear activations. While the non-linearity(non-linear activations) makes the autoencoders much superior and capable of learning more complicated relationships in the data so that reconstruction is performed without losing any significant information.</p><p>The next section will talk about how to implement Autoencoders in Keras and Deep Learning-</p><h3>2. Python Implementation</h3><p>In this exercise, we will train a simple autoencoder and examine how well it reconstructs the data. We will further review, how well the reduced dimensions distinguish the output labels. We will use MNIST handwritten digits dataset for our experiments.</p><h3>Data</h3><p>The following python code will load the MNIST handwritten digits dataset and display some sample images from the dataset. This dataset has 60K training and 10K test images of handwritten digits with dimensions=<strong><em>28*28</em></strong>. It also has corresponding labels for each digit that we won’t need for our experiment. We will train an autoencoder that takes a digit image as input and reduces it to just 2-dimensions and reconstructs it.</p><pre>import numpy as np<br>import matplotlib.pyplot as plt<br>import pandas as pd<br>import seaborn as sns<br>%matplotlib inline</pre><pre>from tensorflow.keras.datasets import mnist</pre><pre>(trainX, trainy), (testX, testy) = mnist.load_data()</pre><pre>print(&#39;Training data shapes: X=%s, y=%s&#39; % (trainX.shape, trainy.shape))<br>print(&#39;Testing data shapes: X=%s, y=%s&#39; % (testX.shape, testy.shape))</pre><pre>for j in range(5):<br>    i = np.random.randint(0, 10000)<br>    plt.subplot(550 + 1 + j)<br>    plt.imshow(trainX[i], cmap=&#39;gray&#39;)<br>    plt.title(trainy[i])<br>plt.show()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/938/0*h9Metix4WtLvcfvJ.png" /></figure><p>These images are 2-D NumPy arrays filled with pixel intensities. We will convert each image into a single dimensional array as we want to pass it into a Multi-layer perceptron model. (Ideally, we should have used Convolutional Neural Network-based autoencoder which is ideal for images).</p><pre># normalizing pixel intensities<br>trainX = trainX/255<br>testX = testX/255<br>#reshaping data into single dimension<br>train_data = np.reshape(trainX, (60000, 28*28))<br>test_data = np.reshape(testX, (10000, 28*28))<br>print (train_data.shape, test_data.shape)</pre><pre>(60000, 784) (10000, 784)</pre><h3>Encoder</h3><p>Let’s define the encoder part of the model. It takes an array of size <strong>784 </strong>as input and passes it through a<strong> </strong>multi-layer dense network. The final layer of the encoder has only two neurons, this layer is expected to represent each given image with these two float numbers.</p><pre>import tensorflow</pre><pre>input_data = tensorflow.keras.layers.Input(shape=(784))</pre><pre>encoder = tensorflow.keras.layers.Dense(100)(input_data)<br>encoder = tensorflow.keras.layers.Activation(&#39;relu&#39;)(encoder)</pre><pre>encoder = tensorflow.keras.layers.Dense(50)(encoder)<br>encoder = tensorflow.keras.layers.Activation(&#39;relu&#39;)(encoder)</pre><pre>encoder = tensorflow.keras.layers.Dense(25)(encoder)<br>encoder = tensorflow.keras.layers.Activation(&#39;relu&#39;)(encoder)</pre><pre>encoded = tensorflow.keras.layers.Dense(2)(encoder)</pre><h3>Decoder</h3><p>Most of the time, the decoder part of the autoencoder network is a mirror image of the encoder model. It will take those reduced dimensions as input and reconstruct the original image by increasing the dimensions again to the original ones. Finally, we will get an array of dimensions 784 as output. This output array is expected to be similar to the input array.</p><pre>decoder = tensorflow.keras.layers.Dense(25)(encoded)<br>decoder = tensorflow.keras.layers.Activation(&#39;relu&#39;)(decoder)</pre><pre>decoder = tensorflow.keras.layers.Dense(50)(decoder)<br>decoder = tensorflow.keras.layers.Activation(&#39;relu&#39;)(decoder)</pre><pre>decoder = tensorflow.keras.layers.Dense(100)(decoder)<br>decoder = tensorflow.keras.layers.Activation(&#39;relu&#39;)(decoder)</pre><pre>decoded = tensorflow.keras.layers.Dense(784)(decoder)</pre><h3>Loss</h3><p>We need a loss function that will tell how similar our reconstructed image is with respect to the original input image. As images are just pixel values, Mean Squared Error (‘mse’) would be a good choice to measure how close each pixel is to its corresponding pixel in the real and predicted images.</p><pre>autoencoder = tensorflow.keras.models.Model(inputs=input_data, outputs=decoded)<br>autoencoder.compile(loss=&#39;mse&#39;, optimizer=&#39;adam&#39;)<br>autoencoder.summary()</pre><pre>Model: &quot;functional_5&quot;<br>_________________________________________________________________<br>Layer (type)                 Output Shape              Param #   <br>=================================================================<br>input_3 (InputLayer)         [(None, 784)]             0         <br>_________________________________________________________________<br>dense_11 (Dense)             (None, 100)               78500     <br>_________________________________________________________________<br>activation_9 (Activation)    (None, 100)               0         <br>_________________________________________________________________<br>dense_12 (Dense)             (None, 50)                5050      <br>_________________________________________________________________<br>activation_10 (Activation)   (None, 50)                0         <br>_________________________________________________________________<br>dense_13 (Dense)             (None, 25)                1275      <br>_________________________________________________________________<br>activation_11 (Activation)   (None, 25)                0         <br>_________________________________________________________________<br>dense_14 (Dense)             (None, 2)                 52        <br>_________________________________________________________________<br>dense_15 (Dense)             (None, 25)                75        <br>_________________________________________________________________<br>activation_12 (Activation)   (None, 25)                0         <br>_________________________________________________________________<br>dense_16 (Dense)             (None, 50)                1300      <br>_________________________________________________________________<br>activation_13 (Activation)   (None, 50)                0         <br>_________________________________________________________________<br>dense_17 (Dense)             (None, 100)               5100      <br>_________________________________________________________________<br>activation_14 (Activation)   (None, 100)               0         <br>_________________________________________________________________<br>dense_18 (Dense)             (None, 784)               79184     <br>=================================================================<br>Total params: 170,536<br>Trainable params: 170,536<br>Non-trainable params: 0</pre><h3>Training</h3><p>Input(x) and output(y) are same for autoencoders. We will train our model on training digit images for 30 epochs with a batch size of 64 images.</p><pre>autoencoder.fit(train_data, train_data, epochs=30, batch_size=64, validation_data=(test_data, test_data))</pre><pre>Epoch 1/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0529 - val_loss: 0.0470<br>Epoch 2/30<br>938/938 [==============================] - 1s 1ms/step - loss: 0.0459 - val_loss: 0.0450<br>Epoch 3/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0441 - val_loss: 0.0434<br>Epoch 4/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0429 - val_loss: 0.0421<br>Epoch 5/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0420 - val_loss: 0.0417<br>Epoch 6/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0413 - val_loss: 0.0408<br>Epoch 7/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0405 - val_loss: 0.0400<br>Epoch 8/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0401 - val_loss: 0.0397<br>Epoch 9/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0396 - val_loss: 0.0394<br>Epoch 10/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0393 - val_loss: 0.0389<br>Epoch 11/30<br>938/938 [==============================] - 1s 2ms/step - loss: 0.0389 - val_loss: 0.0388<br>Epoch 12/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0389 - val_loss: 0.0390<br>Epoch 13/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0386 - val_loss: 0.0382<br>Epoch 14/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0385 - val_loss: 0.0383<br>Epoch 15/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0382 - val_loss: 0.0382<br>Epoch 16/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0380 - val_loss: 0.0380<br>Epoch 17/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0378 - val_loss: 0.0377<br>Epoch 18/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0377 - val_loss: 0.0377<br>Epoch 19/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0378 - val_loss: 0.0376<br>Epoch 20/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0375 - val_loss: 0.0378<br>Epoch 21/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0376 - val_loss: 0.0379<br>Epoch 22/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0376 - val_loss: 0.0375<br>Epoch 23/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0373 - val_loss: 0.0372<br>Epoch 24/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0376 - val_loss: 0.0378<br>Epoch 25/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0375 - val_loss: 0.0378<br>Epoch 26/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0372 - val_loss: 0.0381<br>Epoch 27/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0372 - val_loss: 0.0369<br>Epoch 28/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0370 - val_loss: 0.0371<br>Epoch 29/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0370 - val_loss: 0.0369<br>Epoch 30/30<br>938/938 [==============================] - 2s 2ms/step - loss: 0.0368 - val_loss: 0.0371</pre><h3>Prediction</h3><p>Time to check how well it performs on the test datasets. We will plot the original as well as re-constructed images to check how good our model is performing-</p><pre># Real Images<br>for i in range(5):<br>    plt.subplot(550 + 1 + i)<br>    plt.imshow(testX[i], cmap=&#39;gray&#39;)<br>plt.show()</pre><pre># Reconstructed Images<br>for i in range(5):<br>    plt.subplot(550 + 1 + i)<br>    output = autoencoder.predict(np.array([test_data[i]]))<br>    op_image = np.reshape(output[0]*255, (28, 28))<br>    plt.imshow(op_image, cmap=&#39;gray&#39;)<br>plt.show()</pre><p>The first row has 5 real images, and the second row has corresponding reconstructed images. We can see that the output images are a little blurry still they are quite readable. In the last image, our model mistakes a 4 for a 9 as both digits are very similar in shape. With more training and deeper network, model should be able to learn the difference.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/802/0*8IqoUK-cZAvdvzW5.png" /></figure><h3>Reduced Dimensions</h3><p>We saw that this small network was capable of re-constructing the original image using just two numbers(h: layer) from the encoding layer(bottleneck layer). Now these reduced dimensions can be used in other applications as features for these images. To verify the fact, let’s plot these embeddings(features) for all the test dataset digits.</p><pre>dr_model = tensorflow.keras.models.Model(inputs=autoencoder.get_layer(&#39;input_3&#39;).input, outputs=autoencoder.get_layer(&#39;dense_14&#39;).output)<br>dr_model.summary()</pre><pre>x = []<br>y = []<br>z = []<br>for i in range(10000):<br>    z.append(testy[i])<br>    op = dr_model.predict(np.array([test_data[i]]))<br>    x.append(op[0][0])<br>    y.append(op[0][1])</pre><pre>df = pd.DataFrame()<br>df[&#39;x&#39;] = x<br>df[&#39;y&#39;] = y<br>df[&#39;z&#39;] = [&quot;digit-&quot;+str(k) for k in z]</pre><pre>plt.figure(figsize=(8, 6))<br>sns.scatterplot(x=&#39;x&#39;, y=&#39;y&#39;, hue=&#39;z&#39;, data=df)<br>plt.show()</pre><p>Each image from the test dataset is represented with 2-dimensions and is plotted as a point in the scatterplot below where color represents the label of the image. We can notice that the same digits are closer in the latent space. Even this simple autoencoder is able to separate out digits in different cluster-</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/506/0*4WqhP-SiFDxbyV7x.png" /></figure><p>As we know that the convolutional neural networks are the best choices for image understanding/representations, results would have been even better with CNN-based autoencoder.</p><blockquote><em>Here is my article where I have trained a CNN-based autoencoder to predict future frames in a video-</em></blockquote><blockquote><a href="https://dropsofai.com/python-predicts-pubg-mobile/"><em>Python Predicts PUBG Mobile</em></a></blockquote><h3>3. Types of Autoencoders</h3><p>There are various techniques(regularization techniques) to make autoencoders robust such that they learn the important features instead of just remembering and copying the input data into output.</p><p>Here are a few regularized variants of autoencoders that work really well in practice-</p><h4>Sparse autoencoders (SAE)</h4><p>Sparse autoencoders are typically used when we need to learn features for other tasks, such as classification. These autoencoders involve a sparsity penalty on the embedding layer(h-layer) in addition to the reconstruction error.</p><p>This penalty can be thought of as a regularization parameter to the simple autoencoder where the task was to simply copy the input into an output. This sparsity penalty makes the model learn better representative features for the dataset instead of just copying input into the output.</p><h4>Denoising autoencoders (DAE)</h4><p>Denoising autoencoders are trained by changing the reconstruction error term of the cost function(or loss). Traditionally the input data points and output data points are the same for an autoencoder but in the case of denoising autoencoders, the input data points are noisy in nature while the reconstructed data points are compared with the clean data point(without noise). In this manner, a DAE would learn to ignore(or remove) noise from the noisy dataset.</p><p>Denoising autoencoders have the ability to learn useful features from the input data and discard the useless information(like-noise) at the time of reconstruction. This makes them learn better representations of the data and they are trained to remove noise from noisy datasets.</p><h4>Contractive autoencoders (CAE)</h4><p>Denoising autoencoders typically work well when there is small and limited noise in the dataset, Contractive autoencoders on the other hand are robust to significant perturbations on the input data. Contractive autoencoders apply a contractive penalty on encoder output that encourages the derivatives of the encoder to be as small as possible. This penalty is basically the sum of squared elements of partial derivates from the encoder function.</p><p>Contractive autoencoders are trained to learn the distributions of input instead of copying it, thus they are robust to the slight variations in the inputs.</p><h4>Variational autoencoders (VAE)</h4><p>Variational autoencoders are different from the traditional autoencoders discussed above(like-denoising, sparse, contractive). These are generative models like Generative Adversarial Networks(GANs).</p><p>Traditional autoencoders basically learn latent representations of inputs using reconstruction error. The distribution of these latent representations is usually uneven(input-related). Variational autoencoders use reconstruction loss along with the KL-divergence loss. Here KL-divergence loss encourages the model to learn broader distributions of latent features.</p><p>These latent features from the Variational autoencoder are assumed to follow the Gaussian distribution when trained on sufficient training data. We can sample features from the latent distribution and form a generative model capable of generating new data without any input.</p><h3>4. Summary</h3><p>In this tutorial, we have gained a basic understanding of the autoencoders in Keras and deep learning. We have implemented a simple autoencoder network to learn representations on the MNIST handwritten digit dataset. We have also seen that the model was able to learn effective latent features for different digits.</p><p>We later talk about different variations of the autoencoders that make this algorithm robust by using different regularization techniques. I will explain these techniques in detail in my future tutorials.</p><p>You can find the python notebook here:</p><p><strong>Github Repo: </strong><a href="https://github.com/kartikgill/Autoencoders">https://github.com/kartikgill/Autoencoders</a></p><p>Thanks for reading. Hope this article was helpful. Kindly give your feedback/suggestions by commenting below. See you in the next article.</p><h3>Read Next &gt;&gt;</h3><ol><li><a href="https://dropsofai.com/convolutional-denoising-autoencoders-for-image-noise-reduction/">Convolutional Denoising Autoencoders for image noise reduction</a></li><li><a href="https://dropsofai.com/variational-autoencoders-and-image-generation-with-keras/">Variational AutoEncoders and Image Generation with Keras</a></li><li><a href="https://dropsofai.com/sentiment-classification-with-deep-learning-rnn-lstm-and-cnn/">Sentiment Classification with Deep Learning: RNN, LSTM, and CNN</a></li><li><a href="https://dropsofai.com/optimizers-explained-for-training-neural-networks/">Optimizers explained for training Neural Networks</a></li><li><a href="https://dropsofai.com/optimizing-tensorflow-models-with-quantization-techniques/">Optimizing TensorFlow models with Quantization Techniques</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-introduction/">Deep Learning with PyTorch: Introduction</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-first-neural-network/">Deep Learning with PyTorch: First Neural Network</a></li></ol><h3>Learn More (related research papers)</h3><ol><li><a href="http://proceedings.mlr.press/v27/baldi12a/baldi12a.pdf">Autoencoders, Unsupervised Learning, and Deep<br>Architecture</a></li><li><a href="https://www.jmlr.org/papers/volume11/vincent10a/vincent10a.pdf">Stacked Denoising Autoencoders: Learning Useful Representations in a Deep Network with a Local Denoising Criterion</a></li><li><a href="http://papers.nips.cc/paper/5423-generative-adversarial-nets">Generative Adversarial Nets</a></li><li><a href="https://arxiv.org/abs/1511.06434">Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks</a></li><li><a href="https://arxiv.org/abs/1812.05069">Recent Advances in Autoencoder-Based Representation Learning</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ba802298bc70" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/what-are-autoencoders-in-deep-learning-ba802298bc70">What are AutoEncoders in Deep Learning</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Understanding Optimizers for training Deep Learning Models]]></title>
            <link>https://medium.com/game-of-bits/understanding-optimizers-for-training-deep-learning-models-694c071b5b70?source=rss-3fd5a49d1e91------2</link>
            <guid isPermaLink="false">https://medium.com/p/694c071b5b70</guid>
            <category><![CDATA[stochastic-gradient]]></category>
            <category><![CDATA[neural-networks]]></category>
            <category><![CDATA[gradient-descent]]></category>
            <category><![CDATA[optimization-algorithms]]></category>
            <category><![CDATA[deep-learning]]></category>
            <dc:creator><![CDATA[Kartik Chaudhary]]></dc:creator>
            <pubDate>Wed, 15 Nov 2023 15:06:06 GMT</pubDate>
            <atom:updated>2023-11-15T15:06:06.407Z</atom:updated>
            <content:encoded><![CDATA[<h4>Learn about popular SGD variants knows as optimizers</h4><h3>Overview</h3><p>Training a Deep Learning model (or any machine learning model in fact) is all about bringing the model predictions (model output) close to the real output(Ground truth) for a given set of input-output pairs. Once the model’s results are close to the real results our job is done.</p><p>To understand how close model predictions are with respect to the real outputs, we need a mathematical function(measure) known as a <strong>loss function</strong>. This loss function tells you how good your model is doing at a given step of training.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8xJz-L9V4IH2t9VA.jpg" /><figcaption>Ganga River in India | Image by Author</figcaption></figure><p>Though our loss function helps us understand the quality of our model, it doesn’t solve the complete problem. We actually need a different algorithm that will update the coefficients(or weights) of our model. This optimization algorithm will make sure that the loss value(on training data) decreases at each training step and our model learns from the input-output pairs of the training data.</p><p>In this article, we will discuss some common optimization techniques (Optimizers) used in training neural networks (Deep Learning models).</p><h4>This article will cover the following topics:</h4><ol><li><em>Gradient Descent Algorithm</em></li><li><em>Stochastic Gradient Descent</em></li><li><em>Momentum</em></li><li><em>Adagrad</em></li><li><em>RmsProp</em></li><li><em>Adadelta</em></li><li><em>Adam</em></li><li><em>Summary</em></li></ol><h3>Gradient Descent Algorithm</h3><p>Gradient Descent is a popular algorithm used to find the local minima of any given differentiable function. If the given function is convex, this local minima becomes the global minima.</p><p>While training any machine learning (or Deep Learning) model our objective is to achieve minimum loss value. Thus our optimization algorithm will try to find the local/global minima for our loss function with respect to the given training data.</p><p>The basic intuition behind the working of gradient descent algorithms is-At each point in time, It tries to find the best direction to move and takes a small step such that the overall loss value decreases. To find the best direction at a given point, it calculates the gradient of the loss function at that point.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*l0zcbSOLy8sVDDX8.png" /><figcaption>Illustration of gradient descent learning process</figcaption></figure><blockquote><strong><em>The gradient</em></strong><em> of a differentiable function</em><strong><em>-f </em></strong><em>at a given point p is equal to the value of the partial differentiation of function-</em><strong>f</strong><em> at the point-</em><strong>p</strong><em>.</em></blockquote><p>To get a lower value of the loss function at each succeeding step, we must move towards the direction of the negative <strong><em>gradient</em></strong> from the starting point-p.</p><p>Here is how gradient descent updates the coefficients(weights) of the model with respect to the calculated gradient value over loss function at a given step.</p><pre># calculate the current gradient<br>gradient = calculate_gradient_(args)<br># update weights towards negative gradient<br>weight_new = weight + learning_rate * ((-1)*(gradient))<br># resulting weight value<br>weight_new = weight - learning_rate * gradient</pre><p><strong>Note:</strong> calculate_gradient_(args) is a function that calcualtes current gradient.</p><p><strong><em>learning_rate</em></strong> here decides-how fast(size of jump) you want to move towards the local best direction hinted the by the gradient!</p><p>Convergence to the global minimum is guaranteed when the loss function is convex. As for a convex function-all local minima’s are also the global minima.</p><h3>Stochastic Gradient Descent</h3><p>Although gradient descent guarantees convergence, there is a problem with this optimization method. As it calculates the gradient over the full dataset at each step, it is not always feasible due to the high dimensionality of most real-life datasets(also it’s not always feasible to do such computations over full data due to the hardware constraints).</p><p>To overcome this issue, stochastic gradient descent(also known as ‘<strong><em>SGD</em></strong>’) comes into the picture. The stochastic gradient descent algorithm also works in a similar way but instead of calculating the gradient over the full dataset, it calculates the gradient value over each example of the training dataset and updates the parameters(weights) accordingly.</p><pre>#SGD signature in tf.keras<br>tf.keras.optimizers.SGD(<br>    learning_rate=0.01, momentum=0.0, nesterov=False, name=&#39;SGD&#39;, **kwargs<br>)</pre><p>This makes is computationally awesome and extremely fast. But this great power comes at a cost, that is-lower convergence rate (As noisy examples might mislead the convergence direction).</p><h4>Mini batch Stochastic Gradient Descent</h4><p>To make things better-the mini-batch stochastic gradient descent algorithm calculates the gradient value over a mini-batch (a subset of training data) instead of every single example. Now, this modification keeps the algorithm computationally feasible and as the gradient value is averaged over a few examples it also provides smooth convergence.</p><p>SGD (as an optimization algorithm) has become an important part of machine learning. With small learning rates and some other modifications, mini-batch SGD almost surely converges to the global minimum(or the local minimum in case of pseudo-convex loss functions).</p><blockquote><em>SGD is a popular algorithm used in optimizing many machine learning algorithms like-Linear Regression, Logistic Regression, Support Vector machines (SVM). And it’s the backbone of Artificial Neural Networks(Deep Learning models) when combined with backpropagation.</em></blockquote><h3>Momentum</h3><p>Consider a situation where the loss function surface is not ideal(strictly convex) and you are at a point where local gradient points towards the wrong direction(based on local derivatives). In this scenario, our model might suffer in finding the correct direction towards the global minima.</p><p>Another reason for encountering the same problem could be noisy mini-batch, where the training batch is noisy and pointing the model towards wrong updates to the parameters, thus resulting in slow convergence (or oscillations in convergence).</p><p><strong>Momentum</strong> is a term taken from physics and applied to SGD in order to encounter this issue. The momentum method of SGD optimizer, remembers the last few gradient values from the past training batches and does not just rely on the recently calculated gradient while making updates to the parameters. Instead, it takes inputs from the past gradient values to make sure that we are always moving towards the correct direction of convergence.</p><p>In this way, the momentum method of the SGD optimizer achieves fast convergence without oscillations. Here is how it updates the parameters (weights) of the model-</p><pre>#momentum and velocity terms are from physics used in the similar context here<br>gradient = calculate_gradient_(args)<br>velocity_new = momentum * velocity - learning_rate * gradient<br>weight_new = weight + velocity_new<br>weight_new = weight + momentum * velocity - learning_rate * gradient</pre><h3>Adagrad Optimizer</h3><p>SGD optimizer works with a global learning-rate (A user-defined initial learning rate). It means that it updates each parameter with the same global learning-rate at each step and It may cause the convergence to be quite slow.</p><p>Adagrad, also known as <strong><em>Adaptive Gradient</em></strong>, is a modification of the SGD algorithm. On top of the actual SGD algorithm, it provides parameter specific learning rates (while the SGD method works with a global <em>learning_rate</em> that is applied to all the parameters of the model throughout the training process).</p><pre># signature tf.keras<br>tf.keras.optimizers.Adagrad(<br>    learning_rate=0.001, initial_accumulator_value=0.1, epsilon=1e-07,<br>    name=&#39;Adagrad&#39;, **kwargs<br>)</pre><p>Instead of using a global learning-rate for each weight, the Adagrad algorithm keeps a separate learning rate of each parameter. The learning-rate of a parameter is decided based on the frequency of updates it gets. The parameters that are updated very frequently are updated with smaller learning rates while the parameters that are updated less-frequently are updated with a slightly larger learning rate.</p><p>In mathematical terms- The Adagrad algorithm keeps track of the sum of squares of the gradients for each parameter and divides the learning-rate with it(square-root value of the squared sum of the gradients) before each new update to that parameter. In this way, parameters updated with large values in the past are updated slowly in the next future steps.</p><p><strong>Squared Sum:</strong> because some gradients are <strong>+ve</strong> while some are <strong>-ve</strong>.</p><pre># Here is the algorithm<br>gradient = calculate_gradient_(args)<br>#keep track of the squared sum<br>sq_sum_grad = sq_sum_grad + gradient * gradient<br>#penalize learning rate with square-root of the squared sum of gradients<br>weight_new = weight - (learning_rate/sq_root(sq_sum_grad)) * gradient</pre><p>This algorithm is called ‘adaptive gradient’ because it adapts the learning-rates for each parameter based on its past updates.</p><h3>RMSProp Optimizer</h3><p>RMSProp (Root Mean Square Propagation) algorithm is again based on the Stochastic Gradient algorithm (SGD). RMSProp is very similar to the <strong><em>Adagrad</em></strong> algorithm as it also works with adaptive learning-rates for the parameters.</p><p>The main difference is that instead of calculating the plain squared sum of gradients(like in Adagrad method), it calculates a discounted (or weighted) average of the squared gradients and uses that to penalize the learning-rates for each parameter.</p><pre># signature of RMSProp in tf.keras<br>tf.keras.optimizers.RMSprop(learning_rate=0.001, rho=0.9, momentum=0.0, epsilon=1e-07, centered=False,    name=&#39;RMSprop&#39;, **kwargs)</pre><p>here <strong><em>rho</em></strong> is that discounting factor, here is how this algorithm works-</p><pre># Here is the algorithm<br>gradient = calculate_gradient_(args)<br>dis_sq_grad = rho * dis_sq_grad + (1 - rho) * gradient * gradient<br>weight_new = weight - (learning_rate/sq_root(dis_sq_grad)) * gradient</pre><p>Discounted average is a better option here because the plain squared sum keeps increasing with time and keeps penalizing the learning-rate more and more. Thus model learning becomes quite slow with time.</p><p>RMSProp is a very popular optimizer and provides a really fast convergence in practice.</p><h3>Adadelta Optimizer</h3><p>Adadelta (Adaptive Delta Gradient) is again based on stochastic gradient descent algorithms and is an optimized version of the adaptive gradient(Adagrad) algorithm.</p><p>Instead of adapting learning rates based on all the past gradients(like Adagrad does), it uses a moving window of only a few past gradients in order to penalize the learning-rates for each parameter. This saves the algorithm from continuous decay of learning-rates throughout the training. With this strategy, the model keeps learning even after many updates/iterations.</p><p><strong><em>Adadelta</em></strong> performs well even when your model takes very long to train. Another advantage of using the ‘Adadelta’ algorithm is that you don’t even have to provide the initial learning rate (though you can provide your own) as the default one gets adapted soon.</p><h3>Adam Optimizer</h3><p>Similarly, Adam (Adaptive moments of gradient) is again a stochastic gradient descent based optimization algorithm. Just like Adagrad, RMSProp, and Adadelta, it also works with adaptive learning-rates of the parameters(weights). It combines the benefits of Adagrad and RMSProp both.</p><pre>tf.keras.optimizers.Adam(<br>    learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-07, amsgrad=False,<br>    name=&#39;Adam&#39;, **kwargs<br>)</pre><p>Instead of considering just 1st-order moment of past gradient values(like-RMSProp), Adam utilizes second-order moments of the past gradients also in order to update the weights(parameters) of the model.</p><p>It maintains two different parameters <strong><em>beta_1</em></strong> and <strong><em>beta_2</em></strong> as decay rates for both the moments. You don’t have to set these values explicitly as the default ones often work best.</p><p>Adam has been proved to be very efficient and is widely accepted across different domains/problems/architectures.</p><blockquote><em>Adam is “</em>computationally efficient, has little memory requirement, invariant to diagonal rescaling of gradients, and is well suited for problems that are large in terms of data/parameters<em>”</em></blockquote><blockquote><em>According to </em><a href="http://arxiv.org/abs/1412.6980"><em>Kingma et al., 2014</em></a></blockquote><h3>Summary</h3><p>In this article, we went through multiple optimization algorithms used for training artificial neural network-based models.</p><p>We discussed how each of the algorithms provides additional benefits over vanilla stochastic gradient descent algorithm.</p><p>Though all these optimizers work well (they differ mostly in training time, overall average results do not differ much). But if you want to choose one(one all-time best)-Adam is considered the most effective optimizer among all others.</p><p>Here are few good things about Adam-</p><ol><li><em>Easy to understand and implement</em></li><li><em>Lesser memory requirements</em></li><li><em>Fewer computation requirements</em></li><li><em>Works well even for big/large-data problems.</em></li><li><em>Hyperparameters don’t require much tuning as defaults work well.</em></li></ol><p>With this I would like to end this post here. Thanks for reading!</p><p>Do let me know your thoughts/feedback by commenting below. See you in the next article.</p><h3>Read Next&gt;&gt;</h3><ol><li><a href="https://dropsofai.com/optimizing-tensorflow-models-with-quantization-techniques/">Optimizing TensorFlow models with Quantization Techniques</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-introduction/">Deep Learning with PyTorch: Introduction</a></li><li><a href="https://dropsofai.com/deep-learning-with-pytorch-first-neural-network/">Deep Learning with PyTorch: First Neural Network</a></li><li><a href="https://dropsofai.com/1d-cnn-based-fully-convolutional-model-for-handwriting-recognition/">1D-CNN based Fully Convolutional Model for Handwriting Recognition</a></li></ol><h3>References</h3><ol><li>Tensorflow Documentation (<a href="https://www.tensorflow.org/api_docs/python/tf/keras/optimizers">https://www.tensorflow.org/api_docs/python/tf/keras/optimizers</a>)</li><li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Gradient_descent#:~:text=Gradient%20descent%20is%20a%20first,function%20at%20the%20current%20point.">Gradient Descent</a></li><li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Stochastic_gradient_descent">Stochastic Gradient Descent</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=694c071b5b70" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-bits/understanding-optimizers-for-training-deep-learning-models-694c071b5b70">Understanding Optimizers for training Deep Learning Models</a> was originally published in <a href="https://medium.com/game-of-bits">Game of Bits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>