<?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[Diwakar's blog]]></title><description><![CDATA[Diwakar's blog]]></description><link>https://beafypanda.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 23 Sep 2026 19:50:38 GMT</lastBuildDate><atom:link href="https://beafypanda.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Getting started with Transformers]]></title><description><![CDATA[A brief understanding of working of transformers
Introduction
In the ever-evolving landscape of Natural Language Processing (NLP), one architecture has captured the imagination of researchers, developers, and data scientists alike: the Transformer. S...]]></description><link>https://beafypanda.hashnode.dev/getting-started-with-transformers-b88dcd48e47e</link><guid isPermaLink="true">https://beafypanda.hashnode.dev/getting-started-with-transformers-b88dcd48e47e</guid><category><![CDATA[self-attention]]></category><category><![CDATA[nlp]]></category><category><![CDATA[transformers]]></category><category><![CDATA[Deep Learning]]></category><category><![CDATA[Machine Learning]]></category><dc:creator><![CDATA[Diwakar Basnet]]></dc:creator><pubDate>Wed, 27 Sep 2023 10:50:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/xrrX5_J3Jm4/upload/c14b108213fd618ab084eda9366ae576.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A brief understanding of working of transformers</p>
<h3 id="heading-introduction">Introduction</h3>
<p>In the ever-evolving landscape of Natural Language Processing (NLP), one architecture has captured the imagination of researchers, developers, and data scientists alike: the Transformer. Since its inception, the Transformer has become the cornerstone of modern NLP, revolutionizing the way machines understand, generate, and manipulate human language. In this article we are going to understand about the working of basic blocks used in a transformer and the transformer architecture itself.</p>
<h4 id="heading-recurrent-neural-network-rnn"><strong>Recurrent Neural Network (RNN)</strong></h4>
<p>Traditional deep neural networks assume that inputs and outputs are independent of each other, however in case of RNNs the output from previous sequence can be used as inputs.</p>
<p>While feedforward networks have different weights across each node, RNN share the same weight parameter within each layer of the network. This is because, the shared weights allow the RNN to capture and maintain information about previous time steps in its hidden state. This enables the network to learn and represent temporal dependencies in the data, which is crucial for tasks that involve sequences. For detailed understanding of RNN, you can refer to <a target="_blank" href="https://medium.com/@jianqiangma/all-about-recurrent-neural-networks-9e5ae2936f6e"><strong><em>this article</em></strong></a>.</p>
<p>There are 2 major problems that might arise in RNN:</p>
<ol>
<li>Vanishing gradient — when the gradient is too small, it continues to become smaller until weights become 0 and model stops learning</li>
<li>Exploding gradient — when the gradient is too large, and eventually will be represented as nan.</li>
</ol>
<h4 id="heading-encoder-decoder-network"><strong>Encoder-Decoder Network</strong></h4>
<p>It is basically a neural network consisting of two parts; encoder and decoder. Encoder takes input sequence and creates a contextual representation (context) and decoder takes this context as input and generates output sequence. Using RNN sequence as encoder, the final hidden state of the RNN sequence chain can be used as a representation for context.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220313572/625457a7-bb95-432b-96a1-86975f527595.png" alt="Block representation of traditional RNN based Encoder-Decoder model" /></p>
<p>Traditional RNN based Encoder-Decoder (seq-to-seq) model</p>
<p>Each cell in RNN decoder takes its own estimated output from previous cell as input. One important drawback if context is provided only to the first cell of RNN, than context becomes less and less important as the process continues. To overcome this the “Context” can be made available to each decoding RNN time step. For detailed understanding of encoder decoder model you can refer to <a target="_blank" href="https://medium.com/nerd-for-tech/nlp-theory-and-code-encoder-decoder-models-part-11-30-e686bcb61dc7"><strong><em>this article</em></strong></a>.</p>
<h4 id="heading-attention-mechanism"><strong>Attention Mechanism</strong></h4>
<p>It is the technique that allows Neural Network to focus on specific pats of an input sequence. This is done by assigning weights to different parts of input sequence with important parts containing more weights.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220315345/5a4d2fbf-040a-4350-8119-c6d7da637b77.png" alt="Block diagram of attention mechanism" /></p>
<p>Attention model</p>
<p>An attention model differs from traditional model in 2 ways;</p>
<ol>
<li>Encoder passes more data to decoder or it passes all the hidden states from all time steps rather than just final hidden state in case of traditional model.</li>
<li>Before producing outputs; look at the set of encoder hidden states that it received, give each hidden state a score and then multiply each hidden state by a Softmax score.</li>
</ol>
<p>Thus amplifying hidden states with highest score and down sizing hidden states with low scores. This model has disadvantages i.e. it is slow and we are not sure if it represents the full context.</p>
<h4 id="heading-self-attention-mechanism">Self-Attention Mechanism</h4>
<p>This is an improved attention mechanism because unlike attention mechanism, self-attention can understand how different words or elements in a sentence or sequence are related to each other without going through them one by one. When a sentence is fed to a computer, it considers each word as a token “<strong>t</strong>”, and each token has a word embedding “<strong>V</strong>”. But these word embeddings have no context. So the idea of self-attention is to apply some kind of weighing or similarity to obtain final word embedding “<strong>Y</strong>”, which has more context than the initial embedding V. In an embedding space, similar words appear closer together or have similar embeddings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220317036/fcaaa2f5-6721-4c03-bf20-18002fa9cd7f.png" alt="Self-attention block with query, key and value parameters" /></p>
<p>Self-attention block</p>
<p>Self-attention mechanism in detail;</p>
<ul>
<li>3 vectors (query, key and value) are created from each of encoder’s input vectors by multiplying the embedding with 3 matrices that we trained during training process.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220318525/8f731420-6ebd-4579-8d3b-130baf4e1b26.png" alt /></p>
<ul>
<li>Calculate score of each word of input against the word we’re calculating the self-attention for. The score determines how much focus to place on other parts of input sentence. The score is calculated by taking the dot product of the query vector with the key vector.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220320192/721c0984-d162-4add-b024-6fabb951e7d2.png" alt /></p>
<ul>
<li>The score is then divided by square root of dimension of key vector , which incase of the “<a target="_blank" href="https://arxiv.org/abs/1706.03762"><strong><em>Attention Is All You Need</em></strong></a>” paper is 8. This creates more stable gradient. Then the result is passed through Softmax operation which normalizes scores.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220321799/bed4ace7-c207-4ea3-b5c9-644482b3caf6.jpeg" alt /></p>
<ul>
<li>Multiply each value vector by our normalized score, this keeps intact of values of the words we want to focus on and drown-out irrelevant words by multiplying with tiny numbers.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220323406/ba98cd11-4862-42bc-85ce-a75b08741f8c.png" alt /></p>
<ul>
<li>Sum up the weighted value vectors, thus producing the final word embedding with context.</li>
</ul>
<h4 id="heading-multi-head-attention">Multi-Head Attention</h4>
<p>Multi-head attention extends the basic attention mechanism by performing it multiple times in parallel, with different sets of learnable parameters for each “head.” This improves the performance of the attention layer in two ways;</p>
<ol>
<li>It expands the model’s ability to focus on different positions.</li>
<li>It gives the attention layer multiple “representation subspaces”.</li>
</ol>
<p>The feed forward layer is expecting single matrix(vector for each word). So, we concatenate the matrices then multiply them by an additional weight matrix. For detailed understanding you can refer to <a target="_blank" href="https://paperswithcode.com/method/multi-head-attention"><strong><em>this paper</em></strong></a><strong><em>.</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220325021/2383aed4-1d12-4930-a7f9-e3325d7400c5.png" alt /></p>
<p>Multi-head attention block</p>
<h3 id="heading-transformers">Transformers</h3>
<p>Traditionally RNNs were used for attention mechanisms, but the transformer model mainly relies on “self-attention” mechanism to understand the data. The line below from “Attention is All You Need” paper explains the use of self-attention in transformer quite well.</p>
<blockquote>
<p>“… the Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence aligned RNNs or convolution” — Attention is All you Need, 2017</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702220326820/f9ab339b-6063-4321-9a9f-80d5c1eeceff.png" alt="Transformer encoder-decoder architecture from “Attention is All You Need” paper." /></p>
<p>The encoder-decoder structure of transformer architecture</p>
<p>Both the encoder and decoder consist of stack of N identical layers.</p>
<h4 id="heading-encoder">Encoder:</h4>
<p>Before the inputs are sent to encoder, the inputs are sent through input embedding which is basically a look up table to learn vector representation of each word in the input sentence. Then the positional encoding adds the positional vector to corresponding embedding vector creating positional input embedding. Theses vectors follow a specific pattern that the model learns, which helps it determine the position of each word, or the distance between different words in the sequence. Finally, the encoder block takes this positional input embedding as input and gives a continuous vector representation of these inputs as output.</p>
<blockquote>
<p><strong>Note:</strong> Sine and cosine functions are used in positional encoding because they produce fixed patterns with varying frequencies and they are independent of each other.</p>
</blockquote>
<p>The encoder is composed of two sublayers;</p>
<ol>
<li>The first sublayer implements a multi-head self-attention mechanism.</li>
<li>The second sublayer is a fully connected feed-forward network consisting of two linear transformations with ReLU activation in between .</li>
</ol>
<p>Furthermore, each of these two sublayers has a residual connection around it. Each sublayer is also succeeded by a normalization layer, which normalizes the sum computed between the sublayer input, x, and the output generated by the sublayer itself, sublayer(x). The N layers of the Transformer encoder apply the same linear transformations to all the words in the input sequence, but each layer employs different weight and bias parameters to do so.</p>
<h4 id="heading-decoder">Decoder:</h4>
<p>The decoder shares several similarities with the encoder. It is composed of three sublayers;</p>
<ol>
<li>The first sublayer is a masked multi-head attention, which receives the previous output of the decoder stack. While the encoder is designed to attend to all words in the input sequence regardless of their position in the sequence, this multi-head attention is only allowed to attend to earlier positions in the output sequence . This is done by masking future positions (i.e. -∞) before softmax step in the multi-head attention calculation. The masking makes the decoder unidirectional.</li>
<li>The second sublayer implements a multi-head self-attention mechanism similar to the one implemented in the first sublayer of the encoder, except it creates its <strong><em>Queries</em></strong> matrix from the layer below it, and takes the <strong><em>Keys</em></strong> and <strong><em>Values</em></strong> matrix from the output of the encoder stack.</li>
<li>The third sublayer implements a fully connected feed-forward network, similar to the one implemented in the second sublayer of the encoder</li>
</ol>
<p>Furthermore, the three sublayers on the decoder side also have residual connections around them and are succeeded by a normalization layer similar to the one in encoder. Positional encodings are also added to the output embeddings of the decoder in the same manner as previously explained for the encoder.</p>
<p>For detailed understanding of transformers you can refer to <a target="_blank" href="https://machinelearningmastery.com/the-transformer-model/"><strong><em>this article</em></strong></a>.</p>
<h3 id="heading-references"><strong>References</strong></h3>
<ul>
<li><a target="_blank" href="https://medium.com/@jianqiangma/all-about-recurrent-neural-networks-9e5ae2936f6e">All of Recurrent Neural Networks</a></li>
<li><a target="_blank" href="https://medium.com/nerd-for-tech/nlp-theory-and-code-encoder-decoder-models-part-11-30-e686bcb61dc7">NLP Theory and Code: Encoder-Decoder Models (Part 11/30)</a></li>
<li><a target="_blank" href="https://medium.com/analytics-vidhya/encoders-decoders-sequence-to-sequence-architecture-5644efbb3392">Encoders-Decoders, Sequence to Sequence Architecture</a></li>
<li><a target="_blank" href="https://paperswithcode.com/method/multi-head-attention">Papers with code: Multi-Head Attentio</a>n</li>
<li><a target="_blank" href="https://machinelearningmastery.com/a-gentle-introduction-to-positional-encoding-in-transformer-models-part-1/#:~:text=The%20sine%20and%20cosine%20functions,way%20of%20encoding%20each%20position.">A Gentle Introduction to Positional Encoding in Transformer Models, Part 1</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=tIvKXrEDMhk&amp;ab_channel=Rasa">Rasa Algorithm Whiteboard — Transformers &amp; Attention 2: Keys, Values, Queries</a></li>
<li><a target="_blank" href="https://machinelearningmastery.com/the-transformer-attention-mechanism/">The Transformer Attention Mechanism</a></li>
<li><a target="_blank" href="https://machinelearningmastery.com/the-transformer-model/">The Transformer Model</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Learn to transfer artistic style of an image using Neural style transfer]]></title><description><![CDATA[Learning about neural style transfer is a great place to start if you want to improve in Convolutional Neural Networks (CNN).
In this article, we will be implementing neural style transfer in python using the VGG19 model and applying the styles of on...]]></description><link>https://beafypanda.hashnode.dev/learn-to-transfer-artistic-style-of-an-image-using-neural-style-transfer</link><guid isPermaLink="true">https://beafypanda.hashnode.dev/learn-to-transfer-artistic-style-of-an-image-using-neural-style-transfer</guid><category><![CDATA[Deep Learning]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[CNN]]></category><category><![CDATA[neural style transfer]]></category><dc:creator><![CDATA[Diwakar Basnet]]></dc:creator><pubDate>Wed, 08 Mar 2023 15:50:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1678290219104/3f9b7622-8e20-4849-b5ab-4a9e7d5cdc33.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Learning about neural style transfer is a great place to start if you want to improve in Convolutional Neural Networks (CNN).</p>
<p>In this article, we will be implementing neural style transfer in python using the VGG19 model and applying the styles of one image to another. The codes are implemented using the mathematics from the paper <strong>"</strong><a target="_blank" href="https://arxiv.org/pdf/1508.06576.pdf"><strong>A Neural Algorithm of Artistic Style</strong></a><strong>"</strong> as a reference.</p>
<p>Let's start!</p>
<h1 id="heading-what-is-neural-style-transfer">What is neural style transfer</h1>
<p>Neural style transfer is a technique that takes two input images- a content image and a style reference image and gives an output image called a stylized image. This image has the same content as the content image and has a style similar to the style image.</p>
<h1 id="heading-the-architecture-of-the-vgg-19-model">The architecture of the VGG-19 model</h1>
<p>We will be using this model for our style transfer so let's understand what happens in its architecture first.</p>
<p><a target="_blank" href="https://www.researchgate.net/figure/llustration-of-the-network-architecture-of-VGG-19-model-conv-means-convolution-FC-means_fig2_325137356"><img src="https://www.researchgate.net/publication/325137356/figure/fig2/AS:670371271413777@1536840374533/llustration-of-the-network-architecture-of-VGG-19-model-conv-means-convolution-FC-means.jpg" alt="Photo by Clifford K. Yang on ResearchGate" class="image--center mx-auto" /></a></p>
<h3 id="heading-extracting-content">Extracting content</h3>
<ul>
<li><p>Along the processing hierarchy of the network, the input image is transformed into representations that increasingly care about the actual content of the image compared to its detailed pixel values.</p>
</li>
<li><p>We, refer to the feature responses in higher layers of the network as the content representation.</p>
</li>
<li><p>The second filter of the fifth convolutional layer (conv5_2) of the pre-trained VGG-19 network is used as a content extractor.</p>
</li>
</ul>
<h3 id="heading-extracting-style">Extracting style</h3>
<ul>
<li><p>To obtain a representation of the style of an input image, we use correlations between the different filter responses across the different parts of the image. We obtain a stationary, multi-scale representation of the input image, which captures its texture information but not the global arrangement.</p>
</li>
<li><p>The correlations between feature maps are known as the gram matrix.</p>
</li>
<li><p>The layers used for the calculation of the gram matrix are conv1_1, conv2_1, conv3_1, conv4_1, and conv5_1.</p>
</li>
</ul>
<h1 id="heading-style-transfer-using-vgg-19-in-tensorflow">Style transfer using VGG-19 in Tensorflow</h1>
<h2 id="heading-preparing-environment">Preparing environment</h2>
<p><strong>Note:</strong> If you already know how to enable GPU in Google Colab, you can skip this part👌.</p>
<p>In my case, I am programming in Google Colab so that I can train the neural network on GPUs for free. Using GPU reduces the training time by a huge amount.</p>
<p>To enable GPU on Colab you have to:</p>
<ol>
<li><p>Go to "change runtime type" under Runtime:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678276079839/4dd6feb8-1761-4fad-9b3d-b8d09a54718b.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Select GPU as a hardware accelerator:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678276226791/dc18761c-2ce2-4032-bcc5-0466ef82e31c.png" alt class="image--center mx-auto" /></p>
<p> With that we will have access to a GPU. Now we have to make Tensorflow use it. To do so we have to run the following code.</p>
</li>
</ol>
<pre><code class="lang-python"><span class="hljs-comment"># Make tensorflow use GPU</span>
<span class="hljs-keyword">import</span> tensorflow <span class="hljs-keyword">as</span> tf
device_name = tf.test.gpu_device_name()
<span class="hljs-keyword">if</span> device_name != <span class="hljs-string">'/device:GPU:0'</span>:
  <span class="hljs-keyword">raise</span> SystemError(<span class="hljs-string">'GPU device not found'</span>)
