@driftengine/capture 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +29 -0
- package/README.md +68 -0
- package/dist/browserFrames.d.ts +31 -0
- package/dist/browserFrames.js +105 -0
- package/dist/collide.d.ts +59 -0
- package/dist/collide.js +92 -0
- package/dist/decimate.d.ts +42 -0
- package/dist/decimate.js +439 -0
- package/dist/delight.d.ts +42 -0
- package/dist/delight.js +351 -0
- package/dist/delightScene.d.ts +37 -0
- package/dist/delightScene.js +183 -0
- package/dist/depth.d.ts +44 -0
- package/dist/depth.js +53 -0
- package/dist/features.d.ts +33 -0
- package/dist/features.js +260 -0
- package/dist/frames.d.ts +47 -0
- package/dist/frames.js +87 -0
- package/dist/fusion.d.ts +77 -0
- package/dist/fusion.js +152 -0
- package/dist/gaussians/adam.d.ts +57 -0
- package/dist/gaussians/adam.js +88 -0
- package/dist/gaussians/depth.d.ts +8 -0
- package/dist/gaussians/depth.js +73 -0
- package/dist/gaussians/gradients.d.ts +36 -0
- package/dist/gaussians/gradients.js +228 -0
- package/dist/gaussians/harmonics.d.ts +46 -0
- package/dist/gaussians/harmonics.js +99 -0
- package/dist/gaussians/optimise.d.ts +50 -0
- package/dist/gaussians/optimise.js +125 -0
- package/dist/gaussians/parameters.d.ts +35 -0
- package/dist/gaussians/parameters.js +165 -0
- package/dist/gaussians/project.d.ts +72 -0
- package/dist/gaussians/project.js +137 -0
- package/dist/gaussians/projectGradient.d.ts +15 -0
- package/dist/gaussians/projectGradient.js +213 -0
- package/dist/gaussians/rasterise.d.ts +13 -0
- package/dist/gaussians/rasterise.js +65 -0
- package/dist/gaussians/refine.d.ts +36 -0
- package/dist/gaussians/refine.js +136 -0
- package/dist/gaussians/similarity.d.ts +25 -0
- package/dist/gaussians/similarity.js +80 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +96 -0
- package/dist/marching.d.ts +38 -0
- package/dist/marching.js +258 -0
- package/dist/masks.d.ts +59 -0
- package/dist/masks.js +165 -0
- package/dist/math/dense.d.ts +68 -0
- package/dist/math/dense.js +294 -0
- package/dist/math/schur.d.ts +23 -0
- package/dist/math/schur.js +140 -0
- package/dist/models/batchNorm.d.ts +17 -0
- package/dist/models/batchNorm.js +24 -0
- package/dist/models/clipTokenizer.d.ts +40 -0
- package/dist/models/clipTokenizer.js +122 -0
- package/dist/models/clipTower.d.ts +27 -0
- package/dist/models/clipTower.js +45 -0
- package/dist/models/depthAnything2.d.ts +38 -0
- package/dist/models/depthAnything2.js +163 -0
- package/dist/models/depthAnything3.d.ts +26 -0
- package/dist/models/depthAnything3.js +171 -0
- package/dist/models/dualDpt.d.ts +19 -0
- package/dist/models/dualDpt.js +138 -0
- package/dist/models/hiera.d.ts +49 -0
- package/dist/models/hiera.js +120 -0
- package/dist/models/hieraAttention.d.ts +16 -0
- package/dist/models/hieraAttention.js +68 -0
- package/dist/models/miniature.d.ts +36 -0
- package/dist/models/miniature.js +216 -0
- package/dist/models/mobileSam.d.ts +41 -0
- package/dist/models/mobileSam.js +88 -0
- package/dist/models/owlv2.d.ts +49 -0
- package/dist/models/owlv2.js +131 -0
- package/dist/models/owlv2Detect.d.ts +25 -0
- package/dist/models/owlv2Detect.js +80 -0
- package/dist/models/owlv2Miniature.d.ts +27 -0
- package/dist/models/owlv2Miniature.js +87 -0
- package/dist/models/rope.d.ts +23 -0
- package/dist/models/rope.js +84 -0
- package/dist/models/sam21.d.ts +45 -0
- package/dist/models/sam21.js +126 -0
- package/dist/models/sam21Miniature.d.ts +37 -0
- package/dist/models/sam21Miniature.js +194 -0
- package/dist/models/sam21Video.d.ts +30 -0
- package/dist/models/sam21Video.js +101 -0
- package/dist/models/sam2Choice.d.ts +19 -0
- package/dist/models/sam2Choice.js +55 -0
- package/dist/models/sam2Decoder.d.ts +36 -0
- package/dist/models/sam2Decoder.js +108 -0
- package/dist/models/sam2Memories.d.ts +54 -0
- package/dist/models/sam2Memories.js +93 -0
- package/dist/models/sam2Memory.d.ts +30 -0
- package/dist/models/sam2Memory.js +136 -0
- package/dist/models/sam2Positions.d.ts +24 -0
- package/dist/models/sam2Positions.js +94 -0
- package/dist/models/sam2Tracker.d.ts +69 -0
- package/dist/models/sam2Tracker.js +172 -0
- package/dist/models/samDecoder.d.ts +45 -0
- package/dist/models/samDecoder.js +96 -0
- package/dist/models/samMiniature.d.ts +43 -0
- package/dist/models/samMiniature.js +161 -0
- package/dist/models/samPrompt.d.ts +57 -0
- package/dist/models/samPrompt.js +160 -0
- package/dist/models/seeded.d.ts +16 -0
- package/dist/models/seeded.js +48 -0
- package/dist/models/tinyVit.d.ts +38 -0
- package/dist/models/tinyVit.js +82 -0
- package/dist/models/twoWay.d.ts +46 -0
- package/dist/models/twoWay.js +67 -0
- package/dist/models/vit.d.ts +45 -0
- package/dist/models/vit.js +157 -0
- package/dist/models/windowAttention.d.ts +25 -0
- package/dist/models/windowAttention.js +104 -0
- package/dist/poses.d.ts +31 -0
- package/dist/poses.js +750 -0
- package/dist/prepare.d.ts +30 -0
- package/dist/prepare.js +238 -0
- package/dist/propose.d.ts +36 -0
- package/dist/propose.js +63 -0
- package/dist/resample.d.ts +39 -0
- package/dist/resample.js +165 -0
- package/dist/run.d.ts +3 -0
- package/dist/run.js +1 -0
- package/dist/scene.d.ts +104 -0
- package/dist/scene.js +109 -0
- package/dist/segment.d.ts +40 -0
- package/dist/segment.js +184 -0
- package/dist/testScene.d.ts +55 -0
- package/dist/testScene.js +214 -0
- package/dist/twoView.d.ts +22 -0
- package/dist/twoView.js +435 -0
- package/package.json +63 -0
- package/src/browserFrames.ts +145 -0
- package/src/collide.ts +128 -0
- package/src/decimate.ts +510 -0
- package/src/delight.ts +427 -0
- package/src/delightScene.ts +249 -0
- package/src/depth.ts +100 -0
- package/src/features.ts +302 -0
- package/src/frames.ts +111 -0
- package/src/fusion.ts +229 -0
- package/src/gaussians/adam.ts +131 -0
- package/src/gaussians/depth.ts +87 -0
- package/src/gaussians/gradients.ts +285 -0
- package/src/gaussians/harmonics.ts +122 -0
- package/src/gaussians/optimise.ts +191 -0
- package/src/gaussians/parameters.ts +186 -0
- package/src/gaussians/project.ts +207 -0
- package/src/gaussians/projectGradient.ts +234 -0
- package/src/gaussians/rasterise.ts +81 -0
- package/src/gaussians/refine.ts +176 -0
- package/src/gaussians/similarity.ts +87 -0
- package/src/index.ts +225 -0
- package/src/marching.ts +358 -0
- package/src/masks.ts +201 -0
- package/src/math/dense.ts +317 -0
- package/src/math/schur.ts +167 -0
- package/src/models/batchNorm.ts +57 -0
- package/src/models/clipTokenizer.ts +129 -0
- package/src/models/clipTower.ts +87 -0
- package/src/models/depthAnything2.ts +276 -0
- package/src/models/depthAnything3.ts +229 -0
- package/src/models/dualDpt.ts +233 -0
- package/src/models/hiera.ts +231 -0
- package/src/models/hieraAttention.ts +121 -0
- package/src/models/miniature.ts +241 -0
- package/src/models/mobileSam.ts +135 -0
- package/src/models/owlv2.ts +190 -0
- package/src/models/owlv2Detect.ts +116 -0
- package/src/models/owlv2Miniature.ts +108 -0
- package/src/models/rope.ts +111 -0
- package/src/models/sam21.ts +182 -0
- package/src/models/sam21Miniature.ts +225 -0
- package/src/models/sam21Video.ts +154 -0
- package/src/models/sam2Choice.ts +62 -0
- package/src/models/sam2Decoder.ts +218 -0
- package/src/models/sam2Memories.ts +165 -0
- package/src/models/sam2Memory.ts +247 -0
- package/src/models/sam2Positions.ts +106 -0
- package/src/models/sam2Tracker.ts +300 -0
- package/src/models/samDecoder.ts +225 -0
- package/src/models/samMiniature.ts +190 -0
- package/src/models/samPrompt.ts +227 -0
- package/src/models/seeded.ts +50 -0
- package/src/models/tinyVit.ts +178 -0
- package/src/models/twoWay.ts +122 -0
- package/src/models/vit.ts +265 -0
- package/src/models/windowAttention.ts +155 -0
- package/src/poses.ts +894 -0
- package/src/prepare.ts +306 -0
- package/src/propose.ts +96 -0
- package/src/resample.ts +197 -0
- package/src/run.ts +7 -0
- package/src/scene.ts +141 -0
- package/src/segment.ts +220 -0
- package/src/testScene.ts +283 -0
- package/src/twoView.ts +536 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { draw } from './seeded.js';
|
|
2
|
+
export const MINIATURE_OWLV2 = {
|
|
3
|
+
size: 64,
|
|
4
|
+
patch: 16,
|
|
5
|
+
vision: { dim: 32, heads: 2, depth: 2, hidden: 48 },
|
|
6
|
+
text: { dim: 24, heads: 2, depth: 2, hidden: 40, positions: 16 },
|
|
7
|
+
};
|
|
8
|
+
/** c+a, ca+t</w> and a+t</w>: tokens 512 to 514, and the start and end of text 515 and 516. */
|
|
9
|
+
export const MINIATURE_OWLV2_MERGES = Float32Array.of(66, 64, 512, 339, 64, 339);
|
|
10
|
+
/**
|
|
11
|
+
* Three queries as token ids: one ending early, one with the padding token inside it — the "!" a
|
|
12
|
+
* text may hold — and one filling every position.
|
|
13
|
+
*/
|
|
14
|
+
export const MINIATURE_OWLV2_QUERIES = [
|
|
15
|
+
[515, 513, 516],
|
|
16
|
+
[515, 83, 514, 0, 320, 513, 516],
|
|
17
|
+
[515, 10, 200, 300, 400, 500, 511, 512, 1, 2, 3, 100, 250, 350, 450, 516],
|
|
18
|
+
];
|
|
19
|
+
/** The original image's size the boxes are scaled to: wider than tall, padded below. */
|
|
20
|
+
export const MINIATURE_OWLV2_IMAGE = { height: 36, width: 48 };
|
|
21
|
+
/** Every tensor the upstream's `Owlv2ForObjectDetection` holds, named as its checkpoints are. */
|
|
22
|
+
export function miniatureOwlv2Checkpoint(config, seed) {
|
|
23
|
+
const out = new Map();
|
|
24
|
+
const add = (name, shape) => {
|
|
25
|
+
out.set(name, { shape, data: draw(name, shape, seed) });
|
|
26
|
+
};
|
|
27
|
+
const tower = (prefix, dim, hidden, depth) => {
|
|
28
|
+
for (let i = 0; i < depth; i += 1) {
|
|
29
|
+
const p = `${prefix}encoder.layers.${i}.`;
|
|
30
|
+
for (const norm of ['layer_norm1', 'layer_norm2']) {
|
|
31
|
+
add(`${p}${norm}.weight`, [dim]);
|
|
32
|
+
add(`${p}${norm}.bias`, [dim]);
|
|
33
|
+
}
|
|
34
|
+
for (const projection of ['q_proj', 'k_proj', 'v_proj', 'out_proj']) {
|
|
35
|
+
add(`${p}self_attn.${projection}.weight`, [dim, dim]);
|
|
36
|
+
add(`${p}self_attn.${projection}.bias`, [dim]);
|
|
37
|
+
}
|
|
38
|
+
add(`${p}mlp.fc1.weight`, [hidden, dim]);
|
|
39
|
+
add(`${p}mlp.fc1.bias`, [hidden]);
|
|
40
|
+
add(`${p}mlp.fc2.weight`, [dim, hidden]);
|
|
41
|
+
add(`${p}mlp.fc2.bias`, [dim]);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const { vision, text, patch } = config;
|
|
45
|
+
const cells = (config.size / patch) * (config.size / patch);
|
|
46
|
+
const t = 'owlv2.text_model.';
|
|
47
|
+
add(`${t}embeddings.token_embedding.weight`, [
|
|
48
|
+
512 + MINIATURE_OWLV2_MERGES.length / 2 + 2,
|
|
49
|
+
text.dim,
|
|
50
|
+
]);
|
|
51
|
+
add(`${t}embeddings.position_embedding.weight`, [text.positions, text.dim]);
|
|
52
|
+
tower(t, text.dim, text.hidden, text.depth);
|
|
53
|
+
add(`${t}final_layer_norm.weight`, [text.dim]);
|
|
54
|
+
add(`${t}final_layer_norm.bias`, [text.dim]);
|
|
55
|
+
const v = 'owlv2.vision_model.';
|
|
56
|
+
add(`${v}embeddings.class_embedding`, [vision.dim]);
|
|
57
|
+
add(`${v}embeddings.patch_embedding.weight`, [vision.dim, 3, patch, patch]);
|
|
58
|
+
add(`${v}embeddings.position_embedding.weight`, [cells + 1, vision.dim]);
|
|
59
|
+
for (const norm of ['pre_layernorm', 'post_layernorm']) {
|
|
60
|
+
add(`${v}${norm}.weight`, [vision.dim]);
|
|
61
|
+
add(`${v}${norm}.bias`, [vision.dim]);
|
|
62
|
+
}
|
|
63
|
+
tower(v, vision.dim, vision.hidden, vision.depth);
|
|
64
|
+
add('owlv2.visual_projection.weight', [text.dim, vision.dim]);
|
|
65
|
+
add('owlv2.text_projection.weight', [text.dim, text.dim]);
|
|
66
|
+
add('owlv2.logit_scale', []);
|
|
67
|
+
add('layer_norm.weight', [vision.dim]);
|
|
68
|
+
add('layer_norm.bias', [vision.dim]);
|
|
69
|
+
add('class_head.dense0.weight', [text.dim, vision.dim]);
|
|
70
|
+
add('class_head.dense0.bias', [text.dim]);
|
|
71
|
+
for (const logit of ['logit_shift', 'logit_scale']) {
|
|
72
|
+
add(`class_head.${logit}.weight`, [1, vision.dim]);
|
|
73
|
+
add(`class_head.${logit}.bias`, [1]);
|
|
74
|
+
}
|
|
75
|
+
for (const [head, last] of [
|
|
76
|
+
['box_head', 4],
|
|
77
|
+
['objectness_head', 1],
|
|
78
|
+
]) {
|
|
79
|
+
add(`${head}.dense0.weight`, [vision.dim, vision.dim]);
|
|
80
|
+
add(`${head}.dense0.bias`, [vision.dim]);
|
|
81
|
+
add(`${head}.dense1.weight`, [vision.dim, vision.dim]);
|
|
82
|
+
add(`${head}.dense1.bias`, [vision.dim]);
|
|
83
|
+
add(`${head}.dense2.weight`, [last, vision.dim]);
|
|
84
|
+
add(`${head}.dense2.bias`, [last]);
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { GraphBuilder, Weights } from '@driftengine/texture';
|
|
2
|
+
export declare const LOG_BASE = 4.605170185988092;
|
|
3
|
+
export interface RopeTables {
|
|
4
|
+
/** `[tokens, heads · headDim]`: the cosine of each channel's angle. */
|
|
5
|
+
readonly cos: Float32Array;
|
|
6
|
+
/** The same shape: the sine, negated where `rotate` negates. */
|
|
7
|
+
readonly sin: Float32Array;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The tables for tokens at `positions` — a row and a column each, as integers — over `heads` of
|
|
11
|
+
* `headDim` channels, at the upstream's base of 100.
|
|
12
|
+
*/
|
|
13
|
+
export declare function ropeTables(positions: Int32Array, heads: number, headDim: number): RopeTables;
|
|
14
|
+
/**
|
|
15
|
+
* The rotation of `x`, `[tokens, heads · headDim]`, by tables already added to the graph as the
|
|
16
|
+
* constants `cos` and `sin`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function applyRope(graph: GraphBuilder, x: string, tokens: number, heads: number, headDim: number, cos: string, sin: string): string;
|
|
19
|
+
/** The tables as constants of the graph, named by `name`. */
|
|
20
|
+
export declare function ropeConstants(weights: Weights, name: string, positions: Int32Array, heads: number, headDim: number): {
|
|
21
|
+
readonly cos: string;
|
|
22
|
+
readonly sin: string;
|
|
23
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-dimensional rotary position embedding, as Depth Anything 3's backbone applies it to queries
|
|
3
|
+
* and keys, composed from the runtime's operators.
|
|
4
|
+
*
|
|
5
|
+
* **The rotation is `x·cos + rotate(x)·sin`, per head, with a head's first half turned by the
|
|
6
|
+
* token's row and its second half by its column.** Within each half, `rotate` swaps the two
|
|
7
|
+
* quarters and negates the first — so with the sign folded into the sine table it is a swap, and a
|
|
8
|
+
* swap is two slices and a concatenation. The tables depend only on positions, which the graph's
|
|
9
|
+
* shapes fix, so they are constants of the graph, rebuilt at every size.
|
|
10
|
+
*
|
|
11
|
+
* **What it gives up is a dispatch count**: eight small copies a rotation where a kernel of its own
|
|
12
|
+
* would take one. At a depth model's shapes each is a few microseconds against an attention of a
|
|
13
|
+
* millisecond and a half, and every operator used here already has a device bound; a `rope`
|
|
14
|
+
* operator is the step to take when a measurement says the copies matter.
|
|
15
|
+
*
|
|
16
|
+
* **The tables are computed in single precision, operation by operation**, as the upstream's are:
|
|
17
|
+
* a frequency as `100^(k/16)` rounded, an angle as position times frequency rounded, then its
|
|
18
|
+
* cosine and sine. Computing them in double and rounding once would move an angle near 37 by
|
|
19
|
+
* two millionths, which a parity check would then have to allow for. The transcendentals are the
|
|
20
|
+
* engine's reproducible ones, so the tables are the same bits in every engine.
|
|
21
|
+
*/
|
|
22
|
+
import { exactCos, exactExp, exactSin } from '@driftengine/core';
|
|
23
|
+
const f = Math.fround;
|
|
24
|
+
/*
|
|
25
|
+
* The base every rotary and sinusoidal embedding in these models is built on, as its logarithm:
|
|
26
|
+
* `100^e` is `exp(e · ln 100)`, through the engine's reproducible `exp`, since neither `**` nor
|
|
27
|
+
* `Math.pow` gives the same bits on every engine and a capture reproduces.
|
|
28
|
+
*/
|
|
29
|
+
export const LOG_BASE = 4.605170185988092;
|
|
30
|
+
/**
|
|
31
|
+
* The tables for tokens at `positions` — a row and a column each, as integers — over `heads` of
|
|
32
|
+
* `headDim` channels, at the upstream's base of 100.
|
|
33
|
+
*/
|
|
34
|
+
export function ropeTables(positions, heads, headDim) {
|
|
35
|
+
const tokens = positions.length / 2;
|
|
36
|
+
const half = headDim / 2;
|
|
37
|
+
const quarter = half / 2;
|
|
38
|
+
const inverse = new Float32Array(quarter);
|
|
39
|
+
for (let k = 0; k < quarter; k += 1) {
|
|
40
|
+
inverse[k] = f(1 / f(exactExp(f((2 * k) / half) * LOG_BASE)));
|
|
41
|
+
}
|
|
42
|
+
const width = heads * headDim;
|
|
43
|
+
const cos = new Float32Array(tokens * width);
|
|
44
|
+
const sin = new Float32Array(tokens * width);
|
|
45
|
+
for (let t = 0; t < tokens; t += 1) {
|
|
46
|
+
for (let axis = 0; axis < 2; axis += 1) {
|
|
47
|
+
const position = positions[2 * t + axis];
|
|
48
|
+
for (let j = 0; j < half; j += 1) {
|
|
49
|
+
const angle = f(position * inverse[j % quarter]);
|
|
50
|
+
const c = f(exactCos(angle));
|
|
51
|
+
const s = f(exactSin(angle)) * (j < quarter ? -1 : 1);
|
|
52
|
+
for (let h = 0; h < heads; h += 1) {
|
|
53
|
+
const at = t * width + h * headDim + axis * half + j;
|
|
54
|
+
cos[at] = c;
|
|
55
|
+
sin[at] = s;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { cos, sin };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The rotation of `x`, `[tokens, heads · headDim]`, by tables already added to the graph as the
|
|
64
|
+
* constants `cos` and `sin`.
|
|
65
|
+
*/
|
|
66
|
+
export function applyRope(graph, x, tokens, heads, headDim, cos, sin) {
|
|
67
|
+
const quarter = headDim / 4;
|
|
68
|
+
const quarters = graph.node('reshape', [x], { shape: [tokens * heads * 2, 2, quarter] });
|
|
69
|
+
const first = graph.node('slice', [quarters], { axis: 1, start: 0, end: 1 });
|
|
70
|
+
const second = graph.node('slice', [quarters], { axis: 1, start: 1, end: 2 });
|
|
71
|
+
const swapped = graph.node('reshape', [graph.node('concat', [second, first], { axis: 1 })], {
|
|
72
|
+
shape: [tokens, heads * headDim],
|
|
73
|
+
});
|
|
74
|
+
return graph.node('add', [graph.node('mul', [x, cos]), graph.node('mul', [swapped, sin])]);
|
|
75
|
+
}
|
|
76
|
+
/** The tables as constants of the graph, named by `name`. */
|
|
77
|
+
export function ropeConstants(weights, name, positions, heads, headDim) {
|
|
78
|
+
const tables = ropeTables(positions, heads, headDim);
|
|
79
|
+
const shape = [positions.length / 2, heads * headDim];
|
|
80
|
+
return {
|
|
81
|
+
cos: weights.constant(`${name}.cos`, shape, tables.cos),
|
|
82
|
+
sin: weights.constant(`${name}.sin`, shape, tables.sin),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SAM 2.1: masks from a point or a box, and masks carried through a video, as graphs — an encoder
|
|
3
|
+
* run once a frame, a decoder once a prompt, and the memory that carries an object from one frame
|
|
4
|
+
* to the next.
|
|
5
|
+
*
|
|
6
|
+
* **The encoder takes a frame at 1024 square**, resized without keeping its aspect, as the upstream's
|
|
7
|
+
* processor resizes it, and normalised by ImageNet's mean and deviation. It answers three levels of
|
|
8
|
+
* features — the decoder's input at a sixteenth of the frame and its two skips at an eighth and a
|
|
9
|
+
* quarter — which a video's memory then reads too.
|
|
10
|
+
*/
|
|
11
|
+
import type { Architecture } from '@driftengine/texture';
|
|
12
|
+
import { type HieraConfig } from './hiera.ts';
|
|
13
|
+
import type { SamDecoderConfig } from './samDecoder.ts';
|
|
14
|
+
export interface Sam21Config {
|
|
15
|
+
/** The side the encoder takes a frame at. */
|
|
16
|
+
readonly size: number;
|
|
17
|
+
readonly encoder: HieraConfig;
|
|
18
|
+
readonly decoder: SamDecoderConfig;
|
|
19
|
+
readonly memory: Sam21MemoryConfig;
|
|
20
|
+
}
|
|
21
|
+
export interface Sam21MemoryConfig {
|
|
22
|
+
/** A memory's channels: the encoder's are narrowed to these before they are kept. */
|
|
23
|
+
readonly dim: number;
|
|
24
|
+
readonly attentionLayers: number;
|
|
25
|
+
readonly attentionHeads: number;
|
|
26
|
+
readonly feedForward: number;
|
|
27
|
+
readonly fuserLayers: number;
|
|
28
|
+
readonly fuserHidden: number;
|
|
29
|
+
/** Frames of memory kept, the prompted frame among them, and object pointers read. */
|
|
30
|
+
readonly frames: number;
|
|
31
|
+
readonly pointers: number;
|
|
32
|
+
}
|
|
33
|
+
export declare const SAM_21_TINY: Sam21Config;
|
|
34
|
+
/** `image`, `[3, size, size]`, to `features`, `high1` and `high0`. */
|
|
35
|
+
export declare function sam21Encoder(config: Sam21Config): Architecture;
|
|
36
|
+
/**
|
|
37
|
+
* `embedding`, `high1`, `high0` and `prompt`, `[tokens, dim]` — absent when `tokens` is zero — and
|
|
38
|
+
* `mask` when `refine` is set, to `masks`, `quality`, `object` and `pointers`. With `noMemory` the
|
|
39
|
+
* decoder adds `no_memory_embedding` to the features itself, as an image with nothing remembered
|
|
40
|
+
* is decoded; otherwise the features are the memory attention's.
|
|
41
|
+
*/
|
|
42
|
+
export declare function sam21Decoder(config: Sam21Config, tokens: number, options?: {
|
|
43
|
+
readonly refine?: boolean;
|
|
44
|
+
readonly noMemory?: boolean;
|
|
45
|
+
}): Architecture;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { hiera } from './hiera.js';
|
|
2
|
+
import { sam2Decoder } from './sam2Decoder.js';
|
|
3
|
+
export const SAM_21_TINY = {
|
|
4
|
+
size: 1024,
|
|
5
|
+
encoder: {
|
|
6
|
+
dims: [96, 192, 384, 768],
|
|
7
|
+
blocks: [1, 2, 7, 2],
|
|
8
|
+
heads: [1, 2, 4, 8],
|
|
9
|
+
windows: [8, 4, 14, 7],
|
|
10
|
+
global: [5, 7, 9],
|
|
11
|
+
background: 7,
|
|
12
|
+
mlpRatio: 4,
|
|
13
|
+
fpn: 256,
|
|
14
|
+
topDown: [2, 3],
|
|
15
|
+
},
|
|
16
|
+
decoder: {
|
|
17
|
+
dim: 256,
|
|
18
|
+
heads: 8,
|
|
19
|
+
mlp: 2048,
|
|
20
|
+
depth: 2,
|
|
21
|
+
downsample: 2,
|
|
22
|
+
masks: 4,
|
|
23
|
+
iouHidden: 256,
|
|
24
|
+
iouDepth: 3,
|
|
25
|
+
maskChannels: 16,
|
|
26
|
+
},
|
|
27
|
+
memory: {
|
|
28
|
+
dim: 64,
|
|
29
|
+
attentionLayers: 4,
|
|
30
|
+
attentionHeads: 1,
|
|
31
|
+
feedForward: 2048,
|
|
32
|
+
fuserLayers: 2,
|
|
33
|
+
fuserHidden: 1024,
|
|
34
|
+
frames: 7,
|
|
35
|
+
pointers: 16,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
/** `image`, `[3, size, size]`, to `features`, `high1` and `high0`. */
|
|
39
|
+
export function sam21Encoder(config) {
|
|
40
|
+
return (weights, graph) => {
|
|
41
|
+
for (const prefix of [
|
|
42
|
+
'prompt_encoder.',
|
|
43
|
+
'shared_image_embedding.',
|
|
44
|
+
'memory_attention.',
|
|
45
|
+
'memory_encoder.',
|
|
46
|
+
'object_pointer_proj.',
|
|
47
|
+
'temporal_positional_encoding_projection_layer.',
|
|
48
|
+
'mask_downsample.',
|
|
49
|
+
]) {
|
|
50
|
+
weights.ignore(prefix);
|
|
51
|
+
}
|
|
52
|
+
for (const name of [
|
|
53
|
+
'no_memory_embedding',
|
|
54
|
+
'no_memory_positional_encoding',
|
|
55
|
+
'memory_temporal_positional_encoding',
|
|
56
|
+
'no_object_pointer',
|
|
57
|
+
'occlusion_spatial_embedding_parameter',
|
|
58
|
+
]) {
|
|
59
|
+
weights.ignore(name);
|
|
60
|
+
}
|
|
61
|
+
/* The decoder's, but for the two projections the encoder applies once a frame, which it reads. */
|
|
62
|
+
weights.ignore('mask_decoder.');
|
|
63
|
+
hiera(weights, graph, config.encoder, 'image', config.size, {
|
|
64
|
+
features: 'features',
|
|
65
|
+
high1: 'high1',
|
|
66
|
+
high0: 'high0',
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
inputs: [{ name: 'image', shape: [3, config.size, config.size] }],
|
|
70
|
+
outputs: ['features', 'high1', 'high0'],
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** The prefixes and names of the memory's weights, which the image graphs set aside. */
|
|
75
|
+
const MEMORY = [
|
|
76
|
+
'memory_attention.',
|
|
77
|
+
'memory_encoder.',
|
|
78
|
+
'mask_downsample.',
|
|
79
|
+
'temporal_positional_encoding_projection_layer.',
|
|
80
|
+
'memory_temporal_positional_encoding',
|
|
81
|
+
'no_memory_positional_encoding',
|
|
82
|
+
'occlusion_spatial_embedding_parameter',
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* `embedding`, `high1`, `high0` and `prompt`, `[tokens, dim]` — absent when `tokens` is zero — and
|
|
86
|
+
* `mask` when `refine` is set, to `masks`, `quality`, `object` and `pointers`. With `noMemory` the
|
|
87
|
+
* decoder adds `no_memory_embedding` to the features itself, as an image with nothing remembered
|
|
88
|
+
* is decoded; otherwise the features are the memory attention's.
|
|
89
|
+
*/
|
|
90
|
+
export function sam21Decoder(config, tokens, options = {}) {
|
|
91
|
+
return (weights, graph) => {
|
|
92
|
+
weights.ignore('vision_encoder.');
|
|
93
|
+
weights.ignore('mask_decoder.conv_s0.');
|
|
94
|
+
weights.ignore('mask_decoder.conv_s1.');
|
|
95
|
+
for (const name of MEMORY)
|
|
96
|
+
weights.ignore(name);
|
|
97
|
+
const { dim } = config.decoder;
|
|
98
|
+
const grid = config.size / 16;
|
|
99
|
+
/* Read whether this graph uses them or not: the host's pointer when no object is seen. */
|
|
100
|
+
weights.read('no_object_pointer', [1, dim]);
|
|
101
|
+
const noMemory = weights.read('no_memory_embedding', [1, 1, dim]);
|
|
102
|
+
let embedding = 'embedding';
|
|
103
|
+
if (options.noMemory === true) {
|
|
104
|
+
const flat = graph.node('reshape', [noMemory], { shape: [dim] });
|
|
105
|
+
const tokensFirst = graph.node('permute', [graph.node('reshape', ['embedding'], { shape: [dim, grid * grid] })], { order: [1, 0] });
|
|
106
|
+
embedding = graph.node('reshape', [graph.node('permute', [graph.node('add', [tokensFirst, flat])], { order: [1, 0] })], {
|
|
107
|
+
shape: [dim, grid, grid],
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const inputs = [
|
|
111
|
+
{ name: 'embedding', shape: [dim, grid, grid] },
|
|
112
|
+
{ name: 'high1', shape: [dim / 4, 2 * grid, 2 * grid] },
|
|
113
|
+
{ name: 'high0', shape: [dim / 8, 4 * grid, 4 * grid] },
|
|
114
|
+
...(tokens > 0 ? [{ name: 'prompt', shape: [tokens, dim] }] : []),
|
|
115
|
+
...(options.refine === true ? [{ name: 'mask', shape: [1, 4 * grid, 4 * grid] }] : []),
|
|
116
|
+
];
|
|
117
|
+
sam2Decoder(weights, graph, config.decoder, grid, {
|
|
118
|
+
embedding,
|
|
119
|
+
prompt: tokens > 0 ? 'prompt' : null,
|
|
120
|
+
mask: options.refine === true ? 'mask' : null,
|
|
121
|
+
high1: 'high1',
|
|
122
|
+
high0: 'high0',
|
|
123
|
+
}, { masks: 'masks', quality: 'quality', object: 'object', pointers: 'pointers' });
|
|
124
|
+
return { inputs, outputs: ['masks', 'quality', 'object', 'pointers'] };
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A seeded miniature of SAM 2.1: every tensor name and shape of the upstream's video model, at a
|
|
3
|
+
* size the CPU evaluates in a moment — what the model's tests and its hand-run oracle share.
|
|
4
|
+
*
|
|
5
|
+
* **Small where the upstream lets it be.** A 64-pixel frame, stages of 8, 16, 32 and 64 channels in
|
|
6
|
+
* 1, 2, 3 and 2 blocks, windows of 8, 4, 14 and 7 over grids of 16, 8, 4 and 2 — so windows divide,
|
|
7
|
+
* pad and outgrow their grid, one block attends globally and every stage change pools its queries.
|
|
8
|
+
* **The width is 128**, where the upstream's is 256: a memory is 64 channels wide, a width the
|
|
9
|
+
* upstream writes as a literal, and an object pointer is cut into width/64 tokens, so the width must
|
|
10
|
+
* be a multiple of 64 — and 128 cuts each pointer in two, as the real model's 256 cuts it in four.
|
|
11
|
+
*/
|
|
12
|
+
import type { GraphTensor } from '@driftengine/texture';
|
|
13
|
+
import type { Sam21Config } from './sam21.ts';
|
|
14
|
+
export declare const MINIATURE_SAM_21: Sam21Config;
|
|
15
|
+
/**
|
|
16
|
+
* The original frame the prompts are given in, 36 by 48, which SAM 2 resizes to its square — so
|
|
17
|
+
* each axis scales by its own factor — and a point, a box, and both with a second point off the
|
|
18
|
+
* object.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MINIATURE_SAM_21_IMAGE: {
|
|
21
|
+
readonly height: 36;
|
|
22
|
+
readonly width: 48;
|
|
23
|
+
};
|
|
24
|
+
export declare const MINIATURE_SAM_21_PROMPTS: {
|
|
25
|
+
readonly point: {
|
|
26
|
+
readonly points: readonly [readonly [20.5, 14.25, 1]];
|
|
27
|
+
};
|
|
28
|
+
readonly box: {
|
|
29
|
+
readonly box: readonly [6, 5, 40.5, 30];
|
|
30
|
+
};
|
|
31
|
+
readonly both: {
|
|
32
|
+
readonly points: readonly [readonly [20.5, 14.25, 1], readonly [33, 25.75, 0]];
|
|
33
|
+
readonly box: readonly [6, 5, 40.5, 30];
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/** Every tensor the upstream's `Sam2VideoModel` holds, named as its checkpoints are. */
|
|
37
|
+
export declare function miniatureSam21Checkpoint(config: Sam21Config, seed: number): Map<string, GraphTensor>;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { draw } from './seeded.js';
|
|
2
|
+
export const MINIATURE_SAM_21 = {
|
|
3
|
+
size: 64,
|
|
4
|
+
encoder: {
|
|
5
|
+
dims: [8, 16, 32, 64],
|
|
6
|
+
blocks: [1, 2, 3, 2],
|
|
7
|
+
heads: [1, 2, 2, 4],
|
|
8
|
+
windows: [8, 4, 14, 7],
|
|
9
|
+
global: [4],
|
|
10
|
+
background: 7,
|
|
11
|
+
mlpRatio: 4,
|
|
12
|
+
fpn: 128,
|
|
13
|
+
topDown: [2, 3],
|
|
14
|
+
},
|
|
15
|
+
decoder: {
|
|
16
|
+
dim: 128,
|
|
17
|
+
heads: 2,
|
|
18
|
+
mlp: 32,
|
|
19
|
+
depth: 2,
|
|
20
|
+
downsample: 2,
|
|
21
|
+
masks: 4,
|
|
22
|
+
iouHidden: 16,
|
|
23
|
+
iouDepth: 3,
|
|
24
|
+
maskChannels: 16,
|
|
25
|
+
},
|
|
26
|
+
memory: {
|
|
27
|
+
dim: 64,
|
|
28
|
+
attentionLayers: 2,
|
|
29
|
+
attentionHeads: 1,
|
|
30
|
+
feedForward: 32,
|
|
31
|
+
fuserLayers: 2,
|
|
32
|
+
fuserHidden: 64,
|
|
33
|
+
frames: 7,
|
|
34
|
+
pointers: 16,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The original frame the prompts are given in, 36 by 48, which SAM 2 resizes to its square — so
|
|
39
|
+
* each axis scales by its own factor — and a point, a box, and both with a second point off the
|
|
40
|
+
* object.
|
|
41
|
+
*/
|
|
42
|
+
export const MINIATURE_SAM_21_IMAGE = { height: 36, width: 48 };
|
|
43
|
+
export const MINIATURE_SAM_21_PROMPTS = {
|
|
44
|
+
point: { points: [[20.5, 14.25, 1]] },
|
|
45
|
+
box: { box: [6, 5, 40.5, 30] },
|
|
46
|
+
both: {
|
|
47
|
+
points: [
|
|
48
|
+
[20.5, 14.25, 1],
|
|
49
|
+
[33, 25.75, 0],
|
|
50
|
+
],
|
|
51
|
+
box: [6, 5, 40.5, 30],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
/** Every tensor the upstream's `Sam2VideoModel` holds, named as its checkpoints are. */
|
|
55
|
+
export function miniatureSam21Checkpoint(config, seed) {
|
|
56
|
+
const out = new Map();
|
|
57
|
+
const add = (name, shape) => {
|
|
58
|
+
out.set(name, { shape, data: draw(name, shape, seed) });
|
|
59
|
+
};
|
|
60
|
+
const linear = (p, outputs, inputs) => {
|
|
61
|
+
add(`${p}weight`, [outputs, inputs]);
|
|
62
|
+
add(`${p}bias`, [outputs]);
|
|
63
|
+
};
|
|
64
|
+
const conv = (p, outputs, inputs, kernel) => {
|
|
65
|
+
add(`${p}weight`, [outputs, inputs, kernel, kernel]);
|
|
66
|
+
add(`${p}bias`, [outputs]);
|
|
67
|
+
};
|
|
68
|
+
const norm = (p, dim) => {
|
|
69
|
+
add(`${p}weight`, [dim]);
|
|
70
|
+
add(`${p}bias`, [dim]);
|
|
71
|
+
};
|
|
72
|
+
/* The upstream's two-to-n-layer perceptron: `proj_in`, then `layers`, then `proj_out`. */
|
|
73
|
+
const perceptron = (p, input, hidden, output, depth) => {
|
|
74
|
+
linear(`${p}proj_in.`, hidden, input);
|
|
75
|
+
for (let i = 0; i < depth - 2; i += 1)
|
|
76
|
+
linear(`${p}layers.${i}.`, hidden, hidden);
|
|
77
|
+
linear(`${p}proj_out.`, output, hidden);
|
|
78
|
+
};
|
|
79
|
+
const { encoder, decoder, memory } = config;
|
|
80
|
+
const width = decoder.dim;
|
|
81
|
+
add('no_memory_embedding', [1, 1, width]);
|
|
82
|
+
add('no_memory_positional_encoding', [1, 1, width]);
|
|
83
|
+
add('memory_temporal_positional_encoding', [memory.frames, 1, 1, memory.dim]);
|
|
84
|
+
add('no_object_pointer', [1, width]);
|
|
85
|
+
add('occlusion_spatial_embedding_parameter', [1, memory.dim]);
|
|
86
|
+
add('shared_image_embedding.positional_embedding', [2, width / 2]);
|
|
87
|
+
const b = 'vision_encoder.backbone.';
|
|
88
|
+
const d0 = encoder.dims[0];
|
|
89
|
+
add(`${b}pos_embed`, [1, d0, encoder.background, encoder.background]);
|
|
90
|
+
add(`${b}pos_embed_window`, [1, d0, encoder.windows[0], encoder.windows[0]]);
|
|
91
|
+
conv(`${b}patch_embed.projection.`, d0, 3, 7);
|
|
92
|
+
let index = 0;
|
|
93
|
+
for (let stage = 0; stage < 4; stage += 1) {
|
|
94
|
+
for (let block = 0; block < encoder.blocks[stage]; block += 1) {
|
|
95
|
+
const p = `${b}blocks.${index}.`;
|
|
96
|
+
const first = stage > 0 && block === 0;
|
|
97
|
+
const dim = first ? encoder.dims[stage - 1] : encoder.dims[stage];
|
|
98
|
+
const outDim = encoder.dims[stage];
|
|
99
|
+
norm(`${p}layer_norm1.`, dim);
|
|
100
|
+
linear(`${p}attn.qkv.`, 3 * outDim, dim);
|
|
101
|
+
linear(`${p}attn.proj.`, outDim, outDim);
|
|
102
|
+
norm(`${p}layer_norm2.`, outDim);
|
|
103
|
+
linear(`${p}mlp.proj_in.`, outDim * encoder.mlpRatio, outDim);
|
|
104
|
+
linear(`${p}mlp.proj_out.`, outDim, outDim * encoder.mlpRatio);
|
|
105
|
+
if (first)
|
|
106
|
+
linear(`${p}proj.`, outDim, dim);
|
|
107
|
+
index += 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (let i = 0; i < 4; i += 1)
|
|
111
|
+
conv(`vision_encoder.neck.convs.${i}.`, encoder.fpn, encoder.dims[3 - i], 1);
|
|
112
|
+
const pe = 'prompt_encoder.';
|
|
113
|
+
add(`${pe}shared_embedding.positional_embedding`, [2, width / 2]);
|
|
114
|
+
const c = decoder.maskChannels;
|
|
115
|
+
conv(`${pe}mask_embed.conv1.`, c / 4, 1, 2);
|
|
116
|
+
conv(`${pe}mask_embed.conv2.`, c, c / 4, 2);
|
|
117
|
+
conv(`${pe}mask_embed.conv3.`, width, c, 1);
|
|
118
|
+
norm(`${pe}mask_embed.layer_norm1.`, c / 4);
|
|
119
|
+
norm(`${pe}mask_embed.layer_norm2.`, c);
|
|
120
|
+
add(`${pe}no_mask_embed.weight`, [1, width]);
|
|
121
|
+
add(`${pe}point_embed.weight`, [4, width]);
|
|
122
|
+
add(`${pe}not_a_point_embed.weight`, [1, width]);
|
|
123
|
+
const m = 'mask_decoder.';
|
|
124
|
+
const t = `${m}transformer.`;
|
|
125
|
+
const inner = width / decoder.downsample;
|
|
126
|
+
const attention = (p, dim, kv = width) => {
|
|
127
|
+
linear(`${p}q_proj.`, dim, width);
|
|
128
|
+
linear(`${p}k_proj.`, dim, kv);
|
|
129
|
+
linear(`${p}v_proj.`, dim, kv);
|
|
130
|
+
linear(`${p}o_proj.`, width, dim);
|
|
131
|
+
};
|
|
132
|
+
add(`${m}iou_token.weight`, [1, width]);
|
|
133
|
+
add(`${m}mask_tokens.weight`, [decoder.masks, width]);
|
|
134
|
+
for (let i = 0; i < decoder.depth; i += 1) {
|
|
135
|
+
const p = `${t}layers.${i}.`;
|
|
136
|
+
attention(`${p}self_attn.`, width);
|
|
137
|
+
norm(`${p}layer_norm1.`, width);
|
|
138
|
+
attention(`${p}cross_attn_token_to_image.`, inner);
|
|
139
|
+
norm(`${p}layer_norm2.`, width);
|
|
140
|
+
perceptron(`${p}mlp.`, width, decoder.mlp, width, decoder.depth);
|
|
141
|
+
norm(`${p}layer_norm3.`, width);
|
|
142
|
+
norm(`${p}layer_norm4.`, width);
|
|
143
|
+
attention(`${p}cross_attn_image_to_token.`, inner);
|
|
144
|
+
}
|
|
145
|
+
attention(`${t}final_attn_token_to_image.`, inner);
|
|
146
|
+
norm(`${t}layer_norm_final_attn.`, width);
|
|
147
|
+
add(`${m}upscale_conv1.weight`, [width, width / 4, 2, 2]);
|
|
148
|
+
add(`${m}upscale_conv1.bias`, [width / 4]);
|
|
149
|
+
add(`${m}upscale_conv2.weight`, [width / 4, width / 8, 2, 2]);
|
|
150
|
+
add(`${m}upscale_conv2.bias`, [width / 8]);
|
|
151
|
+
norm(`${m}upscale_layer_norm.`, width / 4);
|
|
152
|
+
for (let i = 0; i < decoder.masks; i += 1) {
|
|
153
|
+
perceptron(`${m}output_hypernetworks_mlps.${i}.`, width, width, width / 8, 3);
|
|
154
|
+
}
|
|
155
|
+
perceptron(`${m}iou_prediction_head.`, width, decoder.iouHidden, decoder.masks, decoder.iouDepth);
|
|
156
|
+
conv(`${m}conv_s0.`, width / 8, width, 1);
|
|
157
|
+
conv(`${m}conv_s1.`, width / 4, width, 1);
|
|
158
|
+
add(`${m}obj_score_token.weight`, [1, width]);
|
|
159
|
+
perceptron(`${m}pred_obj_score_head.`, width, width, 1, 3);
|
|
160
|
+
const a = 'memory_attention.';
|
|
161
|
+
for (let i = 0; i < memory.attentionLayers; i += 1) {
|
|
162
|
+
const p = `${a}layers.${i}.`;
|
|
163
|
+
attention(`${p}self_attn.`, width);
|
|
164
|
+
attention(`${p}cross_attn_image.`, width, memory.dim);
|
|
165
|
+
linear(`${p}linear1.`, memory.feedForward, width);
|
|
166
|
+
linear(`${p}linear2.`, width, memory.feedForward);
|
|
167
|
+
norm(`${p}layer_norm1.`, width);
|
|
168
|
+
norm(`${p}layer_norm2.`, width);
|
|
169
|
+
norm(`${p}layer_norm3.`, width);
|
|
170
|
+
}
|
|
171
|
+
norm(`${a}layer_norm.`, width);
|
|
172
|
+
const e = 'memory_encoder.';
|
|
173
|
+
let channels = 1;
|
|
174
|
+
for (let i = 0; i < 4; i += 1) {
|
|
175
|
+
conv(`${e}mask_downsampler.layers.${i}.conv.`, channels * 4, channels, 3);
|
|
176
|
+
norm(`${e}mask_downsampler.layers.${i}.layer_norm.`, channels * 4);
|
|
177
|
+
channels *= 4;
|
|
178
|
+
}
|
|
179
|
+
conv(`${e}mask_downsampler.final_conv.`, width, channels, 1);
|
|
180
|
+
conv(`${e}feature_projection.`, width, width, 1);
|
|
181
|
+
for (let i = 0; i < memory.fuserLayers; i += 1) {
|
|
182
|
+
const p = `${e}memory_fuser.layers.${i}.`;
|
|
183
|
+
add(`${p}scale`, [width]);
|
|
184
|
+
conv(`${p}depthwise_conv.`, width, 1, 7);
|
|
185
|
+
norm(`${p}layer_norm.`, width);
|
|
186
|
+
linear(`${p}pointwise_conv1.`, memory.fuserHidden, width);
|
|
187
|
+
linear(`${p}pointwise_conv2.`, width, memory.fuserHidden);
|
|
188
|
+
}
|
|
189
|
+
conv(`${e}projection.`, memory.dim, width, 1);
|
|
190
|
+
conv('mask_downsample.', 1, 1, 4);
|
|
191
|
+
perceptron('object_pointer_proj.', width, width, width, 3);
|
|
192
|
+
linear('temporal_positional_encoding_projection_layer.', memory.dim, width);
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The graphs a SAM 2.1 video adds to its image graphs: the memory encoder, the memory attention for
|
|
3
|
+
* each count of remembered frames and pointer tokens, and the mask brought to the frame's size for
|
|
4
|
+
* the memory. `Sam21Tracker` runs them.
|
|
5
|
+
*/
|
|
6
|
+
import type { Architecture } from '@driftengine/texture';
|
|
7
|
+
import type { Sam21Config } from './sam21.ts';
|
|
8
|
+
/**
|
|
9
|
+
* `features`, `[dim, grid, grid]`, and `mask`, `[1, size, size]` — logits, or a binary mask when
|
|
10
|
+
* `binary`, as a frame prompted with points is encoded — to `memory`, `[memory.dim, grid, grid]`.
|
|
11
|
+
* The host adds the occlusion embedding where the object is absent, and keeps the memory rounded to
|
|
12
|
+
* bfloat16, as the upstream keeps it; this graph reads the embedding so the file holds it.
|
|
13
|
+
*/
|
|
14
|
+
export declare function sam21MemoryEncoder(config: Sam21Config, binary: boolean): Architecture;
|
|
15
|
+
/**
|
|
16
|
+
* `features`, `[dim, grid, grid]`, `memory` and its `positions`, `[frames·grid² + pointers,
|
|
17
|
+
* memory.dim]`, to `conditioned`, `[dim, grid, grid]`: one graph for each count of frames and of
|
|
18
|
+
* pointer tokens a tracker holds. The host makes the memory's positions, so this graph reads the
|
|
19
|
+
* temporal table and the pointers' projection for the file to hold them.
|
|
20
|
+
*/
|
|
21
|
+
export declare function sam21MemoryAttention(config: Sam21Config, frames: number, pointers: number): Architecture;
|
|
22
|
+
/** `masks`, `[count, 4·grid, 4·grid]`, to `high`, `[count, size, size]`, bilinearly. Reads no weights. */
|
|
23
|
+
export declare function sam21Upscale(config: Sam21Config, count: number): Architecture;
|
|
24
|
+
/**
|
|
25
|
+
* `masks`, `[count, size / 4, size / 4]`, to `image`, `[count, height, width]`: the tracker's masks
|
|
26
|
+
* brought to the original frame bilinearly, as the upstream's `post_process_masks` brings them —
|
|
27
|
+
* straight from a quarter of the square, since SAM 2 resizes a frame without padding it. Reads no
|
|
28
|
+
* weights.
|
|
29
|
+
*/
|
|
30
|
+
export declare function sam21MasksToImage(config: Sam21Config, count: number, height: number, width: number): Architecture;
|