Gen-AI-Captioning-Lungs-Xrays / model_scratch.py
T0KII's picture
Deploy captioning app
b8c16a3
Raw
History Blame Contribute Delete
7.42 kB
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
class CNN_Encoder(keras.Model):
def __init__(self, embedding_dim=256):
super(CNN_Encoder, self).__init__()
self.conv1 = layers.Conv2D(
filters=32,
kernel_size=3,
strides=2,
padding='same',
name='conv_block1'
)
self.bn1 = layers.BatchNormalization(name='bn1')
self.leaky1 = layers.LeakyReLU(alpha=0.2, name='leaky1')
self.pool1 = layers.MaxPool2D(pool_size=2, strides=2, padding='same', name='pool1')
self.conv2 = layers.Conv2D(
filters=64,
kernel_size=3,
strides=2,
padding='same',
name='conv_block2'
)
self.bn2 = layers.BatchNormalization(name='bn2')
self.leaky2 = layers.LeakyReLU(alpha=0.2, name='leaky2')
self.pool2 = layers.MaxPool2D(pool_size=2, strides=2, padding='same', name='pool2')
self.conv3 = layers.Conv2D(
filters=128,
kernel_size=3,
strides=2,
padding='same',
name='conv_block3'
)
self.bn3 = layers.BatchNormalization(name='bn3')
self.leaky3 = layers.LeakyReLU(alpha=0.2, name='leaky3')
self.pool3 = layers.MaxPool2D(pool_size=2, strides=2, padding='same', name='pool3')
self.conv4 = layers.Conv2D(
filters=256,
kernel_size=3,
strides=2,
padding='same',
name='conv_block4'
)
self.bn4 = layers.BatchNormalization(name='bn4')
self.leaky4 = layers.LeakyReLU(alpha=0.2, name='leaky4')
self.reshape = layers.Reshape((-1, 256), name='reshape_features')
self.fc = layers.Dense(embedding_dim, activation='relu', name='fc_projection')
self.embedding_dim = embedding_dim
def call(self, x, training=False):
x = self.conv1(x)
x = self.bn1(x, training=training)
x = self.leaky1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.bn2(x, training=training)
x = self.leaky2(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.bn3(x, training=training)
x = self.leaky3(x)
x = self.pool3(x)
x = self.conv4(x)
x = self.bn4(x, training=training)
x = self.leaky4(x)
x = self.reshape(x)
features = self.fc(x)
return features
class BahdanauAttention(keras.layers.Layer):
def __init__(self, units):
super(BahdanauAttention, self).__init__()
self.W1 = layers.Dense(units, name='attention_W1')
self.W2 = layers.Dense(units, name='attention_W2')
self.V = layers.Dense(1, name='attention_V')
self.units = units
def call(self, features, hidden):
hidden_with_time_axis = tf.expand_dims(hidden, 1)
score = tf.nn.tanh(self.W1(features) + self.W2(hidden_with_time_axis))
attention_weights = self.V(score)
attention_weights = tf.nn.softmax(attention_weights, axis=1)
context_vector = attention_weights * features
context_vector = tf.reduce_sum(context_vector, axis=1)
attention_weights = tf.squeeze(attention_weights, axis=-1)
return context_vector, attention_weights
class RNN_Decoder(keras.Model):
def __init__(self, embedding_dim=256, units=512, vocab_size=10000, rnn_type='lstm'):
super(RNN_Decoder, self).__init__()
self.units = units
self.embedding_dim = embedding_dim
self.vocab_size = vocab_size
self.rnn_type = rnn_type.lower()
self.embedding = layers.Embedding(vocab_size, embedding_dim, name='word_embedding')
self.attention = BahdanauAttention(self.units)
if self.rnn_type == 'lstm':
self.rnn = layers.LSTM(
self.units,
return_sequences=True,
return_state=True,
recurrent_initializer='glorot_uniform',
name='lstm_decoder'
)
else:
self.rnn = layers.GRU(
self.units,
return_sequences=True,
return_state=True,
recurrent_initializer='glorot_uniform',
name='gru_decoder'
)
self.fc1 = layers.Dense(self.units, activation='relu', name='fc1')
self.fc2 = layers.Dense(vocab_size, name='fc2_output')
def call(self, x, features, hidden, carry=None, training=False):
context_vector, attention_weights = self.attention(features, hidden)
x = self.embedding(x)
context_vector_expanded = tf.expand_dims(context_vector, 1)
x = tf.concat([context_vector_expanded, x], axis=-1)
if self.rnn_type == 'lstm':
if carry is None:
carry = tf.zeros_like(hidden)
output, state_h, state_c = self.rnn(x, initial_state=[hidden, carry], training=training)
hidden = state_h
carry = state_c
else:
output, state = self.rnn(x, initial_state=hidden, training=training)
hidden = state
carry = None
x = self.fc1(output)
x = tf.reshape(x, (-1, x.shape[2]))
predictions = self.fc2(x)
return predictions, hidden, carry, attention_weights
def reset_state(self, batch_size):
hidden = tf.zeros((batch_size, self.units))
if self.rnn_type == 'lstm':
carry = tf.zeros((batch_size, self.units))
return [hidden, carry]
else:
return [hidden]
if __name__ == "__main__":
print("Testing Custom CNN Encoder-Decoder Model...")
EMBEDDING_DIM = 256
UNITS = 512
VOCAB_SIZE = 10000
BATCH_SIZE = 4
IMG_SIZE = 299
encoder = CNN_Encoder(embedding_dim=EMBEDDING_DIM)
print(f"\nEncoder created with embedding_dim={EMBEDDING_DIM}")
decoder = RNN_Decoder(
embedding_dim=EMBEDDING_DIM,
units=UNITS,
vocab_size=VOCAB_SIZE,
rnn_type='lstm'
)
print(f"Decoder created with units={UNITS}, vocab_size={VOCAB_SIZE}")
print("\nTesting forward pass...")
dummy_img = tf.random.normal((BATCH_SIZE, IMG_SIZE, IMG_SIZE, 3))
print(f"Input image shape: {dummy_img.shape}")
features = encoder(dummy_img, training=False)
print(f"Encoder output (features) shape: {features.shape}")
decoder_states = decoder.reset_state(batch_size=BATCH_SIZE)
hidden = decoder_states[0]
carry = decoder_states[1] if len(decoder_states) > 1 else None
print(f"Decoder hidden state shape: {hidden.shape}")
dummy_token = tf.constant([[1], [2], [3], [4]])
predictions, new_hidden, new_carry, attn_weights = decoder(
dummy_token, features, hidden, carry, training=False
)
print(f"Decoder predictions shape: {predictions.shape}")
print(f"Decoder attention weights shape: {attn_weights.shape}")
print(f"New hidden state shape: {new_hidden.shape}")
print("\n✅ Model test completed successfully!")