Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to run NSFW.js on Cloudflare? #868

Open
ambrt opened this issue Jul 4, 2024 · 4 comments
Open

Is it possible to run NSFW.js on Cloudflare? #868

ambrt opened this issue Jul 4, 2024 · 4 comments

Comments

@ambrt
Copy link

ambrt commented Jul 4, 2024

I'm seeking a cloud host for NSFW.js and wonder if Cloudflare Workers can do it.

Can anyone share some experience?

@L4Ph
Copy link

L4Ph commented Jul 11, 2024

I'm not sure how long my motivation will last, but I'm creating something like this now.
https://github.com/L4Ph/nsfwts

Furthermore, in the project I'm contributing to, I've implemented it as follows and confirmed it's working on Remix (Cloudflare Pages).
https://github.com/aipictors/aipictors/blob/fd1adf889a8ea8ffa820f9e9bdde166f3ae43d60/app/routes/(%24lang).debug.nsfw/route.tsx
aipictors/aipictors#560

While the performance might depend on the CPU and memory available, I believe there's a high possibility that it can run on Cloudflare Workers since it's WASM (WebAssembly).

@ambrt
Copy link
Author

ambrt commented Aug 19, 2024

I might try and see.

I wonder if 128MB ram of worker would be enough.

@ambrt
Copy link
Author

ambrt commented Sep 23, 2024

There is a project using TensorFlow -UpscalerJS- that has CF worker example.
If that works then its possible that NSFW.js will too.

EDIT:
Tensor in UpscalerJS is made in browser and then sent to CF worker. So it seems that without node environment it won't work.

@ambrt
Copy link
Author

ambrt commented Dec 2, 2024

I managed to run it on Cloudflare with five caveats:

  • models except one that you use have to be removed manually from node modules
  • you have to have paid Cloudflare account for this version
  • you have to monkey patch 'dist/esm/index.js` to rename all models imports to one that you use only
  • it takes ~25 seconds on a live deploy to classify one image
  • image has to be smaller otherwise you'll end up with worker OOM error

Code for the app:

import { Hono } from 'hono';
import * as tf from '@tensorflow/tfjs';
import * as nsfwjs from "nsfwjs";
import * as jpeg from "jpeg-js";
const app = new Hono<{ Bindings: CloudflareBindings }>()

const convert = async (img) => {
  // Decoded image in UInt8 Byte array
console.log(jpeg)
  const image = await jpeg.decode(img, { useTArray: true });

  const numChannels = 3;
  const numPixels = image.width * image.height;
  const values = new Int32Array(numPixels * numChannels);

  for (let i = 0; i < numPixels; i++)
    for (let c = 0; c < numChannels; ++c)
      values[i * numChannels + c] = image.data[i * 4 + c];

  return tf.tensor3d(values, [image.height, image.width, numChannels], "int32");
};
await tf.setBackend("cpu");

app.get('/', async (c) => {
let img = await fetch("https://picsum.photos/id/237/200/300")
img =await  img.arrayBuffer();


let model=await nsfwjs.load("MobileNetV2Mid", {type:"graph"});
const image = await convert(img);
const predictions = await model.classify(image);
image.dispose();
return   c.json(predictions);

console.log("ok");
})

export default app

Renaming example is:

(...)
           case 2:
                weightBundles = void 0;
                if (!(modelName === "MobileNetV2")) return [3, 4];
                return [4, import("./model_imports/mobilenet_v2_mid.js")];
            case 3:
                (weightBundles = (_c.sent()).weightBundles);
                return [3, 8];
            case 4:
                if (!(modelName === "MobileNetV2Mid")) return [3, 6];
                return [4, import("./model_imports/mobilenet_v2_mid.js")];
            case 5:
                (weightBundles = (_c.sent()).weightBundles);
                return [3, 8];
            case 6:
                if (!(modelName === "InceptionV3")) return [3, 8];
                return [4, import("./model_imports/mobilenet_v2_mid.js")];

(...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants