Ultralytics YOLO27: Join the waitlist.

Export to TF.js Model Format From a YOLO26 Model Format (Deprecated)

Deprecated — replaced by LiteRT

As of Ultralytics 8.4.83, the tfjs (TensorFlow.js) export format has been deprecated and replaced by the unified Google LiteRT format. LiteRT runs in the browser via LiteRT.js (with WebGPU acceleration) — covering the in-browser and Node.js use cases TF.js handled, alongside mobile, embedded, and edge, from a single .tflite model.

format="tfjs" still works but emits a deprecation warning and exports a LiteRT model instead. Use format="litert" going forward; for current export instructions and the browser deployment path, see the LiteRT export guide.

Deploying machine learning models directly in the browser or on Node.js can be tricky. You'll need to make sure your model format is optimized for faster performance so that the model can be used to run interactive applications locally on the user's device. The TensorFlow.js, or TF.js, model format is designed to use minimal power while delivering fast performance.

Why Should You Export to TF.js?#

Exporting your machine learning models to TensorFlow.js, developed by the TensorFlow team as part of the broader TensorFlow ecosystem, offers numerous advantages for deploying machine learning applications. It helps enhance user privacy and security by keeping sensitive data on the device. The image below shows the TensorFlow.js architecture, and how machine learning models are converted and deployed on both web browsers and Node.js.

TensorFlow.js browser ML inference architecture

Running models locally also reduces latency and provides a more responsive user experience. TensorFlow.js also comes with offline capabilities, allowing users to use your application even without an internet connection. TF.js is designed for efficient execution of complex models on devices with limited resources as it is engineered for scalability, with GPU acceleration support.

Key Features of TF.js#

Here are the key features that make TF.js useful for developers:

  • Cross-Platform Support: TensorFlow.js can be used in both browser and Node.js environments, providing flexibility in deployment across different platforms. It lets developers build and deploy applications more easily.

  • Support for Multiple Backends: TensorFlow.js supports various backends for computation including CPU, WebGL for GPU acceleration, WebAssembly (WASM) for near-native execution speed, and WebGPU for advanced browser-based machine learning capabilities.

  • Offline Capabilities: With TensorFlow.js, models can run in the browser without the need for an internet connection, making it possible to develop applications that are functional offline.

Deployment Options with TensorFlow.js#

TF.js provides a range of options to deploy your machine learning models:

  • In-Browser ML Applications: You can build web applications that run machine learning models directly in the browser. The need for server-side computation is eliminated and the server load is reduced.

  • Node.js Applications: TensorFlow.js also supports deployment in Node.js environments, enabling the development of server-side machine learning applications. It is particularly useful for applications that require the processing power of a server or access to server-side data.

  • Chrome Extensions: An interesting deployment scenario is the creation of Chrome extensions with TensorFlow.js. For instance, you can develop an extension that allows users to right-click on an image within any webpage to classify it using a pretrained ML model. TensorFlow.js can be integrated into everyday web browsing experiences to provide immediate insights or augmentations based on machine learning.

Replace TF.js Export with LiteRT#

For new exports, convert your model to LiteRT.

Installation#

To install the required package, run:

Installation
# Install the required package for YOLO26
pip install ultralytics

For detailed instructions and best practices related to the installation process, check our Ultralytics Installation guide. While installing the required packages for YOLO26, if you encounter any difficulties, consult our Common Issues guide for solutions and tips.

Usage#

All Ultralytics YOLO26 models are designed to support export out of the box, making it easy to integrate them into your preferred deployment workflow. You can view the full list of supported export formats and configuration options to choose the best setup for your application.

The tfjs argument now exports a LiteRT .tflite model, which supports the Export, Predict, and Validate modes locally and runs in the browser via LiteRT.js.

Export
from ultralytics import YOLO

# Load a YOLO26 model
model = YOLO("yolo26n.pt")

# Export the model to LiteRT format (replaces TF.js)
model.export(format="litert", imgsz=640)  # use imgsz=224 for classification
Predict and Validate

The exported LiteRT .tflite model loads directly with yolo predict and yolo val, and runs in the browser via LiteRT.js.

Export Arguments#

See the LiteRT export arguments. For more details about the export process, visit the Ultralytics documentation page on exporting.

Deploying Exported YOLO26 TensorFlow.js Models#

Now that you have exported your YOLO26 model, the next step is to deploy it. The export produces a LiteRT .tflite model that runs on-device and in the browser via LiteRT.js.

For reference, the legacy TensorFlow.js runtime resources are below:

Summary#

This guide preserves the legacy TF.js deployment context. Use LiteRT for new exports.

For further details on usage, visit the TensorFlow.js official documentation.

FAQ#

  • Export to LiteRT instead. format="tfjs" still works but emits a deprecation warning and exports the same LiteRT model:

    Usage
    from ultralytics import YOLO
    
    # Load a YOLO26 model
    model = YOLO("yolo26n.pt")
    
    # Export the model to LiteRT format (replaces TF.js)
    model.export(format="litert", imgsz=640)  # use imgsz=224 for classification
    
    # The exported '.tflite' model runs in the browser via LiteRT.js or locally with yolo predict/val.

    For more details about supported export options, visit the Ultralytics documentation page on deployment options.

  • TensorFlow.js is specifically designed for efficient execution of ML models in browsers and Node.js environments. Here's how it benefits browser-based applications:

    • Reduces Latency: Runs machine learning models locally, providing immediate results without relying on server-side computations.
    • Improves Privacy: Keeps sensitive data on the user's device, minimizing security risks.
    • Enables Offline Use: Models can operate without an internet connection, ensuring consistent functionality.
    • Supports Multiple Backends: Offers flexibility with backends like CPU, WebGL, WebAssembly (WASM), and WebGPU for varying computational needs.

    Interested in learning more about TF.js? Check out the official TensorFlow.js guide.

Comments45