print(<span class="hljs-string">'Found GPU at: {}'</span>.format(device_name))
</code></pre>
<p>Now everything we do on Colab will run on GPU.</p>
<h2 id="heading-importing-libraries-and-images">Importing libraries and images</h2>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
<span class="hljs-keyword">import</span> os

%matplotlib inline

<span class="hljs-keyword">from</span> tensorflow <span class="hljs-keyword">import</span> keras
<span class="hljs-keyword">from</span> keras <span class="hljs-keyword">import</span> optimizers
<span class="hljs-keyword">from</span> keras.optimizers <span class="hljs-keyword">import</span> schedules

<span class="hljs-keyword">import</span> PIL
<span class="hljs-keyword">import</span> cv2
</code></pre>
<p>For content and style images, I mounted my google drive and then used the drive images file path.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Load content and style images</span>
content_path = <span class="hljs-string">'/content/drive/MyDrive/Images/chicago.jpg'</span>
style_path = <span class="hljs-string">'/content/drive/MyDrive/Images/great-wave.jpg'</span>

<span class="hljs-comment"># read the image file in numpy array</span>
content = plt.imread(content_path)
style = plt.imread(style_path)

<span class="hljs-comment"># Display the images</span>
fig, (ax1, ax2) = plt.subplots(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>, figsize=(<span class="hljs-number">15</span>,<span class="hljs-number">15</span>))
ax1.imshow(content)
ax1.set_title(<span class="hljs-string">'Content image'</span>)
ax2.imshow(style)
ax2.set_title(<span class="hljs-string">'Style image'</span>)
plt.show()
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678276981933/ae0cc13f-9592-40df-925f-2d6e0c8873f8.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-gram-matrix-and-loss-functions">Gram matrix and loss functions</h2>
<h3 id="heading-gram-matrix">Gram matrix</h3>
<p>To get the correlation of all the channels w.r.t each other we need to calculate the gram matrix, we will use the gram matrix to measure the degree of correlation between channels which later will act as a measure of style itself.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678278054870/e61c3e45-3733-4a43-9593-30002978a8fc.png" alt class="image--center mx-auto" /></p>
<p>In simple words, a gram matrix is a matrix created by multiplying a matrix with its transpose. The dot product of the transpose of the matrix is created by a vector of feature maps and the matrix itself gives a gram matrix.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">gram_matrix</span>(<span class="hljs-params">input_tensor</span>):</span>
  input_tensor = tf.transpose(input_tensor, (<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>))
  features = tf.reshape(input_tensor, [tf.shape(input_tensor)[<span class="hljs-number">0</span>], <span class="hljs-number">-1</span>])
  gram = tf.matmul(features, tf.transpose(features)) 
  <span class="hljs-keyword">return</span> gram
