Variational Autoencoder (VAE): জেনারেটিভ মডেলের জাদু

🌀 Variational Autoencoder (VAE): জেনারেটিভ মডেলের জাদু

Variational Autoencoder (VAE) কি এবং এটা কিভাবে কাজ করে?

Variational Autoencoder বা VAE হচ্ছে Autoencoder-এর একটি উন্নত সংস্করণ, যা কেবলমাত্র ইনপুট ডেটাকে পুনর্গঠন (reconstruction) করতে পারে না, বরং নতুন ডেটাও জেনারেট করতে সক্ষম। এটি একটি জেনারেটিভ মডেল — অর্থাৎ, এটি শেখা ডেটার distribution থেকে নতুন, অজানা কিন্তু মানানসই ডেটা তৈরি করতে পারে।

VAE-এর কাজের মূল ধারণা:

সাধারণ Autoencoder তে, ইনপুট ডেটাকে কম মাত্রার latent space-এ compress করা হয় এবং পরে সেই latent representation থেকে ইনপুট পুনর্গঠন করা হয়। কিন্তু এখানে latent vector ঠিক একটি fixed point না, বরং একটি probability distribution (সাধারণত Gaussian distribution) হিসেবে ধরা হয়। ফলে, latent space থেকে sampling করে বিভিন্ন নতুন ডেটা তৈরি করা যায়।

১. Encoder:

Encoder ইনপুট ডেটা থেকে দুটি ভেক্টর শেখে —

  • μ (Mean): ডেটার latent distribution এর গড় মান
  • σ (Standard Deviation): ডেটার latent distribution এর বিচ্যুতি বা variability

এই দুটি ভেক্টরের মাধ্যমে latent distribution নির্ধারণ হয়।

২. Sampling (Latent Vector তৈরি):

Encoder থেকে পাওয়া μ ও σ ব্যবহার করে আমরা latent space থেকে একটা random sample নেই। এই sampling এর মাধ্যমে একই ইনপুট ডেটার বিভিন্ন ভ্যারিয়েন্ট তৈরি সম্ভব হয়। এটি VAE-কে নতুন ডেটা জেনারেট করতে সাহায্য করে।

৩. Decoder:

Decoder এই sampled latent vector থেকে ইনপুট ডেটা পুনর্গঠন করে। অর্থাৎ, এটি latent space থেকে আসল ডেটার approximation তৈরি করে।


কেন VAE ব্যবহার করা হয়?

  • জেনারেটিভ মডেল হিসেবে:
    VAE দিয়ে নতুন ছবি, টেক্সট, সাউন্ড বা যেকোনো ধরনের ডেটা তৈরি করা যায়, যা মূল ডেটার distribution এর মধ্যে পড়ে। উদাহরণস্বরূপ, নতুন মানুষের মুখের ছবি তৈরি, নতুন কবিতা লেখা, বা মিউজিক কম্পোজ করা।
  • ডেটা কম্প্রেশন:
    কম মাত্রার latent space এ ডেটার গুরুত্বপূর্ণ বৈশিষ্ট্যগুলো ধরে রাখা হয়, যা ডেটাকে সংকুচিত করে।
  • অ্যানোমালি ডিটেকশন:
    যদি কোনো ডেটা VAE-এর latent distribution থেকে যথাযথভাবে পুনর্গঠন না হয়, তাহলে সেটাকে অস্বাভাবিক বা anomalous ডেটা হিসেবে চিহ্নিত করা যায়।
  • মিসিং ডেটা পূরণ (Data Imputation):
    কিছু ডেটা মিসিং থাকলে, VAE তার latent representation থেকে মিসিং অংশ পূরণে সাহায্য করতে পারে।
  • Creative AI:
    কল্পনাপ্রসূত আর্ট, সঙ্গীত, সাহিত্য ইত্যাদি তৈরিতে VAE ব্যবহার করা হয়, যা সৃজনশীল এআই অ্যাপ্লিকেশন গড়ে তোলে।

VAE এর গুরুত্বপূর্ণ সুবিধাসমূহ

  • স্ট্রাকচার্ড ল্যাটেন্ট স্পেস:
    VAE latent space একটি smooth এবং স্ট্রাকচার্ড probability distribution, যার ফলে নতুন সেম্পল সহজেই তৈরি করা যায়।
  • ডিটারমিনিস্টিক নয়, Probabilistic:
    VAE একেকবার ইনপুটের জন্য ভিন্ন ভিন্ন latent vector তৈরি করতে পারে, ফলে নতুন ডেটা জেনারেশন ফ্লেক্সিবল ও বৈচিত্র্যময় হয়।
  • End-to-End ট্রেনিং:
    VAE পুরো মডেলটা একই সাথে ট্রেন করা যায় এবং gradient-based optimization ব্যবহার করে লস কমানো হয়।