Ask a question, share your results, or help someone else.

  1. jupiter-mzajupiter-mzaGitHub

    Hi, iam trying use yolov8n_web_model in my REACT project, all works fine, the model was loaded, predictions works, but the result, even making conversions stay wrong, its returned from my predictions: { "kept": false, "isDisposedInternal": false, "shape": [ 1, 84, 8400 ], "dtype": "float32", "size": 705600, "strides": [ 705600, 8400 ], "dataId": { "id": 1030 }, "id": 719, "rankType": "3", "scopeId": 575 } when i try to catch the results using this: const handleIdentify = async () => { if (!model) { console.warn('Modelo não carregado.'); return; } const canvas = canvasRef.current; const imageElement = canvas; const tensor = tf.browser.fromPixels(imageElement).expandDims(0).toFloat().div(tf.scalar(255)); const predictions = await model.executeAsync(tensor); // console.log("Predictions:", predictions); const result = await predictions.array(); console.log("Result:", result); // // Parâmetros da sua imagem const imgWidth = 640;
    const imgHeight = 480;

    // Array para armazenar deteções filtradas
    const detections = [];
    
    for (let i = 0; i < result[0].length; i++) {
      const prediction = result[0][i]; // vetor de 84 elementos
    
      const x = prediction[0];
      const y = prediction[1];
      const w = prediction[2];
      const h = prediction[3];
      const objConfidence = prediction[4];
      const classProbs = prediction.slice(5); // de 5 a 83
    
      // Encontra a classe com maior probabilidade
      const maxClassProb = Math.max(...classProbs);
      const classIndex = classProbs.indexOf(maxClassProb);
    
      // Calcula a confiança do objeto
      const confidence = objConfidence * maxClassProb;
    
      // Define um limiar de confiança
      const confidenceThreshold = 0.25;
      if (confidence > confidenceThreshold) {
        // Escala as coordenadas para o tamanho da imagem
        const bx = x * imgWidth;
        const by = y * imgHeight;
        const bw = w * imgWidth;
        const bh = h * imgHeight;
    
        detections.push({
          bbox: [bx - bw / 2, by - bh / 2, bw, bh],
          confidence: confidence,
          class: classIndex,
        });
      }
      console.log("Detections:", detections)
    
    };

    } its return a resultset completely wrong like this: [ { "bbox": [ -2065.0027465820312, -2358.991241455078, 12443.428955078125, 14857.036743164062 ], "confidence": 23974.878087386023, "class": 2154 }, { "bbox": [ 2059.2428588867188, 1746.5789794921875, 2604.3841552734375, 2417.2320556640625 ], "confidence": 2756.7185883242637, "class": 6330 }, { "bbox": [ 3684.2034912109375, 1313.7918090820312, 8792.0166015625, 16787.200927734375 ], "confidence": 18003.25029833475, "class": 8224 }, { "bbox": [ 4112.9534912109375, 3463.8272094726562, 5174.500732421875, 4886.737060546875 ], "confidence": 5542.858029322, "class": 8182 } ] why ?

  2. SarvagyaVaishSarvagyaVaishGitHub

    What version of ultralytics was the tfjs export tested with?

    I am running this minimal example to convert a model to tfjs.

    from ultralytics import YOLO
    
    model = YOLO("yolo11l.pt")
    model.export(format='tfjs')

    Error i am seeing the following error:

    Ultralytics 8.3.133 🚀 Python-3.11.12 torch-2.6.0+cu124 CPU (Intel Xeon 2.20GHz)
    YOLO11l summary (fused): 190 layers, 25,340,992 parameters, 0 gradients, 86.9 GFLOPs
    
    PyTorch: starting from 'yolo11l.pt' with input shape (1, 3, 640, 640) BCHW and output shape(s) (1, 84, 8400) (49.0 MB)
    
    TensorFlow SavedModel: starting export with tensorflow 2.18.0...
    
    ONNX: starting export with onnx 1.18.0 opset 19...
    ONNX: slimming with onnxslim 0.1.52...
    ONNX: export success ✅ 4.4s, saved as 'yolo11l.onnx' (97.0 MB)
    TensorFlow SavedModel: starting TFLite export with onnx2tf 1.27.4...
    ERROR:root:Internal Python error in the inspect module.
    Below is the traceback from this internal error.
    
    ERROR: The trace log is below.
    Traceback (most recent call last):
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py", line 313, in print_wrapper_func
        result = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py", line 386, in inverted_operation_enable_disable_wrapper_func
        result = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py", line 56, in get_replacement_parameter_wrapper_func
        func(*args, **kwargs)
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/ops/Conv.py", line 459, in make_node
        conv_bias(
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/ops/Conv.py", line 308, in conv_bias
        tf.nn.convolution(
      File "/usr/local/lib/python3.11/dist-packages/tensorflow/python/util/traceback_utils.py", line 153, in error_handler
        raise e.with_traceback(filtered_tb) from None
      File "/usr/local/lib/python3.11/dist-packages/tf_keras/src/layers/core/tf_op_layer.py", line 119, in handle
        return TFOpLambda(op)(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/tf_keras/src/utils/traceback_utils.py", line 72, in error_handler
        del filtered_tb
    ValueError: Exception encountered when calling layer "tf.nn.convolution_35" (type TFOpLambda).
    
    Depth of input (384) is not a multiple of input depth of filter (256) for '{{node tf.nn.convolution_35/convolution}} = Conv2D[T=DT_FLOAT, data_format="NHWC", dilations=[1, 1, 1, 1], explicit_paddings=[], padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](Placeholder, tf.nn.convolution_35/convolution/filter)' with input shapes: [1,64,160,384], [1,1,256,256].
    
    Call arguments received by layer "tf.nn.convolution_35" (type TFOpLambda):
      • input=tf.Tensor(shape=(1, 64, 160, 384), dtype=float32)
      • filters=tf.Tensor(shape=(1, 1, 256, 256), dtype=float32)
      • strides=['1', '1']
      • padding='SAME'
      • data_format=None
      • dilations=['1', '1']
      • name=None
    
    ERROR: input_onnx_file_path: yolo11l.onnx
    ERROR: onnx_op_name: wa/model.2/cv2/conv/Conv
    ERROR: Read this and deal with it. https://github.com/PINTO0309/onnx2tf#parameter-replacement
    ERROR: Alternatively, if the input OP has a dynamic dimension, use the -b or -ois option to rewrite it to a static shape and try again.
    ERROR: If the input OP of ONNX before conversion is NHWC or an irregular channel arrangement other than NCHW, use the -kt or -kat option.
    ERROR: Also, for models that include NonMaxSuppression in the post-processing, try the -onwdt option.
    Traceback (most recent call last):
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py", line 313, in print_wrapper_func
        result = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py", line 386, in inverted_operation_enable_disable_wrapper_func
        result = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py", line 56, in get_replacement_parameter_wrapper_func
        func(*args, **kwargs)
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/ops/Conv.py", line 459, in make_node
        conv_bias(
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/ops/Conv.py", line 308, in conv_bias
        tf.nn.convolution(
      File "/usr/local/lib/python3.11/dist-packages/tensorflow/python/util/traceback_utils.py", line 153, in error_handler
        raise e.with_traceback(filtered_tb) from None
      File "/usr/local/lib/python3.11/dist-packages/tf_keras/src/layers/core/tf_op_layer.py", line 119, in handle
        return TFOpLambda(op)(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/tf_keras/src/utils/traceback_utils.py", line 72, in error_handler
        del filtered_tb
    ValueError: Exception encountered when calling layer "tf.nn.convolution_35" (type TFOpLambda).
    
    Depth of input (384) is not a multiple of input depth of filter (256) for '{{node tf.nn.convolution_35/convolution}} = Conv2D[T=DT_FLOAT, data_format="NHWC", dilations=[1, 1, 1, 1], explicit_paddings=[], padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](Placeholder, tf.nn.convolution_35/convolution/filter)' with input shapes: [1,64,160,384], [1,1,256,256].
    
    Call arguments received by layer "tf.nn.convolution_35" (type TFOpLambda):
      • input=tf.Tensor(shape=(1, 64, 160, 384), dtype=float32)
      • filters=tf.Tensor(shape=(1, 1, 256, 256), dtype=float32)
      • strides=['1', '1']
      • padding='SAME'
      • data_format=None
      • dilations=['1', '1']
      • name=None
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/usr/local/lib/python3.11/dist-packages/IPython/core/interactiveshell.py", line 3553, in run_code
        exec(code_obj, self.user_global_ns, self.user_ns)
      File "<ipython-input-2-960d66694119>", line 5, in <cell line: 0>
        model.export(format="tfjs")
      File "/usr/local/lib/python3.11/dist-packages/ultralytics/engine/model.py", line 730, in export
        return Exporter(overrides=args, _callbacks=self.callbacks)(model=self.model)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/ultralytics/engine/exporter.py", line 468, in __call__
        f[5], keras_model = self.export_saved_model()
                            ^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/ultralytics/engine/exporter.py", line 192, in outer_func
        f, model = inner_func(*args, **kwargs)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/ultralytics/engine/exporter.py", line 975, in export_saved_model
        keras_model = onnx2tf.convert(
                      ^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/onnx2tf.py", line 1149, in convert
        op.make_node(
      File "/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py", line 379, in print_wrapper_func
        sys.exit(1)
    SystemExit: 1
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/usr/local/lib/python3.11/dist-packages/IPython/core/ultratb.py", line 1101, in get_records
        return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/IPython/core/ultratb.py", line 248, in wrapped
        return f(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/dist-packages/IPython/core/ultratb.py", line 281, in _fixed_getinnerframes
        records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/lib/python3.11/inspect.py", line 1739, in getinnerframes
        traceback_info = getframeinfo(tb, context)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/lib/python3.11/inspect.py", line 1671, in getframeinfo
        lineno = frame.f_lineno
                 ^^^^^^^^^^^^^^
    AttributeError: 'tuple' object has no attribute 'f_lineno'
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    [/usr/local/lib/python3.11/dist-packages/onnx2tf/utils/common_functions.py](https://localhost:8080/#) in print_wrapper_func(*args, **kwargs)
        312         try:
    --> 313             result = func(*args, **kwargs)
        314 
    
    21 frames
    ValueError: Exception encountered when calling layer "tf.nn.convolution_35" (type TFOpLambda).
    
    Depth of input (384) is not a multiple of input depth of filter (256) for '{{node tf.nn.convolution_35/convolution}} = Conv2D[T=DT_FLOAT, data_format="NHWC", dilations=[1, 1, 1, 1], explicit_paddings=[], padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](Placeholder, tf.nn.convolution_35/convolution/filter)' with input shapes: [1,64,160,384], [1,1,256,256].
    
    Call arguments received by layer "tf.nn.convolution_35" (type TFOpLambda):
      • input=tf.Tensor(shape=(1, 64, 160, 384), dtype=float32)
      • filters=tf.Tensor(shape=(1, 1, 256, 256), dtype=float32)
      • strides=['1', '1']
      • padding='SAME'
      • data_format=None
      • dilations=['1', '1']
      • name=None
    
    During handling of the above exception, another exception occurred:
    
    SystemExit                                Traceback (most recent call last)
        [... skipping hidden 1 frame]
    
    SystemExit: 1
    
    During handling of the above exception, another exception occurred:
    
    TypeError                                 Traceback (most recent call last)
        [... skipping hidden 1 frame]
    
    [/usr/local/lib/python3.11/dist-packages/IPython/core/ultratb.py](https://localhost:8080/#) in find_recursion(etype, value, records)
        380     # first frame (from in to out) that looks different.
        381     if not is_recursion_error(etype, value, records):
    --> 382         return len(records), 0
        383 
        384     # Select filename, lineno, func_name to track frames with
    
    TypeError: object of type 'NoneType' has no len()
  3. WereUs666WereUs666GitHub

    Hello, I tried to convert the yolo pose model into tfjs format. Then I encountered an issue. I am using AWS EC2 Linux server to run the code.

    python version: 3.12.0 Pytorch version: 2.6.0+cu124 tensorflow version: 2.18.0

    This is the code:

    from ultralytics import YOLO
    model = YOLO("yolo11n-pose")
    model.export(format="tfjs")

    This is the error:

    Traceback (most recent call last):
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/onnx2tf/utils/common_functions.py", line 312, in print_wrapper_func
        result = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/onnx2tf/utils/common_functions.py", line 385, in inverted_operation_enable_disable_wrapper_func
        result = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/onnx2tf/utils/common_functions.py", line 55, in get_replacement_parameter_wrapper_func
        func(*args, **kwargs)
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/onnx2tf/ops/Add.py", line 281, in make_node
        merge_two_consecutive_identical_ops_into_one(
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/onnx2tf/utils/common_functions.py", line 5466, in merge_two_consecutive_identical_ops_into_one
        tf.math.add(
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/tensorflow/python/ops/weak_tensor_ops.py", line 142, in wrapper
        return op(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/tensorflow/python/util/traceback_utils.py", line 153, in error_handler
        raise e.with_traceback(filtered_tb) from None
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/tf_keras/src/layers/core/tf_op_layer.py", line 119, in handle
        return TFOpLambda(op)(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/opt/conda/envs/py312/lib/python3.12/site-packages/tf_keras/src/utils/traceback_utils.py", line 72, in error_handler
        del filtered_tb
            ^^^^^^^^^^^
    ValueError: Exception encountered when calling layer "tf.math.add_5" (type TFOpLambda).
    
    Dimensions must be equal, but are 32 and 16 for '{{node tf.math.add_5/Add}} = AddV2[T=DT_FLOAT](Placeholder, Placeholder_1)' with input shapes: [1,16,160,32], [1,16,160,16].
    
    Call arguments received by layer "tf.math.add_5" (type TFOpLambda):
      • x=tf.Tensor(shape=(1, 16, 160, 32), dtype=float32)
      • y=tf.Tensor(shape=(1, 16, 160, 16), dtype=float32)
      • name='/model.2/m.0/Add'
    
    ERROR: input_onnx_file_path: yolo11n-pose.onnx
    ERROR: onnx_op_name: /model.2/m.0/Add
    ERROR: Read this and deal with it. https://github.com/PINTO0309/onnx2tf#parameter-replacement
    ERROR: Alternatively, if the input OP has a dynamic dimension, use the -b or -ois option to rewrite it to a static shape and try again.
    ERROR: If the input OP of ONNX before conversion is NHWC or an irregular channel arrangement other than NCHW, use the -kt or -kat option.
    ERROR: Also, for models that include NonMaxSuppression in the post-processing, try the -onwdt option.
    1. Glenn JocherGlenn JocherUltralytics(edited)

      @WereUs666 thanks for sharing the details. For pose models in TF.js format, we recommend trying model.export(format='tfjs', imgsz=(640, 640)) with a fixed input size. Note that tfjs is deprecated since Ultralytics 8.4.83 and now exports a LiteRT model, so for new work use format='litert' (see the LiteRT guide). If issues persist, please ensure you're using the latest ultralytics and onnx2tf packages. For commercial deployment needs, visit https://ultralytics.com/license.

  4. priyalpatel1503priyalpatel1503GitHub

    I am working on an Angular project, and I have integrated the YOLOv8 model using TensorFlow.js. However, I am facing an issue where the model does not provide the predicted bounding box coordinates, but instead, I receive the following tensor output: { "kept": false, "isDisposedInternal": false, "shape": [1, 84, 8400], "dtype": "float32", "size": 705600, "strides": [705600, 8400], "dataId": {"id": 801}, "id": 492, "rankType": "3", "scopeId": 7 } This output is not giving me the expected bounding box coordinates. I am unsure how to extract the bounding boxes from this tensor output and interpret the predictions. Could you please guide me on how to retrieve the bounding box coordinates, class labels, and confidence scores from this tensor?

    Here is the code I am using to load and run the model:

    // Loading YOLOv8 model this.model = await tf.loadGraphModel('../../assets/yolov8n_web_model/model.json'); alert('YOLOv8 model loaded successfully');

    // Preparing the image for model input const image = document.getElementById('input-image') as HTMLImageElement; const tensor = tf.browser .fromPixels(image) .resizeBilinear([640, 640]) // Resize to model input size .toFloat() .expandDims(0) .div(tf.scalar(255.0)); // Normalize

    // Running the model and obtaining predictions const predictions = await this.model.execute(tensor); console.log('Predictions:', predictions); To clarify, I am working with the model directly in Angular using TensorFlow.js and do not have a Python backend. Any advice on how to proceed in this setup would be greatly appreciated.

    Thank you!

    1. Glenn JocherGlenn JocherUltralytics

      @priyalpatel1503 the tensor output you are encountering contains raw predictions, which need decoding to extract bounding box coordinates, class labels, and confidence scores. YOLO models typically output a tensor where each grid cell holds predictions including bounding boxes, objectness scores, and class probabilities. You can apply non-maximum suppression (NMS) and appropriate post-processing on this tensor to interpret the results. Refer to the TensorFlow.js YOLO post-processing example for guidance, as it follows a similar concept.

    2. priyalpatel1503priyalpatel1503GitHub

      I have tried implementing your above solution to run inference on an image, but I am encountering an issue where the predictions object is not iterable. Despite following the suggested solutions, it still doesn't work.

      Here's the solution I tried: async function runInference() { // Load the model const model = await tf.loadGraphModel('/path/to/yolov8n_web_model/model.json');

      // Load and preprocess the image
      const img = document.getElementById('input-image');
      const tensor = tf.browser.fromPixels(img).expandDims(0).toFloat().div(tf.scalar(255));
      
      // Run inference
      const predictions = await model.executeAsync(tensor);
      
      // Process the output tensors
      const [boxes, scores, classes] = predictions;
      const boxesData = boxes.dataSync();
      const scoresData = scores.dataSync();
      const classesData = classes.dataSync();
      
      // Filter predictions by confidence threshold
      const confidenceThreshold = 0.5;
      const validDetections = [];
      for (let i = 0; i < scoresData.length; i++) {
          if (scoresData[i] > confidenceThreshold) {
              validDetections.push({
                  box: boxesData.slice(i * 4, (i + 1) * 4),
                  score: scoresData[i],
                  class: classesData[i]
              });
          }
      }
      
      // Display results
      validDetections.forEach(detection => {
          const [x, y, width, height] = detection.box;
          const score = detection.score;
          const className = detection.class;
      
          // Draw bounding box and label on the image
          // (Implement your drawing logic here)
      });

      }

      window.onload = runInference; However, when running this code, I am getting the following error:

      Error: predictions is not iterable

      I have tried several approaches based on your earlier suggestions, but none of them resolved the issue. I am unsure how to correctly extract the bounding boxes, class labels, and confidence scores from the output.

      Could you please provide guidance on how to properly handle the output of model.executeAsync(tensor) and how to extract the predictions (bounding boxes, class labels, and scores)?

    3. Glenn JocherGlenn JocherUltralytics

      The error occurs because model.executeAsync(tensor) returns a single tensor or an array of tensors, depending on the model's output structure. In your case, ensure the model's output aligns with your extraction logic. Use predictions.array() or predictions.dataSync() to inspect the raw output structure and adjust your code to handle it correctly. For YOLO models, you may need to decode the tensor output into bounding boxes, classes, and scores using custom logic or post-processing functions.

    4. priyalpatel1503priyalpatel1503GitHub

      @glenn-jocher After calling model.executeAsync(tensor), the output I receive is a tensor object with the following shape and details: { "kept": false, "isDisposedInternal": false, "shape": [ 1, 84, 8400 ], "dtype": "float32", "size": 705600, "strides": [ 705600, 8400 ], "dataId": { "id": 864 }, "id": 555, "rankType": "3", "scopeId": 641 }

      1. When using predictions.array(), it returns a Promise in TensorFlow.js .The Promise resolves to a nested array structure: [ [Array(8400), Array(8400), ..., Array(8400)] ] (84 arrays, each containing 8400 values).
      2. When using predictions.dataSync(), I receive a Float32Array with 705600 values.

      I need guidance on how to properly decode and interpret this output, especially in terms of extracting bounding box coordinates, class IDs, and class probabilities. Could you provide advice or code examples for decoding these predictions, particularly for the YOLOv8 model in TensorFlow.js? Any references, examples, or explanations will be helpful.

    5. Glenn JocherGlenn JocherUltralytics(edited)

      To decode the YOLOv8 TensorFlow.js output, you need to understand that the tensor contains raw predictions. The shape [1, 84, 8400] represents [batch_size, num_features, num_predictions_per_feature]. Here's a breakdown of processing it:

      1. Use predictions.array() to resolve the tensor into a nested array structure.
      2. The 84 features are the bounding box (x, y, w, h) followed by 80 class scores. YOLOv8 has no separate objectness score:
        • The first 4 values are the bounding box coordinates.
        • The remaining 80 values (indices 4–83) are the per-class scores.
      3. For each prediction:
        • Scale the bounding box coordinates to your image size if they are normalized.
        • Take the highest class score as the confidence, filter by a confidence threshold, and apply Non-Maximum Suppression (NMS) to remove duplicates.

      For detailed implementation, you can refer to TensorFlow.js's post-processing examples or adapt the logic to YOLOv8's output format. Let us know if you need further clarification!

  5. lilinebolilineboGitHub

    I'm having performance issues when dealing with tensors. After the inference is completed, nms needs to be performed, and then I perform the following operation const indicesTensor = await tf.whereAsync(xcSlice); which takes about 2s, which is too long.xcSlice is [21504].In my expectation, this will only take up to 400 milliseconds

    1. Glenn JocherGlenn JocherUltralytics

      @mozeqiu123 the delay you're encountering with tf.whereAsync may be due to the large size of your tensor. To improve performance, consider optimizing the data preparation and operations preceding this step. Also, ensure you're leveraging appropriate TensorFlow.js backends like WebGL or WASM for better execution speed.

    2. lilinebolilineboGitHub

      Yes, my tensor is very large. What exactly do you mean by optimizing data preparation and operations?

    3. Glenn JocherGlenn JocherUltralytics

      Optimizing data preparation and operations can involve ensuring the tensor is only as large as necessary by filtering or reducing dimensions early, leveraging TensorFlow.js efficient backends (e.g., WebGL for GPU acceleration), and minimizing unnecessary tensor transformations before calling costly operations. You can also experiment with batching or slicing your data into smaller chunks before processing.

    4. lilinebolilineboGitHub

      Thanks for the reply. I turned on webgl at the beginning, but it was still very slow. Then I solved the problem by changing to a smaller model.

    5. Glenn JocherGlenn JocherUltralytics

      Thank you for sharing your update! Switching to a smaller model is a great solution for handling performance constraints. If further optimizations are needed, consider exporting your YOLO11 to TensorFlow.js or experimenting with different backends like WebGL or WASM. For more context, you can refer to the TF.js documentation.

  6. viniciusmraviniciusmraGitHub

    I've been trying to export some models that I trained, but I keep getting several errors when trying to run the command. Erros:

    requirements: Ultralytics requirements ['sng4onnx>=1.0.1', 'onnx_graphsurgeon>=0.3.26', 'onnxslim>=0.1.31', 'tflite_support', 'onnxruntime'] not found, attempting AutoUpdate...

    The message says that the Ultralytics library is missing these dependencies (which is strange because I just installed Ultralytics, so it should be complete). The 'autoupdate' fails, and installing them manually also fails..

    1. Glenn JocherGlenn JocherUltralytics

      @viniciusmra the error indicates that some dependencies required for exporting are missing. First, try updating all packages by running pip install ultralytics --upgrade to ensure you have the latest version. If manual dependency installation issues persist, verify your Python environment and ensure compatibility with the supported Ultralytics and dependency versions. For further guidance, refer to our Common Issues guide. Let me know if you encounter further issues.

      1
  7. lilinebolilineboGitHub

    Hello author, I am a newbie. I trained a yolov11n OBB detection model and then converted it to tfjs format. I found that the pt model inference result is an object, so how to parse the result in tfjs?

    1. Glenn JocherGlenn JocherUltralytics

      @mozeqiu123 to parse the inference results in TensorFlow.js, check the format of the output from the exported YOLO model. Typically, it should provide arrays of tensor data. Map the output tensors to expected object properties like bounding box coordinates, class IDs, and confidence scores in your application logic to process and display the results. Let me know if you need more details!

      1
    2. Glenn JocherGlenn JocherUltralytics

      Thank you for sharing the reference issue. To parse YOLO11 OBB detection results in TensorFlow.js, you will need to interpret the model's output tensors correctly based on your trained model's format. Typically, the outputs include bounding box coordinates, class predictions, confidence scores, and oriented box angles. You can check the model's documentation or inspect the export code to map these outputs properly. Let us know if further clarification is needed!

  8. venkatshan707venkatshan707GitHub(edited)

    @glenn-jocher sorry for correcting. When I convert yolov8n.pt I am getting 4 bin files. when I convert yolov8m.pt and yolov8m-obb.pt I am getting 26 bin files. I could understand your point explains model complexity of yolov8m.pt and yolov8m-obb.pt are higher than yolov8n.pt. I have tried finding code snippet which can help us pruning the model and gives us small number bin files. But I have failed in that.

    Would you kindly help me with code example which can fix this issue ?

    #This is the code I have used to get web model from official yolov8m-obb.pt

    from ultralytics import YOLO

    Load the YOLO11 model

    model = YOLO("yolov8m-obb.pt")

    Export the model to TF.js format

    model.export(format="tfjs") # creates '/yolov8m-obb.pt_web_model'

    more_bins

    1. Glenn JocherGlenn JocherUltralytics

      @venkatshan707 to reduce the number of bin files when exporting to TF.js, consider model pruning or quantization techniques. Unfortunately, we don't provide specific code examples for this, but you can explore TensorFlow.js documentation for optimization strategies. For more guidance, visit Ultralytics TF.js integration.

  9. Fernand0GCFernand0GCGitHub

    buenas, alguien podria ayudarme a interpretar mi output? el modelo es de deteccion de objetos y esta entrenado para reconocer 5 clases names: 0: black-shape 1: diana 2: targets-holes 3: targets-holes-2 4: targets-holes-black en la consola recibo el siguiente objeto: { "kept": false, "isDisposedInternal": false, "shape": [ 1, 9, 8400 ], "dtype": "float32", "size": 75600, "strides": [ 75600, 8400 ], "dataId": { "id": 801 }, "id": 492, "rankType": "3", "scopeId": 578 }

    pude acceder al tensor mediante predictions.array() lo cual me da un output de un arreglo de 9 arreglos. este arreglo contiene valores numericos que aun no logro decifrar. 0 : (8400) [2.8815157413482666, 16.799739837646484, 35.85880661010742 ...] 1 : (8400) [4.487062931060791, 6.242208003997803, 7.13232421875 ...] 2 : (8400) [6.577016353607178, 32.058311462402344, 74.6260757446289 ...] 3 : (8400) [8.778525352478027, 12.535199165344238, 13.99738883972168 ...] 4 : (8400) [0.000003607327244026237, 0.000010992955139954574, 0.000006420665613404708 ...] 5 : (8400) [0.0000034999770832655486, 0.000010910729542956688, 0.000004991020887246123 ...] 6 : (8400) [0.000057105469750240445, 0.000025020823159138672, 0.000024430628400295973 ...] 7 : (8400) [0.000027735275580198504, 0.000019603612599894404, 0.000015360352335846983 ...] 8 : (8400) [0.00006247103010537103, 0.000020798512196051888, 0.000007502545486204326 ...]

    me podrian ayudar a interpretar este output porfabor

    1. Glenn JocherGlenn JocherUltralytics

      @Fernand0GC hola, para interpretar tu output, los valores numéricos en los arreglos representan las predicciones del modelo. Cada arreglo de 8400 valores corresponde a diferentes aspectos de la detección, como coordenadas de cajas delimitadoras y puntuaciones de confianza para cada clase. Te recomiendo revisar cómo se estructuran las salidas de tu modelo en la documentación de TensorFlow.js para entender mejor cada componente. Si necesitas más detalles sobre el formato TF.js, puedes visitar aquí.

    1. Glenn JocherGlenn JocherUltralytics(edited)

      Update: the TF.js export is deprecated. As of Ultralytics 8.4.83, format="tfjs" exports a LiteRT .tflite model instead of a *_web_model/model.json; use format="litert" and see the LiteRT guide. The TF.js snippets below are legacy.

      Hello @teengineer,

      Thank you for reaching out and for your interest in exporting YOLOv8 models to TensorFlow.js! The process indeed allows for efficient, high-speed, and locally-run object detection inference on various platforms, including web browsers and Node.js environments.

      To get started, you can follow the example provided in our documentation to export your YOLOv8 model to the TF.js format. Here’s a concise example to guide you through the process:

      Python Example
      from ultralytics import YOLO
      
      # Load the YOLOv8 model
      model = YOLO("yolov8n.pt")
      
      # Export the model to TF.js format
      model.export(format="tfjs")  # creates '/yolov8n_web_model'
      
      # Load the exported TF.js model
      tfjs_model = YOLO("./yolov8n_web_model")
      
      # Run inference
      results = tfjs_model("https://ultralytics.com/images/bus.jpg")
      CLI Example
      # Export a YOLOv8n PyTorch model to TF.js format
      yolo export model=yolov8n.pt format=tfjs  # creates '/yolov8n_web_model'
      
      # Run inference with the exported model
      yolo predict model='./yolov8n_web_model' source='https://ultralytics.com/images/bus.jpg'

      For more detailed instructions, you can visit our TF.js integration guide.

      If you encounter any issues, please ensure you are using the latest version of the Ultralytics package. Additionally, providing a minimum reproducible example of your issue can greatly help in diagnosing and resolving any problems. You can find more information on creating a reproducible example here.

      Feel free to reach out if you have any further questions or need additional assistance. Happy coding! 😊

    2. Glenn JocherGlenn JocherUltralytics(edited)

      Update: the TF.js export is deprecated. As of Ultralytics 8.4.83, format="tfjs" exports a LiteRT .tflite model instead of a *_web_model/model.json; use format="litert" and see the LiteRT guide. The TF.js snippets below are legacy.

      Hi @salim4n,

      Thank you for your message! I'm glad to hear you're working on integrating YOLOv8 with a React Chrome extension. To help you better understand the predictions and bounding boxes, you might want to inspect the structure of the results returned by the model.

      Here’s a quick example to guide you on how to handle the predictions in your React app:

      Example Code Snippet
      import React, { useEffect, useState } from 'react';
      import { YOLO } from 'ultralytics';
      
      const App = () => {
        const [results, setResults] = useState(null);
      
        useEffect(() => {
          const runInference = async () => {
            const model = await YOLO.load('./yolov8n_web_model');
            const results = await model.predict('https://ultralytics.com/images/bus.jpg');
            setResults(results);
          };
      
          runInference();
        }, []);
      
        return (
          <div>
            {results && results.map((result, index) => (
              <div key={index}>
                <h3>Prediction {index + 1}</h3>
                <p>Class: {result.class}</p>
                <p>Confidence: {result.confidence}</p>
                <p>Bounding Box: {result.bbox.join(', ')}</p>
              </div>
            ))}
          </div>
        );
      };
      
      export default App;
      Explanation
      1. Loading the Model: The YOLO.load function loads the exported TF.js model.
      2. Running Inference: The model.predict function runs inference on the provided image URL.
      3. Displaying Results: The results are stored in the state and displayed in the component.

      This should help you visualize the predictions and bounding boxes in your React app. For more detailed information, you can refer to our TF.js integration guide.

      If you encounter any issues, please ensure you are using the latest version of the Ultralytics package. Additionally, providing a minimum reproducible example can greatly help in diagnosing and resolving any problems. You can find more information on creating a reproducible example here.

      Feel free to reach out if you have any further questions or need additional assistance. Happy coding! 😊

    3. salim4nsalim4nGitHub

      Hi @glenn-jocher , thank's for your response, but I don't find any package ultralytics on NPM, with tfjs the load-graph on custom model is very hard to use. I need to try more on a server side version, trying implementation directly on a chrome extension is not the easy way.

    4. Glenn JocherGlenn JocherUltralytics(edited)

      Update: the TF.js export is deprecated. As of Ultralytics 8.4.83, format="tfjs" exports a LiteRT .tflite model instead of a *_web_model/model.json; use format="litert" and see the LiteRT guide. The TF.js snippets below are legacy.

      Hi @salim4n,

      Thank you for your feedback and for sharing your experience. I understand that integrating TensorFlow.js (TF.js) models directly into a Chrome extension can be challenging, especially when dealing with custom models.

      To address your concerns:

      1. NPM Package: Currently, there is no ultralytics package available on NPM. The recommended approach is to use the Python package to export your model to the TF.js format and then integrate the exported model into your JavaScript project.

      2. Loading Custom Models in TF.js: Loading custom models in TF.js can indeed be complex. Here’s a simplified approach to help you get started:

        • Export the Model: Use the Ultralytics Python package to export your YOLOv8 model to the TF.js format.
        • Integrate with TF.js: Use the exported model in your JavaScript code.
      Example Code for Integration

      Here’s a basic example to load and use the exported TF.js model in a Chrome extension:

      Export the Model (Python)
      from ultralytics import YOLO
      
      # Load the YOLOv8 model
      model = YOLO("yolov8n.pt")
      
      # Export the model to TF.js format
      model.export(format="tfjs")  # creates '/yolov8n_web_model'
      Load and Use the Model (JavaScript)
      import * as tf from '@tensorflow/tfjs';
      
      async function loadModel() {
        const model = await tf.loadGraphModel('/path/to/yolov8n_web_model/model.json');
        return model;
      }
      
      async function runInference(imageElement) {
        const model = await loadModel();
        const tensor = tf.browser.fromPixels(imageElement).expandDims(0);
        const predictions = await model.executeAsync(tensor);
        console.log(predictions);
      }
      
      // Example usage
      const imageElement = document.getElementById('input-image');
      runInference(imageElement);
      Additional Resources

      For more detailed instructions on deploying TF.js models, you can refer to:

      If you encounter any issues, please ensure you are using the latest version of the Ultralytics package and provide a minimum reproducible example if possible. This helps us diagnose and resolve any problems more effectively. You can find more information on creating a reproducible example here.

      Feel free to reach out if you have any further questions or need additional assistance. Happy coding! 😊

    5. wuhongleiwuhongleiGitHub

      i have the same problem about how to get the boxes, scores and classes from the predictions variable, predictions is an object ,not an array, there is no property named boxes, scores and classes, does anyone know how to solve this, very appreciate 😄

      my html code is below:

      <!DOCTYPE html>
      <html>
        <head>
          <title>YOLOv8 Model Inference</title>
        </head>
        <body>
          <!-- 用于显示输入图片和绘制推理结果 -->
          <canvas id="input-image" width="640" height="640"></canvas>
          <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
          <script>
            async function runModel() {
              const model = await tf.loadGraphModel("./best_web_model/model.json");
      
              // 1. 准备图片数据(这里使用示例图片)
              const imgElement = document.getElementById("input-image");
              const tensor = tf.browser
                .fromPixels(imgElement)
                .expandDims(0)
                .toFloat()
                .div(tf.scalar(255));
      
              // 2. 进行推理
              const predictions = await model.executeAsync([tensor]);
            }
          </script>
          <script>
            // 获取 canvas 元素
            const canvas = document.getElementById("input-image");
            const ctx = canvas.getContext("2d");
      
            // 创建新的图片对象
            const img = new Image();
      
            // 图片加载完成后绘制到 canvas 上
            img.onload = function () {
              ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
              runModel();
            };
      
            // 设置图片的来源
            img.src = "./imgs/20217191442296037.jpg"; // 替换为您的图片路径
          </script>
        </body>
      </html>

      the output of predictions is below:

      {
          "kept": false,
          "isDisposedInternal": false,
          "shape": [
              1,
              5,
              8400
          ],
          "dtype": "float32",
          "size": 42000,
          "strides": [
              42000,
              8400
          ],
          "dataId": {
              "id": 1212
          },
          "id": 701,
          "rankType": "3",
          "scopeId": 879
      }

      predictions

    6. Glenn JocherGlenn JocherUltralytics(edited)

      Update: the TF.js export is deprecated. As of Ultralytics 8.4.83, format="tfjs" exports a LiteRT .tflite model instead of a *_web_model/model.json; use format="litert" and see the LiteRT guide. The TF.js snippets below are legacy.

      Hi @wuhonglei,

      Thank you for your detailed question and for sharing your code! 😊

      To extract the boxes, scores, and classes from the predictions object in TensorFlow.js, you need to process the tensor outputs correctly. The predictions object you have is a tensor, and you can use TensorFlow.js methods to extract the necessary information.

      Here’s how you can modify your code to get the boxes, scores, and classes:

      Updated JavaScript Code
      import * as tf from '@tensorflow/tfjs';
      
      async function runModel() {
        const model = await tf.loadGraphModel('./best_web_model/model.json');
      
        // Prepare image data
        const imgElement = document.getElementById('input-image');
        const tensor = tf.browser.fromPixels(imgElement).expandDims(0).toFloat().div(tf.scalar(255));
      
        // Run inference
        const predictions = await model.executeAsync(tensor);
      
        // Extract boxes, scores, and classes
        const [boxes, scores, classes] = await Promise.all([
          predictions[0].array(),
          predictions[1].array(),
          predictions[2].array()
        ]);
      
        console.log('Boxes:', boxes);
        console.log('Scores:', scores);
        console.log('Classes:', classes);
      
        // Optionally, draw boxes on the canvas
        drawBoxes(imgElement, boxes, scores, classes);
      }
      
      function drawBoxes(imgElement, boxes, scores, classes) {
        const canvas = document.getElementById('input-image');
        const ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(imgElement, 0, 0, canvas.width, canvas.height);
      
        boxes.forEach((box, i) => {
          const [y, x, height, width] = box;
          ctx.strokeStyle = 'red';
          ctx.lineWidth = 2;
          ctx.strokeRect(x, y, width, height);
          ctx.fillStyle = 'red';
          ctx.fillText(`Class: ${classes[i]}, Score: ${scores[i].toFixed(2)}`, x, y > 10 ? y - 5 : 10);
        });
      }
      
      // Load image and run model
      const img = new Image();
      img.onload = function () {
        const canvas = document.getElementById('input-image');
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        runModel();
      };
      img.src = './imgs/20217191442296037.jpg'; // Replace with your image path
      Explanation
      1. Model Loading: Load the model using tf.loadGraphModel.
      2. Image Preparation: Convert the image to a tensor and normalize it.
      3. Run Inference: Execute the model and get the predictions.
      4. Extract Data: Use array() to convert tensors to JavaScript arrays.
      5. Draw Boxes: Optionally, draw the bounding boxes on the canvas.

      This should help you extract and visualize the boxes, scores, and classes from your predictions. If you encounter any issues, please ensure you are using the latest version of TensorFlow.js and the Ultralytics package.

      For more detailed information, you can refer to our TF.js integration guide.

      Feel free to reach out if you have any further questions or need additional assistance. Happy coding! 😊

    7. wuhongleiwuhongleiGitHub

      thanks very much for your detailed response, In order to better assist future developers, I will paste the code that I have successfully run in the end。 My business background: i use the yolov8 to detect the penguin in the image(object detection ). my final html code:

      <!DOCTYPE html>
      <html>
        <head>
          <title>YOLOv8 Object Detection with TensorFlow.js</title>
          <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
        </head>
        <body>
          <input type="file" id="upload" accept="image/*" />
          <canvas id="canvas"></canvas>
          <script>
            async function loadModel() {
              // 加载模型
              const model = await tf.loadGraphModel("./best_web_model/model.json");
              return model;
            }
      
            async function predict(model, imageElement) {
              // 将图像转换为张量
              const tensor = tf.browser
                .fromPixels(imageElement)
                .resizeNearestNeighbor([640, 640]) // 调整大小到模型输入大小
                .toFloat()
                .expandDims(0)
                .div(tf.scalar(255.0));
      
              // inference
              const predictions = await model.executeAsync(tensor);
      
              //  predictions shape is [1, 5, 8400]
              const reshapedPredictions = predictions.reshape([5, 8400]);
              const boxesTensor = reshapedPredictions.slice([0, 0], [4, 8400]);
              const scoresTensor = reshapedPredictions
                .slice([4, 0], [1, 8400])
                .squeeze();
      
              // Assuming that the category label of each box is fixed (you can adjust it as needed)
              const classesTensor = tf.fill([8400], 0);
      
              return {
                boxes: boxesTensor,
                scores: scoresTensor,
                classes: classesTensor,
              };
            }
      
            function drawBoxes(imageElement, canvas, boxes, scores, classes) {
              const ctx = canvas.getContext("2d");
              canvas.width = imageElement.width;
              canvas.height = imageElement.height;
              ctx.drawImage(imageElement, 0, 0, canvas.width, canvas.height);
      
              const labels = ["企鹅"]; // Replace with actual label
              const validBoxes = [];
      
              for (let i = 0; i < scores.length; i++) {
                if (scores[i] > 0.5) {
                  const x_c = boxes[0][i] / 640;
                  const y_c = boxes[1][i] / 640;
                  const w = boxes[2][i] / 640;
                  const h = boxes[3][i] / 640;
      
                  const x = x_c - w / 2;
                  const y = y_c - h / 2;
      
                  validBoxes.push([x, y, w, h, scores[i], classes[i]]);
                }
              }
      
              validBoxes.forEach((box) => {
                const [x, y, w, h, score, className] = box;
                ctx.strokeStyle = "red";
                ctx.lineWidth = 2;
                ctx.strokeRect(
                  x * canvas.width,
                  y * canvas.height,
                  w * canvas.width,
                  h * canvas.height
                );
                const text = `${className}: ${(score * 100).toFixed(2)}%`;
                ctx.fillText(text, x * canvas.width, y * canvas.height - 10);
              });
            }
      
            document
              .getElementById("upload")
              .addEventListener("change", async (event) => {
                const file = event.target.files[0];
                const imageElement = new Image();
                const reader = new FileReader();
      
                reader.onload = () => {
                  imageElement.src = reader.result;
                  imageElement.onload = async () => {
                    const canvas = document.getElementById("canvas");
                    const model = await loadModel();
                    const { boxes, scores, classes } = await predict(
                      model,
                      imageElement
                    );
                    drawBoxes(
                      imageElement,
                      canvas,
                      boxes.arraySync(),
                      scores.arraySync(),
                      classes.arraySync()
                    );
                  };
                };
      
                reader.readAsDataURL(file);
              });
          </script>
        </body>
      </html>

      the predictions variable is a tensor, the format is as below:

      the chrome html running result is below:

    8. Glenn JocherGlenn JocherUltralytics(edited)

      Update: the TF.js export is deprecated. As of Ultralytics 8.4.83, format="tfjs" exports a LiteRT .tflite model instead of a *_web_model/model.json; use format="litert" and see the LiteRT guide. The TF.js snippets below are legacy.

      Hi @wuhonglei,

      Thank you for sharing your detailed implementation and the final working code! It's fantastic to see how you've successfully integrated YOLOv8 with TensorFlow.js for penguin detection in your web application. 🐧

      For those looking to extract boxes, scores, and classes from the predictions tensor, your approach is spot on. Here's a concise summary and a few additional tips for clarity:

      Key Steps:
      1. Load the Model:

        const model = await tf.loadGraphModel("./best_web_model/model.json");
      2. Prepare the Image:

        const tensor = tf.browser.fromPixels(imageElement)
          .resizeNearestNeighbor([640, 640])
          .toFloat()
          .expandDims(0)
          .div(tf.scalar(255.0));
      3. Run Inference:

        const predictions = await model.executeAsync(tensor);
      4. Extract Predictions:

        const reshapedPredictions = predictions.reshape([5, 8400]);
        const boxesTensor = reshapedPredictions.slice([0, 0], [4, 8400]);
        const scoresTensor = reshapedPredictions.slice([4, 0], [1, 8400]).squeeze();
        const classesTensor = tf.fill([8400], 0); // Adjust as needed
      5. Draw Boxes:

        function drawBoxes(imageElement, canvas, boxes, scores, classes) {
          const ctx = canvas.getContext("2d");
          canvas.width = imageElement.width;
          canvas.height = imageElement.height;
          ctx.drawImage(imageElement, 0, 0, canvas.width, canvas.height);
        
          const labels = ["企鹅"]; // Replace with actual label
          const validBoxes = [];
        
          for (let i = 0; i < scores.length; i++) {
            if (scores[i] > 0.5) {
              const x_c = boxes[0][i] / 640;
              const y_c = boxes[1][i] / 640;
              const w = boxes[2][i] / 640;
              const h = boxes[3][i] / 640;
        
              const x = x_c - w / 2;
              const y = y_c - h / 2;
        
              validBoxes.push([x, y, w, h, scores[i], classes[i]]);
            }
          }
        
          validBoxes.forEach((box) => {
            const [x, y, w, h, score, className] = box;
            ctx.strokeStyle = "red";
            ctx.lineWidth = 2;
            ctx.strokeRect(
              x * canvas.width,
              y * canvas.height,
              w * canvas.width,
              h * canvas.height
            );
            const text = `${className}: ${(score * 100).toFixed(2)}%`;
            ctx.fillText(text, x * canvas.width, y * canvas.height - 10);
          });
        }
      Additional Tips:
      • Model Optimization: Ensure your model is optimized for TF.js to improve performance.
      • Threshold Adjustment: Adjust the score threshold (0.5 in this case) based on your application's requirements.
      • Class Labels: Replace the placeholder labels with actual class names if you have multiple classes.

      For more detailed information on deploying YOLOv8 models with TensorFlow.js, you can refer to our TF.js integration guide.

      If you encounter any issues or have further questions, feel free to reach out. We're here to help! 😊

      3