</code></pre>
<p>Now that we have the Gram matrix we can calculate the loss function of the style, which is the degree of correlation between the styles within a layer.</p>
<h3 id="heading-style-cost">Style cost</h3>
<p>To calculate the loss function we are going to calculate the Gram matrix of both the image to be transferred and the resulting image and calculate the mean square error.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678278807782/656fb706-4927-4632-b249-aca12f614360.png" alt class="image--center mx-auto" /></p>
<p>Where "A" and "G" are the style representations in layer l which are calculated using the gram matrix function. This cost function will later get used to calculate style loss.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">style_cost</span>(<span class="hljs-params">style, combination</span>):</span>
  G = gram_matrix(style)
  A = gram_matrix(combination)
  channels = <span class="hljs-number">3</span>
  size = img_nrows * img_ncols
  <span class="hljs-keyword">return</span> tf.reduce_sum(tf.square(G-A)) / (<span class="hljs-number">4.0</span> * (channels ** <span class="hljs-number">2</span>)*(size ** <span class="hljs-number">2</span>))
</code></pre>
<h3 id="heading-content-cost">Content cost</h3>
<p>The content loss function is much simpler than the style function. Because similar images tend to have similar deep layers. Therefore, if two images have similar content, then they will have similar deep layers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678279627539/1a53a85b-c5c1-40fb-9aaf-4ebc304b0d0c.png" alt class="image--center mx-auto" /></p>
<p>Where "p" is the input content image, "x" is generated combined image and "l" is the layer whose activation we are going to use to compute loss. In my function below there won't be any necessity to send an activation layer.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">content_cost</span>(<span class="hljs-params">content, combination</span>):</span>
  <span class="hljs-keyword">return</span> tf.reduce_sum(tf.square(combination - content)) / <span class="hljs-number">2</span>
