parakeet.ts 1.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 +21 -0
- package/README.md +286 -0
- package/dist/alignment.d.ts +36 -0
- package/dist/alignment.d.ts.map +1 -0
- package/dist/alignment.js +202 -0
- package/dist/alignment.js.map +1 -0
- package/dist/audio.d.ts +59 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/audio.js +324 -0
- package/dist/audio.js.map +1 -0
- package/dist/backend.d.ts +61 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +14 -0
- package/dist/backend.js.map +1 -0
- package/dist/decode.d.ts +38 -0
- package/dist/decode.d.ts.map +1 -0
- package/dist/decode.js +124 -0
- package/dist/decode.js.map +1 -0
- package/dist/hub.d.ts +18 -0
- package/dist/hub.d.ts.map +1 -0
- package/dist/hub.js +86 -0
- package/dist/hub.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/load.d.ts +51 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +34 -0
- package/dist/load.js.map +1 -0
- package/dist/mlx/attention.d.ts +61 -0
- package/dist/mlx/attention.d.ts.map +1 -0
- package/dist/mlx/attention.js +330 -0
- package/dist/mlx/attention.js.map +1 -0
- package/dist/mlx/audio.d.ts +46 -0
- package/dist/mlx/audio.d.ts.map +1 -0
- package/dist/mlx/audio.js +309 -0
- package/dist/mlx/audio.js.map +1 -0
- package/dist/mlx/backend.d.ts +22 -0
- package/dist/mlx/backend.d.ts.map +1 -0
- package/dist/mlx/backend.js +67 -0
- package/dist/mlx/backend.js.map +1 -0
- package/dist/mlx/cache.d.ts +23 -0
- package/dist/mlx/cache.d.ts.map +1 -0
- package/dist/mlx/cache.js +98 -0
- package/dist/mlx/cache.js.map +1 -0
- package/dist/mlx/cli.d.ts +12 -0
- package/dist/mlx/cli.d.ts.map +1 -0
- package/dist/mlx/cli.js +145 -0
- package/dist/mlx/cli.js.map +1 -0
- package/dist/mlx/conformer.d.ts +81 -0
- package/dist/mlx/conformer.d.ts.map +1 -0
- package/dist/mlx/conformer.js +315 -0
- package/dist/mlx/conformer.js.map +1 -0
- package/dist/mlx/index.d.ts +6 -0
- package/dist/mlx/index.d.ts.map +1 -0
- package/dist/mlx/index.js +9 -0
- package/dist/mlx/index.js.map +1 -0
- package/dist/mlx/load.d.ts +27 -0
- package/dist/mlx/load.d.ts.map +1 -0
- package/dist/mlx/load.js +161 -0
- package/dist/mlx/load.js.map +1 -0
- package/dist/mlx/nn.d.ts +121 -0
- package/dist/mlx/nn.d.ts.map +1 -0
- package/dist/mlx/nn.js +511 -0
- package/dist/mlx/nn.js.map +1 -0
- package/dist/mlx/rnnt.d.ts +59 -0
- package/dist/mlx/rnnt.d.ts.map +1 -0
- package/dist/mlx/rnnt.js +233 -0
- package/dist/mlx/rnnt.js.map +1 -0
- package/dist/mlx/server.d.ts +34 -0
- package/dist/mlx/server.d.ts.map +1 -0
- package/dist/mlx/server.js +115 -0
- package/dist/mlx/server.js.map +1 -0
- package/dist/mlx/utils.d.ts +19 -0
- package/dist/mlx/utils.d.ts.map +1 -0
- package/dist/mlx/utils.js +103 -0
- package/dist/mlx/utils.js.map +1 -0
- package/dist/model.d.ts +112 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +196 -0
- package/dist/model.js.map +1 -0
- package/dist/onnx/backend.d.ts +55 -0
- package/dist/onnx/backend.d.ts.map +1 -0
- package/dist/onnx/backend.js +111 -0
- package/dist/onnx/backend.js.map +1 -0
- package/dist/onnx/index.d.ts +7 -0
- package/dist/onnx/index.d.ts.map +1 -0
- package/dist/onnx/index.js +6 -0
- package/dist/onnx/index.js.map +1 -0
- package/dist/onnx/parakeet.d.ts +44 -0
- package/dist/onnx/parakeet.d.ts.map +1 -0
- package/dist/onnx/parakeet.js +135 -0
- package/dist/onnx/parakeet.js.map +1 -0
- package/dist/tokenizer.d.ts +6 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +8 -0
- package/dist/tokenizer.js.map +1 -0
- package/package.json +85 -0
package/dist/hub.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HuggingFace Hub downloads — backend-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* Files are cached under the HF hub layout so both backends share one cache
|
|
5
|
+
* directory. Downloads are atomic (write to `.tmp`, then rename) so an
|
|
6
|
+
* interrupted fetch never leaves a truncated file that later looks cached.
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
/** Default HF cache root, honouring HF_HOME / HF_HUB_CACHE like huggingface_hub. */
|
|
11
|
+
export function defaultCacheDir() {
|
|
12
|
+
if (process.env['HF_HUB_CACHE'])
|
|
13
|
+
return process.env['HF_HUB_CACHE'];
|
|
14
|
+
if (process.env['HF_HOME'])
|
|
15
|
+
return path.join(process.env['HF_HOME'], 'hub');
|
|
16
|
+
return path.join(process.env['HOME'] ?? process.env['USERPROFILE'] ?? '/tmp', '.cache', 'huggingface', 'hub');
|
|
17
|
+
}
|
|
18
|
+
/** Local directory a repo's files are cached in. */
|
|
19
|
+
export function repoDir(repoId, cacheDir) {
|
|
20
|
+
return path.join(cacheDir ?? defaultCacheDir(), repoId.replace(/\//g, '--'));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Fetch one file from a repo, returning its local path. No-op if already cached.
|
|
24
|
+
*/
|
|
25
|
+
export async function downloadFromHub(repoId, filename, cacheDir, onProgress) {
|
|
26
|
+
const modelDir = repoDir(repoId, cacheDir);
|
|
27
|
+
fs.mkdirSync(modelDir, { recursive: true });
|
|
28
|
+
const localPath = path.join(modelDir, filename);
|
|
29
|
+
if (fs.existsSync(localPath))
|
|
30
|
+
return localPath;
|
|
31
|
+
fs.mkdirSync(path.dirname(localPath), { recursive: true });
|
|
32
|
+
const url = `https://huggingface.co/${repoId}/resolve/main/${filename}`;
|
|
33
|
+
const response = await fetch(url, { headers: { 'User-Agent': 'parakeet.ts/1.0.0' } });
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const total = parseInt(response.headers.get('content-length') ?? '0', 10);
|
|
38
|
+
const tmpPath = `${localPath}.tmp`;
|
|
39
|
+
if (response.body) {
|
|
40
|
+
const writeStream = fs.createWriteStream(tmpPath);
|
|
41
|
+
let downloaded = 0;
|
|
42
|
+
const reader = response.body.getReader();
|
|
43
|
+
try {
|
|
44
|
+
for (;;) {
|
|
45
|
+
const { done, value } = await reader.read();
|
|
46
|
+
if (done)
|
|
47
|
+
break;
|
|
48
|
+
if (!writeStream.write(value)) {
|
|
49
|
+
await new Promise(resolve => writeStream.once('drain', () => resolve()));
|
|
50
|
+
}
|
|
51
|
+
downloaded += value.byteLength;
|
|
52
|
+
if (onProgress)
|
|
53
|
+
onProgress(downloaded, total);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
reader.releaseLock();
|
|
58
|
+
}
|
|
59
|
+
await new Promise((resolve, reject) => {
|
|
60
|
+
writeStream.end((err) => (err ? reject(err) : resolve()));
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
65
|
+
fs.writeFileSync(tmpPath, Buffer.from(arrayBuffer));
|
|
66
|
+
}
|
|
67
|
+
fs.renameSync(tmpPath, localPath);
|
|
68
|
+
return localPath;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Fetch several files, skipping any marked optional that 404.
|
|
72
|
+
* Returns the repo's local directory.
|
|
73
|
+
*/
|
|
74
|
+
export async function downloadRepoFiles(repoId, files, cacheDir, onProgress) {
|
|
75
|
+
for (const { name, optional } of files) {
|
|
76
|
+
try {
|
|
77
|
+
await downloadFromHub(repoId, name, cacheDir, onProgress ? (d, t) => onProgress(name, d, t) : undefined);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (!optional)
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return repoDir(repoId, cacheDir);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=hub.js.map
|
package/dist/hub.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub.js","sourceRoot":"","sources":["../src/hub.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { load, detectBackend, DEFAULT_MODELS } from './load.js';
|
|
2
|
+
export type { LoadOptions, BackendKind } from './load.js';
|
|
3
|
+
export { downloadFromHub, downloadRepoFiles, defaultCacheDir, repoDir } from './hub.js';
|
|
4
|
+
export { ParakeetModel, StreamingParakeet, consumePcmStream } from './model.js';
|
|
5
|
+
export type { ParakeetModelArgs, TranscribeOptions, StreamOptions } from './model.js';
|
|
6
|
+
export type { ParakeetBackend, EncoderOutput, EncoderLayout, DecodeStepResult, DecoderStateHandle, } from './backend.js';
|
|
7
|
+
export { decodeTDTGreedy, decodeRNNTGreedy } from './decode.js';
|
|
8
|
+
export type { DecoderState, GreedyOptions } from './decode.js';
|
|
9
|
+
export { getLogMel, loadAudioRaw, getWindow, makePreprocessArgs, computeMelFilterbanks, computeMelFilterbanksInterpolated, } from './audio.js';
|
|
10
|
+
export type { PreprocessArgs, LogMel } from './audio.js';
|
|
11
|
+
export { AlignedToken, AlignedSentence, AlignedResult, SentenceConfig, makeAlignedToken, makeAlignedSentence, makeAlignedResult, tokensToSentences, sentencesToResult, } from './alignment.js';
|
|
12
|
+
export { decode } from './tokenizer.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChF,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtF,YAAY,EACV,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,iCAAiC,GAClC,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EACL,YAAY,EACZ,eAAe,EACf,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// parakeet.ts — shared, backend-agnostic API
|
|
2
|
+
//
|
|
3
|
+
// The model class, audio front-end, decode loops, alignment and tokenizer are
|
|
4
|
+
// all backend-independent. Pick a backend by importing its loader:
|
|
5
|
+
//
|
|
6
|
+
// import { fromLocal } from 'parakeet.ts/onnx'; // ONNX Runtime (CUDA on Linux)
|
|
7
|
+
// import { fromLocal } from 'parakeet.ts/mlx'; // MLX (Apple Silicon)
|
|
8
|
+
//
|
|
9
|
+
// Both return the same `ParakeetModel`.
|
|
10
|
+
// Zero-config entry point: picks the backend for this platform and fetches the
|
|
11
|
+
// model on first use.
|
|
12
|
+
export { load, detectBackend, DEFAULT_MODELS } from './load.js';
|
|
13
|
+
export { downloadFromHub, downloadRepoFiles, defaultCacheDir, repoDir } from './hub.js';
|
|
14
|
+
export { ParakeetModel, StreamingParakeet, consumePcmStream } from './model.js';
|
|
15
|
+
export { decodeTDTGreedy, decodeRNNTGreedy } from './decode.js';
|
|
16
|
+
export { getLogMel, loadAudioRaw, getWindow, makePreprocessArgs, computeMelFilterbanks, computeMelFilterbanksInterpolated, } from './audio.js';
|
|
17
|
+
export { makeAlignedToken, makeAlignedSentence, makeAlignedResult, tokensToSentences, sentencesToResult, } from './alignment.js';
|
|
18
|
+
export { decode } from './tokenizer.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,8EAA8E;AAC9E,mEAAmE;AACnE,EAAE;AACF,oFAAoF;AACpF,2EAA2E;AAC3E,EAAE;AACF,wCAAwC;AAExC,+EAA+E;AAC/E,sBAAsB;AACtB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGhE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAWhF,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,qBAAqB,EACrB,iCAAiC,GAClC,MAAM,YAAY,CAAC;AAGpB,OAAO,EAKL,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/load.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-detecting loader — the entry point most callers should use.
|
|
3
|
+
*
|
|
4
|
+
* import { load } from 'parakeet.ts';
|
|
5
|
+
* const model = await load(); // picks the backend, fetches the model
|
|
6
|
+
* const result = await model.transcribe('audio.wav');
|
|
7
|
+
*
|
|
8
|
+
* Backend selection:
|
|
9
|
+
* - Apple Silicon -> MLX / Metal
|
|
10
|
+
* - everything else -> ONNX Runtime (CUDA execution provider on Linux/Nvidia,
|
|
11
|
+
* CPU otherwise)
|
|
12
|
+
*
|
|
13
|
+
* Each backend has its own default checkpoint on the Hub, because the two need
|
|
14
|
+
* different asset formats (safetensors vs exported ONNX graphs). Both produce
|
|
15
|
+
* the same transcripts — see docs/cuda.md.
|
|
16
|
+
*/
|
|
17
|
+
import type { ParakeetModel } from './model.js';
|
|
18
|
+
export type BackendKind = 'auto' | 'mlx' | 'onnx';
|
|
19
|
+
export interface LoadOptions {
|
|
20
|
+
/** Force a backend. Default 'auto'. */
|
|
21
|
+
backend?: BackendKind;
|
|
22
|
+
/**
|
|
23
|
+
* HF repo id or local directory. Defaults to the chosen backend's standard
|
|
24
|
+
* checkpoint.
|
|
25
|
+
*/
|
|
26
|
+
model?: string;
|
|
27
|
+
/** Override the HF cache root. */
|
|
28
|
+
cacheDir?: string;
|
|
29
|
+
/** Called as each file downloads. */
|
|
30
|
+
onProgress?: (file: string, downloaded: number, total: number) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Mel filterbank. 'interpolated' (default) matches NVIDIA's reference
|
|
33
|
+
* preprocessor; 'floor' reproduces the legacy parakeet-mlx filterbank.
|
|
34
|
+
*/
|
|
35
|
+
filterbank?: 'floor' | 'interpolated';
|
|
36
|
+
/** ONNX only: override the execution provider (default: CUDA where available). */
|
|
37
|
+
executionProvider?: 'cuda' | 'cpu' | 'tensorrt' | 'coreml' | 'dml';
|
|
38
|
+
}
|
|
39
|
+
/** Standard checkpoint per backend — different asset formats, same transcripts. */
|
|
40
|
+
export declare const DEFAULT_MODELS: {
|
|
41
|
+
readonly mlx: "mlx-community/parakeet-tdt-0.6b-v3";
|
|
42
|
+
readonly onnx: "istupakov/parakeet-tdt-0.6b-v3-onnx";
|
|
43
|
+
};
|
|
44
|
+
/** Which backend `load()` would choose on this machine. */
|
|
45
|
+
export declare function detectBackend(): 'mlx' | 'onnx';
|
|
46
|
+
/**
|
|
47
|
+
* Load Parakeet using the backend native to this platform, downloading the
|
|
48
|
+
* model on first use.
|
|
49
|
+
*/
|
|
50
|
+
export declare function load(options?: LoadOptions): Promise<ParakeetModel>;
|
|
51
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvE;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IACtC,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,CAAC;CACpE;AAED,mFAAmF;AACnF,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,2DAA2D;AAC3D,wBAAgB,aAAa,IAAI,KAAK,GAAG,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAqB5E"}
|
package/dist/load.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Standard checkpoint per backend — different asset formats, same transcripts. */
|
|
2
|
+
export const DEFAULT_MODELS = {
|
|
3
|
+
mlx: 'mlx-community/parakeet-tdt-0.6b-v3',
|
|
4
|
+
onnx: 'istupakov/parakeet-tdt-0.6b-v3-onnx',
|
|
5
|
+
};
|
|
6
|
+
/** Which backend `load()` would choose on this machine. */
|
|
7
|
+
export function detectBackend() {
|
|
8
|
+
return process.platform === 'darwin' && process.arch === 'arm64' ? 'mlx' : 'onnx';
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Load Parakeet using the backend native to this platform, downloading the
|
|
12
|
+
* model on first use.
|
|
13
|
+
*/
|
|
14
|
+
export async function load(options = {}) {
|
|
15
|
+
const kind = !options.backend || options.backend === 'auto'
|
|
16
|
+
? detectBackend()
|
|
17
|
+
: options.backend;
|
|
18
|
+
if (kind === 'mlx') {
|
|
19
|
+
const { fromPretrained } = await import('./mlx/load.js');
|
|
20
|
+
return fromPretrained(options.model ?? DEFAULT_MODELS.mlx, {
|
|
21
|
+
cacheDir: options.cacheDir,
|
|
22
|
+
onProgress: options.onProgress,
|
|
23
|
+
filterbank: options.filterbank,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const { fromPretrained } = await import('./onnx/parakeet.js');
|
|
27
|
+
return fromPretrained(options.model ?? DEFAULT_MODELS.onnx, {
|
|
28
|
+
cacheDir: options.cacheDir,
|
|
29
|
+
onProgress: options.onProgress,
|
|
30
|
+
filterbank: options.filterbank,
|
|
31
|
+
executionProvider: options.executionProvider,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=load.js.map
|
package/dist/load.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAyCA,mFAAmF;AACnF,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,GAAG,EAAE,oCAAoC;IACzC,IAAI,EAAE,qCAAqC;CACnC,CAAC;AAEX,2DAA2D;AAC3D,MAAM,UAAU,aAAa;IAC3B,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACpF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,UAAuB,EAAE;IAClD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM;QACzD,CAAC,CAAC,aAAa,EAAE;QACjB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAEpB,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QACzD,OAAO,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC,GAAG,EAAE;YACzD,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC9D,OAAO,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC,IAAI,EAAE;QAC1D,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;KAC7C,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { MxArray } from '@mlx-node/core';
|
|
2
|
+
import { Module, Linear, WeightMap } from './nn.js';
|
|
3
|
+
import { ConformerCache } from './cache.js';
|
|
4
|
+
export declare class MultiHeadAttention extends Module {
|
|
5
|
+
linearQ: Linear;
|
|
6
|
+
linearK: Linear;
|
|
7
|
+
linearV: Linear;
|
|
8
|
+
linearOut: Linear;
|
|
9
|
+
readonly nHead: number;
|
|
10
|
+
readonly headDim: number;
|
|
11
|
+
readonly scale: number;
|
|
12
|
+
constructor(nHead: number, nFeat: number, bias?: boolean);
|
|
13
|
+
forward(q: MxArray, k: MxArray, v: MxArray, posEmb: MxArray | null, mask: MxArray | null, cache: ConformerCache | null): MxArray;
|
|
14
|
+
loadWeights(weights: WeightMap, prefix: string): void;
|
|
15
|
+
}
|
|
16
|
+
export declare class RelPositionMultiHeadAttention extends Module {
|
|
17
|
+
linearQ: Linear;
|
|
18
|
+
linearK: Linear;
|
|
19
|
+
linearV: Linear;
|
|
20
|
+
linearOut: Linear;
|
|
21
|
+
linearPos: Linear;
|
|
22
|
+
posBiasU: MxArray;
|
|
23
|
+
posBiasV: MxArray;
|
|
24
|
+
readonly nHead: number;
|
|
25
|
+
readonly headDim: number;
|
|
26
|
+
readonly scale: number;
|
|
27
|
+
constructor(nHead: number, nFeat: number, bias?: boolean);
|
|
28
|
+
private relShift;
|
|
29
|
+
forward(q: MxArray, k: MxArray, v: MxArray, posEmb: MxArray | null, mask: MxArray | null, cache: ConformerCache | null): MxArray;
|
|
30
|
+
loadWeights(weights: WeightMap, prefix: string): void;
|
|
31
|
+
}
|
|
32
|
+
export declare class RelPositionMultiHeadLocalAttention extends RelPositionMultiHeadAttention {
|
|
33
|
+
readonly contextSize: [number, number];
|
|
34
|
+
constructor(nHead: number, nFeat: number, bias?: boolean, contextSize?: [number, number]);
|
|
35
|
+
forward(q: MxArray, k: MxArray, v: MxArray, posEmb: MxArray | null, mask: MxArray | null, cache: ConformerCache | null): MxArray;
|
|
36
|
+
}
|
|
37
|
+
export declare class RelPositionalEncoding extends Module {
|
|
38
|
+
readonly dModel: number;
|
|
39
|
+
maxLen: number;
|
|
40
|
+
readonly scaleInput: boolean;
|
|
41
|
+
readonly scale: number;
|
|
42
|
+
pe: MxArray;
|
|
43
|
+
constructor(dModel: number, maxLen?: number, scaleInput?: boolean);
|
|
44
|
+
calculatePE(): void;
|
|
45
|
+
forward(x: MxArray, offset?: number): [MxArray, MxArray];
|
|
46
|
+
loadWeights(_weights: WeightMap, _prefix: string): void;
|
|
47
|
+
}
|
|
48
|
+
export declare class LocalRelPositionalEncoding extends Module {
|
|
49
|
+
readonly dModel: number;
|
|
50
|
+
readonly maxLen: number;
|
|
51
|
+
readonly scaleInput: boolean;
|
|
52
|
+
readonly scale: number;
|
|
53
|
+
readonly leftContext: number;
|
|
54
|
+
readonly rightContext: number;
|
|
55
|
+
pe: MxArray;
|
|
56
|
+
constructor(dModel: number, maxLen?: number, scaleInput?: boolean, contextSize?: [number, number]);
|
|
57
|
+
calculatePE(): void;
|
|
58
|
+
forward(x: MxArray, _offset?: number): [MxArray, MxArray];
|
|
59
|
+
loadWeights(_weights: WeightMap, _prefix: string): void;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=attention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention.d.ts","sourceRoot":"","sources":["../../src/mlx/attention.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAoB,MAAM,SAAS,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAiC5C,qBAAa,kBAAmB,SAAQ,MAAM;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAElB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,UAAO;IAYrD,OAAO,CACL,CAAC,EAAE,OAAO,EACV,CAAC,EAAE,OAAO,EACV,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,KAAK,EAAE,cAAc,GAAG,IAAI,GAC3B,OAAO;IAuBV,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAMtD;AAMD,qBAAa,6BAA8B,SAAQ,MAAM;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAElB,QAAQ,EAAG,OAAO,CAAC;IACnB,QAAQ,EAAG,OAAO,CAAC;IAEnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,UAAO;IAarD,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CACL,CAAC,EAAE,OAAO,EACV,CAAC,EAAE,OAAO,EACV,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,KAAK,EAAE,cAAc,GAAG,IAAI,GAC3B,OAAO;IA0DV,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAoBtD;AAOD,qBAAa,kCAAmC,SAAQ,6BAA6B;IACnF,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAGrC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,UAAO,EACX,WAAW,GAAE,CAAC,MAAM,EAAE,MAAM,CAAc;IAM5C,OAAO,CACL,CAAC,EAAE,OAAO,EACV,CAAC,EAAE,OAAO,EACV,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,KAAK,EAAE,cAAc,GAAG,IAAI,GAC3B,OAAO;CAoEX;AAMD,qBAAa,qBAAsB,SAAQ,MAAM;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,EAAE,EAAG,OAAO,CAAC;gBAED,MAAM,EAAE,MAAM,EAAE,MAAM,SAAO,EAAE,UAAU,UAAO;IAS5D,WAAW,IAAI,IAAI;IAkBnB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,SAAI,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC;IAkBnD,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;CAGxD;AAED,qBAAa,0BAA2B,SAAQ,MAAM;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,EAAE,EAAG,OAAO,CAAC;gBAGX,MAAM,EAAE,MAAM,EACd,MAAM,SAAO,EACb,UAAU,UAAO,EACjB,WAAW,GAAE,CAAC,MAAM,EAAE,MAAM,CAAc;IAW5C,WAAW,IAAI,IAAI;IAkBnB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,SAAI,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC;IAKpD,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;CACxD"}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { MxArray } from '@mlx-node/core';
|
|
2
|
+
import { Module, Linear, softmax } from './nn.js';
|
|
3
|
+
function s(...dims) {
|
|
4
|
+
return BigInt64Array.from(dims.map(BigInt));
|
|
5
|
+
}
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Scaled dot-product attention (standard)
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
function scaledDotProductAttention(q, // [batch, heads, q_seq, head_dim]
|
|
10
|
+
k, // [batch, heads, k_seq, head_dim]
|
|
11
|
+
v, // [batch, heads, k_seq, head_dim]
|
|
12
|
+
scale, mask) {
|
|
13
|
+
// scores: [batch, heads, q_seq, k_seq]
|
|
14
|
+
let scores = q.matmul(k.transpose(new Int32Array([0, 1, 3, 2]))).mulScalar(scale);
|
|
15
|
+
if (mask !== null) {
|
|
16
|
+
// mask is additive (0 or -inf) or boolean — add directly
|
|
17
|
+
scores = scores.add(mask);
|
|
18
|
+
}
|
|
19
|
+
const attn = softmax(scores, 3);
|
|
20
|
+
return attn.matmul(v); // [batch, heads, q_seq, head_dim]
|
|
21
|
+
}
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Standard multi-head attention
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export class MultiHeadAttention extends Module {
|
|
26
|
+
linearQ;
|
|
27
|
+
linearK;
|
|
28
|
+
linearV;
|
|
29
|
+
linearOut;
|
|
30
|
+
nHead;
|
|
31
|
+
headDim;
|
|
32
|
+
scale;
|
|
33
|
+
constructor(nHead, nFeat, bias = true) {
|
|
34
|
+
super();
|
|
35
|
+
this.nHead = nHead;
|
|
36
|
+
this.headDim = Math.floor(nFeat / nHead);
|
|
37
|
+
this.scale = Math.pow(this.headDim, -0.5);
|
|
38
|
+
this.linearQ = new Linear(nFeat, nFeat, bias);
|
|
39
|
+
this.linearK = new Linear(nFeat, nFeat, bias);
|
|
40
|
+
this.linearV = new Linear(nFeat, nFeat, bias);
|
|
41
|
+
this.linearOut = new Linear(nFeat, nFeat, bias);
|
|
42
|
+
}
|
|
43
|
+
forward(q, k, v, posEmb, mask, cache) {
|
|
44
|
+
const Qp = this.linearQ.forward(q);
|
|
45
|
+
const Kp = this.linearK.forward(k);
|
|
46
|
+
const Vp = this.linearV.forward(v);
|
|
47
|
+
const qShape = Qp.shape();
|
|
48
|
+
const batch = Number(qShape[0]);
|
|
49
|
+
const qSeq = Number(qShape[1]);
|
|
50
|
+
const kSeq = Number(Kp.shape()[1]);
|
|
51
|
+
const Qr = Qp.reshape(s(batch, qSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
52
|
+
let Kr = Kp.reshape(s(batch, kSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
53
|
+
let Vr = Vp.reshape(s(batch, kSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
54
|
+
if (cache) {
|
|
55
|
+
[Kr, Vr] = cache.updateAndFetchKV(Kr, Vr);
|
|
56
|
+
}
|
|
57
|
+
const o = scaledDotProductAttention(Qr, Kr, Vr, this.scale, mask);
|
|
58
|
+
const out = o.transpose(new Int32Array([0, 2, 1, 3])).reshape(s(batch, qSeq, this.headDim * this.nHead));
|
|
59
|
+
return this.linearOut.forward(out);
|
|
60
|
+
}
|
|
61
|
+
loadWeights(weights, prefix) {
|
|
62
|
+
this.linearQ.loadWeights(weights, `${prefix}.linear_q`);
|
|
63
|
+
this.linearK.loadWeights(weights, `${prefix}.linear_k`);
|
|
64
|
+
this.linearV.loadWeights(weights, `${prefix}.linear_v`);
|
|
65
|
+
this.linearOut.loadWeights(weights, `${prefix}.linear_out`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Relative-position multi-head attention
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
export class RelPositionMultiHeadAttention extends Module {
|
|
72
|
+
linearQ;
|
|
73
|
+
linearK;
|
|
74
|
+
linearV;
|
|
75
|
+
linearOut;
|
|
76
|
+
linearPos;
|
|
77
|
+
posBiasU; // [nHead, headDim]
|
|
78
|
+
posBiasV; // [nHead, headDim]
|
|
79
|
+
nHead;
|
|
80
|
+
headDim;
|
|
81
|
+
scale;
|
|
82
|
+
constructor(nHead, nFeat, bias = true) {
|
|
83
|
+
super();
|
|
84
|
+
this.nHead = nHead;
|
|
85
|
+
this.headDim = Math.floor(nFeat / nHead);
|
|
86
|
+
this.scale = Math.pow(this.headDim, -0.5);
|
|
87
|
+
this.linearQ = new Linear(nFeat, nFeat, bias);
|
|
88
|
+
this.linearK = new Linear(nFeat, nFeat, bias);
|
|
89
|
+
this.linearV = new Linear(nFeat, nFeat, bias);
|
|
90
|
+
this.linearOut = new Linear(nFeat, nFeat, bias);
|
|
91
|
+
this.linearPos = new Linear(nFeat, nFeat, false);
|
|
92
|
+
}
|
|
93
|
+
relShift(x) {
|
|
94
|
+
// x: [B, H, Tq, posLen]
|
|
95
|
+
const xShape = x.shape();
|
|
96
|
+
const B = Number(xShape[0]);
|
|
97
|
+
const H = Number(xShape[1]);
|
|
98
|
+
const Tq = Number(xShape[2]);
|
|
99
|
+
const posLen = Number(xShape[3]);
|
|
100
|
+
// Pad: [B, H, Tq, posLen+1]
|
|
101
|
+
const padded = x.pad(new Int32Array([0, 0, 0, 0, 0, 0, 1, 0]), 0.0);
|
|
102
|
+
// Reshape: [B, H, posLen+1, Tq]
|
|
103
|
+
const reshaped = padded.reshape(s(B, H, posLen + 1, Tq));
|
|
104
|
+
// Slice off first row: [B, H, posLen, Tq]
|
|
105
|
+
const sliced = reshaped.slice(s(0, 0, 1, 0), s(B, H, posLen + 1, Tq));
|
|
106
|
+
// Reshape back: [B, H, Tq, posLen]
|
|
107
|
+
return sliced.reshape(s(B, H, Tq, posLen));
|
|
108
|
+
}
|
|
109
|
+
forward(q, k, v, posEmb, mask, cache) {
|
|
110
|
+
if (posEmb === null)
|
|
111
|
+
throw new Error('posEmb is required for RelPositionMultiHeadAttention');
|
|
112
|
+
const Qp = this.linearQ.forward(q);
|
|
113
|
+
const Kp = this.linearK.forward(k);
|
|
114
|
+
const Vp = this.linearV.forward(v);
|
|
115
|
+
const P = this.linearPos.forward(posEmb);
|
|
116
|
+
const qShape = Qp.shape();
|
|
117
|
+
const batch = Number(qShape[0]);
|
|
118
|
+
const qSeq = Number(qShape[1]);
|
|
119
|
+
const kSeq = Number(Kp.shape()[1]);
|
|
120
|
+
const pBatch = Number(P.shape()[0]);
|
|
121
|
+
const posLen = Number(P.shape()[1]);
|
|
122
|
+
// posEmb broadcast if batch > 1
|
|
123
|
+
const Pb = pBatch === 1 && batch > 1
|
|
124
|
+
? P.broadcastTo(s(batch, posLen, Number(P.shape()[2])))
|
|
125
|
+
: P;
|
|
126
|
+
const Qr = Qp.reshape(s(batch, qSeq, this.nHead, this.headDim));
|
|
127
|
+
const Qu = Qr.add(this.posBiasU).transpose(new Int32Array([0, 2, 1, 3]));
|
|
128
|
+
const Qv = Qr.add(this.posBiasV).transpose(new Int32Array([0, 2, 1, 3]));
|
|
129
|
+
let Kr = Kp.reshape(s(batch, kSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
130
|
+
let Vr = Vp.reshape(s(batch, kSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
131
|
+
const Pr = Pb.reshape(s(batch, posLen, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
132
|
+
if (cache) {
|
|
133
|
+
[Kr, Vr] = cache.updateAndFetchKV(Kr, Vr);
|
|
134
|
+
}
|
|
135
|
+
const kLen = Number(Kr.shape()[2]);
|
|
136
|
+
// Content-based scores: [batch, heads, qSeq, kLen]
|
|
137
|
+
const matrixAC = Qu.matmul(Kr.transpose(new Int32Array([0, 1, 3, 2]))).mulScalar(this.scale);
|
|
138
|
+
// Position-based scores: [batch, heads, qSeq, posLen] → rel_shift → [batch, heads, qSeq, kLen]
|
|
139
|
+
let matrixBD = Qv.matmul(Pr.transpose(new Int32Array([0, 1, 3, 2])));
|
|
140
|
+
matrixBD = this.relShift(matrixBD);
|
|
141
|
+
matrixBD = matrixBD
|
|
142
|
+
.slice(s(0, 0, 0, 0), s(batch, this.nHead, qSeq, kLen))
|
|
143
|
+
.mulScalar(this.scale);
|
|
144
|
+
let scores = matrixAC.add(matrixBD);
|
|
145
|
+
if (mask !== null) {
|
|
146
|
+
scores = scores.add(mask);
|
|
147
|
+
}
|
|
148
|
+
const attn = softmax(scores, 3);
|
|
149
|
+
const o = attn.matmul(Vr);
|
|
150
|
+
const out = o.transpose(new Int32Array([0, 2, 1, 3])).reshape(s(batch, qSeq, -1 /* nHead*headDim */));
|
|
151
|
+
// Note: -1 not supported by reshape; use actual size:
|
|
152
|
+
const outReshaped = o.transpose(new Int32Array([0, 2, 1, 3])).reshape(s(batch, qSeq, this.nHead * this.headDim));
|
|
153
|
+
return this.linearOut.forward(outReshaped);
|
|
154
|
+
}
|
|
155
|
+
loadWeights(weights, prefix) {
|
|
156
|
+
this.linearQ.loadWeights(weights, `${prefix}.linear_q`);
|
|
157
|
+
this.linearK.loadWeights(weights, `${prefix}.linear_k`);
|
|
158
|
+
this.linearV.loadWeights(weights, `${prefix}.linear_v`);
|
|
159
|
+
this.linearOut.loadWeights(weights, `${prefix}.linear_out`);
|
|
160
|
+
this.linearPos.loadWeights(weights, `${prefix}.linear_pos`);
|
|
161
|
+
const entry = weights.get(`${prefix}.pos_bias_u`);
|
|
162
|
+
if (entry) {
|
|
163
|
+
this.posBiasU = MxArray.fromFloat32(entry.data, BigInt64Array.from(entry.shape.map(BigInt)));
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
this.posBiasU = MxArray.zeros(s(this.nHead, this.headDim), null);
|
|
167
|
+
}
|
|
168
|
+
const entryV = weights.get(`${prefix}.pos_bias_v`);
|
|
169
|
+
if (entryV) {
|
|
170
|
+
this.posBiasV = MxArray.fromFloat32(entryV.data, BigInt64Array.from(entryV.shape.map(BigInt)));
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
this.posBiasV = MxArray.zeros(s(this.nHead, this.headDim), null);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// Local relative-position attention
|
|
179
|
+
// Uses standard attention with a local window mask (no custom Metal kernel)
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
export class RelPositionMultiHeadLocalAttention extends RelPositionMultiHeadAttention {
|
|
182
|
+
contextSize;
|
|
183
|
+
constructor(nHead, nFeat, bias = true, contextSize = [256, 256]) {
|
|
184
|
+
super(nHead, nFeat, bias);
|
|
185
|
+
this.contextSize = contextSize;
|
|
186
|
+
}
|
|
187
|
+
forward(q, k, v, posEmb, mask, cache) {
|
|
188
|
+
if (posEmb === null)
|
|
189
|
+
throw new Error('posEmb is required');
|
|
190
|
+
const Qp = this.linearQ.forward(q);
|
|
191
|
+
const Kp = this.linearK.forward(k);
|
|
192
|
+
const Vp = this.linearV.forward(v);
|
|
193
|
+
const P = this.linearPos.forward(posEmb);
|
|
194
|
+
const qShape = Qp.shape();
|
|
195
|
+
const batch = Number(qShape[0]);
|
|
196
|
+
const qSeq = Number(qShape[1]);
|
|
197
|
+
const kSeq = Number(Kp.shape()[1]);
|
|
198
|
+
const posLen = Number(P.shape()[1]);
|
|
199
|
+
const Pb = Number(P.shape()[0]) === 1 && batch > 1
|
|
200
|
+
? P.broadcastTo(s(batch, posLen, Number(P.shape()[2])))
|
|
201
|
+
: P;
|
|
202
|
+
const Qr = Qp.reshape(s(batch, qSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
203
|
+
let Kr = Kp.reshape(s(batch, kSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
204
|
+
let Vr = Vp.reshape(s(batch, kSeq, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
205
|
+
const Pr = Pb.reshape(s(batch, posLen, this.nHead, this.headDim)).transpose(new Int32Array([0, 2, 1, 3]));
|
|
206
|
+
if (cache) {
|
|
207
|
+
[Kr, Vr] = cache.updateAndFetchKV(Kr, Vr);
|
|
208
|
+
}
|
|
209
|
+
const kLen = Number(Kr.shape()[2]);
|
|
210
|
+
const [leftCtx, rightCtx] = this.contextSize;
|
|
211
|
+
// Content scores
|
|
212
|
+
const Qu = Qr.add(this.posBiasU.expandDims(1));
|
|
213
|
+
const Qv = Qr.add(this.posBiasV.expandDims(1));
|
|
214
|
+
const matrixAC = Qu.matmul(Kr.transpose(new Int32Array([0, 1, 3, 2]))).mulScalar(this.scale);
|
|
215
|
+
// Position scores — simplified: use relative positions from posEmb
|
|
216
|
+
const matrixBD = Qv.matmul(Pr.transpose(new Int32Array([0, 1, 3, 2]))).mulScalar(this.scale);
|
|
217
|
+
let scores = matrixAC; // start with content scores
|
|
218
|
+
// Build local attention mask — positions outside [t-left, t+right] get -inf
|
|
219
|
+
// We build a [1, 1, qSeq, kLen] mask
|
|
220
|
+
const maskData = new Float32Array(qSeq * kLen).fill(-Infinity);
|
|
221
|
+
for (let qi = 0; qi < qSeq; qi++) {
|
|
222
|
+
// Align q to the right side of k (k might be longer due to cache)
|
|
223
|
+
const kOffset = kLen - qSeq;
|
|
224
|
+
const ki_start = Math.max(0, kOffset + qi - leftCtx);
|
|
225
|
+
const ki_end = Math.min(kLen, kOffset + qi + rightCtx + 1);
|
|
226
|
+
for (let ki = ki_start; ki < ki_end; ki++) {
|
|
227
|
+
maskData[qi * kLen + ki] = 0.0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const localMask = MxArray.fromFloat32(maskData, s(1, 1, qSeq, kLen));
|
|
231
|
+
scores = scores.add(localMask);
|
|
232
|
+
if (mask !== null) {
|
|
233
|
+
scores = scores.add(mask);
|
|
234
|
+
}
|
|
235
|
+
// Add position bias where in range
|
|
236
|
+
scores = scores.add(matrixBD);
|
|
237
|
+
const attn = softmax(scores, 3);
|
|
238
|
+
const o = attn.matmul(Vr);
|
|
239
|
+
const outReshaped = o.transpose(new Int32Array([0, 2, 1, 3])).reshape(s(batch, qSeq, this.nHead * this.headDim));
|
|
240
|
+
return this.linearOut.forward(outReshaped);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
// Positional encodings
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
export class RelPositionalEncoding extends Module {
|
|
247
|
+
dModel;
|
|
248
|
+
maxLen;
|
|
249
|
+
scaleInput;
|
|
250
|
+
scale;
|
|
251
|
+
pe; // [1, 2*maxLen-1, dModel]
|
|
252
|
+
constructor(dModel, maxLen = 5000, scaleInput = true) {
|
|
253
|
+
super();
|
|
254
|
+
this.dModel = dModel;
|
|
255
|
+
this.maxLen = maxLen;
|
|
256
|
+
this.scaleInput = scaleInput;
|
|
257
|
+
this.scale = scaleInput ? Math.sqrt(dModel) : 1.0;
|
|
258
|
+
this.calculatePE();
|
|
259
|
+
}
|
|
260
|
+
calculatePE() {
|
|
261
|
+
const totalLen = 2 * this.maxLen - 1;
|
|
262
|
+
const pe = new Float32Array(totalLen * this.dModel);
|
|
263
|
+
for (let i = 0; i < totalLen; i++) {
|
|
264
|
+
const pos = this.maxLen - 1 - i; // from (maxLen-1) down to -(maxLen-1)
|
|
265
|
+
for (let j = 0; j < this.dModel; j += 2) {
|
|
266
|
+
const expFactor = Math.exp((-j * Math.log(10000.0)) / this.dModel);
|
|
267
|
+
pe[i * this.dModel + j] = Math.sin(pos * expFactor);
|
|
268
|
+
if (j + 1 < this.dModel) {
|
|
269
|
+
pe[i * this.dModel + j + 1] = Math.cos(pos * expFactor);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
this.pe = MxArray.fromFloat32(pe, BigInt64Array.from([1n, BigInt(totalLen), BigInt(this.dModel)]));
|
|
274
|
+
}
|
|
275
|
+
forward(x, offset = 0) {
|
|
276
|
+
const inputLen = Number(x.shape()[1]) + offset;
|
|
277
|
+
if (inputLen > this.maxLen) {
|
|
278
|
+
this.maxLen = inputLen + 1;
|
|
279
|
+
this.calculatePE();
|
|
280
|
+
}
|
|
281
|
+
const scaledX = x.mulScalar(this.scale);
|
|
282
|
+
const bufferLen = Number(this.pe.shape()[1]);
|
|
283
|
+
const startIdx = Math.floor(bufferLen / 2) - (inputLen - 1);
|
|
284
|
+
const endIdx = Math.floor(bufferLen / 2) + (inputLen - 1) + 1;
|
|
285
|
+
const posEmb = this.pe.slice(s(0, startIdx, 0), s(1, endIdx, this.dModel));
|
|
286
|
+
return [scaledX, posEmb];
|
|
287
|
+
}
|
|
288
|
+
loadWeights(_weights, _prefix) {
|
|
289
|
+
// PE is computed, not learned (though pos_bias_u/v in attention are learned)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
export class LocalRelPositionalEncoding extends Module {
|
|
293
|
+
dModel;
|
|
294
|
+
maxLen;
|
|
295
|
+
scaleInput;
|
|
296
|
+
scale;
|
|
297
|
+
leftContext;
|
|
298
|
+
rightContext;
|
|
299
|
+
pe; // [1, leftCtx+rightCtx+1, dModel]
|
|
300
|
+
constructor(dModel, maxLen = 5000, scaleInput = true, contextSize = [256, 256]) {
|
|
301
|
+
super();
|
|
302
|
+
this.dModel = dModel;
|
|
303
|
+
this.maxLen = maxLen;
|
|
304
|
+
this.scaleInput = scaleInput;
|
|
305
|
+
this.scale = scaleInput ? Math.sqrt(dModel) : 1.0;
|
|
306
|
+
[this.leftContext, this.rightContext] = contextSize;
|
|
307
|
+
this.calculatePE();
|
|
308
|
+
}
|
|
309
|
+
calculatePE() {
|
|
310
|
+
const totalLen = this.leftContext + this.rightContext + 1;
|
|
311
|
+
const pe = new Float32Array(totalLen * this.dModel);
|
|
312
|
+
for (let i = 0; i < totalLen; i++) {
|
|
313
|
+
const pos = this.leftContext - i; // from leftCtx down to -rightCtx
|
|
314
|
+
for (let j = 0; j < this.dModel; j += 2) {
|
|
315
|
+
const expFactor = Math.exp((-j * Math.log(10000.0)) / this.dModel);
|
|
316
|
+
pe[i * this.dModel + j] = Math.sin(pos * expFactor);
|
|
317
|
+
if (j + 1 < this.dModel) {
|
|
318
|
+
pe[i * this.dModel + j + 1] = Math.cos(pos * expFactor);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
this.pe = MxArray.fromFloat32(pe, BigInt64Array.from([1n, BigInt(totalLen), BigInt(this.dModel)]));
|
|
323
|
+
}
|
|
324
|
+
forward(x, _offset = 0) {
|
|
325
|
+
const scaledX = x.mulScalar(this.scale);
|
|
326
|
+
return [scaledX, this.pe];
|
|
327
|
+
}
|
|
328
|
+
loadWeights(_weights, _prefix) { }
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=attention.js.map
|