<?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"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://blogs.harshithsai.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 26 Apr 2026 23:32:00 GMT</lastBuildDate><atom:link href="https://blogs.harshithsai.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[NormCompressAI: Exploring Image Compression with Different Norms]]></title><description><![CDATA[In the world of deep learning and computer vision, image compression plays a crucial role in efficient data storage and transmission. Today, we’ll dive into a fascinating project called NormCompressAI, which explores how different mathematical norms ...]]></description><link>https://blogs.harshithsai.com/normcompressai-exploring-image-compression-with-different-norms</link><guid isPermaLink="true">https://blogs.harshithsai.com/normcompressai-exploring-image-compression-with-different-norms</guid><category><![CDATA[ML]]></category><category><![CDATA[AI]]></category><category><![CDATA[linear algebra ]]></category><category><![CDATA[llm]]></category><dc:creator><![CDATA[Harshith Sai V]]></dc:creator><pubDate>Sat, 28 Sep 2024 23:20:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727565449202/2beb189c-b095-40a9-9f3b-04ec06176e2d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the world of deep learning and computer vision, image compression plays a crucial role in efficient data storage and transmission. Today, we’ll dive into a fascinating project called NormCompressAI, which explores how different mathematical norms affect image compression using autoencoders.</p>
<h1 id="heading-project-overview">Project Overview</h1>
<p>NormCompressAI aims to compress images using a deep learning model (specifically, an autoencoder) and apply various norms (L1, L2, and L-infinity) as loss functions to measure reconstruction error. The project evaluates how these norms impact the quality and efficiency of the compression.</p>
<h1 id="heading-the-dataset-cifar-10">The Dataset: CIFAR-10</h1>
<p>For this project, we’ve chosen the CIFAR-10 dataset. It’s a collection of 60,000 32x32 color images across 10 classes. CIFAR-10 provides a good balance between simplicity and complexity, making it an excellent starting point for our autoencoder architecture.</p>
<h1 id="heading-implementation-details">Implementation Details</h1>
<p>The project is implemented in PyTorch, a popular deep learning framework. Here’s a breakdown of the key components:</p>
<p><strong>GitHub Repository</strong>: You can find the full code for the NormCompressAI project on <a target="_blank" href="https://github.com/harshithsaiv/NormCompressAI">GitHub</a>. Feel free to clone and experiment with different norms and datasets.</p>
<h1 id="heading-1-autoencoder-architecture">1. Autoencoder Architecture</h1>
<p>We’ve designed a convolutional autoencoder with the following structure:</p>
<ul>
<li><p>Encoder: Three convolutional layers with ReLU activation</p>
</li>
<li><p>Decoder: Three transposed convolutional layers with ReLU activation and a final Sigmoid layer</p>
</li>
</ul>
<h1 id="heading-2-loss-functions">2. Loss Functions</h1>
<p>The project implements three different norm-based loss functions:</p>
<ul>
<li><p>L2 Norm (Mean Squared Error): Measures the average squared difference between the original and reconstructed images</p>
</li>
<li><p>L1 Norm (Mean Absolute Error): Measures the average absolute difference between the original and reconstructed images</p>
</li>
<li><p>L-infinity Norm: Measures the maximum absolute difference between the original and reconstructed images</p>
</li>
</ul>
<h1 id="heading-3-training-process">3. Training Process</h1>
<p>The model is trained for 10 epochs using the Adam optimizer. The training loop includes:</p>
<ul>
<li><p>Forward pass through the autoencoder</p>
</li>
<li><p>Loss calculation using the selected norm</p>
</li>
<li><p>Backpropagation and parameter updates</p>
</li>
</ul>
<h1 id="heading-code-implementation">Code Implementation</h1>
<p>Below is a basic implementation of our autoencoder model using <strong>PyTorch</strong>. This model compresses and reconstructs images from the CIFAR-10 dataset. You can experiment with different norms (L1, L2, and L-infinity) by modifying the loss function.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> torch
<span class="hljs-keyword">import</span> torch.nn <span class="hljs-keyword">as</span> nn
<span class="hljs-keyword">import</span> torch.optim <span class="hljs-keyword">as</span> optim
<span class="hljs-keyword">import</span> torchvision
<span class="hljs-keyword">import</span> torchvision.transforms <span class="hljs-keyword">as</span> transforms
<span class="hljs-keyword">import</span> argparse
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt

<span class="hljs-comment"># Define the autoencoder architecture by inheriting from the nn.Module </span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Autoencoder</span>(<span class="hljs-params">nn.Module</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super(Autoencoder, self).__init__()  <span class="hljs-comment"># Calling the parent class constructor to initialize the module correctly</span>
        self.encoder = nn.Sequential(
            nn.Conv2d(<span class="hljs-number">3</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, stride=<span class="hljs-number">2</span>, padding=<span class="hljs-number">1</span>),
            nn.ReLU(),
            nn.Conv2d(<span class="hljs-number">16</span>, <span class="hljs-number">32</span>, <span class="hljs-number">3</span>, stride=<span class="hljs-number">2</span>, padding=<span class="hljs-number">1</span>),
            nn.ReLU(),
            nn.Conv2d(<span class="hljs-number">32</span>, <span class="hljs-number">64</span>, <span class="hljs-number">7</span>)
        )
        self.decoder = nn.Sequential(
            nn.ConvTranspose2d(<span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">7</span>),
            nn.ReLU(),
            nn.ConvTranspose2d(<span class="hljs-number">32</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, stride=<span class="hljs-number">2</span>, padding=<span class="hljs-number">1</span>, output_padding=<span class="hljs-number">1</span>),
            nn.ReLU(),
            nn.ConvTranspose2d(<span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, stride=<span class="hljs-number">2</span>, padding=<span class="hljs-number">1</span>, output_padding=<span class="hljs-number">1</span>),
            nn.Sigmoid()
        )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">forward</span>(<span class="hljs-params">self, x</span>):</span>
        x = self.encoder(x)
        x = self.decoder(x)
        <span class="hljs-keyword">return</span> x

<span class="hljs-comment">#loss infinity function that is calculated using the formula max | x - y | </span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">l_infinity_loss</span>(<span class="hljs-params">output, target</span>):</span>
    <span class="hljs-keyword">return</span> torch.max(torch.abs(output - target))

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    <span class="hljs-comment"># Parse command line arguments for selecting norm loss</span>
    parser = argparse.ArgumentParser(description=<span class="hljs-string">"Train autoencoder with specified norm loss"</span>)
    parser.add_argument(<span class="hljs-string">'--norm'</span>, type=str, choices=[<span class="hljs-string">'L2'</span>, <span class="hljs-string">'L1'</span>, <span class="hljs-string">'Linf'</span>], default=<span class="hljs-string">'L2'</span>, help=<span class="hljs-string">'Select norm type (L2, L1, or Linf)'</span>)
    args = parser.parse_args()

    <span class="hljs-comment"># Load and preprocess the CIFAR-10 dataset</span>
    transform = transforms.Compose([transforms.ToTensor()])
    trainset = torchvision.datasets.CIFAR10(root=<span class="hljs-string">'./data'</span>, train=<span class="hljs-literal">True</span>, download=<span class="hljs-literal">True</span>, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=<span class="hljs-number">128</span>, shuffle=<span class="hljs-literal">True</span>, num_workers=<span class="hljs-number">2</span>)

    <span class="hljs-comment"># Initialize the model</span>
    model = Autoencoder()

    <span class="hljs-comment"># Choose loss function based on user input</span>
    <span class="hljs-keyword">if</span> args.norm == <span class="hljs-string">'L2'</span>:
        criterion = nn.MSELoss()  <span class="hljs-comment"># L2 norm (Mean Squared Error)</span>
        print(<span class="hljs-string">"Using L2 Norm Loss (MSE)"</span>)
    <span class="hljs-keyword">elif</span> args.norm == <span class="hljs-string">'L1'</span>:
        criterion = nn.L1Loss()  <span class="hljs-comment"># L1 norm (Mean Absolute Error)</span>
        print(<span class="hljs-string">"Using L1 Norm Loss (MAE)"</span>)
    <span class="hljs-keyword">else</span>:
        criterion = l_infinity_loss  <span class="hljs-comment"># L-infinity norm (Maximum Absolute Error)</span>
        print(<span class="hljs-string">"Using L-infinity Norm Loss"</span>)

    <span class="hljs-comment"># Initialize optimizer</span>
    optimizer = optim.Adam(model.parameters())

    <span class="hljs-comment"># Training loop</span>
    num_epochs = <span class="hljs-number">10</span>
    device = torch.device(<span class="hljs-string">"cuda"</span> <span class="hljs-keyword">if</span> torch.cuda.is_available() <span class="hljs-keyword">else</span> <span class="hljs-string">"cpu"</span>)
    model.to(device)

    loss_values = []

    <span class="hljs-keyword">for</span> epoch <span class="hljs-keyword">in</span> range(num_epochs):
        epoch_loss = <span class="hljs-number">0.0</span>
        <span class="hljs-keyword">for</span> data <span class="hljs-keyword">in</span> trainloader:
            img, _ = data
            img = img.to(device)

            <span class="hljs-comment"># Forward pass</span>
            output = model(img)
            loss = criterion(output, img)

            <span class="hljs-comment"># Backward pass and optimize</span>
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            epoch_loss += loss.item()

        avg_loss = epoch_loss / len(trainloader)
        loss_values.append(avg_loss)

        print(<span class="hljs-string">f'Epoch [<span class="hljs-subst">{epoch+<span class="hljs-number">1</span>}</span>/<span class="hljs-subst">{num_epochs}</span>], Loss: <span class="hljs-subst">{avg_loss:<span class="hljs-number">.4</span>f}</span>'</span>)

    print(<span class="hljs-string">"Training finished!"</span>)

    <span class="hljs-comment"># Plot the loss over epochs</span>
    plt.plot(range(<span class="hljs-number">1</span>, num_epochs+<span class="hljs-number">1</span>), loss_values, label=<span class="hljs-string">f'<span class="hljs-subst">{args.norm}</span> Norm Loss'</span>)
    plt.xlabel(<span class="hljs-string">'Epoch'</span>)
    plt.ylabel(<span class="hljs-string">'Loss'</span>)
    plt.title(<span class="hljs-string">f'Training Loss using <span class="hljs-subst">{args.norm}</span> Norm'</span>)
    plt.legend()
    plt.show()
</code></pre>
<h1 id="heading-results">Results</h1>
<h1 id="heading-l1-norm">L1 Norm:</h1>
<p>The <strong>L1 norm</strong>, also known as <strong>Mean Absolute Error (MAE)</strong>, penalizes large errors less harshly compared to L2. This tends to produce slightly <strong>blurrier reconstructions</strong> but is often more robust to outliers.</p>
<pre><code class="lang-bash">python main.py --norm L1
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:765/1*f_neGlwQ-VaM7sE76N1NZg.png" alt /></p>
<p>Training loss over epochs using L1 norm (MAE)</p>
<h1 id="heading-l2-norm">L2 Norm:</h1>
<p>The <strong>L2 norm</strong>, or <strong>Mean Squared Error (MSE)</strong>, is commonly used in image reconstruction tasks. It heavily penalizes large errors, resulting in <strong>sharper reconstructions</strong> but can be more sensitive to noise in the data.</p>
<pre><code class="lang-bash">python main.py --norm L2
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:761/1*HlJBzID1F_MS04qQBDXLaQ.png" alt /></p>
<p>Training loss over epochs using L2 norm (MLE)</p>
<h1 id="heading-l-infinity-norm">L-infinity Norm:</h1>
<p>The <strong>L-infinity norm</strong> measures the <strong>maximum absolute error</strong> in the reconstructed image, focusing on the largest discrepancy between the original and the reconstructed images. This can be useful for applications where large individual pixel errors need to be minimized.</p>
<pre><code class="lang-bash">python main.py --norm Linf
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:875/1*FQllaV1XSiGbWv9LIJa5BA.png" alt /></p>
<p>Training loss over epochs using L inf</p>
<h1 id="heading-results-and-analysis">Results and Analysis</h1>
<p>The project provides visualizations of the training loss for each norm:</p>
<ul>
<li><p>L1 Norm: Shows a steady decrease in loss over epochs</p>
</li>
<li><p>L2 Norm: Exhibits a similar trend to L1, but with slightly different convergence characteristics</p>
</li>
<li><p>L-infinity Norm: Demonstrates a unique loss curve, reflecting its focus on maximum error</p>
</li>
</ul>
<p>These results highlight how different norms can affect the learning process and potentially the quality of the compressed images.</p>
<h1 id="heading-conclusion-and-future-work">Conclusion and Future Work</h1>
<p>NormCompressAI provides valuable insights into the impact of different norms on image compression using autoencoders. Future work could include:</p>
<ul>
<li><p>Comparing the visual quality of reconstructed images across different norms</p>
</li>
<li><p>Exploring hybrid loss functions that combine multiple norms</p>
</li>
<li><p>Extending the project to higher-resolution datasets or more complex architectures</p>
</li>
</ul>
<p>This project serves as an excellent starting point for researchers and enthusiasts interested in the intersection of deep learning and image compression. By understanding the nuances of different norms, we can develop more efficient and effective compression techniques for the ever-growing world of visual data.</p>
<p>Feel free to explore the full code and experiment with different norms yourself. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Thread Group in JAVA]]></title><description><![CDATA[Tasks are a logical unit of work, we use threads so that these tasks can run asynchronously. We know that there are two policies for executing a particular task using threads- execute them sequentially in a single thread and execute each task in its ...]]></description><link>https://blogs.harshithsai.com/thread-group-in-java</link><guid isPermaLink="true">https://blogs.harshithsai.com/thread-group-in-java</guid><category><![CDATA[Java]]></category><category><![CDATA[Threads]]></category><category><![CDATA[concurrency]]></category><dc:creator><![CDATA[Harshith Sai V]]></dc:creator><pubDate>Thu, 04 Apr 2024 02:15:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712197061744/20446c2c-7e0b-4805-a93d-56955899c38c.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tasks are a logical unit of work, we use threads so that these tasks can run asynchronously. We know that there are two policies for executing a particular task using threads- execute them sequentially in a single thread and execute each task in its own thread. Both have respective disadvantages the prior has poor throughput and responsiveness while the other approach has the worst resource management. Therefore JAVA has a concept of <em>a Thread group</em> that offers better thread management.</p>
<p><strong>What is a Thread Group?</strong></p>
<p><strong>Thread Group</strong> is a java class present in <em>java.lang</em> package and is a direct child class of <em>Object.</em></p>
<p><img src="https://miro.medium.com/v2/resize:fit:279/0*tY-RyP2EqWRjKXlI" alt class="image--center mx-auto" /></p>
<p><em>fig1. Thread Group is a child class of Object</em></p>
<p>Based on the functionality of a thread we can group them into a single unit which is nothing but a Thread Group.</p>
<p>Thread Group contains a group of threads. They can also contain a Sub-Thread Group.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:875/0*umGgAoE5s3rx8_64" alt class="image--center mx-auto" /></p>
<p><em>Fig2. A depiction of Thread Group</em></p>
<p>The advantage of Thread Group is that it becomes easy for us to perform common operations. The best example that we can consider is the Whatsapp group, we create a group so that we can send common messages instead of sending the same message to different individuals. The same thing is done in threads we group threads so that common functionalities can be performed easily, for example, by setting up priority to some particular threads we can set up maximum priority to all consumer threads and minimum priority to printer threads.</p>
<p><strong>An Important Note</strong></p>
<p>Every thread in JAVA belongs to some thread group.</p>
<p><strong>Main Thread Group</strong></p>
<p>Let us now consider an example of the main thread and check to which thread group it belongs.</p>
<pre><code class="lang-plaintext">class Test 
{
   public static void main(String[] args)
    {
      System.out.println(Thread.currentThread().getThreadGroup().getName());
    }
}
</code></pre>
<p>Output:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:661/1*DelAEsWSh46ciHjX61pv_g.png" alt /></p>
<p>So we can see that the main thread belongs to a thread group called main.</p>
<p>But It must be noted that every thread group is a child group of the System group directly or indirectly.</p>
<p><strong>System Thread Group</strong></p>
<p><img src="https://miro.medium.com/v2/resize:fit:875/0*_7mSiirGdRQbCLVE" alt class="image--center mx-auto" /></p>
<p><em>fig3. Different system threads</em></p>
<p>System Thread Group contains different system level threads For example:- Finalizer (i.e Garbage Collector), Reference Handler, Signal Dispatcher, Attach Listener and so on…</p>
<p>Let us now understand the below code snippet.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:875/0*xN7JTEA9o2ZjF9MX" alt /></p>
<p>Here we can see that when we try to get the currentThread method we get <em>main thread</em> and when we call the ThreadGroup method we get <em>main ThreadGroup</em> and when we call getParent method we get <em>system</em> as the output.</p>
<p>Output:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:651/1*6yoHytZRwDzicIAC7xP5qQ.png" alt /></p>
<p><strong>Conclusion</strong></p>
<p>Thread group class was created in JDK 1.0 to manage the state of multiple threads at once e.g suspend, resume, etc. The thread groups form a tree in which every thread group except the initial thread group has a parent.</p>
]]></content:encoded></item></channel></rss>