</code></pre>
<h2 id="heading-loading-the-model">Loading the model</h2>
<pre><code class="lang-python"><span class="hljs-comment"># Loading VGG19 model</span>
<span class="hljs-keyword">from</span> keras.applications <span class="hljs-keyword">import</span> vgg19
<span class="hljs-keyword">from</span> keras.utils <span class="hljs-keyword">import</span> plot_model

model = vgg19.VGG19(weights=<span class="hljs-string">"imagenet"</span>, include_top=<span class="hljs-literal">False</span>)
</code></pre>
<p>The "include_top" parameter is set to false because we are using our model for feature extraction so we won't need the classifier part. And we are using the weights used by VGG19 on <strong>imagenet</strong> dataset.</p>
<h2 id="heading-calculation-of-loss-function">Calculation of loss function</h2>
<p>First, let us create a feature extractor from a pre-trained model.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> keras.models <span class="hljs-keyword">import</span> Model
outputs_dict = dict([(layer.name, layer.output) <span class="hljs-keyword">for</span> layer <span class="hljs-keyword">in</span> model.layers])
feature_extractor = Model(inputs=model.inputs, outputs=outputs_dict)
</code></pre>
<p>The first line of the code creates a Python dictionary that maps the name of each layer in the pre-trained model to its output tensor. The second line of the code creates a new model object named feature_extractor. This new model takes the same inputs as the original pre-trained model (model.inputs) but its outputs are the dictionary created in the previous step. The resulting feature_extractor can be used to extract features from inputs using the pre-trained model's layers.</p>
<p>Now, we are going to define which layers we are going to use to calculate the loss function of the style and which layer we are going to use to calculate the loss function of the content.</p>
<pre><code class="lang-python">style_layers = [
    <span class="hljs-string">"block1_conv1"</span>,
    <span class="hljs-string">"block2_conv1"</span>,
    <span class="hljs-string">"block3_conv1"</span>,
    <span class="hljs-string">"block4_conv1"</span>,
    <span class="hljs-string">"block5_conv1"</span>,
]

