question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

tfjs does not work with hermes engine

See original GitHub issue

System information

  • Have I written custom code (as opposed to using a stock example script provided in TensorFlow.js): No
  • OS Platform and Distribution (e.g., Linux Ubuntu 16.04): MacOS 12.2.1 (21D62), M1
  • Mobile device (e.g. iPhone 8, Pixel 2, Samsung Galaxy) if the issue happens on mobile device: NA
  • TensorFlow.js installed from (npm or script link): npm
  • TensorFlow.js version (use command below): 3.18.0
  • Browser version: NA
  • Tensorflow.js Converter Version: NA

Describe the current behavior

When using tfjs for React Native, tfjs does not work when using hermes JavaScript engine. It works with the default jsc engine.

It fails at instanceof Tensor assertion, even though the constructor is correctly identified as Tensor: Screenshot 2022-06-11 at 4 54 15 PM

Screenshot 2022-06-11 at 6 54 02 PM copy

Describe the expected behavior

tfjs should run without errors when using hermes engine.

Standalone code to reproduce the issue

Minimum reproduction repo: https://github.com/paradite/tfjs-hermes-bug

From the repo, running npm run test:hermes throws an error:

tensor.js:1:1: error: class declaration exports are unsupported

This means that probably the original code was transformed by babel/typescript before reaching hermes and caused the instance of assertion to fail.

I should raise an issue in https://github.com/facebook/hermes, but it is hard to reproduce the exact issue when tfjs uses a lot of import across different files (hermes-cli needs to take input of all files being imported).

On the other hand, the fix for this issue on tfjs side is easy:

Other info / logs

I have tried a hacky fix and it seems to work:

Instead of using

if (x instanceof Tensor) {
    assertDtype(parseAsDtype, x.dtype, argName, functionName);
    return x;
}

, use

if (x instanceof Tensor || x.constructor.name === 'Tensor') {
    assertDtype(parseAsDtype, x.dtype, argName, functionName);
    return x;
}

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
paraditecommented, Oct 4, 2022

@mattsoulanille thanks for taking a look.

I want to share a walkaround that I found to be working for my use case:

  • Patch the tfjs code directly at node_modules/@tensorflow/tfjs/dist/tf.node.js
 function convertToTensor(x, argName, functionName, parseAsDtype = 'numeric') {
-    if (x instanceof Tensor) {
+    if (x instanceof Tensor || x.constructor.name === 'Tensor') {
         assertDtype(parseAsDtype, x.dtype, argName, functionName);
         return x;
     }
npx patch-package @tensorflow/tfjs

I am using yarn v1 so I ran

yarn add patch-package postinstall-postinstall

The additional setup in package.json looks like this:

{
  "scripts": {
    "postinstall": "patch-package"
  },
  "dependencies": {
    "patch-package": "^6.4.7",
    "postinstall-postinstall": "^2.1.0"
  }
}

I did also spent a few hours digging into this issue but did not make much progress. Some findings:

  • @tensorflow/tfjs-react-native package does not matter. the issue happens with or without it
  • the issue gets trigger when a Tensor was returned by some operation and then the Tensor instance chains other operations such as argMax or mul, which leads to getGlobalTensorClass call:
getGlobalTensorClass().prototype.argMax = function (axis) {
    this.throwIfDisposed();
    return argMax(this, axis);
};


getGlobalTensorClass().prototype.mul = function (b) {
  this.throwIfDisposed();
  return mul(this, b);
};
  • Rewriting chained operation tensor.argMax(-1) into tf.argMax(tensor, -1) seems to solve the issue for that particular instance, as I was getting different errors after the rewrite
  • Tensor object from @tensorflow/tfjs, @tensorflow/tfjs/dist/tf.node and @tensorflow/tfjs-core/dist/tf-core.node appear to be identical on Hermes in my testing:
import * as tf from '@tensorflow/tfjs';
import * as tfnode from '@tensorflow/tfjs/dist/tf.node';
import * as tfcorenode from '@tensorflow/tfjs-core/dist/tf-core.node';
console.log('tf.Tensor === tfnode.Tensor', tf.Tensor === tfnode.Tensor);
console.log(
  'tfcorenode.Tensor === tfnode.Tensor',
  tfcorenode.Tensor === tfnode.Tensor
);
// true
// true
2reactions
mattsoulanillecommented, Sep 21, 2022

Sorry for the lack of updates. We would like to support Hermes, if possible, but it’s not at the top of our priority list right now.

Looking at the error message, this seems to be a case of having multiple versions of the Tensor class, possibly due to importing Tensor from @tensorflow/tfjs-core, which points to a rollup bundle, and from @tensorflow/tfjs-core/dist/tensor, which points to a file. If you . In the future, we may add an exports field to the package.json file, which should prevent these kinds of imports by only allowing a set of imports we specify. I expect this change will fix the issue here or at least reveal what’s causing it.

I took a quick look at the reproduction (thanks for posting one!), and it seems like it’s not using tfjs (It has its own tensor class). I don’t think Hermes supports exporting classes yet, but the example might work if it’s compiled down to use prototypes instead of classes (es5 I think).

I also tried getting hermes to import @tensorflow/tfjs. Here are a few fixes we need to make in tfjs to make this happen:

  1. Use globalThis as the global variable in getGlobalNamespace (For my test, I replaced global with globalThis in node_modules/@tensorflow/tfjs/dist/tf.js bundle)
  2. Use print instead of console.log - We should probably add a log function to the Platform interface (For my test, I just string-replaced console.log with print in node_modules/@tensorflow/tfjs/dist/tf.js).
  3. Make tfjs backends work.

After these changes, the following test code works (on my linux machine):

// index.js
import { Tensor } from './node_modules/@tensorflow/tfjs/dist/tf.js';

const tensor = new Tensor([1,2,3]);

print(tensor.size);
yarn add @tensorflow/tfjs
./hermes -commonjs index.js node_modules/@tensorflow/tfjs/dist/tf.js

However, I’m not able to load any tfjs backends, so all I can do is print the size.

Edit: Actually, I’m able to load the CPU backend, but it seems as though the weak map that holds tensor data is losing the data too early when I try to run readSync.

Please leave this issue open so I can take another look when I have some time.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using Hermes - React Native
Hermes is an open-source JavaScript engine optimized for React Native. For many apps, using Hermes will result in improved start-up time, ...
Read more >
Latest TF.js topics - TensorFlow Forum
Topic Replies Views Activity About the SIG TF.js category 0 1158 April 13, 2021 Dynamic optimizer · tfjs , models , help_request 0 361 September...
Read more >
TypeError: property is not configurable, js engine: hermes
spent ages on this error today and cannot figure it out at all. It was working fine and then I installed nativewind.
Read more >
Troubleshooting my builds - Help Center - Jscrambler Docs
Application breaks on Hermes Engine. Problem. Hermes is an open-source JavaScript engine optimized for React Native. Some of those optimizations cause a mal- ......
Read more >
disadvantages of robots in our daily life - Casa Hermes
Human beings are driven by emotions, whether we like it or not. Robots reduce check-in/check-out line waiting times while robots operate faster than...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found