এই কারণে VAE মডেল আজকের কৃত্রিম বুদ্ধিমত্তার জেনারেটিভ কাজের অন্যতম প্রধান হাতিয়ার। আপনার ডেটাসেটের ধরন অনুসারে VAE কে কাস্টমাইজ করে ইমেজ জেনারেশন, অ্যানোমালি ডিটেকশন, কিংবা ডেটা পুনর্গঠনে ব্যবহার করতে পারেন।

💻 Python কোডের উদাহরণ (TensorFlow)


import tensorflow as tf
from tensorflow.keras import layers
import numpy as np

# Set dimensions
input_dim = 784
latent_dim = 2

# ----- Encoder -----
encoder_inputs = tf.keras.Input(shape=(input_dim,))
x = layers.Dense(256, activation='relu')(encoder_inputs)
z_mean = layers.Dense(latent_dim, name='z_mean')(x)
z_log_var = layers.Dense(latent_dim, name='z_log_var')(x)

class Sampling(layers.Layer):
    def call(self, inputs):
        z_mean, z_log_var = inputs
        epsilon = tf.random.normal(shape=tf.shape(z_mean))
        return z_mean + tf.exp(0.5 * z_log_var) * epsilon

z = Sampling()([z_mean, z_log_var])
encoder = tf.keras.Model(encoder_inputs, [z_mean, z_log_var, z], name="encoder")

# ----- Decoder -----
latent_inputs = tf.keras.Input(shape=(latent_dim,))
x = layers.Dense(256, activation='relu')(latent_inputs)
decoder_outputs = layers.Dense(input_dim, activation='sigmoid')(x)
decoder = tf.keras.Model(latent_inputs, decoder_outputs, name="decoder")

# ----- VAE Model -----
class VAE(tf.keras.Model):
    def __init__(self, encoder, decoder, **kwargs):
        super(VAE, self).__init__(**kwargs)
        self.encoder = encoder
        self.decoder = decoder
        self.loss_tracker = tf.keras.metrics.Mean(name="loss")

    def compile(self, optimizer):
        super().compile()
        self.optimizer = optimizer

    def train_step(self, data):
        if isinstance(data, tuple):
            data = data[0]
        with tf.GradientTape() as tape:
            z_mean, z_log_var, z = self.encoder(data)
            reconstruction = self.decoder(z)
            
            # Compute reconstruction loss
            reconstruction_loss = tf.reduce_sum(
                tf.keras.backend.binary_crossentropy(data, reconstruction), axis=1
            )
            
            # Compute KL divergence
            kl_loss = -0.5 * tf.reduce_sum(
                1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var), axis=1
            )
            
            # Total loss
            total_loss = tf.reduce_mean(reconstruction_loss + kl_loss)

        grads = tape.gradient(total_loss, self.trainable_weights)
        self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
        self.loss_tracker.update_state(total_loss)
        return {"loss": self.loss_tracker.result()}

    @property
    def metrics(self):
        return [self.loss_tracker]

# ----- Instantiate and Train -----
vae = VAE(encoder, decoder)
vae.compile(optimizer=tf.keras.optimizers.Adam())

# Dummy training data
x_train = np.random.rand(1000, 784).astype("float32")

# Train
vae.fit(x_train, epochs=10, batch_size=32)

# Reconstruct some samples
print("\n--- Sample Reconstructions ---")
num_samples = 5
z_mean, z_log_var, z = encoder(x_train[:num_samples])
reconstructed = decoder(z)

for i in range(num_samples):
    print(f"\nSample {i+1}")
    print("Original:", np.round(x_train[i][:10], 3))        # Print first 10 features
    print("Reconstructed:", np.round(reconstructed[i][:10].numpy(), 3))

Training Output


Epoch 1/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - loss: 544.8913
Epoch 2/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - loss: 543.5429
Epoch 3/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step - loss: 543.4837
Epoch 4/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step - loss: 543.4379
Epoch 5/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - loss: 543.4333
Epoch 6/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step - loss: 543.4067
Epoch 7/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step - loss: 543.4094
Epoch 8/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step - loss: 543.3601
Epoch 9/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step - loss: 543.3900
Epoch 10/10
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - loss: 543.3724
  

Sample Reconstructions