content_layer = <span class="hljs-string">"block5_conv2"</span>

content_weight = <span class="hljs-number">2.5e-8</span>
style_weight = <span class="hljs-number">1e-6</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">loss_function</span>(<span class="hljs-params">combination_image, content_image, style_image</span>):</span>
  <span class="hljs-comment"># 1. Combine all the images in the same tensor</span>
  input_tensor = tf.concat(
      [content_image, style_image, combination_image],
      axis = <span class="hljs-number">0</span>
  )
  <span class="hljs-comment"># 2. Get the values in all the layers for the three image</span>
  features = feature_extractor(input_tensor)
  <span class="hljs-comment"># 3. Initialize the loss</span>
  loss = tf.zeros(shape=())
  <span class="hljs-comment"># 4. Extract the content layers + content loss</span>
  layer_features = features[content_layer]
  content_image_features = layer_features[<span class="hljs-number">0</span>, :, :, :]
  combination_features = layer_features[<span class="hljs-number">2</span>, :, :, :]

  loss = loss + content_weight * content_cost(
      content_image_features, combination_features
  )
  <span class="hljs-comment"># 5. Extract the style layers + style loss</span>
  <span class="hljs-keyword">for</span> layer_name <span class="hljs-keyword">in</span> style_layers:
    layer_features = features[layer_name]
    style_features = layer_features[<span class="hljs-number">1</span>, :, :, :]
    combination_features = layer_features[<span class="hljs-number">2</span>, :, :, :]
    sl = style_cost(style_features, combination_features)
    loss += (style_weight / len(style_layers)) * sl

  <span class="hljs-keyword">return</span> loss
