1// ââ Deformable Convolution Entry âââââââââââââââââââââââââââââââââââââââââââââ 2microblogEntries.push({ 3 content: `<p>Standard convolutions sample on a fixed rectangular grid, limiting for irregular shapes. Deformable Convolutions (<a href="https://arxiv.org/abs/1703.06211" target="_blank">Dai et al., ICCV 2017</a>) add learnable offsets to each sampling position so the receptive field adapts to the geometry of the content. DCNv2 (<a href="https://arxiv.org/abs/1811.11168" target="_blank">Zhu et al., CVPR 2019</a>) adds per-sample modulation scalars that control <em>how much</em> each offset position contributes. DCNv3 (<a href="https://arxiv.org/abs/2211.05778" target="_blank">Wang et al., CVPR 2023</a>) shares weights across groups and softmax-normalises the modulation, and DCNv4 (<a href="https://arxiv.org/abs/2401.06197" target="_blank">Xiong et al., CVPR 2024</a>) removes the softmax constraint and optimises memory access for faster inference.</p>`, 4 date: "Mar. '26", 5 diagram: "deformable-conv", 6 id: "deformable-convolutions", 7 links: [], 8 tags: ["computer-vision", "convolutions"], 9 title: "Deformable Convolutions", 10}); 11 12// ââ DCN Diagram Builder ââââââââââââââââââââââââââââââââââââââââââââââââââââââ 13function buildMicroblogDiagramDCN(type) { 14 if (type !== "deformable-conv") { 15 return; 16 } 17 const container = document.getElementById( 18 "microblog-diagram-deformable-conv" 19 ); 20 if (!container) { 21 return; 22 } 23 24 // 3x3 kernel positions on a normalised grid 25 const gridPts = []; 26 for (let r = 0; r < 3; r += 1) { 27 for (let c = 0; c < 3; c += 1) { 28 gridPts.push({ x: 25 + c * 25, y: 25 + r * 25 }); 29 } 30 } 31 32 // Deformed offsets â points that hug the ellipse boundary (cx=50, cy=50, rx=34, ry=28, rot=-12deg) 33 const deformedPts = [ 34 { x: 20, y: 28 }, 35 { x: 50, y: 20 }, 36 { x: 80, y: 26 }, 37 { x: 16, y: 50 }, 38 { x: 50, y: 50 }, 39 { x: 84, y: 48 }, 40 { x: 22, y: 72 }, 41 { x: 50, y: 78 }, 42 { x: 78, y: 72 }, 43 ]; 44 45 let mode = "standard"; 46 const currentPts = gridPts.map((p) => ({ x: p.x, y: p.y })); 47 48 // Blob shape (irregular region the kernel adapts to) 49 const blobSvg = `<ellipse cx="50" cy="50" rx="34" ry="28" 50 transform="rotate(-12 50 50)" 51 fill="none" stroke="var(--border)" stroke-width="1.2" 52 stroke-dasharray="4 3" opacity="0.6"/>`; 53 54 // Build SVG 55 const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 56 svg.setAttribute("viewBox", "5 12 90 80"); 57 svg.setAttribute("class", "dcn-svg"); 58 svg.innerHTML = blobSvg; 59 60 // Connection lines (grid edges) 61 const lines = []; 62 const lineIdxPairs = [ 63 [0, 1], 64 [1, 2], 65 [3, 4], 66 [4, 5], 67 [6, 7], 68 [7, 8], 69 [0, 3], 70 [3, 6], 71 [1, 4], 72 [4, 7], 73 [2, 5], 74 [5, 8], 75 ]; 76 for (const [a, b] of lineIdxPairs) { 77 const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); 78 line.setAttribute("class", "dcn-line"); 79 svg.appendChild(line); 80 lines.push({ a, b, el: line }); 81 } 82 83 // Sample points 84 const dots = gridPts.map(() => { 85 const circle = document.createElementNS( 86 "http://www.w3.org/2000/svg", 87 "circle" 88 ); 89 circle.setAttribute("r", "2.8"); 90 circle.setAttribute("class", "dcn-dot"); 91 svg.appendChild(circle); 92 return circle; 93 }); 94 95 // Offset arrows (only visible in deformable mode) 96 const arrows = gridPts.map(() => { 97 const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); 98 line.setAttribute("class", "dcn-arrow"); 99 svg.appendChild(line); 100 return line; 101 }); 102 103 function updatePositions() { 104 for (const [i, dot] of dots.entries()) { 105 dot.setAttribute("cx", currentPts[i].x); 106 dot.setAttribute("cy", currentPts[i].y); 107 } 108 for (const { el, a, b } of lines) { 109 el.setAttribute("x1", currentPts[a].x); 110 el.setAttribute("y1", currentPts[a].y);
111 el.setAttribute("x2", currentPts[b].x); 112 el.setAttribute("y2", currentPts[b].y); 113 } 114 for (const [i, arrow] of arrows.entries()) { 115 arrow.setAttribute("x1", gridPts[i].x); 116 arrow.setAttribute("y1", gridPts[i].y); 117 arrow.setAttribute("x2", currentPts[i].x); 118 arrow.setAttribute("y2", currentPts[i].y); 119 } 120 } 121 122 function animateTo(targetPts) { 123 const startPts = currentPts.map((p) => ({ x: p.x, y: p.y })); 124 const duration = 500; 125 const start = performance.now(); 126 function tick(now) { 127 const t = Math.min(1, (now - start) / duration); 128 const ease = 1 - (1 - t) ** 3; 129 for (const [i, p] of currentPts.entries()) { 130 p.x = startPts[i].x + (targetPts[i].x - startPts[i].x) * ease; 131 p.y = startPts[i].y + (targetPts[i].y - startPts[i].y) * ease; 132 } 133 updatePositions(); 134 if (t < 1) { 135 requestAnimationFrame(tick); 136 } 137 } 138 requestAnimationFrame(tick); 139 } 140 141 // Toggle buttons 142 const toggle = document.createElement("div"); 143 toggle.className = "dcn-toggle"; 144 145 const btnStd = document.createElement("button"); 146 btnStd.className = "dcn-btn active"; 147 btnStd.textContent = "Standard"; 148 149 const btnDef = document.createElement("button"); 150 btnDef.className = "dcn-btn"; 151 btnDef.textContent = "Deformable"; 152 153 function applyMode(m) { 154 if (m === mode) { 155 return; 156 } 157 mode = m; 158 btnStd.classList.toggle("active", mode === "standard"); 159 btnDef.classList.toggle("active", mode === "deformable"); 160 svg.classList.toggle("dcn-deformable", mode === "deformable"); 161 animateTo(mode === "deformable" ? deformedPts : gridPts); 162 } 163 164 btnStd.addEventListener("click", () => setMode("standard")); 165 btnDef.addEventListener("click", () => setMode("deformable")); 166 167 toggle.appendChild(btnStd); 168 toggle.appendChild(btnDef); 169 170 // Equation panel 171 const eqPanel = document.createElement("div"); 172 eqPanel.className = "dcn-eq"; 173 eqPanel.innerHTML = ` 174 <div class="dcn-eq-standard dcn-eq-block active"> 175 <span class="dcn-eq-label">Standard</span> 176 <span class="dcn-eq-formula">y(p<sub>0</sub>) = Σ w(p<sub>n</sub>) · x(p<sub>0</sub> + p<sub>n</sub>)</span> 177 </div> 178 <div class="dcn-eq-deformable dcn-eq-block"> 179 <span class="dcn-eq-label">Deformable</span> 180 <span class="dcn-eq-formula">y(p<sub>0</sub>) = Σ w(p<sub>n</sub>) · x(p<sub>0</sub> + p<sub>n</sub> + <em>Δp<sub>n</sub></em>)</span> 181 </div> 182 <div class="dcn-eq-v2 dcn-eq-block"> 183 <span class="dcn-eq-label">v2 / v3 / v4</span> 184 <span class="dcn-eq-formula">y(p<sub>0</sub>) = Σ w(p<sub>n</sub>) · <em>m<sub>n</sub></em> · x(p<sub>0</sub> + p<sub>n</sub> + <em>Δp<sub>n</sub></em>)</span> 185 <span class="dcn-eq-note">v3 & v4 differ architecturally, not in the sampling formula.</span> 186 </div> 187 `; 188 189 const eqBlocks = eqPanel.querySelectorAll(".dcn-eq-block"); 190 191 // Wrap SVG + equation side by side 192 const body = document.createElement("div"); 193 body.className = "dcn-body"; 194 body.appendChild(svg); 195 body.appendChild(eqPanel); 196 197 function setMode(m) { 198 applyMode(m); 199 for (const b of eqBlocks) { 200 b.classList.remove("active"); 201 } 202 if (m === "standard") { 203 eqPanel.querySelector(".dcn-eq-standard").classList.add("active"); 204 } else { 205 eqPanel.querySelector(".dcn-eq-deformable").classList.add("active"); 206 eqPanel.querySelector(".dcn-eq-v2").classList.add("active"); 207 } 208 } 209 210 // Caption 211 const caption = document.createElement("p"); 212 caption.className = "dcn-caption"; 213 caption.textContent = 214 "Click to toggle between fixed and learnable sampling positions."; 215 216 container.appendChild(toggle); 217 container.appendChild(body); 218 container.appendChild(caption); 219 updatePositions(); 220}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.