{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# GroundingDINO: BERT Text Encoder\n",
"\n",
"## Notebook 03 of 14\n",
"\n",
"This notebook covers the **BERT-based text encoder** used in GroundingDINO:\n",
"- Tokenization and input formatting\n",
"- BERT architecture internals\n",
"- Tensor shapes at every layer\n",
"- Token-level vs sentence-level features\n",
"- Sub-sentence phrase grounding\n",
"- Visualization of text embeddings and attention\n",
"\n",
"---\n",
"\n",
"## Table of Contents\n",
"1. [Why BERT for Text Encoding?](#why-bert)\n",
"2. [Tokenization & Input Formatting](#tokenization)\n",
"3. [BERT Architecture](#bert-arch)\n",
"4. [Multi-Head Self-Attention in BERT](#bert-attention)\n",
"5. [Tensor Shapes Through BERT](#tensor-shapes)\n",
"6. [Token-Level Features for Grounding](#token-features)\n",
"7. [Text Feature Visualization](#visualization)\n",
"8. [Special Tokens & Phrase Alignment](#special-tokens)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Why BERT for Text Encoding? \n",
"\n",
"GroundingDINO uses **BERT** (Bidirectional Encoder Representations from Transformers) as its text backbone because:\n",
"\n",
"| Property | Benefit |\n",
"|----------|--------|\n",
"| **Bidirectional** | Understands context from both directions |\n",
"| **Token-level outputs** | Each token gets its own embedding → phrase grounding |\n",
"| **Pre-trained** | Rich semantic representations from large text corpora |\n",
"| **Sub-word tokenization** | Handles rare words and morphological variations |\n",
"| **Attention patterns** | Captures syntactic and semantic relationships |\n",
"\n",
"### BERT vs Other Text Encoders\n",
"\n",
"| Encoder | Type | Output | Used in |\n",
"|---------|------|--------|--------|\n",
"| CLIP text | Causal | [CLS] token only | CLIP, OWL-ViT |\n",
"| BERT | Bidirectional | All tokens | GroundingDINO, GLIP |\n",
"| T5 encoder | Bidirectional | All tokens | Flamingo |\n",
"| LLaMA | Causal | All tokens | LLaVA |\n",
"\n",
"### Key Insight: Token-Level Features\n",
"For phrase grounding, we need **per-token features** so each word can be matched to a specific region:\n",
"```\n",
"Query: \"cat sitting on the mat\"\n",
"Tokens: [CLS] cat sitting on the mat [SEP]\n",
" ↓ ↓ ↓ ↓ ↓ ↓ ↓\n",
" f0 f1 f2 f3 f4 f5 f6 ← 256-dim features\n",
" ↑\n",
" f1 matches bounding box of cat\n",
" f5 matches bounding box of mat\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/nadurthi/.local/lib/python3.10/site-packages/matplotlib/projections/__init__.py:63: UserWarning: Unable to import Axes3D. This may be due to multiple versions of Matplotlib being installed (e.g. as a system package and as a pip package). As a result, the 3D projection is not available.\n",
" warnings.warn(\"Unable to import Axes3D. This may be due to multiple versions of \"\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"transformers already installed\n",
"Using device: cuda\n"
]
}
],
"source": [
"import torch\n",
"import torch.nn as nn\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as patches\n",
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"\n",
"# Install transformers if needed\n",
"try:\n",
" from transformers import BertTokenizer, BertModel, BertConfig\n",
" print(\"transformers already installed\")\n",
"except ImportError:\n",
" import subprocess\n",
" subprocess.run(['pip', 'install', 'transformers', '-q'])\n",
" from transformers import BertTokenizer, BertModel, BertConfig\n",
"\n",
"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
"print(f\"Using device: {device}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Tokenization & Input Formatting \n",
"\n",
"### WordPiece Tokenization\n",
"BERT uses **WordPiece** tokenization:\n",
"- Common words → single token: `cat` → `[cat]`\n",
"- Rare words → sub-words: `grounding` → `[ground, ##ing]`\n",
"- Unknown words → `[UNK]`\n",
"\n",
"### Input Format\n",
"```\n",
"[CLS] token1 token2 ... tokenN [SEP]\n",
"```\n",
"\n",
"### GroundingDINO Text Format\n",
"Multiple categories are separated by `.`:\n",
"```\n",
"\"cat . dog . bird\"\n",
"→ [CLS] cat . dog . bird [SEP]\n",
"```\n",
"\n",
"### Input Tensors\n",
"- `input_ids`: Token IDs from vocabulary (vocab size = 30,522)\n",
"- `attention_mask`: 1 for real tokens, 0 for padding\n",
"- `token_type_ids`: 0 for all tokens (single sentence)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f708b3ebc3e84bb481fb0d93059ff0df",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"tokenizer_config.json: 0%| | 0.00/48.0 [00:00, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7ace34e27afb4bc6984925a925a3c9b6",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"vocab.txt: 0.00B [00:00, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "67cef654cb444eac99a06f88bc31e714",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"tokenizer.json: 0.00B [00:00, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "45055248f6564570a6c4380f7320251f",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"config.json: 0%| | 0.00/570 [00:00, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"======================================================================\n",
"BERT Tokenization Examples\n",
"======================================================================\n",
"\n",
"Query: 'cat'\n",
" Tokens: ['cat']\n",
" IDs: [101, 4937, 102]\n",
" Length: 3 (including [CLS] and [SEP])\n",
"\n",
"Query: 'cat . dog . bird'\n",
" Tokens: ['cat', '.', 'dog', '.', 'bird']\n",
" IDs: [101, 4937, 1012, 3899, 1012, 4743, 102]\n",
" Length: 7 (including [CLS] and [SEP])\n",
"\n",
"Query: 'person wearing a red hat'\n",
" Tokens: ['person', 'wearing', 'a', 'red', 'hat']\n",
" IDs: [101, 2711, 4147, 1037, 2417, 6045, 102]\n",
" Length: 7 (including [CLS] and [SEP])\n",
"\n",
"Query: 'the large brown dog sitting on the grass'\n",
" Tokens: ['the', 'large', 'brown', 'dog', 'sitting', 'on', 'the', 'grass']\n",
" IDs: [101, 1996, 2312, 2829, 3899, 3564, 2006, 1996, 5568, 102]\n",
" Length: 10 (including [CLS] and [SEP])\n",
"\n",
"======================================================================\n",
"Vocabulary size: 30522\n",
"[CLS] token ID: 101\n",
"[SEP] token ID: 102\n",
"[PAD] token ID: 0\n",
"Max sequence length: 512\n"
]
}
],
"source": [
"# Load BERT tokenizer\n",
"tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')\n",
"\n",
"# Example queries\n",
"queries = [\n",
" \"cat\",\n",
" \"cat . dog . bird\",\n",
" \"person wearing a red hat\",\n",
" \"the large brown dog sitting on the grass\",\n",
"]\n",
"\n",
"print(\"=\" * 70)\n",
"print(\"BERT Tokenization Examples\")\n",
"print(\"=\" * 70)\n",
"\n",
"for query in queries:\n",
" tokens = tokenizer.tokenize(query)\n",
" ids = tokenizer.encode(query)\n",
" print(f\"\\nQuery: '{query}'\")\n",
" print(f\" Tokens: {tokens}\")\n",
" print(f\" IDs: {ids}\")\n",
" print(f\" Length: {len(ids)} (including [CLS] and [SEP])\")\n",
"\n",
"print(\"\\n\" + \"=\" * 70)\n",
"print(f\"Vocabulary size: {tokenizer.vocab_size}\")\n",
"print(f\"[CLS] token ID: {tokenizer.cls_token_id}\")\n",
"print(f\"[SEP] token ID: {tokenizer.sep_token_id}\")\n",
"print(f\"[PAD] token ID: {tokenizer.pad_token_id}\")\n",
"print(f\"Max sequence length: {tokenizer.model_max_length}\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Batch Tokenization:\n",
" input_ids shape: torch.Size([3, 13]) (B, max_seq_len)\n",
" attention_mask shape: torch.Size([3, 13])\n",
" token_type_ids shape: torch.Size([3, 13])\n",
"\n",
"Input IDs (first 3 sequences):\n",
" [0] 'cat . dog'\n",
" Tokens: ['[CLS]', 'cat', '.', 'dog', '[SEP]']\n",
" Padded length: 13, Real length: 5\n",
" [1] 'person wearing a red hat'\n",
" Tokens: ['[CLS]', 'person', 'wearing', 'a', 'red', 'hat', '[SEP]']\n",
" Padded length: 13, Real length: 7\n",
" [2] 'the large brown dog sitting on the grass near the fence'\n",
" Tokens: ['[CLS]', 'the', 'large', 'brown', 'dog', 'sitting', 'on', 'the', 'grass', 'near', 'the', 'fence', '[SEP]']\n",
" Padded length: 13, Real length: 13\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Batch tokenization with padding\n",
"batch_queries = [\n",
" \"cat . dog\",\n",
" \"person wearing a red hat\",\n",
" \"the large brown dog sitting on the grass near the fence\",\n",
"]\n",
"\n",
"encoded = tokenizer(\n",
" batch_queries,\n",
" padding=True,\n",
" truncation=True,\n",
" max_length=256,\n",
" return_tensors='pt'\n",
")\n",
"\n",
"print(\"Batch Tokenization:\")\n",
"print(f\" input_ids shape: {encoded['input_ids'].shape} (B, max_seq_len)\")\n",
"print(f\" attention_mask shape: {encoded['attention_mask'].shape}\")\n",
"print(f\" token_type_ids shape: {encoded['token_type_ids'].shape}\")\n",
"\n",
"print(\"\\nInput IDs (first 3 sequences):\")\n",
"for i, (query, ids, mask) in enumerate(zip(batch_queries, encoded['input_ids'], encoded['attention_mask'])):\n",
" tokens = tokenizer.convert_ids_to_tokens(ids[mask.bool()])\n",
" print(f\" [{i}] '{query}'\")\n",
" print(f\" Tokens: {tokens}\")\n",
" print(f\" Padded length: {len(ids)}, Real length: {mask.sum().item()}\")\n",
"\n",
"# Visualize attention mask\n",
"fig, axes = plt.subplots(1, 2, figsize=(14, 4))\n",
"\n",
"ax1 = axes[0]\n",
"im = ax1.imshow(encoded['input_ids'].numpy(), cmap='viridis', aspect='auto')\n",
"ax1.set_title('Input IDs (token vocabulary indices)', fontsize=11, fontweight='bold')\n",
"ax1.set_xlabel('Token position')\n",
"ax1.set_ylabel('Batch index')\n",
"ax1.set_yticks(range(3))\n",
"ax1.set_yticklabels([f'Query {i}' for i in range(3)])\n",
"plt.colorbar(im, ax=ax1)\n",
"\n",
"ax2 = axes[1]\n",
"im2 = ax2.imshow(encoded['attention_mask'].numpy(), cmap='RdYlGn', aspect='auto', vmin=0, vmax=1)\n",
"ax2.set_title('Attention Mask\\n(Green=real token, Red=padding)', fontsize=11, fontweight='bold')\n",
"ax2.set_xlabel('Token position')\n",
"ax2.set_ylabel('Batch index')\n",
"ax2.set_yticks(range(3))\n",
"ax2.set_yticklabels([f'Query {i}' for i in range(3)])\n",
"plt.colorbar(im2, ax=ax2)\n",
"\n",
"plt.suptitle('BERT Tokenization Visualization', fontsize=13, fontweight='bold')\n",
"plt.tight_layout()\n",
"plt.savefig('bert_tokenization.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
" [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],\n",
" [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"encoded['attention_mask']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. BERT Architecture \n",
"\n",
"### BERT-Base Configuration\n",
"\n",
"| Parameter | Value |\n",
"|-----------|-------|\n",
"| Hidden size (d_model) | 768 |\n",
"| Number of layers | 12 |\n",
"| Number of attention heads | 12 |\n",
"| Head dimension | 64 |\n",
"| FFN hidden size | 3072 (4× hidden) |\n",
"| Max sequence length | 512 |\n",
"| Vocabulary size | 30,522 |\n",
"| Total parameters | ~110M |\n",
"\n",
"### BERT Layer Structure\n",
"\n",
"Each of the 12 BERT layers contains:\n",
"```\n",
"Input x (B, L, 768)\n",
" ↓\n",
"Multi-Head Self-Attention\n",
" ↓\n",
"Add & LayerNorm\n",
" ↓\n",
"Feed-Forward Network (768 → 3072 → 768)\n",
" ↓\n",
"Add & LayerNorm\n",
" ↓\n",
"Output (B, L, 768)\n",
"```\n",
"\n",
"### Embeddings\n",
"BERT input = Token Embedding + Position Embedding + Segment Embedding:\n",
"$$E_{input} = E_{token} + E_{position} + E_{segment}$$"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"BERT-Base Configuration:\n",
" Hidden size: 768\n",
" Num hidden layers: 12\n",
" Num attention heads: 12\n",
" Head dimension: 64\n",
" Intermediate size: 3072\n",
" Max position embed: 512\n",
" Vocab size: 30522\n",
" Hidden act: gelu\n",
"\n",
"Total parameters: 109,482,240 (109.5M)\n"
]
}
],
"source": [
"# Load BERT model\n",
"bert_model = BertModel.from_pretrained('bert-base-uncased', output_attentions=True, output_hidden_states=True)\n",
"bert_model.eval()\n",
"\n",
"config = bert_model.config\n",
"print(\"BERT-Base Configuration:\")\n",
"print(f\" Hidden size: {config.hidden_size}\")\n",
"print(f\" Num hidden layers: {config.num_hidden_layers}\")\n",
"print(f\" Num attention heads: {config.num_attention_heads}\")\n",
"print(f\" Head dimension: {config.hidden_size // config.num_attention_heads}\")\n",
"print(f\" Intermediate size: {config.intermediate_size}\")\n",
"print(f\" Max position embed: {config.max_position_embeddings}\")\n",
"print(f\" Vocab size: {config.vocab_size}\")\n",
"print(f\" Hidden act: {config.hidden_act}\")\n",
"\n",
"total_params = sum(p.numel() for p in bert_model.parameters())\n",
"print(f\"\\nTotal parameters: {total_params:,} ({total_params/1e6:.1f}M)\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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zkVERERERB5T0mTJ6fXlIJtlOeIBtT1djzdSQI+EMcbY7PZW5atUNwHJknm6HBERERERkWdC8dLlSJ4iZQjQ0tO1eCMF9MgldoSEpCtVrqKn6xAREREREXlm2O12SpWraLf7+BTydC3eSAE9ckkAkgQEeLgMERERERGRZ0uSgKRgWQpbkVBAj5wdwEdfpSYiIiIiIhKjfH19sSxn5pLwFNBFREREREREvIACuoiIiIiIiIgXUEAXERERERER8QIK6CIiIiIiIiJeQAFdRERERERExAsooIuIiIiIiIh4AQV0ERERERERES+ggC4iIiIiIiLiBRTQRURERERERLyAArqIiIiIiIiIF1BAFxEREREREfECCugiIiIiIiIiXkABXURERERERMQLKKCLiIiIiIiIeAEFdBEREREREREvoIAuIiIiIiIi4gUU0EVERERERES8gAK6iIiIiIiIiBdQQBcRERERERHxAgroIiIiIiIiIl5AAV1ERERERETECyigi4iIiIiIiHgBBXQRERERERERL6CALiIiIiIiIuIFFNBFREREREREvIACuoiIiIiIiIgXUEAXERERERER8QIK6CIiIiIiIiJeQAFdRERERERExAsooIuIeNDRw4fIkMhO26Z1Y3U7//vmC379/rtoL//u66+SIZGdDInsTB4/GoDr167R66N3KZYrI9lSxKNc4VyMHfETAE1rVSJDIjsXzp+L0NbAPj0pkiM92VLEo0TeLPT9tBsAk8ePdm/j3ddfffydBDauW82gAb35b+u/j93Wls0bY7S26LjfcRw0oDcZEtmZM31qtNqaM30qGRLZGTSgd4R5a1Yucx/7prUqAXDsyGHaNKxJrrSJyZ0uCdVKFWbVssXhth32p9dH74arOUMiO9lSxKNm2aL8vXxJhHlrVi57+APyEEJfs1s2b4y1bSyZP5dBA3pz9PCh+y5XMl9WcqZJFOm8tk3rkiGR/YFt3Kt39/cplisjwcHB4Z6/TEl8KZI9HT0/eJuQkJAHthP67+6nod+Gmx4cHEzRnBncz6uIiHiGj6cLEBGR2Dfs2y9Imiw5Hd565+HWGzmewkWLY1kWbZvVY+2q5ZStWIU6DZtw9MhhtmzeyEvto15/wdyZ/O+bAVSvU5/qtetz9PAhTp08DkCJ0uUZNnI8ndu1fpxdC2fjujUM/rIP6TNlIm+B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nknGmECgAZAdSIw+EBOR2FMUyApsBA54uBYReXYFA5eAf4AZlmWd9Ww5Is8eBXSRGGaMqWqz2b51OBz5AZImTBySOEFC7DblcxGJHWcunrdduXHdpEgS4EgcP6H+YxeRWBEUfIeLV6+Yqzeu2wCHMWaVZVkdLcva4+naRJ4VCugiMcgYU88YMzUwbQZ7p7pNbfVKVyJz6nSeLktEnnFvDu7DyLl/MqxrDzrUbuLpckTkGWZZFlv372b6qiX8OGOi4+qNa+dDHI6KlmX95+naRJ4FPp4uQORZYYzJb+DPwtlzmzlf/mQLSJjI0yWJiIiIxChjDAWz5aJgtlw0q1jdVv2DjknPXbm03BiT0bKsG56uT+RppzG3IjHnJZvNbpvRf5jCuYiIiDzzcmcKZFT3AXaHw5EMqOPpekSeBQroIjHAGGOz22ytqhYtaVIkSerpckRERESeiAoFi5EySdIQoIWnaxF5Fiigi8SMTCEOR7raJcp7ug4RERGRJ8Zut1O7ZHm73War5OlaRJ4FCugiMSMpQOpkyT1dh4iIiMgTlTppCkIcjkTGGGULkcekf0QiMcMPII6vv6frEBEREXmi4vj5ARh0A2qRx6aALiIiIiIiIuIFFNBFREREREREvIACuoiIiIiIiIgXUEAXERERERER8QIK6CIiIiIiIiJeQAFdRERERERExAsooIuIiIiIiIh4AQV0ERERERERES+ggC4iIiIiIiLiBRTQRURERERERLyAArqIiIiIiIiIF1BAFxEREREREfECCugiIiIiIiIiXkABXURERERERMQLKKCLiIiIiIiIeAEFdBEREREREREvoIAuIiIiIiIi4gUU0EVERERERES8gAK6iIiIiIiIiBdQQBcRERERERHxAgroIiIiIiIiIl5AAV1ERERERETECyigi4iIiIiIiHgBBXQRERERERERL6CALiIiIiIiIuIFFNBFREREREREvIACuoiIiIiIiIgXUEAXERERERER8QIK6CIiIiIiIiJeQAFdROQZtXX/buJWK8z89asAyNGmJnGqFgr3s2XfLg6dOk6cqoVo2KOLhyuGNf/9S98xP7Jl367HamfM/BnEqVqIwVN+i5G6Dp8+Qd3ub5K8XilS1C9NsdeasWTzuhhpO1SZzq1p+nnXGGsvTtVCvNCxcYy19zBCX2t9x/wI4FWvsQdp3us9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\n",
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Visualize BERT architecture\n",
"fig, ax = plt.subplots(figsize=(14, 14))\n",
"ax.set_xlim(0, 14)\n",
"ax.set_ylim(0, 14)\n",
"ax.axis('off')\n",
"\n",
"def draw_box(ax, x, y, w, h, label, color, fontsize=9):\n",
" rect = patches.FancyBboxPatch((x, y), w, h, boxstyle='round,pad=0.1',\n",
" facecolor=color, edgecolor='black', linewidth=1.5)\n",
" ax.add_patch(rect)\n",
" ax.text(x + w/2, y + h/2, label, ha='center', va='center', \n",
" fontsize=fontsize, fontweight='bold', multialignment='center')\n",
"\n",
"# Input\n",
"draw_box(ax, 1, 12.5, 12, 1.0, 'Input: [CLS] cat . dog . bird [SEP] → input_ids (B, L)', '#E3F2FD', 10)\n",
"\n",
"# Embeddings\n",
"draw_box(ax, 1, 11.0, 3.5, 1.0, 'Token\\nEmbedding\\n(30522 × 768)', '#FFF9C4', 9)\n",
"draw_box(ax, 5.0, 11.0, 3.5, 1.0, 'Position\\nEmbedding\\n(512 × 768)', '#FFF9C4', 9)\n",
"draw_box(ax, 9.0, 11.0, 3.5, 1.0, 'Segment\\nEmbedding\\n(2 × 768)', '#FFF9C4', 9)\n",
"\n",
"for x in [2.75, 6.75, 10.75]:\n",
" ax.annotate('', xy=(x, 11.0), xytext=(x, 12.5), arrowprops=dict(arrowstyle='->', lw=1.5))\n",
"\n",
"# Sum\n",
"draw_box(ax, 3, 9.5, 8, 1.0, '+ (Element-wise Sum) → LayerNorm → (B, L, 768)', '#F8BBD0', 10)\n",
"ax.annotate('', xy=(7, 9.5), xytext=(7, 11.0), arrowprops=dict(arrowstyle='->', lw=2))\n",
"\n",
"# BERT Layers (show 3, indicate 12 total)\n",
"layer_colors = ['#C8E6C9', '#BBDEFB', '#E1BEE7']\n",
"for i, (y_start, color) in enumerate(zip([7.5, 5.5, 3.5], layer_colors)):\n",
" draw_box(ax, 1, y_start, 12, 1.7, \n",
" f'BERT Layer {i+1}:\\n Multi-Head Self-Attention (12 heads, d_k=64) + Add&Norm\\n FFN (768→3072→768, GELU) + Add&Norm',\n",
" color, 9)\n",
" ax.annotate('', xy=(7, y_start), xytext=(7, y_start+1.7 if i > 0 else 9.5), \n",
" arrowprops=dict(arrowstyle='->', lw=2))\n",
"\n",
"# Ellipsis\n",
"ax.text(7, 3.2, '... (12 layers total) ...', ha='center', fontsize=12, color='gray', style='italic')\n",
"\n",
"# Output\n",
"draw_box(ax, 1, 0.5, 12, 1.5, \n",
" 'Output: (B, L, 768)\\n[CLS] token → sentence embedding | All tokens → phrase features',\n",
" '#E8F5E9', 10)\n",
"ax.annotate('', xy=(7, 2.0), xytext=(7, 3.5), arrowprops=dict(arrowstyle='->', lw=2))\n",
"\n",
"ax.set_title('BERT-Base Architecture\\n(Used as Text Encoder in GroundingDINO)', \n",
" fontsize=14, fontweight='bold')\n",
"plt.tight_layout()\n",
"plt.savefig('bert_architecture.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Multi-Head Self-Attention in BERT \n",
"\n",
"### Attention Formula\n",
"\n",
"$$\\text{Attention}(Q, K, V) = \\text{softmax}\\left(\\frac{QK^T}{\\sqrt{d_k}}\\right)V$$\n",
"\n",
"For BERT-base:\n",
"- $d_{model} = 768$\n",
"- $h = 12$ heads\n",
"- $d_k = d_v = 768/12 = 64$\n",
"\n",
"### Multi-Head Attention\n",
"\n",
"$$\\text{MultiHead}(Q, K, V) = \\text{Concat}(\\text{head}_1, ..., \\text{head}_h)W^O$$\n",
"\n",
"where $\\text{head}_i = \\text{Attention}(QW_i^Q, KW_i^K, VW_i^V)$\n",
"\n",
"### Tensor Shapes in BERT Attention\n",
"\n",
"For input `(B, L, 768)` with L=10 tokens:\n",
"```\n",
"Q = x @ W_Q: (B, L, 768) @ (768, 768) → (B, L, 768) → (B, 12, L, 64)\n",
"K = x @ W_K: (B, L, 768) @ (768, 768) → (B, L, 768) → (B, 12, L, 64)\n",
"V = x @ W_V: (B, L, 768) @ (768, 768) → (B, L, 768) → (B, 12, L, 64)\n",
"Attn = QK^T / sqrt(64): (B, 12, L, 64) @ (B, 12, 64, L) → (B, 12, L, L)\n",
"Out = softmax(Attn) @ V: (B, 12, L, L) @ (B, 12, L, 64) → (B, 12, L, 64)\n",
"Concat + proj: (B, 12, L, 64) → (B, L, 768)\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"BERT Self-Attention Tensor Shapes:\n",
"==================================================\n",
"Input x: torch.Size([2, 15, 768]) (B=2, L=15, D=768)\n",
"Q, K, V (before reshape): torch.Size([2, 15, 768]) (B, L, D)\n",
"Q, K, V (multi-head): torch.Size([2, 12, 15, 64]) (B, H=12, L, d_k=64)\n",
"Attention scores: torch.Size([2, 12, 15, 15]) (B, H, L, L)\n",
"Attention weights: torch.Size([2, 12, 15, 15]) (B, H, L, L) [after softmax]\n",
"Context (attn @ V): torch.Size([2, 12, 15, 64]) (B, H, L, d_k)\n",
"After concat heads: torch.Size([2, 15, 768]) (B, L, D)\n",
"Output: torch.Size([2, 15, 768]) (B, L, D)\n",
"\n",
"Final output: torch.Size([2, 15, 768])\n"
]
}
],
"source": [
"# Implement BERT attention to show tensor shapes\n",
"class BertSelfAttentionDetailed(nn.Module):\n",
" \"\"\"BERT self-attention with detailed shape tracking.\"\"\"\n",
" \n",
" def __init__(self, hidden_size=768, num_heads=12):\n",
" super().__init__()\n",
" self.hidden_size = hidden_size\n",
" self.num_heads = num_heads\n",
" self.head_dim = hidden_size // num_heads\n",
" self.scale = self.head_dim ** -0.5\n",
" \n",
" self.query = nn.Linear(hidden_size, hidden_size)\n",
" self.key = nn.Linear(hidden_size, hidden_size)\n",
" self.value = nn.Linear(hidden_size, hidden_size)\n",
" self.out_proj = nn.Linear(hidden_size, hidden_size)\n",
" \n",
" def forward(self, x, attention_mask=None, verbose=True):\n",
" B, L, D = x.shape\n",
" H = self.num_heads\n",
" d_k = self.head_dim\n",
" \n",
" if verbose:\n",
" print(f\"Input x: {x.shape} (B={B}, L={L}, D={D})\")\n",
" \n",
" # Linear projections\n",
" Q = self.query(x) # B, L, D\n",
" K = self.key(x) # B, L, D\n",
" V = self.value(x) # B, L, D\n",
" if verbose:\n",
" print(f\"Q, K, V (before reshape): {Q.shape} (B, L, D)\")\n",
" \n",
" # Reshape to multi-head\n",
" Q = Q.view(B, L, H, d_k).transpose(1, 2) # B, H, L, d_k\n",
" K = K.view(B, L, H, d_k).transpose(1, 2) # B, H, L, d_k\n",
" V = V.view(B, L, H, d_k).transpose(1, 2) # B, H, L, d_k\n",
" if verbose:\n",
" print(f\"Q, K, V (multi-head): {Q.shape} (B, H={H}, L, d_k={d_k})\")\n",
" \n",
" # Attention scores\n",
" attn_scores = torch.matmul(Q, K.transpose(-2, -1)) * self.scale # B, H, L, L\n",
" if verbose:\n",
" print(f\"Attention scores: {attn_scores.shape} (B, H, L, L)\")\n",
" \n",
" # Apply mask\n",
" if attention_mask is not None:\n",
" # attention_mask: B, L → B, 1, 1, L\n",
" mask = (1.0 - attention_mask.float()).unsqueeze(1).unsqueeze(2) * -10000.0\n",
" attn_scores = attn_scores + mask\n",
" \n",
" # Softmax\n",
" attn_weights = torch.softmax(attn_scores, dim=-1) # B, H, L, L\n",
" if verbose:\n",
" print(f\"Attention weights: {attn_weights.shape} (B, H, L, L) [after softmax]\")\n",
" \n",
" # Weighted sum\n",
" context = torch.matmul(attn_weights, V) # B, H, L, d_k\n",
" if verbose:\n",
" print(f\"Context (attn @ V): {context.shape} (B, H, L, d_k)\")\n",
" \n",
" # Concatenate heads\n",
" context = context.transpose(1, 2).contiguous().view(B, L, D) # B, L, D\n",
" if verbose:\n",
" print(f\"After concat heads: {context.shape} (B, L, D)\")\n",
" \n",
" # Output projection\n",
" output = self.out_proj(context) # B, L, D\n",
" if verbose:\n",
" print(f\"Output: {output.shape} (B, L, D)\")\n",
" \n",
" return output, attn_weights\n",
"\n",
"# Test\n",
"B, L, D = 2, 15, 768\n",
"bert_attn = BertSelfAttentionDetailed(hidden_size=768, num_heads=12)\n",
"x = torch.randn(B, L, D)\n",
"mask = torch.ones(B, L)\n",
"mask[0, 12:] = 0 # padding for first sequence\n",
"\n",
"print(\"BERT Self-Attention Tensor Shapes:\")\n",
"print(\"=\" * 50)\n",
"out, attn = bert_attn(x, mask)\n",
"print(f\"\\nFinal output: {out.shape}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Tensor Shapes Through BERT \n",
"\n",
"Complete tensor shape tracking for BERT-base with a sample query:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Query: 'cat sitting on the mat . dog running in the park'\n",
"Tokens: ['cat', 'sitting', 'on', 'the', 'mat', '.', 'dog', 'running', 'in', 'the', 'park']\n",
"Sequence length L = 13 (including [CLS] and [SEP])\n",
"\n",
"BERT Output Shapes:\n",
" last_hidden_state: torch.Size([1, 13, 768]) (B, L, 768)\n",
" pooler_output: torch.Size([1, 768]) (B, 768) [CLS token after linear+tanh]\n",
" hidden_states: 13 tensors (embedding + 12 layers)\n",
" Each: torch.Size([1, 13, 768])\n",
" attentions: 12 tensors (12 layers)\n",
" Each: torch.Size([1, 12, 13, 13]) (B, num_heads, L, L)\n",
"\n",
"Total shape entries: 44\n",
" Component Shape Description\n",
" Input IDs 1 × 13 Token vocabulary indices\n",
" Attention Mask 1 × 13 1=real, 0=padding\n",
" Token Embeddings 1 × 13 × 768 Lookup from 30522×768 table\n",
"Position Embeddings 1 × 13 × 768 Lookup from 512×768 table\n",
" Segment Embeddings 1 × 13 × 768 Lookup from 2×768 table\n",
" Embedding Sum + LN 1 × 13 × 768 Input to transformer layers\n",
" Layer 1 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 1 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 1 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 2 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 2 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 2 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 3 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 3 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 3 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 4 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 4 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 4 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 5 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 5 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 5 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 6 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 6 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 6 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 7 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 7 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 7 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 8 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 8 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 8 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 9 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 9 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 9 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 10 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 10 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 10 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 11 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 11 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 11 Output 1 × 13 × 768 After FFN + residual\n",
" Layer 12 Q/K/V 1 × 12 × 13 × 64 12 heads, d_k=64\n",
" Layer 12 Attn 1 × 12 × 13 × 13 Attention weights\n",
" Layer 12 Output 1 × 13 × 768 After FFN + residual\n",
" Final Output 1 × 13 × 768 Token-level features for grounding\n",
" [CLS] Output 1 × 768 Sentence-level feature\n"
]
}
],
"source": [
"# Run actual BERT and track shapes\n",
"query = \"cat sitting on the mat . dog running in the park\"\n",
"inputs = tokenizer(query, return_tensors='pt', padding=True)\n",
"\n",
"print(f\"Query: '{query}'\")\n",
"print(f\"Tokens: {tokenizer.tokenize(query)}\")\n",
"L = inputs['input_ids'].shape[1]\n",
"print(f\"Sequence length L = {L} (including [CLS] and [SEP])\")\n",
"print()\n",
"\n",
"with torch.no_grad():\n",
" outputs = bert_model(**inputs)\n",
"\n",
"print(\"BERT Output Shapes:\")\n",
"print(f\" last_hidden_state: {outputs.last_hidden_state.shape} (B, L, 768)\")\n",
"print(f\" pooler_output: {outputs.pooler_output.shape} (B, 768) [CLS token after linear+tanh]\")\n",
"print(f\" hidden_states: {len(outputs.hidden_states)} tensors (embedding + 12 layers)\")\n",
"print(f\" Each: {outputs.hidden_states[0].shape}\")\n",
"print(f\" attentions: {len(outputs.attentions)} tensors (12 layers)\")\n",
"print(f\" Each: {outputs.attentions[0].shape} (B, num_heads, L, L)\")\n",
"\n",
"# Detailed shape table\n",
"import pandas as pd\n",
"\n",
"shapes_data = [\n",
" ('Input IDs', f'1 × {L}', 'Token vocabulary indices'),\n",
" ('Attention Mask', f'1 × {L}', '1=real, 0=padding'),\n",
" ('Token Embeddings', f'1 × {L} × 768', 'Lookup from 30522×768 table'),\n",
" ('Position Embeddings', f'1 × {L} × 768', 'Lookup from 512×768 table'),\n",
" ('Segment Embeddings', f'1 × {L} × 768', 'Lookup from 2×768 table'),\n",
" ('Embedding Sum + LN', f'1 × {L} × 768', 'Input to transformer layers'),\n",
"]\n",
"for i in range(12):\n",
" shapes_data.append((f'Layer {i+1} Q/K/V', f'1 × 12 × {L} × 64', f'12 heads, d_k=64'))\n",
" shapes_data.append((f'Layer {i+1} Attn', f'1 × 12 × {L} × {L}', f'Attention weights'))\n",
" shapes_data.append((f'Layer {i+1} Output', f'1 × {L} × 768', f'After FFN + residual'))\n",
"\n",
"shapes_data.append(('Final Output', f'1 × {L} × 768', 'Token-level features for grounding'))\n",
"shapes_data.append(('[CLS] Output', '1 × 768', 'Sentence-level feature'))\n",
"\n",
"df = pd.DataFrame(shapes_data, columns=['Component', 'Shape', 'Description'])\n",
"print(f\"\\nTotal shape entries: {len(df)}\")\n",
"print(df.to_string(index=False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Token-Level Features for Grounding \n",
"\n",
"### How GroundingDINO Uses BERT Features\n",
"\n",
"GroundingDINO uses the **full token-level output** (not just [CLS]):\n",
"\n",
"1. **Feature Enhancer**: All token features participate in cross-modal attention\n",
"2. **Contrastive Loss**: Each detected box is matched to specific tokens\n",
"3. **Phrase Grounding**: Token features are used to identify which words correspond to which box\n",
"\n",
"### Projection to 256-dim\n",
"BERT outputs 768-dim features, but GroundingDINO uses 256-dim:\n",
"$$\\text{BERT output} \\in \\mathbb{R}^{B \\times L \\times 768} \\xrightarrow{\\text{Linear}} \\mathbb{R}^{B \\times L \\times 256}$$\n",
"\n",
"### Text Feature Masking\n",
"The attention mask is used to ignore padding tokens in all subsequent operations."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Demonstrate token-level features\n",
"query = \"cat . dog . bird\"\n",
"inputs = tokenizer(query, return_tensors='pt')\n",
"tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])\n",
"\n",
"with torch.no_grad():\n",
" outputs = bert_model(**inputs)\n",
"\n",
"token_features = outputs.last_hidden_state[0] # L, 768\n",
"\n",
"# Project to 256-dim\n",
"proj = nn.Linear(768, 256)\n",
"with torch.no_grad():\n",
" token_features_256 = proj(token_features) # L, 256\n",
"\n",
"print(f\"Query: '{query}'\")\n",
"print(f\"Tokens: {tokens}\")\n",
"print(f\"\\nToken features (768-dim): {token_features.shape}\")\n",
"print(f\"Token features (256-dim): {token_features_256.shape}\")\n",
"\n",
"# Show feature norms per token\n",
"norms = token_features.norm(dim=-1).numpy()\n",
"print(f\"\\nFeature L2 norms per token:\")\n",
"for tok, norm in zip(tokens, norms):\n",
" bar = '█' * int(norm / 5)\n",
" print(f\" {tok:15s}: {norm:.2f} {bar}\")\n",
"\n",
"# Visualize token features\n",
"fig, axes = plt.subplots(1, 2, figsize=(16, 5))\n",
"\n",
"# Token feature heatmap\n",
"ax1 = axes[0]\n",
"feat_np = token_features.numpy() # L, 768\n",
"im = ax1.imshow(feat_np[:, :64], cmap='RdBu', aspect='auto', vmin=-2, vmax=2)\n",
"ax1.set_yticks(range(len(tokens)))\n",
"ax1.set_yticklabels(tokens, fontsize=10)\n",
"ax1.set_xlabel('Feature dimension (first 64 of 768)')\n",
"ax1.set_title('BERT Token Features\\n(first 64 dimensions)', fontsize=11, fontweight='bold')\n",
"plt.colorbar(im, ax=ax1)\n",
"\n",
"# Token similarity matrix\n",
"ax2 = axes[1]\n",
"feat_norm = feat_np / (np.linalg.norm(feat_np, axis=-1, keepdims=True) + 1e-8)\n",
"sim_matrix = feat_norm @ feat_norm.T\n",
"im2 = ax2.imshow(sim_matrix, cmap='viridis', aspect='equal', vmin=-0.5, vmax=1.0)\n",
"ax2.set_xticks(range(len(tokens)))\n",
"ax2.set_yticks(range(len(tokens)))\n",
"ax2.set_xticklabels(tokens, rotation=45, ha='right', fontsize=9)\n",
"ax2.set_yticklabels(tokens, fontsize=9)\n",
"ax2.set_title('Token Cosine Similarity Matrix\\n(captures semantic relationships)', fontsize=11, fontweight='bold')\n",
"plt.colorbar(im2, ax=ax2)\n",
"\n",
"plt.suptitle('BERT Token-Level Features', fontsize=13, fontweight='bold')\n",
"plt.tight_layout()\n",
"plt.savefig('bert_token_features.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Text Feature Visualization \n",
"\n",
"Let's visualize BERT attention patterns and how they capture semantic relationships."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Visualize BERT attention patterns\n",
"query = \"the large brown dog sitting on the grass\"\n",
"inputs = tokenizer(query, return_tensors='pt')\n",
"tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])\n",
"\n",
"with torch.no_grad():\n",
" outputs = bert_model(**inputs)\n",
"\n",
"# Get attention from all layers\n",
"attentions = outputs.attentions # 12 layers, each (1, 12, L, L)\n",
"\n",
"fig, axes = plt.subplots(3, 4, figsize=(20, 15))\n",
"\n",
"for layer_idx in range(12):\n",
" ax = axes[layer_idx // 4, layer_idx % 4]\n",
" # Average across heads\n",
" attn_avg = attentions[layer_idx][0].mean(0).numpy() # L, L\n",
" im = ax.imshow(attn_avg, cmap='Blues', aspect='equal', vmin=0)\n",
" ax.set_xticks(range(len(tokens)))\n",
" ax.set_yticks(range(len(tokens)))\n",
" ax.set_xticklabels(tokens, rotation=45, ha='right', fontsize=7)\n",
" ax.set_yticklabels(tokens, fontsize=7)\n",
" ax.set_title(f'Layer {layer_idx+1} (avg 12 heads)', fontsize=9, fontweight='bold')\n",
"\n",
"plt.suptitle(f'BERT Attention Patterns Across All 12 Layers\\nQuery: \"{query}\"', \n",
" fontsize=13, fontweight='bold')\n",
"plt.tight_layout()\n",
"plt.savefig('bert_attention_all_layers.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Visualize individual attention heads in last layer\n",
"last_layer_attn = attentions[-1][0].detach().numpy() # 12, L, L\n",
"\n",
"fig, axes = plt.subplots(3, 4, figsize=(20, 15))\n",
"\n",
"for head_idx in range(12):\n",
" ax = axes[head_idx // 4, head_idx % 4]\n",
" im = ax.imshow(last_layer_attn[head_idx], cmap='hot', aspect='equal', vmin=0)\n",
" ax.set_xticks(range(len(tokens)))\n",
" ax.set_yticks(range(len(tokens)))\n",
" ax.set_xticklabels(tokens, rotation=45, ha='right', fontsize=7)\n",
" ax.set_yticklabels(tokens, fontsize=7)\n",
" ax.set_title(f'Head {head_idx+1}', fontsize=9, fontweight='bold')\n",
"\n",
"plt.suptitle(f'BERT Layer 12: Individual Attention Heads\\nQuery: \"{query}\"', \n",
" fontsize=13, fontweight='bold')\n",
"plt.tight_layout()\n",
"plt.savefig('bert_attention_heads.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Visualize hidden state evolution across layers\n",
"query = \"cat . dog\"\n",
"inputs = tokenizer(query, return_tensors='pt')\n",
"tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])\n",
"\n",
"with torch.no_grad():\n",
" outputs = bert_model(**inputs)\n",
"\n",
"hidden_states = outputs.hidden_states # 13 tensors (embedding + 12 layers)\n",
"\n",
"# Track how [CLS] token evolves\n",
"cls_evolution = torch.stack([h[0, 0] for h in hidden_states]) # 13, 768\n",
"cat_evolution = torch.stack([h[0, 1] for h in hidden_states]) # 13, 768 (\"cat\" token)\n",
"dog_evolution = torch.stack([h[0, 3] for h in hidden_states]) # 13, 768 (\"dog\" token)\n",
"\n",
"fig, axes = plt.subplots(1, 3, figsize=(18, 5))\n",
"\n",
"# Feature norm evolution\n",
"ax1 = axes[0]\n",
"layers = range(13)\n",
"ax1.plot(layers, cls_evolution.norm(dim=-1).numpy(), 'b-o', label='[CLS]', linewidth=2)\n",
"ax1.plot(layers, cat_evolution.norm(dim=-1).numpy(), 'r-o', label='cat', linewidth=2)\n",
"ax1.plot(layers, dog_evolution.norm(dim=-1).numpy(), 'g-o', label='dog', linewidth=2)\n",
"ax1.set_xlabel('Layer')\n",
"ax1.set_ylabel('Feature L2 Norm')\n",
"ax1.set_title('Token Feature Norm\\nAcross BERT Layers', fontsize=11, fontweight='bold')\n",
"ax1.legend()\n",
"ax1.grid(True, alpha=0.3)\n",
"ax1.set_xticks(range(13))\n",
"ax1.set_xticklabels(['Emb'] + [str(i) for i in range(1, 13)])\n",
"\n",
"# Cosine similarity between cat and dog across layers\n",
"ax2 = axes[1]\n",
"sims = []\n",
"for h in hidden_states:\n",
" cat_f = h[0, 1]\n",
" dog_f = h[0, 3]\n",
" sim = torch.cosine_similarity(cat_f.unsqueeze(0), dog_f.unsqueeze(0)).item()\n",
" sims.append(sim)\n",
"ax2.plot(layers, sims, 'purple', linewidth=2, marker='o')\n",
"ax2.set_xlabel('Layer')\n",
"ax2.set_ylabel('Cosine Similarity')\n",
"ax2.set_title('Cosine Similarity: \"cat\" vs \"dog\"\\nAcross BERT Layers', fontsize=11, fontweight='bold')\n",
"ax2.grid(True, alpha=0.3)\n",
"ax2.set_xticks(range(13))\n",
"ax2.set_xticklabels(['Emb'] + [str(i) for i in range(1, 13)])\n",
"\n",
"# Feature heatmap at last layer\n",
"ax3 = axes[2]\n",
"last_hidden = hidden_states[-1][0].numpy() # L, 768\n",
"im = ax3.imshow(last_hidden[:, :100], cmap='RdBu', aspect='auto', vmin=-3, vmax=3)\n",
"ax3.set_yticks(range(len(tokens)))\n",
"ax3.set_yticklabels(tokens, fontsize=10)\n",
"ax3.set_xlabel('Feature dimension (first 100 of 768)')\n",
"ax3.set_title('Final BERT Features\\n(Layer 12 output)', fontsize=11, fontweight='bold')\n",
"plt.colorbar(im, ax=ax3)\n",
"\n",
"plt.suptitle('BERT Feature Evolution Analysis', fontsize=13, fontweight='bold')\n",
"plt.tight_layout()\n",
"plt.savefig('bert_feature_evolution.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Special Tokens & Phrase Alignment \n",
"\n",
"### GroundingDINO Text Format\n",
"\n",
"GroundingDINO uses a specific text format for multi-category detection:\n",
"\n",
"```python\n",
"# Single category\n",
"text = \"cat\"\n",
"\n",
"# Multiple categories (dot-separated)\n",
"text = \"cat . dog . bird\"\n",
"\n",
"# Referring expression\n",
"text = \"the large brown dog sitting on the grass\"\n",
"```\n",
"\n",
"### Phrase Alignment\n",
"After detection, each bounding box is matched to specific tokens:\n",
"- The model outputs a **logit vector** of size L (sequence length)\n",
"- High logits at token positions indicate the box corresponds to those words\n",
"- This enables **phrase grounding**: knowing which words describe which box\n",
"\n",
"### Token Position Tracking\n",
"For `\"cat . dog . bird\"` → `[CLS] cat . dog . bird [SEP]`:\n",
"- Token 1 (`cat`) → category 1\n",
"- Token 3 (`dog`) → category 2 \n",
"- Token 5 (`bird`) → category 3\n",
"- Tokens 2, 4 (`.`) → separators (ignored)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Demonstrate phrase alignment\n",
"def get_phrase_positions(tokenizer, text):\n",
" \"\"\"Get token positions for each phrase in dot-separated text.\"\"\"\n",
" phrases = [p.strip() for p in text.split('.')]\n",
" \n",
" # Tokenize full text\n",
" full_tokens = tokenizer.tokenize(text)\n",
" full_ids = tokenizer.encode(text)\n",
" all_tokens = tokenizer.convert_ids_to_tokens(full_ids)\n",
" \n",
" print(f\"Text: '{text}'\")\n",
" print(f\"Phrases: {phrases}\")\n",
" print(f\"All tokens: {all_tokens}\")\n",
" print()\n",
" \n",
" # Find positions of each phrase\n",
" phrase_positions = {}\n",
" for phrase in phrases:\n",
" phrase_tokens = tokenizer.tokenize(phrase)\n",
" # Find in full token list\n",
" for i in range(len(all_tokens)):\n",
" if all_tokens[i:i+len(phrase_tokens)] == phrase_tokens:\n",
" phrase_positions[phrase] = list(range(i, i+len(phrase_tokens)))\n",
" break\n",
" \n",
" return phrase_positions, all_tokens\n",
"\n",
"# Example\n",
"text = \"cat . dog . bird\"\n",
"positions, tokens = get_phrase_positions(tokenizer, text)\n",
"\n",
"print(\"Phrase → Token Positions:\")\n",
"for phrase, pos in positions.items():\n",
" print(f\" '{phrase}' → positions {pos} → tokens {[tokens[p] for p in pos]}\")\n",
"\n",
"# Visualize phrase alignment\n",
"fig, ax = plt.subplots(figsize=(14, 5))\n",
"ax.set_xlim(-0.5, len(tokens) - 0.5)\n",
"ax.set_ylim(-1, 3)\n",
"ax.axis('off')\n",
"\n",
"colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']\n",
"phrase_colors = {phrase: colors[i] for i, phrase in enumerate(positions.keys())}\n",
"\n",
"# Draw tokens\n",
"for i, tok in enumerate(tokens):\n",
" # Find which phrase this token belongs to\n",
" tok_color = '#E0E0E0'\n",
" for phrase, pos in positions.items():\n",
" if i in pos:\n",
" tok_color = phrase_colors[phrase]\n",
" break\n",
" \n",
" rect = patches.FancyBboxPatch((i - 0.4, 1.0), 0.8, 0.8, \n",
" boxstyle='round,pad=0.05',\n",
" facecolor=tok_color, edgecolor='black', linewidth=1.5)\n",
" ax.add_patch(rect)\n",
" ax.text(i, 1.4, tok, ha='center', va='center', fontsize=10, fontweight='bold')\n",
" ax.text(i, 0.7, str(i), ha='center', va='center', fontsize=8, color='gray')\n",
"\n",
"# Draw phrase labels\n",
"for phrase, pos in positions.items():\n",
" mid = np.mean(pos)\n",
" ax.text(mid, 2.2, f'→ \"{phrase}\"', ha='center', va='center', fontsize=11,\n",
" color=phrase_colors[phrase], fontweight='bold',\n",
" bbox=dict(boxstyle='round', facecolor='white', edgecolor=phrase_colors[phrase]))\n",
" for p in pos:\n",
" ax.annotate('', xy=(p, 1.8), xytext=(mid, 2.1),\n",
" arrowprops=dict(arrowstyle='->', color=phrase_colors[phrase], lw=1.5))\n",
"\n",
"ax.set_title(f'Phrase Alignment: \"{text}\"\\nEach phrase maps to specific token positions', \n",
" fontsize=12, fontweight='bold')\n",
"plt.tight_layout()\n",
"plt.savefig('phrase_alignment.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Complete BERT pipeline for GroundingDINO\n",
"class BERTTextEncoder(nn.Module):\n",
" \"\"\"BERT text encoder as used in GroundingDINO.\"\"\"\n",
" \n",
" def __init__(self, hidden_size=768, output_dim=256):\n",
" super().__init__()\n",
" self.bert = BertModel.from_pretrained('bert-base-uncased')\n",
" self.proj = nn.Linear(hidden_size, output_dim)\n",
" \n",
" def forward(self, input_ids, attention_mask, token_type_ids=None):\n",
" # Run BERT\n",
" outputs = self.bert(\n",
" input_ids=input_ids,\n",
" attention_mask=attention_mask,\n",
" token_type_ids=token_type_ids\n",
" )\n",
" \n",
" # Get token-level features\n",
" token_features = outputs.last_hidden_state # B, L, 768\n",
" \n",
" # Project to 256-dim\n",
" token_features_256 = self.proj(token_features) # B, L, 256\n",
" \n",
" return {\n",
" 'token_features': token_features_256, # B, L, 256\n",
" 'attention_mask': attention_mask, # B, L\n",
" 'cls_feature': token_features_256[:, 0, :] # B, 256\n",
" }\n",
"\n",
"# Test\n",
"text_encoder = BERTTextEncoder()\n",
"text_encoder.eval()\n",
"\n",
"query = \"cat . dog . bird\"\n",
"inputs = tokenizer(query, return_tensors='pt')\n",
"\n",
"with torch.no_grad():\n",
" text_out = text_encoder(**inputs)\n",
"\n",
"print(\"BERT Text Encoder Output:\")\n",
"print(f\" Input query: '{query}'\")\n",
"print(f\" Sequence length: {inputs['input_ids'].shape[1]}\")\n",
"print(f\" token_features: {text_out['token_features'].shape} (B, L, 256)\")\n",
"print(f\" attention_mask: {text_out['attention_mask'].shape} (B, L)\")\n",
"print(f\" cls_feature: {text_out['cls_feature'].shape} (B, 256)\")\n",
"\n",
"total_params = sum(p.numel() for p in text_encoder.parameters())\n",
"print(f\"\\nTotal parameters: {total_params:,} ({total_params/1e6:.1f}M)\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"The BERT text encoder in GroundingDINO:\n",
"\n",
"1. **Tokenizes** the text query using WordPiece tokenization\n",
"2. **Encodes** tokens through 12 bidirectional transformer layers\n",
"3. **Outputs** token-level features `(B, L, 768)` — one vector per token\n",
"4. **Projects** to 256-dim for the Feature Enhancer\n",
"\n",
"Key tensor shapes:\n",
"- Input: `(B, L)` token IDs\n",
"- Embeddings: `(B, L, 768)`\n",
"- Each layer Q/K/V: `(B, 12, L, 64)`\n",
"- Each layer attention: `(B, 12, L, L)`\n",
"- Final output: `(B, L, 768)` → projected to `(B, L, 256)`\n",
"\n",
"The token-level features enable **phrase grounding** — matching specific words to specific detected regions.\n",
"\n",
"**Next**: [Notebook 04 - Feature Enhancer](04_feature_enhancer.ipynb)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}