Attention LSTM Image Captioning

SkillMedia

Show-Attend-Tell decoder: Bahdanau additive attention over CNN spatial features driving a gated LSTMCell for autoregressive image-to-sequence generation.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Attention LSTM Image Captioning skill

What this skill tells your AI

The instructions your AI receives, as published by wenmin-wu/ds-skills in skills/cv/attention-lstm-image-captioning/SKILL.md and read by ahel’s review.

Overview

Generate sequences (captions, chemical formulas, LaTeX) from images using an attention-based LSTM decoder. At each timestep the decoder attends to CNN spatial features via additive (Bahdanau) attention, applies a learned sigmoid gate, then feeds the context vector + previous token embedding into an LSTMCell. The hidden state is initialized from the mean-pooled encoder output.

Quick Start

class Attention(nn.Module):
    def __init__(self, encoder_dim, decoder_dim, attn_dim):
        super().__init__()
        self.encoder_att = nn.Linear(encoder_dim, attn_dim)
        self.decoder_att = nn.Linear(decoder_dim, attn_dim)
        self.full_att = nn.Linear(attn_dim, 1)

    def forward(self, encoder_out, h):
        att1 = self.encoder_att(encoder_out)           # (B, pixels, attn_dim)
        att2 = self.decoder_att(h).unsqueeze(1)        # (B, 1, attn_dim)
        alpha = F.softmax(self.full_att(torch.tanh(att1 + att2)).squeeze(2), dim=1)
        context = (encoder_out * alpha.unsqueeze(2)).sum(dim=1)
        return context, alpha

class Decoder(nn.Module):
    def __init__(self, vocab_size, embed_dim, encoder_dim, decoder_dim, attn_dim):
        super().__init__()
        self.attention = Attention(encoder_dim, decoder_dim, attn_dim)
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        self.lstm_cell = nn.LSTMCell(embed_dim + encoder_dim, decoder_dim)
        self.f_beta = nn.Linear(decoder_dim, encoder_dim)
        self.fc = nn.Linear(decoder_dim, vocab_size)

    def forward_step(self, encoder_out, embed_t, h, c):
        context, alpha = self.attention(encoder_out, h)
        gate = torch.sigmoid(self.f_beta(h))
        context = gate * context
        h, c = self.lstm_cell(torch.cat([embed_t, context], dim=1), (h, c))
        return self.fc(h), h, c, alpha

Key Decisions

  • Gate (f_beta): Learned sigmoid gate controls how much visual context flows in; improves convergence
  • Init h/c: Project mean-pooled encoder features through linear layers
  • Teacher forcing: Use ground truth tokens during training; greedy/beam search at inference
  • Attention dim: 256 is typical; larger = more expressive but slower

References

Signals

GitHub stars
60
Forks
4
Last commit
Apr 2026
Advanced
Catalog kind
skill
Gateway key
cv-attention-lstm-image-captioning
Source
github.com/wenmin-wu/ds-skills