Sample 1
Original:      [0.127 0.196 0.228 0.898 0.733 0.17  0.857 0.766 0.545 0.833]
Reconstructed: [0.479 0.492 0.496 0.49  0.492 0.477 0.509 0.506 0.496 0.529]

Sample 2
Original:      [0.233 0.207 0.766 0.033 0.397 0.709 0.367 0.209 0.838 0.268]
Reconstructed: [0.487 0.5   0.507 0.498 0.497 0.486 0.5   0.506 0.5   0.513]

Sample 3
Original:      [0.88  0.986 0.484 0.005 0.886 0.805 0.924 0.05  0.682 0.278]
Reconstructed: [0.468 0.502 0.506 0.499 0.492 0.475 0.508 0.504 0.502 0.52 ]

Sample 4
Original:      [0.01  0.571 0.034 0.537 0.168 0.82  0.566 0.892 0.584 0.346]
Reconstructed: [0.485 0.501 0.5   0.496 0.497 0.483 0.493 0.505 0.5   0.523]

Sample 5
Original:      [0.652 0.18  0.722 0.066 0.574 0.648 0.54  0.887 0.089 0.802]
Reconstructed: [0.488 0.5   0.504 0.498 0.499 0.485 0.496 0.507 0.501 0.51 ]
  

Variational Autoencoder (VAE) কোডের ব্যাখ্যা

আমি TensorFlow Keras দিয়ে লেখা Variational Autoencoder (VAE) এর কোডটি বাংলায় সহজ ভাষায় ব্যাখ্যা করবো। নিচে প্রতিটি ধাপের কাজ বিস্তারিতভাবে তুলে ধরা হলো।

১. লাইব্রেরি ইম্পোর্ট করা

প্রথমে TensorFlow এবং NumPy লাইব্রেরিগুলো ইম্পোর্ট করা হয়, যেগুলো মেশিন লার্নিং মডেল তৈরির জন্য প্রয়োজনীয়।

import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
  

২. ইনপুট ও ল্যাটেন্ট স্পেসের আকার নির্ধারণ

আমাদের ইনপুট ডেটা ৭৮৪ মাত্রার (যেমন ২৮x২৮ পিক্সেলের ছবি ফ্ল্যাটেন করা) এবং ল্যাটেন্ট স্পেসের মাত্রা ২ রাখা হয়েছে যাতে ভিজ্যুয়ালাইজেশন সহজ হয়।

input_dim = 784
latent_dim = 2
  

৩. এনকোডার নেটওয়ার্ক

এনকোডার ইনপুট থেকে দুটি ভেক্টর তৈরি করে: z_mean এবং z_log_var, যেগুলো ল্যাটেন্ট স্পেসের গড় এবং লগ ভেরিয়েন্স নির্দেশ করে।

encoder_inputs = tf.keras.Input(shape=(input_dim,))
x = layers.Dense(256, activation='relu')(encoder_inputs)
z_mean = layers.Dense(latent_dim, name='z_mean')(x)
z_log_var = layers.Dense(latent_dim, name='z_log_var')(x)
  

৪. সাম্পলিং লেয়ার (Reparameterization Trick)

আমরা র্যান্ডম নরমাল ভেরিয়েবল (epsilon) ব্যবহার করে ল্যাটেন্ট ভেক্টর z তৈরি করি যা ব্যাকপ্রোপাগেশন সক্ষম।

class Sampling(layers.Layer):
    def call(self, inputs):
        z_mean, z_log_var = inputs
        epsilon = tf.random.normal(shape=tf.shape(z_mean))
        return z_mean + tf.exp(0.5 * z_log_var) * epsilon
  

৫. এনকোডার মডেল তৈরি

এখন আমরা এনকোডার মডেল তৈরি করব যা ইনপুট থেকে z_mean, z_log_var এবং z রিটার্ন করবে।

z = Sampling()([z_mean, z_log_var])
encoder = tf.keras.Model(encoder_inputs, [z_mean, z_log_var, z], name="encoder")
  

৬. ডিকোডার নেটওয়ার্ক

ডিকোডার ল্যাটেন্ট ভেক্টর থেকে ইনপুটের পুনর্গঠন তৈরি করে। আউটপুট ইনপুটের মতো ৭৮৪ মাত্রার এবং ০-১ এর মধ্যে থাকে।

latent_inputs = tf.keras.Input(shape=(latent_dim,))
x = layers.Dense(256, activation='relu')(latent_inputs)
decoder_outputs = layers.Dense(input_dim, activation='sigmoid')(x)
decoder = tf.keras.Model(latent_inputs, decoder_outputs, name="decoder")
  