</code></pre>
<h2 id="heading-learning-of-the-neural-style-transfer-network">Learning of the Neural Style Transfer network</h2>
<p>We will now write another function which will:</p>
<ul>
<li><p>Calculate the gradients of the loss function we just defined.</p>
</li>
<li><p>Use these gradients to update the target image.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678284437879/1b50dbc0-374d-4560-9546-8360e058614e.png" alt class="image--center mx-auto" /></p>
<p>With GradientTape, we can take advantage of automatic differentiation, which can calculate the gradients of a function based on its composition. We will also use the tf.function decorator to speed up the operations.</p>
<p>When a function is decorated with @tf.function(), Tensorflow will convert the python function into a Tensorflow graph, which can be executed much more efficiently than the original Python code.</p>
<pre><code class="lang-python"><span class="hljs-meta">@tf.function</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compute_loss_and_grads</span>(<span class="hljs-params">combination_image, content_image, style_image</span>):</span>
  <span class="hljs-keyword">with</span> tf.GradientTape() <span class="hljs-keyword">as</span> tape:
    loss = loss_function(combination_image, content_image, style_image)
    grads = tape.gradient(loss, combination_image)
    <span class="hljs-keyword">return</span> loss, grads
</code></pre>
<p>With this we have the learning phase done.</p>
<h2 id="heading-image-processing-and-generation">Image processing and generation</h2>
<h3 id="heading-preprocess-image">Preprocess image</h3>
<p>The preprocessing of the images consists of giving the images the format that our network requires.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">preprocess_image</span>(<span class="hljs-params">image_path</span>):</span>
  <span class="hljs-comment"># Util function to open, resize and format images into appropriate tensors</span>
  img = keras.preprocessing.image.load_img(
      image_path, target_size=(img_nrows, img_ncols)
  )
  img = keras.preprocessing.image.img_to_array(img)
  img = np.expand_dims(img, axis=<span class="hljs-number">0</span>)
  img = vgg19.preprocess_input(img)
  <span class="hljs-keyword">return</span> tf.convert_to_tensor(img)
