bradynapier commited on
Commit
b470e31
·
verified ·
1 Parent(s): 6e5c530

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +68 -1
README.md CHANGED
@@ -44,4 +44,71 @@ const model = await AutoModel.from_pretrained(MODEL_ID, {
44
 
45
 
46
  // the types are wildy incorrect... but this should get you what you need!
47
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
 
46
  // the types are wildy incorrect... but this should get you what you need!
47
+ ```
48
+
49
+ #### Rough Outline of Getting Attentions
50
+
51
+ > This may not be the best way but the documentation is truly lacking and this does the job :-P
52
+
53
+ ```typescript
54
+ /**
55
+ * Collect attentions across layers from a model.forward(...) output.
56
+ *
57
+ * ⚠️ Transformers.js variation:
58
+ * - Some builds return `{ attentions: Tensor[] }`.
59
+ * - Others return a dict with `attention_1`, `attention_2`, ... per layer.
60
+ *
61
+ * @internal
62
+ * @param out Raw dictionary from `model.forward(...)`.
63
+ * @returns Array of attention tensors (one per layer) with dims `[1, H, T, T]`.
64
+ */
65
+ function collectAttentions(out: Record<string, Tensor>): XtTensor[] {
66
+ // Prefer array form if present (runtime feature; TS types don’t guarantee it).
67
+ const anyOut = out as unknown as { attentions?: XtTensor[] };
68
+ if (Array.isArray(anyOut.attentions)) return anyOut.attentions;
69
+
70
+ // Otherwise gather attention_1..attention_N and sort numerically by suffix.
71
+ const keys = Object.keys(out)
72
+ .filter((k) => /^attention_\d+$/i.test(k))
73
+ .sort(
74
+ (a, b) => parseInt(a.split('_')[1], 10) - parseInt(b.split('_')[1], 10),
75
+ );
76
+
77
+ return keys.map((k) => out[k] as unknown as XtTensor);
78
+ }
79
+
80
+ /**
81
+ * Tokenization:
82
+ * Prefer the public callable form `tokenizer(text, {...})` which returns tensors.
83
+ * In case your wrapper only exposes a `_call` (private-ish) we fall back to it here.
84
+ * The return includes `input_ids` and `attention_mask` tensors.
85
+ */
86
+ const enc =
87
+ typeof (tokenizer as typeof tokenizer._call) === 'function' ?
88
+ // eslint-disable-next-line @typescript-eslint/await-thenable
89
+ await (tokenizer as typeof tokenizer._call)(text, {
90
+ add_special_tokens: true,
91
+ })
92
+ : tokenizer._call(text, { add_special_tokens: true }); // <-- documented hack
93
+
94
+ // Convert tensor buffers (may be BigInt) → number[] for downstream processing.
95
+ const input_ids = Array.from(
96
+ (enc.input_ids as Tensor).data as ArrayLike<number | bigint>,
97
+ ).map(Number);
98
+
99
+ /**
100
+ * Forward pass with attentions.
101
+ *
102
+ * Another "crazy" bit: different Transformers.js builds expose attentions differently. We:
103
+ * - accept `{ attentions: Tensor[] }`, or
104
+ * - collect `attention_1, attention_2, ...` and sort them.
105
+ * Also, `Tensor` has no `.get(...)` so we do **flat buffer indexing** with `dims`.
106
+ */
107
+ const out = (await model.forward({
108
+ input_ids,
109
+ attention_mask: windowAttentionMask,
110
+ output_attentions: true,
111
+ })) as unknown as Record<string, Tensor>;
112
+
113
+ const attentions = collectAttentions(out)
114
+ ```