google / yggdrasil-decision-forests

A library to train, evaluate, interpret, and productionize decision forest models such as Random Forest and Gradient Boosted Decision Trees.
https://ydf.readthedocs.io/
Apache License 2.0
498 stars 53 forks source link

Cannot run inference with Javascript API in the Node.js REPL #99

Open akshaan opened 5 months ago

akshaan commented 5 months ago

Attempts to call YggdrasilModel.predict in a Node.js REPL yield this exception: [ERR_INVALID_REPL_INPUT]: Listeners for uncaughtException cannot be used in the REPL. We're using version 0.0.2 of the JS code published to NPM.

achoum commented 5 months ago

Hi, Sorry to hear about your issue. Can you share your version of node, the commands you are running, and the full error stack?

On my side, using node v18.19.1, both of the following setup works. Would you mind trying them? 1.

Download model.zip from https://github.com/google/yggdrasil-decision-forests/tree/main/yggdrasil_decision_forests/port/javascript/example Then run

node

Then run

const ydf = await require("yggdrasil-decision-forests")();
const fs = require("node:fs");
let model = await ydf.loadModelFromZipBlob(fs.readFileSync("./model.zip"));
let examples = {
        "age": [39, 40, 40, 35],
        "workclass": ["State-gov", "Private", "Private", "Federal-gov"],
        "fnlwgt": [77516, 121772, 193524, 76845],
        "education": ["Bachelors", "Assoc-voc", "Doctorate", "9th"],
        "education_num": ["13", "11", "16", "5"],
        "marital_status": ["Never-married", "Married-civ-spouse", "Married-civ-spouse", "Married-civ-spouse"],
        "occupation": ["Adm-clerical", "Craft-repair", "Prof-specialty", "Farming-fishing"],
        "relationship": ["Not-in-family", "Husband", "Husband", "Husband"],
        "race": ["White", "Asian-Pac-Islander", "White", "Black"],
        "sex": ["Male", "Male", "Male", "Male"],
        "capital_gain": [2174, 0, 0, 0],
        "capital_loss": [0, 0, 0, 0],
        "hours_per_week": [40, 40, 60, 40],
        "native_country": ["United-States", null, "United-States", "United-States"]
    };
model.predict(examples);

2. Create a test.jsfile with the following:

(async function (){
    // Load the YDF library
    const ydf = await require("yggdrasil-decision-forests")();

    // Load the model
    const fs = require("node:fs");
    let model = await ydf.loadModelFromZipBlob(fs.readFileSync("./model.zip"));

    // Create a batch of examples.
    let examples = {
        "age": [39, 40, 40, 35],
        "workclass": ["State-gov", "Private", "Private", "Federal-gov"],
        "fnlwgt": [77516, 121772, 193524, 76845],
        "education": ["Bachelors", "Assoc-voc", "Doctorate", "9th"],
        "education_num": ["13", "11", "16", "5"],
        "marital_status": ["Never-married", "Married-civ-spouse", "Married-civ-spouse", "Married-civ-spouse"],
        "occupation": ["Adm-clerical", "Craft-repair", "Prof-specialty", "Farming-fishing"],
        "relationship": ["Not-in-family", "Husband", "Husband", "Husband"],
        "race": ["White", "Asian-Pac-Islander", "White", "Black"],
        "sex": ["Male", "Male", "Male", "Male"],
        "capital_gain": [2174, 0, 0, 0],
        "capital_loss": [0, 0, 0, 0],
        "hours_per_week": [40, 40, 60, 40],
        "native_country": ["United-States", null, "United-States", "United-States"]
    };

    // Make predictions
    let predictions = model.predict(examples);
    console.log("predictions:", predictions);

    // Release model
    model.unload();
}())

Then

node
.load test.js

If the above does not work According to the repl doc, this error can be caused by an uncaughtException listener. https://github.com/nodejs/node/blob/main/doc/api/repl.md#global-uncaught-exceptions

Assuming your code does not have such a statement, YDF has one (injected by webassembly) which could be the cause of the issue. It can be seen here: https://www.npmjs.com/package/yggdrasil-decision-forests?activeTab=code

process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});

It would be interesting to see if removing it manually / temporally solves your issue.