</code></pre>
<h3 id="heading-deprocess-image">Deprocess image</h3>
<p>To deprocess the images we will have to follow an almost reverse process to the one we have used to process the images.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Deprocess image</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">deprocess_image</span>(<span class="hljs-params">x</span>):</span>
  <span class="hljs-comment"># Convert tensor to array</span>
  x = x.reshape((img_nrows, img_ncols, <span class="hljs-number">3</span>))
  x[:, :, <span class="hljs-number">0</span>] += <span class="hljs-number">103.939</span>
  x[:, :, <span class="hljs-number">1</span>] += <span class="hljs-number">116.779</span>
  x[:, :, <span class="hljs-number">2</span>] += <span class="hljs-number">123.68</span>
  <span class="hljs-comment"># Convert BGR to RGB</span>
  x = x[:, :, ::<span class="hljs-number">-1</span>]
  <span class="hljs-comment"># We make sure it is in between 0 and 255</span>
  x = np.clip(x, <span class="hljs-number">0</span>, <span class="hljs-number">255</span>).astype(<span class="hljs-string">"uint8"</span>)
  <span class="hljs-keyword">return</span> x
</code></pre>
<h2 id="heading-training-our-neural-style-transfer-network">Training our Neural Style Transfer network</h2>
<p>Now that we have all the functions ready, creating the training loop is quite simple. But first, we are going to create a simple function that generates our final image.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Function to generate an image</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show_result</span>(<span class="hljs-params">iteration</span>):</span>
  img = deprocess_image(combination_image.numpy())
  img = np.array(img, dtype=np.uint8)
  <span class="hljs-keyword">if</span> np.ndim(img)&gt;<span class="hljs-number">3</span>:
    <span class="hljs-keyword">assert</span> img.shape[<span class="hljs-number">0</span>] == <span class="hljs-number">1</span>
    img = img[<span class="hljs-number">0</span>]
  img = PIL.Image.fromarray(img)
  plt.imshow(np.array(img))
  plt.show()<span class="hljs-keyword">from</span> keras.optimizers <span class="hljs-keyword">import</span> SGD
width, height = tf.keras.utils.load_img(content_path).size
img_nrows = <span class="hljs-number">400</span>
img_ncols = int(width * img_nrows / height)

