umap-gpu 0.2.11 → 0.2.13
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/dist/index.js +250 -246
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var G = (e,
|
|
4
|
-
import { loadHnswlib as
|
|
5
|
-
async function
|
|
6
|
-
const { M: s = 16, efConstruction:
|
|
7
|
-
a.initIndex(
|
|
1
|
+
var V = Object.defineProperty;
|
|
2
|
+
var Y = (e, t, r) => t in e ? V(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
|
|
3
|
+
var G = (e, t, r) => Y(e, typeof t != "symbol" ? t + "" : t, r);
|
|
4
|
+
import { loadHnswlib as D } from "hnswlib-wasm";
|
|
5
|
+
async function Q(e, t, r = {}) {
|
|
6
|
+
const { M: s = 16, efConstruction: n = 200, efSearch: g = 50 } = r, c = await D(), d = e[0].length, f = e.length, a = new c.HierarchicalNSW("l2", d, "");
|
|
7
|
+
a.initIndex(f, s, n, 200), a.setEfSearch(Math.max(g, t)), a.addItems(e, !1);
|
|
8
8
|
const o = [], i = [];
|
|
9
|
-
for (let h = 0; h <
|
|
10
|
-
const
|
|
11
|
-
o.push(u.map(({ idx:
|
|
9
|
+
for (let h = 0; h < f; h++) {
|
|
10
|
+
const l = a.searchKnn(e[h], t + 1, void 0), u = l.neighbors.map((p, m) => ({ idx: p, dist: l.distances[m] })).filter(({ idx: p }) => p !== h).slice(0, t);
|
|
11
|
+
o.push(u.map(({ idx: p }) => p)), i.push(u.map(({ dist: p }) => p));
|
|
12
12
|
}
|
|
13
13
|
return { indices: o, distances: i };
|
|
14
14
|
}
|
|
15
|
-
async function
|
|
16
|
-
const { M: s = 16, efConstruction:
|
|
17
|
-
a.initIndex(
|
|
15
|
+
async function J(e, t, r = {}) {
|
|
16
|
+
const { M: s = 16, efConstruction: n = 200, efSearch: g = 50 } = r, c = await D(), d = e[0].length, f = e.length, a = new c.HierarchicalNSW("l2", d, "");
|
|
17
|
+
a.initIndex(f, s, n, 200), a.setEfSearch(Math.max(g, t)), a.addItems(e, !1);
|
|
18
18
|
const o = [], i = [];
|
|
19
|
-
for (let
|
|
20
|
-
const u = a.searchKnn(e[
|
|
21
|
-
o.push(
|
|
19
|
+
for (let l = 0; l < f; l++) {
|
|
20
|
+
const u = a.searchKnn(e[l], t + 1, void 0), p = u.neighbors.map((m, _) => ({ idx: m, dist: u.distances[_] })).filter(({ idx: m }) => m !== l).slice(0, t);
|
|
21
|
+
o.push(p.map(({ idx: m }) => m)), i.push(p.map(({ dist: m }) => m));
|
|
22
22
|
}
|
|
23
23
|
return { knn: { indices: o, distances: i }, index: {
|
|
24
|
-
searchKnn(
|
|
25
|
-
const
|
|
26
|
-
for (const
|
|
27
|
-
const
|
|
28
|
-
|
|
24
|
+
searchKnn(l, u) {
|
|
25
|
+
const p = [], m = [];
|
|
26
|
+
for (const _ of l) {
|
|
27
|
+
const w = a.searchKnn(_, u, void 0), b = w.neighbors.map((A, x) => ({ idx: A, dist: w.distances[x] })).sort((A, x) => A.dist - x.dist).slice(0, u);
|
|
28
|
+
p.push(b.map(({ idx: A }) => A)), m.push(b.map(({ dist: A }) => A));
|
|
29
29
|
}
|
|
30
|
-
return { indices:
|
|
30
|
+
return { indices: p, distances: m };
|
|
31
31
|
}
|
|
32
32
|
} };
|
|
33
33
|
}
|
|
34
|
-
function
|
|
35
|
-
const
|
|
36
|
-
for (let i = 0; i <
|
|
34
|
+
function L(e, t, r, s = 1) {
|
|
35
|
+
const n = e.length, { sigmas: g, rhos: c } = W(t, r), d = [], f = [], a = [];
|
|
36
|
+
for (let i = 0; i < n; i++)
|
|
37
37
|
for (let h = 0; h < e[i].length; h++) {
|
|
38
|
-
const
|
|
39
|
-
|
|
38
|
+
const l = t[i][h], u = l <= c[i] ? 1 : Math.exp(-((l - c[i]) / g[i]));
|
|
39
|
+
d.push(i), f.push(e[i][h]), a.push(u);
|
|
40
40
|
}
|
|
41
|
-
return { ...
|
|
41
|
+
return { ...Z(d, f, a, n, s), nVertices: n };
|
|
42
42
|
}
|
|
43
|
-
function
|
|
44
|
-
const s = e.length, { sigmas:
|
|
43
|
+
function X(e, t, r) {
|
|
44
|
+
const s = e.length, { sigmas: n, rhos: g } = W(t, r), c = [], d = [], f = [];
|
|
45
45
|
for (let a = 0; a < s; a++)
|
|
46
46
|
for (let o = 0; o < e[a].length; o++) {
|
|
47
|
-
const i =
|
|
48
|
-
|
|
47
|
+
const i = t[a][o], h = i <= g[a] ? 1 : Math.exp(-((i - g[a]) / n[a]));
|
|
48
|
+
c.push(a), d.push(e[a][o]), f.push(h);
|
|
49
49
|
}
|
|
50
50
|
return {
|
|
51
|
-
rows: new Float32Array(
|
|
52
|
-
cols: new Float32Array(
|
|
53
|
-
vals: new Float32Array(
|
|
51
|
+
rows: new Float32Array(c),
|
|
52
|
+
cols: new Float32Array(d),
|
|
53
|
+
vals: new Float32Array(f),
|
|
54
54
|
nVertices: s
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
const s = e.length,
|
|
59
|
-
for (let
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
let
|
|
63
|
-
const i = Math.log2(
|
|
57
|
+
function W(e, t) {
|
|
58
|
+
const s = e.length, n = new Float32Array(s), g = new Float32Array(s);
|
|
59
|
+
for (let c = 0; c < s; c++) {
|
|
60
|
+
const d = e[c];
|
|
61
|
+
g[c] = d.find((h) => h > 0) ?? 0;
|
|
62
|
+
let f = 0, a = 1 / 0, o = 1;
|
|
63
|
+
const i = Math.log2(t);
|
|
64
64
|
for (let h = 0; h < 64; h++) {
|
|
65
|
-
let
|
|
66
|
-
for (let u = 0; u <
|
|
67
|
-
|
|
68
|
-
if (Math.abs(
|
|
69
|
-
|
|
65
|
+
let l = 0;
|
|
66
|
+
for (let u = 0; u < d.length; u++)
|
|
67
|
+
l += Math.exp(-Math.max(0, d[u] - g[c]) / o);
|
|
68
|
+
if (Math.abs(l - i) < 1e-5) break;
|
|
69
|
+
l > i ? (a = o, o = (f + a) / 2) : (f = o, o = a === 1 / 0 ? o * 2 : (f + a) / 2);
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
n[c] = o;
|
|
72
72
|
}
|
|
73
|
-
return { sigmas:
|
|
73
|
+
return { sigmas: n, rhos: g };
|
|
74
74
|
}
|
|
75
|
-
function
|
|
76
|
-
const
|
|
75
|
+
function Z(e, t, r, s, n) {
|
|
76
|
+
const g = /* @__PURE__ */ new Map();
|
|
77
77
|
for (let a = 0; a < e.length; a++)
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
for (const [a, o] of
|
|
81
|
-
const i = Math.floor(a / s), h = a % s,
|
|
82
|
-
|
|
78
|
+
g.set(e[a] * s + t[a], r[a]);
|
|
79
|
+
const c = [], d = [], f = [];
|
|
80
|
+
for (const [a, o] of g) {
|
|
81
|
+
const i = Math.floor(a / s), h = a % s, l = g.get(h * s + i) ?? 0, u = o + l - o * l, p = o * l;
|
|
82
|
+
c.push(i), d.push(h), f.push(n * u + (1 - n) * p);
|
|
83
83
|
}
|
|
84
84
|
return {
|
|
85
|
-
rows: new Float32Array(
|
|
86
|
-
cols: new Float32Array(
|
|
87
|
-
vals: new Float32Array(
|
|
85
|
+
rows: new Float32Array(c),
|
|
86
|
+
cols: new Float32Array(d),
|
|
87
|
+
vals: new Float32Array(f)
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
|
-
const
|
|
90
|
+
const $ = `// UMAP SGD compute shader — processes one graph edge per GPU thread.
|
|
91
91
|
// Applies attraction forces between connected nodes and repulsion forces
|
|
92
92
|
// against negative samples.
|
|
93
93
|
|
|
@@ -197,18 +197,18 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
197
197
|
epochs_per_sample[edge_idx] / f32(params.negative_sample_rate);
|
|
198
198
|
}
|
|
199
199
|
`;
|
|
200
|
-
class
|
|
200
|
+
class j {
|
|
201
201
|
constructor() {
|
|
202
202
|
G(this, "device");
|
|
203
203
|
G(this, "pipeline");
|
|
204
204
|
}
|
|
205
205
|
async init() {
|
|
206
|
-
const
|
|
207
|
-
if (!
|
|
208
|
-
this.device = await
|
|
206
|
+
const t = await navigator.gpu.requestAdapter();
|
|
207
|
+
if (!t) throw new Error("WebGPU not supported");
|
|
208
|
+
this.device = await t.requestDevice(), this.pipeline = this.device.createComputePipeline({
|
|
209
209
|
layout: "auto",
|
|
210
210
|
compute: {
|
|
211
|
-
module: this.device.createShaderModule({ code:
|
|
211
|
+
module: this.device.createShaderModule({ code: $ }),
|
|
212
212
|
entryPoint: "main"
|
|
213
213
|
}
|
|
214
214
|
});
|
|
@@ -226,203 +226,207 @@ class W {
|
|
|
226
226
|
* @param params - UMAP curve parameters and repulsion settings
|
|
227
227
|
* @returns Optimized embedding as Float32Array
|
|
228
228
|
*/
|
|
229
|
-
async optimize(
|
|
229
|
+
async optimize(t, r, s, n, g, c, d, f, a) {
|
|
230
230
|
const { device: o } = this, i = r.length, h = this.makeBuffer(
|
|
231
|
-
|
|
231
|
+
t,
|
|
232
232
|
GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
233
|
-
),
|
|
234
|
-
for (let
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
for (let
|
|
238
|
-
|
|
239
|
-
const x = this.makeBuffer(
|
|
233
|
+
), l = this.makeBuffer(r, GPUBufferUsage.STORAGE), u = this.makeBuffer(s, GPUBufferUsage.STORAGE), p = this.makeBuffer(n, GPUBufferUsage.STORAGE), m = new Float32Array(i).fill(0), _ = this.makeBuffer(m, GPUBufferUsage.STORAGE), w = new Float32Array(i);
|
|
234
|
+
for (let M = 0; M < i; M++)
|
|
235
|
+
w[M] = n[M] / f.negativeSampleRate;
|
|
236
|
+
const b = this.makeBuffer(w, GPUBufferUsage.STORAGE), A = new Uint32Array(i);
|
|
237
|
+
for (let M = 0; M < i; M++)
|
|
238
|
+
A[M] = Math.random() * 4294967295 | 0;
|
|
239
|
+
const x = this.makeBuffer(A, GPUBufferUsage.STORAGE), U = o.createBuffer({
|
|
240
240
|
size: 40,
|
|
241
241
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
242
242
|
});
|
|
243
|
-
for (let
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
const
|
|
243
|
+
for (let M = 0; M < d; M++) {
|
|
244
|
+
const v = 1 - M / d, S = new ArrayBuffer(40), y = new Uint32Array(S), B = new Float32Array(S);
|
|
245
|
+
y[0] = i, y[1] = g, y[2] = c, y[3] = M, y[4] = d, B[5] = v, B[6] = f.a, B[7] = f.b, B[8] = f.gamma, y[9] = f.negativeSampleRate, o.queue.writeBuffer(U, 0, S);
|
|
246
|
+
const k = o.createBindGroup({
|
|
247
247
|
layout: this.pipeline.getBindGroupLayout(0),
|
|
248
248
|
entries: [
|
|
249
|
-
{ binding: 0, resource: { buffer:
|
|
250
|
-
{ binding: 1, resource: { buffer:
|
|
249
|
+
{ binding: 0, resource: { buffer: p } },
|
|
250
|
+
{ binding: 1, resource: { buffer: l } },
|
|
251
251
|
{ binding: 2, resource: { buffer: u } },
|
|
252
252
|
{ binding: 3, resource: { buffer: h } },
|
|
253
|
-
{ binding: 4, resource: { buffer:
|
|
254
|
-
{ binding: 5, resource: { buffer:
|
|
255
|
-
{ binding: 6, resource: { buffer:
|
|
253
|
+
{ binding: 4, resource: { buffer: _ } },
|
|
254
|
+
{ binding: 5, resource: { buffer: b } },
|
|
255
|
+
{ binding: 6, resource: { buffer: U } },
|
|
256
256
|
{ binding: 7, resource: { buffer: x } }
|
|
257
257
|
]
|
|
258
|
-
}),
|
|
259
|
-
|
|
258
|
+
}), E = o.createCommandEncoder(), P = E.beginComputePass();
|
|
259
|
+
P.setPipeline(this.pipeline), P.setBindGroup(0, k), P.dispatchWorkgroups(Math.ceil(i / 256)), P.end(), o.queue.submit([E.finish()]), M % 10 === 0 && (await o.queue.onSubmittedWorkDone(), a == null || a(M, d));
|
|
260
260
|
}
|
|
261
|
-
const
|
|
262
|
-
size:
|
|
261
|
+
const N = o.createBuffer({
|
|
262
|
+
size: t.byteLength,
|
|
263
263
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
264
264
|
}), R = o.createCommandEncoder();
|
|
265
|
-
R.copyBufferToBuffer(h, 0,
|
|
266
|
-
const
|
|
267
|
-
return
|
|
265
|
+
R.copyBufferToBuffer(h, 0, N, 0, t.byteLength), o.queue.submit([R.finish()]), await N.mapAsync(GPUMapMode.READ);
|
|
266
|
+
const O = new Float32Array(N.getMappedRange().slice(0));
|
|
267
|
+
return N.unmap(), h.destroy(), l.destroy(), u.destroy(), p.destroy(), _.destroy(), b.destroy(), x.destroy(), U.destroy(), N.destroy(), O;
|
|
268
268
|
}
|
|
269
|
-
makeBuffer(
|
|
269
|
+
makeBuffer(t, r) {
|
|
270
270
|
const s = this.device.createBuffer({
|
|
271
|
-
size:
|
|
271
|
+
size: t.byteLength,
|
|
272
272
|
usage: r,
|
|
273
273
|
mappedAtCreation: !0
|
|
274
274
|
});
|
|
275
|
-
return
|
|
275
|
+
return t instanceof Float32Array ? new Float32Array(s.getMappedRange()).set(t) : new Uint32Array(s.getMappedRange()).set(t), s.unmap(), s;
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
-
function
|
|
278
|
+
function z(e) {
|
|
279
279
|
return Math.max(-4, Math.min(4, e));
|
|
280
280
|
}
|
|
281
|
-
function
|
|
282
|
-
const { a:
|
|
283
|
-
for (let
|
|
284
|
-
m[
|
|
285
|
-
for (let
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
for (let
|
|
289
|
-
if (
|
|
290
|
-
const
|
|
291
|
-
let
|
|
292
|
-
for (let
|
|
293
|
-
const
|
|
294
|
-
|
|
281
|
+
function I(e, t, r, s, n, g, c, d) {
|
|
282
|
+
const { a: f, b: a, gamma: o = 1, negativeSampleRate: i = 5 } = c, h = t.rows.length, l = new Uint32Array(t.rows), u = new Uint32Array(t.cols), p = new Float32Array(h).fill(0), m = new Float32Array(h);
|
|
283
|
+
for (let _ = 0; _ < h; _++)
|
|
284
|
+
m[_] = r[_] / i;
|
|
285
|
+
for (let _ = 0; _ < g; _++) {
|
|
286
|
+
d == null || d(_, g);
|
|
287
|
+
const w = 1 - _ / g;
|
|
288
|
+
for (let b = 0; b < h; b++) {
|
|
289
|
+
if (p[b] > _) continue;
|
|
290
|
+
const A = l[b], x = u[b];
|
|
291
|
+
let U = 0;
|
|
292
|
+
for (let v = 0; v < n; v++) {
|
|
293
|
+
const S = e[A * n + v] - e[x * n + v];
|
|
294
|
+
U += S * S;
|
|
295
295
|
}
|
|
296
|
-
const
|
|
297
|
-
for (let
|
|
298
|
-
const
|
|
299
|
-
e[
|
|
296
|
+
const N = Math.pow(U, a), R = -2 * f * a * (U > 0 ? N / U : 0) / (f * N + 1);
|
|
297
|
+
for (let v = 0; v < n; v++) {
|
|
298
|
+
const S = e[A * n + v] - e[x * n + v], y = z(R * S);
|
|
299
|
+
e[A * n + v] += w * y, e[x * n + v] -= w * y;
|
|
300
300
|
}
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
301
|
+
p[b] += r[b];
|
|
302
|
+
const O = r[b] / i, M = Math.max(0, Math.floor(
|
|
303
|
+
(_ - m[b]) / O
|
|
304
|
+
));
|
|
305
|
+
m[b] += M * O;
|
|
306
|
+
for (let v = 0; v < M; v++) {
|
|
307
|
+
const S = Math.floor(Math.random() * s);
|
|
308
|
+
if (S === A) continue;
|
|
309
|
+
let y = 0;
|
|
310
|
+
for (let E = 0; E < n; E++) {
|
|
311
|
+
const P = e[A * n + E] - e[S * n + E];
|
|
312
|
+
y += P * P;
|
|
310
313
|
}
|
|
311
|
-
const
|
|
312
|
-
for (let
|
|
313
|
-
const
|
|
314
|
-
e[
|
|
314
|
+
const B = Math.pow(y, a), k = 2 * o * a / ((1e-3 + y) * (f * B + 1));
|
|
315
|
+
for (let E = 0; E < n; E++) {
|
|
316
|
+
const P = e[A * n + E] - e[S * n + E], F = z(k * P);
|
|
317
|
+
e[A * n + E] += w * F;
|
|
315
318
|
}
|
|
316
319
|
}
|
|
317
|
-
m[y] += r[y] / i;
|
|
318
320
|
}
|
|
319
321
|
}
|
|
320
322
|
return e;
|
|
321
323
|
}
|
|
322
|
-
function
|
|
323
|
-
const { a: o, b: i, gamma: h = 1, negativeSampleRate:
|
|
324
|
-
for (let
|
|
325
|
-
b
|
|
326
|
-
for (let
|
|
327
|
-
const
|
|
324
|
+
function ee(e, t, r, s, n, g, c, d, f, a) {
|
|
325
|
+
const { a: o, b: i, gamma: h = 1, negativeSampleRate: l = 5 } = f, u = r.rows.length, p = new Uint32Array(r.rows), m = new Uint32Array(r.cols), _ = new Float32Array(u).fill(0), w = new Float32Array(u);
|
|
326
|
+
for (let b = 0; b < u; b++)
|
|
327
|
+
w[b] = s[b] / l;
|
|
328
|
+
for (let b = 0; b < d; b++) {
|
|
329
|
+
const A = 1 - b / d;
|
|
328
330
|
for (let x = 0; x < u; x++) {
|
|
329
|
-
if (
|
|
330
|
-
const
|
|
331
|
+
if (_[x] > b) continue;
|
|
332
|
+
const U = p[x], N = m[x];
|
|
331
333
|
let R = 0;
|
|
332
|
-
for (let
|
|
333
|
-
const
|
|
334
|
-
R +=
|
|
334
|
+
for (let y = 0; y < c; y++) {
|
|
335
|
+
const B = e[U * c + y] - t[N * c + y];
|
|
336
|
+
R += B * B;
|
|
335
337
|
}
|
|
336
|
-
const
|
|
337
|
-
for (let
|
|
338
|
-
const
|
|
339
|
-
e[
|
|
338
|
+
const O = Math.pow(R, i), M = -2 * o * i * (R > 0 ? O / R : 0) / (o * O + 1);
|
|
339
|
+
for (let y = 0; y < c; y++) {
|
|
340
|
+
const B = e[U * c + y] - t[N * c + y];
|
|
341
|
+
e[U * c + y] += A * z(M * B);
|
|
340
342
|
}
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
_[x] += s[x];
|
|
344
|
+
const v = s[x] / l, S = Math.max(0, Math.floor(
|
|
345
|
+
(b - w[x]) / v
|
|
346
|
+
));
|
|
347
|
+
w[x] += S * v;
|
|
348
|
+
for (let y = 0; y < S; y++) {
|
|
349
|
+
const B = Math.floor(Math.random() * g);
|
|
350
|
+
if (B === N) continue;
|
|
351
|
+
let k = 0;
|
|
352
|
+
for (let F = 0; F < c; F++) {
|
|
353
|
+
const q = e[U * c + F] - t[B * c + F];
|
|
354
|
+
k += q * q;
|
|
350
355
|
}
|
|
351
|
-
const
|
|
352
|
-
for (let
|
|
353
|
-
const
|
|
354
|
-
e[
|
|
356
|
+
const E = Math.pow(k, i), P = 2 * h * i / ((1e-3 + k) * (o * E + 1));
|
|
357
|
+
for (let F = 0; F < c; F++) {
|
|
358
|
+
const q = e[U * c + F] - t[B * c + F];
|
|
359
|
+
e[U * c + F] += A * z(P * q);
|
|
355
360
|
}
|
|
356
361
|
}
|
|
357
|
-
b[x] += s[x] / d;
|
|
358
362
|
}
|
|
359
363
|
}
|
|
360
364
|
return e;
|
|
361
365
|
}
|
|
362
|
-
function
|
|
366
|
+
function K() {
|
|
363
367
|
return typeof navigator < "u" && !!navigator.gpu;
|
|
364
368
|
}
|
|
365
|
-
async function
|
|
369
|
+
async function re(e, t = {}, r) {
|
|
366
370
|
const {
|
|
367
371
|
nComponents: s = 2,
|
|
368
|
-
nNeighbors:
|
|
369
|
-
minDist:
|
|
370
|
-
spread:
|
|
371
|
-
hnsw:
|
|
372
|
-
} =
|
|
372
|
+
nNeighbors: n = 15,
|
|
373
|
+
minDist: g = 0.1,
|
|
374
|
+
spread: c = 1,
|
|
375
|
+
hnsw: d = {}
|
|
376
|
+
} = t, f = t.nEpochs ?? (e.length > 1e4 ? 200 : 500);
|
|
373
377
|
console.time("knn");
|
|
374
|
-
const { indices: a, distances: o } = await
|
|
375
|
-
M:
|
|
376
|
-
efConstruction:
|
|
377
|
-
efSearch:
|
|
378
|
+
const { indices: a, distances: o } = await Q(e, n, {
|
|
379
|
+
M: d.M ?? 16,
|
|
380
|
+
efConstruction: d.efConstruction ?? 200,
|
|
381
|
+
efSearch: d.efSearch ?? 50
|
|
378
382
|
});
|
|
379
383
|
console.timeEnd("knn"), console.time("fuzzy-set");
|
|
380
|
-
const i =
|
|
384
|
+
const i = L(a, o, n);
|
|
381
385
|
console.timeEnd("fuzzy-set");
|
|
382
|
-
const { a: h, b:
|
|
383
|
-
for (let
|
|
384
|
-
m[
|
|
386
|
+
const { a: h, b: l } = H(g, c), u = T(i.vals), p = e.length, m = new Float32Array(p * s);
|
|
387
|
+
for (let w = 0; w < m.length; w++)
|
|
388
|
+
m[w] = Math.random() * 20 - 10;
|
|
385
389
|
console.time("sgd");
|
|
386
|
-
let
|
|
387
|
-
if (
|
|
390
|
+
let _;
|
|
391
|
+
if (K())
|
|
388
392
|
try {
|
|
389
|
-
const
|
|
390
|
-
await
|
|
393
|
+
const w = new j();
|
|
394
|
+
await w.init(), _ = await w.optimize(
|
|
391
395
|
m,
|
|
392
396
|
new Uint32Array(i.rows),
|
|
393
397
|
new Uint32Array(i.cols),
|
|
394
398
|
u,
|
|
395
|
-
|
|
399
|
+
p,
|
|
396
400
|
s,
|
|
397
|
-
|
|
398
|
-
{ a: h, b:
|
|
401
|
+
f,
|
|
402
|
+
{ a: h, b: l, gamma: 1, negativeSampleRate: 5 },
|
|
399
403
|
r
|
|
400
404
|
);
|
|
401
|
-
} catch (
|
|
402
|
-
console.warn("WebGPU SGD failed, falling back to CPU:",
|
|
405
|
+
} catch (w) {
|
|
406
|
+
console.warn("WebGPU SGD failed, falling back to CPU:", w), _ = I(m, i, u, p, s, f, { a: h, b: l }, r);
|
|
403
407
|
}
|
|
404
408
|
else
|
|
405
|
-
|
|
406
|
-
return console.timeEnd("sgd"),
|
|
409
|
+
_ = I(m, i, u, p, s, f, { a: h, b: l }, r);
|
|
410
|
+
return console.timeEnd("sgd"), _;
|
|
407
411
|
}
|
|
408
|
-
function
|
|
409
|
-
if (Math.abs(
|
|
412
|
+
function H(e, t) {
|
|
413
|
+
if (Math.abs(t - 1) < 1e-6 && Math.abs(e - 0.1) < 1e-6)
|
|
410
414
|
return { a: 1.9292, b: 0.7915 };
|
|
411
|
-
if (Math.abs(
|
|
415
|
+
if (Math.abs(t - 1) < 1e-6 && Math.abs(e - 0) < 1e-6)
|
|
412
416
|
return { a: 1.8956, b: 0.8006 };
|
|
413
|
-
if (Math.abs(
|
|
417
|
+
if (Math.abs(t - 1) < 1e-6 && Math.abs(e - 0.5) < 1e-6)
|
|
414
418
|
return { a: 1.5769, b: 0.8951 };
|
|
415
|
-
const r =
|
|
416
|
-
return { a: ne(e,
|
|
419
|
+
const r = te(e, t);
|
|
420
|
+
return { a: ne(e, t, r), b: r };
|
|
417
421
|
}
|
|
418
|
-
function
|
|
419
|
-
return 1 / (
|
|
422
|
+
function te(e, t) {
|
|
423
|
+
return 1 / (t * 1.2);
|
|
420
424
|
}
|
|
421
|
-
function ne(e,
|
|
425
|
+
function ne(e, t, r) {
|
|
422
426
|
return e < 1e-6 ? 1.8956 : (1 / (1 + 1e-3) - 1) / -Math.pow(e, 2 * r);
|
|
423
427
|
}
|
|
424
|
-
class
|
|
425
|
-
constructor(
|
|
428
|
+
class ie {
|
|
429
|
+
constructor(t = {}) {
|
|
426
430
|
G(this, "_nComponents");
|
|
427
431
|
G(this, "_nNeighbors");
|
|
428
432
|
G(this, "_minDist");
|
|
@@ -435,8 +439,8 @@ class re {
|
|
|
435
439
|
G(this, "embedding", null);
|
|
436
440
|
G(this, "_hnswIndex", null);
|
|
437
441
|
G(this, "_nTrain", 0);
|
|
438
|
-
this._nComponents =
|
|
439
|
-
const { a: r, b: s } =
|
|
442
|
+
this._nComponents = t.nComponents ?? 2, this._nNeighbors = t.nNeighbors ?? 15, this._minDist = t.minDist ?? 0.1, this._spread = t.spread ?? 1, this._nEpochs = t.nEpochs, this._hnswOpts = t.hnsw ?? {};
|
|
443
|
+
const { a: r, b: s } = H(this._minDist, this._spread);
|
|
440
444
|
this._a = r, this._b = s;
|
|
441
445
|
}
|
|
442
446
|
/**
|
|
@@ -445,42 +449,42 @@ class re {
|
|
|
445
449
|
* index so that transform() can project new points later.
|
|
446
450
|
* Returns `this` for chaining.
|
|
447
451
|
*/
|
|
448
|
-
async fit(
|
|
449
|
-
const s =
|
|
452
|
+
async fit(t, r) {
|
|
453
|
+
const s = t.length, n = this._nEpochs ?? (s > 1e4 ? 200 : 500), { M: g = 16, efConstruction: c = 200, efSearch: d = 50 } = this._hnswOpts;
|
|
450
454
|
console.time("knn");
|
|
451
|
-
const { knn:
|
|
452
|
-
M:
|
|
453
|
-
efConstruction:
|
|
454
|
-
efSearch:
|
|
455
|
+
const { knn: f, index: a } = await J(t, this._nNeighbors, {
|
|
456
|
+
M: g,
|
|
457
|
+
efConstruction: c,
|
|
458
|
+
efSearch: d
|
|
455
459
|
});
|
|
456
460
|
this._hnswIndex = a, this._nTrain = s, console.timeEnd("knn"), console.time("fuzzy-set");
|
|
457
|
-
const o =
|
|
461
|
+
const o = L(f.indices, f.distances, this._nNeighbors);
|
|
458
462
|
console.timeEnd("fuzzy-set");
|
|
459
|
-
const i =
|
|
460
|
-
for (let
|
|
461
|
-
h[
|
|
462
|
-
if (console.time("sgd"),
|
|
463
|
+
const i = T(o.vals), h = new Float32Array(s * this._nComponents);
|
|
464
|
+
for (let l = 0; l < h.length; l++)
|
|
465
|
+
h[l] = Math.random() * 20 - 10;
|
|
466
|
+
if (console.time("sgd"), K())
|
|
463
467
|
try {
|
|
464
|
-
const
|
|
465
|
-
await
|
|
468
|
+
const l = new j();
|
|
469
|
+
await l.init(), this.embedding = await l.optimize(
|
|
466
470
|
h,
|
|
467
471
|
new Uint32Array(o.rows),
|
|
468
472
|
new Uint32Array(o.cols),
|
|
469
473
|
i,
|
|
470
474
|
s,
|
|
471
475
|
this._nComponents,
|
|
472
|
-
|
|
476
|
+
n,
|
|
473
477
|
{ a: this._a, b: this._b, gamma: 1, negativeSampleRate: 5 },
|
|
474
478
|
r
|
|
475
479
|
);
|
|
476
|
-
} catch (
|
|
477
|
-
console.warn("WebGPU SGD failed, falling back to CPU:",
|
|
480
|
+
} catch (l) {
|
|
481
|
+
console.warn("WebGPU SGD failed, falling back to CPU:", l), this.embedding = I(h, o, i, s, this._nComponents, n, {
|
|
478
482
|
a: this._a,
|
|
479
483
|
b: this._b
|
|
480
484
|
}, r);
|
|
481
485
|
}
|
|
482
486
|
else
|
|
483
|
-
this.embedding =
|
|
487
|
+
this.embedding = I(h, o, i, s, this._nComponents, n, {
|
|
484
488
|
a: this._a,
|
|
485
489
|
b: this._b
|
|
486
490
|
}, r);
|
|
@@ -497,35 +501,35 @@ class re {
|
|
|
497
501
|
* returned embedding to [0, 1]. The stored training embedding is never
|
|
498
502
|
* mutated. Defaults to `false`.
|
|
499
503
|
*/
|
|
500
|
-
async transform(
|
|
504
|
+
async transform(t, r = !1) {
|
|
501
505
|
if (!this._hnswIndex || !this.embedding)
|
|
502
506
|
throw new Error("UMAP.transform() must be called after fit()");
|
|
503
|
-
const s =
|
|
504
|
-
for (let u = 0; u <
|
|
505
|
-
const
|
|
506
|
-
o[
|
|
507
|
-
for (let
|
|
508
|
-
i[
|
|
507
|
+
const s = t.length, n = this._nEpochs ?? (this._nTrain > 1e4 ? 200 : 500), g = Math.max(100, Math.floor(n / 4)), c = this._hnswIndex.searchKnn(t, this._nNeighbors), d = X(c.indices, c.distances, this._nNeighbors), f = new Uint32Array(d.rows), a = new Uint32Array(d.cols), o = new Float32Array(s), i = new Float32Array(s * this._nComponents);
|
|
508
|
+
for (let u = 0; u < f.length; u++) {
|
|
509
|
+
const p = f[u], m = a[u], _ = d.vals[u];
|
|
510
|
+
o[p] += _;
|
|
511
|
+
for (let w = 0; w < this._nComponents; w++)
|
|
512
|
+
i[p * this._nComponents + w] += _ * this.embedding[m * this._nComponents + w];
|
|
509
513
|
}
|
|
510
514
|
for (let u = 0; u < s; u++)
|
|
511
515
|
if (o[u] > 0)
|
|
512
|
-
for (let
|
|
513
|
-
i[u * this._nComponents +
|
|
516
|
+
for (let p = 0; p < this._nComponents; p++)
|
|
517
|
+
i[u * this._nComponents + p] /= o[u];
|
|
514
518
|
else
|
|
515
|
-
for (let
|
|
516
|
-
i[u * this._nComponents +
|
|
517
|
-
const h =
|
|
519
|
+
for (let p = 0; p < this._nComponents; p++)
|
|
520
|
+
i[u * this._nComponents + p] = Math.random() * 20 - 10;
|
|
521
|
+
const h = T(d.vals), l = ee(
|
|
518
522
|
i,
|
|
519
523
|
this.embedding,
|
|
520
|
-
|
|
524
|
+
d,
|
|
521
525
|
h,
|
|
522
526
|
s,
|
|
523
527
|
this._nTrain,
|
|
524
528
|
this._nComponents,
|
|
525
|
-
|
|
529
|
+
g,
|
|
526
530
|
{ a: this._a, b: this._b }
|
|
527
531
|
);
|
|
528
|
-
return r ?
|
|
532
|
+
return r ? C(l, s, this._nComponents) : l;
|
|
529
533
|
}
|
|
530
534
|
/**
|
|
531
535
|
* Convenience method equivalent to `fit(vectors)` followed by
|
|
@@ -536,37 +540,37 @@ class re {
|
|
|
536
540
|
* returned embedding to [0, 1]. `this.embedding` is never mutated.
|
|
537
541
|
* Defaults to `false`.
|
|
538
542
|
*/
|
|
539
|
-
async fit_transform(
|
|
540
|
-
return await this.fit(
|
|
543
|
+
async fit_transform(t, r, s = !1) {
|
|
544
|
+
return await this.fit(t, r), s ? C(this.embedding, t.length, this._nComponents) : this.embedding;
|
|
541
545
|
}
|
|
542
546
|
}
|
|
543
|
-
function
|
|
547
|
+
function C(e, t, r) {
|
|
544
548
|
const s = new Float32Array(e.length);
|
|
545
|
-
for (let
|
|
546
|
-
let
|
|
547
|
-
for (let
|
|
548
|
-
const a = e[
|
|
549
|
-
a <
|
|
549
|
+
for (let n = 0; n < r; n++) {
|
|
550
|
+
let g = 1 / 0, c = -1 / 0;
|
|
551
|
+
for (let f = 0; f < t; f++) {
|
|
552
|
+
const a = e[f * r + n];
|
|
553
|
+
a < g && (g = a), a > c && (c = a);
|
|
550
554
|
}
|
|
551
|
-
const
|
|
552
|
-
for (let
|
|
553
|
-
s[
|
|
555
|
+
const d = c - g;
|
|
556
|
+
for (let f = 0; f < t; f++)
|
|
557
|
+
s[f * r + n] = d > 0 ? (e[f * r + n] - g) / d : 0;
|
|
554
558
|
}
|
|
555
559
|
return s;
|
|
556
560
|
}
|
|
557
|
-
function
|
|
561
|
+
function T(e, t) {
|
|
558
562
|
let r = -1 / 0;
|
|
559
|
-
for (let
|
|
560
|
-
e[
|
|
563
|
+
for (let n = 0; n < e.length; n++)
|
|
564
|
+
e[n] > r && (r = e[n]);
|
|
561
565
|
const s = new Float32Array(e.length);
|
|
562
|
-
for (let
|
|
563
|
-
const
|
|
564
|
-
s[
|
|
566
|
+
for (let n = 0; n < e.length; n++) {
|
|
567
|
+
const g = e[n] / r;
|
|
568
|
+
s[n] = g > 0 ? 1 / g : -1;
|
|
565
569
|
}
|
|
566
570
|
return s;
|
|
567
571
|
}
|
|
568
572
|
export {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
573
|
+
ie as UMAP,
|
|
574
|
+
re as fit,
|
|
575
|
+
K as isWebGPUAvailable
|
|
572
576
|
};
|