@wlearn/lightgbm 0.1.0 → 0.2.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/CHANGELOG.md +9 -0
- package/LICENSE +3 -2
- package/README.md +181 -17
- package/dist/lightgbm.js +2 -0
- package/dist/lightgbm.mjs +3 -0
- package/package.json +31 -8
- package/src/booster.js +4 -2
- package/src/dataset.js +4 -2
- package/src/index.js +9 -4
- package/src/model.js +35 -7
- package/src/wasm.js +5 -8
- package/wasm/BUILD_INFO +1 -1
- package/wasm/lightgbm.js +2 -0
- package/wasm/lightgbm.cjs +0 -0
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wlearn/lightgbm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "LightGBM WASM port for wlearn",
|
|
5
|
-
"type": "
|
|
5
|
+
"type": "commonjs",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"exports": {
|
|
8
|
-
".":
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./src/index.js",
|
|
10
|
+
"default": "./src/index.js"
|
|
11
|
+
}
|
|
9
12
|
},
|
|
10
13
|
"files": [
|
|
11
14
|
"src/",
|
|
12
15
|
"wasm/",
|
|
16
|
+
"dist/",
|
|
13
17
|
"LICENSE",
|
|
14
18
|
"README.md",
|
|
15
19
|
"CHANGELOG.md"
|
|
@@ -19,17 +23,36 @@
|
|
|
19
23
|
"access": "public"
|
|
20
24
|
},
|
|
21
25
|
"scripts": {
|
|
22
|
-
"test": "node
|
|
26
|
+
"test": "node test/test.js",
|
|
23
27
|
"build": "bash scripts/build-wasm.sh",
|
|
24
|
-
"verify": "bash scripts/verify-exports.sh"
|
|
28
|
+
"verify": "bash scripts/verify-exports.sh",
|
|
29
|
+
"build:browser": "bash scripts/build-browser.sh",
|
|
30
|
+
"prepack": "node scripts/prepack.js",
|
|
31
|
+
"prepublishOnly": "node scripts/prepublish.js"
|
|
25
32
|
},
|
|
26
33
|
"dependencies": {
|
|
27
|
-
"@wlearn/
|
|
28
|
-
"@wlearn/core": "0.1.0"
|
|
34
|
+
"@wlearn/core": "0.2.0"
|
|
29
35
|
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"lightgbm",
|
|
38
|
+
"gradient-boosting",
|
|
39
|
+
"machine-learning",
|
|
40
|
+
"wasm",
|
|
41
|
+
"webassembly",
|
|
42
|
+
"wlearn"
|
|
43
|
+
],
|
|
44
|
+
"author": "Anton Zemlyansky",
|
|
30
45
|
"license": "MIT",
|
|
31
46
|
"repository": {
|
|
32
47
|
"type": "git",
|
|
33
48
|
"url": "https://github.com/wlearn-org/lightgbm-wasm.git"
|
|
34
|
-
}
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"esbuild": "^0.27.3",
|
|
52
|
+
"playwright": "^1.58.2"
|
|
53
|
+
},
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/wlearn-org/lightgbm-wasm/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://wlearn.org"
|
|
35
58
|
}
|
package/src/booster.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const { getWasm } = require('./wasm.js')
|
|
2
2
|
|
|
3
3
|
// FinalizationRegistry safety net
|
|
4
4
|
const registry = typeof FinalizationRegistry !== 'undefined'
|
|
@@ -28,7 +28,7 @@ function getLastError(wasm) {
|
|
|
28
28
|
// Internal sentinel for loadModel path
|
|
29
29
|
const LOAD_SENTINEL = Symbol('load')
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
class Booster {
|
|
32
32
|
#handle = null
|
|
33
33
|
#freed = false
|
|
34
34
|
#ptrRef = null
|
|
@@ -227,3 +227,5 @@ export class Booster {
|
|
|
227
227
|
this.#handle = null
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
|
+
|
|
231
|
+
module.exports = { Booster }
|
package/src/dataset.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const { getWasm } = require('./wasm.js')
|
|
2
2
|
|
|
3
3
|
// FinalizationRegistry safety net
|
|
4
4
|
const registry = typeof FinalizationRegistry !== 'undefined'
|
|
@@ -25,7 +25,7 @@ function getLastError(wasm) {
|
|
|
25
25
|
return wasm.UTF8ToString(wasm._wl_lgb_get_last_error())
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
class Dataset {
|
|
29
29
|
#handle = null
|
|
30
30
|
#freed = false
|
|
31
31
|
#ptrRef = null
|
|
@@ -101,3 +101,5 @@ export class Dataset {
|
|
|
101
101
|
this.#handle = null
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
+
|
|
105
|
+
module.exports = { Dataset }
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const { LGBModel: LGBModelImpl } = require('./model.js')
|
|
2
|
+
const { loadLGB } = require('./wasm.js')
|
|
3
|
+
const { Dataset } = require('./dataset.js')
|
|
4
|
+
const { Booster } = require('./booster.js')
|
|
5
|
+
const { createModelClass } = require('@wlearn/core')
|
|
6
|
+
|
|
7
|
+
const LGBModel = createModelClass(LGBModelImpl, LGBModelImpl, { name: 'LGBModel', load: loadLGB })
|
|
8
|
+
|
|
9
|
+
module.exports = { LGBModel, loadLGB, Dataset, Booster }
|
package/src/model.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const { loadLGB, getWasm } = require('./wasm.js')
|
|
2
|
+
const { Dataset } = require('./dataset.js')
|
|
3
|
+
const { Booster } = require('./booster.js')
|
|
4
|
+
const {
|
|
5
5
|
normalizeY,
|
|
6
6
|
encodeBundle, decodeBundle,
|
|
7
7
|
register,
|
|
8
8
|
DisposedError, NotFittedError
|
|
9
|
-
}
|
|
9
|
+
} = require('@wlearn/core')
|
|
10
10
|
|
|
11
11
|
// FinalizationRegistry safety net
|
|
12
12
|
const leakRegistry = typeof FinalizationRegistry !== 'undefined'
|
|
@@ -29,14 +29,14 @@ const PROBA_OBJECTIVES = new Set([
|
|
|
29
29
|
])
|
|
30
30
|
|
|
31
31
|
// LightGBM params that are wlearn-only (not passed to Booster)
|
|
32
|
-
const WLEARN_PARAMS = new Set(['numRound', 'coerce'])
|
|
32
|
+
const WLEARN_PARAMS = new Set(['numRound', 'coerce', 'task'])
|
|
33
33
|
|
|
34
34
|
// --- Internal sentinel for load path ---
|
|
35
35
|
const LOAD_SENTINEL = Symbol('load')
|
|
36
36
|
|
|
37
37
|
// --- LGBModel ---
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
class LGBModel {
|
|
40
40
|
#booster = null
|
|
41
41
|
#freed = false
|
|
42
42
|
#boosterRef = null
|
|
@@ -78,6 +78,9 @@ export class LGBModel {
|
|
|
78
78
|
fit(X, y) {
|
|
79
79
|
this.#ensureNotDisposed()
|
|
80
80
|
|
|
81
|
+
// Map task param to objective if needed
|
|
82
|
+
this.#resolveTask(y)
|
|
83
|
+
|
|
81
84
|
// Dispose previous booster if refitting
|
|
82
85
|
if (this.#booster) {
|
|
83
86
|
this.#booster.dispose()
|
|
@@ -412,6 +415,29 @@ export class LGBModel {
|
|
|
412
415
|
if (!this.#fitted) throw new NotFittedError('LGBModel is not fitted. Call fit() first.')
|
|
413
416
|
}
|
|
414
417
|
|
|
418
|
+
#resolveTask(y) {
|
|
419
|
+
const task = this.#params.task
|
|
420
|
+
if (!task) return
|
|
421
|
+
// If objective is already set, it takes precedence over task
|
|
422
|
+
if (this.#params.objective) return
|
|
423
|
+
if (task === 'classification') {
|
|
424
|
+
// Count unique values in y to decide binary vs multiclass
|
|
425
|
+
const yNorm = normalizeY(y)
|
|
426
|
+
const unique = new Set()
|
|
427
|
+
for (let i = 0; i < yNorm.length; i++) unique.add(yNorm[i])
|
|
428
|
+
if (unique.size > 2) {
|
|
429
|
+
this.#params.objective = 'multiclass'
|
|
430
|
+
this.#params.num_class = unique.size
|
|
431
|
+
} else {
|
|
432
|
+
this.#params.objective = 'binary'
|
|
433
|
+
}
|
|
434
|
+
} else if (task === 'regression') {
|
|
435
|
+
this.#params.objective = 'regression'
|
|
436
|
+
} else {
|
|
437
|
+
throw new Error(`Unknown task: '${task}'. Use 'classification' or 'regression'.`)
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
415
441
|
#isClassifier() {
|
|
416
442
|
const obj = this.#params.objective || 'regression'
|
|
417
443
|
return CLASSIFIER_OBJECTIVES.has(obj)
|
|
@@ -422,3 +448,5 @@ export class LGBModel {
|
|
|
422
448
|
|
|
423
449
|
register('wlearn.lightgbm.classifier@1', async (m, t, b) => LGBModel._fromBundle(m, t, b))
|
|
424
450
|
register('wlearn.lightgbm.regressor@1', async (m, t, b) => LGBModel._fromBundle(m, t, b))
|
|
451
|
+
|
|
452
|
+
module.exports = { LGBModel }
|
package/src/wasm.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
// WASM loader -- loads the LightGBM WASM module (singleton, lazy init)
|
|
2
2
|
|
|
3
|
-
import { createRequire } from 'module'
|
|
4
|
-
|
|
5
3
|
let wasmModule = null
|
|
6
4
|
let loading = null
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
async function loadLGB(options = {}) {
|
|
9
7
|
if (wasmModule) return wasmModule
|
|
10
8
|
if (loading) return loading
|
|
11
9
|
|
|
12
10
|
loading = (async () => {
|
|
13
|
-
|
|
14
|
-
// Emscripten output is CJS, use createRequire for ESM compatibility
|
|
15
|
-
const require = createRequire(import.meta.url)
|
|
16
|
-
const createLightGBM = require('../wasm/lightgbm.cjs')
|
|
11
|
+
const createLightGBM = require('../wasm/lightgbm.js')
|
|
17
12
|
wasmModule = await createLightGBM(options)
|
|
18
13
|
return wasmModule
|
|
19
14
|
})()
|
|
@@ -21,7 +16,9 @@ export async function loadLGB(options = {}) {
|
|
|
21
16
|
return loading
|
|
22
17
|
}
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
function getWasm() {
|
|
25
20
|
if (!wasmModule) throw new Error('WASM not loaded -- call loadLGB() first')
|
|
26
21
|
return wasmModule
|
|
27
22
|
}
|
|
23
|
+
|
|
24
|
+
module.exports = { loadLGB, getWasm }
|
package/wasm/BUILD_INFO
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
upstream: LightGBM v4.6.0
|
|
2
2
|
upstream_commit: d02a01ac6f51d36c9e62388243bcb75c3b1b1774
|
|
3
|
-
build_date: 2026-
|
|
3
|
+
build_date: 2026-05-25T14:51:03Z
|
|
4
4
|
emscripten: emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 5.0.2 (dc80f645ee70178c11666de0c3860d9e064d50e4)
|
|
5
5
|
build_flags: -O2 -fexceptions SINGLE_FILE=1
|
|
6
6
|
wasm_embedded: true
|