৭. VAE মডেল ক্লাস

এই কাস্টম মডেলে আমরা ইনপুটকে এনকোড করি, ল্যাটেন্ট স্পেস থেকে ডিকোড করি এবং লস হিসাব করি: রিকন্সট্রাকশন লস ও KL ডাইভারজেন্স।

class VAE(tf.keras.Model):
    def __init__(self, encoder, decoder, **kwargs):
        super(VAE, self).__init__(**kwargs)
        self.encoder = encoder
        self.decoder = decoder

    def train_step(self, data):
        with tf.GradientTape() as tape:
            z_mean, z_log_var, z = self.encoder(data)
            reconstruction = self.decoder(z)
            reconstruction_loss = tf.reduce_sum(
                tf.keras.losses.binary_crossentropy(data, reconstruction), axis=1
            )
            kl_loss = -0.5 * tf.reduce_sum(
                1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var), axis=1
            )
            total_loss = tf.reduce_mean(reconstruction_loss + kl_loss)
        grads = tape.gradient(total_loss, self.trainable_variables)
        self.optimizer.apply_gradients(zip(grads, self.trainable_variables))
        return {"loss": total_loss}
  

৮. মডেল কম্পাইল ও ট্রেনিং

মডেলটি Adam অপটিমাইজার দিয়ে কম্পাইল করা হয় এবং ডামি ডেটা দিয়ে ট্রেন করা হয়। প্রকৃত প্রয়োগে অবশ্যই বাস্তব ডেটাসেট ব্যবহার করতে হবে।

vae = VAE(encoder, decoder)
vae.compile(optimizer=tf.keras.optimizers.Adam())
x_train = np.random.rand(1000, 784).astype("float32")
vae.fit(x_train, epochs=10, batch_size=32)
  

৯. রিকন্সট্রাকশন ফলাফল দেখা

ট্রেনিং শেষে কিছু স্যাম্পল ডেটার আসল ও পুনর্গঠিত মান দেখানো হয়, যাতে মডেলের কার্যকারিতা বোঝা যায়।

z_mean, z_log_var, z = encoder(x_train[:5])
reconstructed = decoder(z)

for i in range(5):
    print("Original:", np.round(x_train[i][:10], 3))
    print("Reconstructed:", np.round(reconstructed[i][:10].numpy(), 3))
  

সারসংক্ষেপ

VAE কোডের মূল বিষয়বস্তু হলো:

  • এনকোডার ইনপুটকে কম মাত্রার ল্যাটেন্ট স্পেসে রূপান্তর করে।
  • সাম্পলিং লেয়ার stochastic sampling করে ব্যাকপ্রোপাগেশন সম্ভব করে।
  • ডিকোডার ল্যাটেন্ট ভেক্টর থেকে ইনপুট পুনর্গঠন করে।
  • মডেল ট্রেনিংয়ের সময় রিকন্সট্রাকশন লস এবং KL ডাইভারজেন্স একসাথে ব্যবহার করে ল্যাটেন্ট স্পেসের মানে ও বৈচিত্র্য বজায় রাখে।

এটি একটি শক্তিশালী মডেল যা কম্প্রেশন এবং নতুন ডেটা জেনারেশনের কাজে ব্যবহৃত হয়।

📌 বিশেষ টিপস

VAE এর গুরুত্বপূর্ণ দিক হলো তার সম্ভাবনামূলক (probabilistic) প্রকৃতি। এটি শুধুমাত্র নির্দিষ্ট ইনপুটকে পুনর্গঠন করে না, বরং নতুন ইনপুটও "কল্পনা" করতে পারে, যা বাস্তবের মতোই হতে পারে!

✍️ লেখক পরিচিতি

Amanul Islam বর্তমানে PhD in Security করছেন University of Colorado at Colorado Springs-এ। তাঁর গবেষণার বিষয়বস্তু হল AI, Secure Networking এবং Anomaly Detection। তিনি ICT Academy Bangladesh-এর মাধ্যমে বাংলা ভাষায় প্রযুক্তি শিক্ষাকে সহজ ও জনবান্ধব করতে কাজ করছেন।

👉 সকল ব্লগ পড়ুন: ICT Academy Bangladesh

🔮 পরবর্তী ব্লগ:

GAN (Generative Adversarial Networks): দুটি AI যখন একে অপরকে শেখায়!

একটি মন্তব্য পোস্ট করুন

0 মন্তব্যসমূহ