optimizer = SGD(
    keras.optimizers.schedules.ExponentialDecay(
        initial_learning_rate=<span class="hljs-number">100.0</span>, decay_steps=<span class="hljs-number">100</span>, decay_rate=<span class="hljs-number">0.96</span>
    )
)

content_image = preprocess_image(content_path)
style_image = preprocess_image(style_path)
combination_image = tf.Variable(preprocess_image(content_path))

iterations = <span class="hljs-number">4000</span>

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, iterations + <span class="hljs-number">1</span>):
  loss, grads = compute_loss_and_grads(
      combination_image, content_image, style_image
  )
  grads_and_vars = [(grads, combination_image)]
  optimizer.apply_gradients(grads_and_vars)
  <span class="hljs-keyword">if</span> i % <span class="hljs-number">500</span> == <span class="hljs-number">0</span>:
    print(<span class="hljs-string">"Iteration %d: loss=%.2f"</span> % (i, loss))
  <span class="hljs-keyword">if</span> i == <span class="hljs-number">4000</span>:
    show_result(i)
</code></pre>
<p>Now that we have everything prepared, let's code the main training loop of our Neural style transfer network. We will be using Stochastic Gradient Descent i.e SGD optimizer which is an iterative method for optimizing an objective function with suitable smoothness properties. We can use other optimizers as well but upon using the Adam optimizer I couldn't get as good of a result as SGD so I used this optimizer.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> keras.optimizers <span class="hljs-keyword">import</span> SGD
width, height = tf.keras.utils.load_img(content_path).size
img_nrows = <span class="hljs-number">400</span>
img_ncols = int(width * img_nrows / height)

optimizer = SGD(
    keras.optimizers.schedules.ExponentialDecay(
        initial_learning_rate=<span class="hljs-number">100.0</span>, decay_steps=<span class="hljs-number">100</span>, decay_rate=<span class="hljs-number">0.96</span>
    )
)

content_image = preprocess_image(content_path)
style_image = preprocess_image(style_path)
combination_image = tf.Variable(preprocess_image(content_path))

iterations = <span class="hljs-number">4000</span>

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, iterations + <span class="hljs-number">1</span>):
  loss, grads = compute_loss_and_grads(
      combination_image, content_image, style_image
  )
  grads_and_vars = [(grads, combination_image)]
  optimizer.apply_gradients(grads_and_vars)
  <span class="hljs-keyword">if</span> i % <span class="hljs-number">500</span> == <span class="hljs-number">0</span>:
    print(<span class="hljs-string">"Iteration %d: loss=%.2f"</span> % (i, loss))
  <span class="hljs-keyword">if</span> i == <span class="hljs-number">4000</span>:
    show_result(i)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678286755210/09955a39-e3b9-4ad9-80f1-6497577123f9.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Our implementation style transfer ends here, you can play with the hyper-parameters and can also use other networks like Alexnet to produce even better effects. This was my code implementation project as a part of understanding CNN. For the full Colab notebook, you can look <a target="_blank" href="https://github.com/DiwakarBasnet/Style_Transfer/blob/main/NST.ipynb">here</a>. Hope this article helped you.</p>
<p>Do you have any suggestions for improving my code? Let me know 😊.</p>
<p>See you later!</p>
<h1 id="heading-references">References</h1>
<ul>
<li><p><a target="_blank" href="https://arxiv.org/pdf/1508.06576.pdf">https://arxiv.org/pdf/1508.06576.pdf</a></p>
</li>
<li><p><a target="_blank" href="https://anderfernandez.com/en/blog/how-to-code-neural-style-transfer-in-python/">https://anderfernandez.com/en/blog/how-to-code-neural-style-transfer-in-python/</a></p>
</li>
<li><p><a target="_blank" href="https://towardsdatascience.com/a-brief-introduction-to-neural-style-transfer-d05d0403901d">https://towardsdatascience.com/a-brief-introduction-to-neural-style-transfer-d05d0403901d</a></p>
</li>
</ul>
<h3 id="heading-image-references">Image references</h3>
<ul>
<li><p><a target="_blank" href="https://github.com/elleryqueenhomels/fast_neural_style_transfer">Cover photo</a></p>
</li>
<li><p><a target="_blank" href="https://www.researchgate.net/figure/llustration-of-the-network-architecture-of-VGG-19-model-conv-means-convolution-FC-means_fig2_325137356">VGG architecture</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>