opennsfw2

repository·main·Indexed 19 days ago

https://github.com/bhky/opennsfw2

A Keras-based implementation of the Yahoo Open-NSFW model for detecting pornographic content in images and videos. It supports TensorFlow, JAX, and PyTorch backends via Keras 3. The library provides high-level prediction functions for images and video frames, a low-level Keras API for custom inference and fine-tuning, and a deployable HTTP API service available via Docker or uvicorn.

Tokens
3.8K
Snippets
13
Records
20
Agent score
68%

What's inside opennsfw2

  1. Configure image preprocessing options

    main

    The library provides two preprocessing modes that affect how images are prepared before inference. Choosing a mode will change the resulting NSFW probability scores.

    • YAHOO: The default mode. It mimics the original Yahoo Caffe and TensorFlow 1 implementations. It involves resizing to (256, 256), an intermediate JPEG memory step, cropping to a (224, 224) center, swapping to BGR, and subtracting the mean [104, 117, 123].
    • SIMPLE: A more intuitive mode. It resizes directly to (224, 224), converts to NumPy, swaps to BGR, and subtracts the mean [104, 117, 123].

    Note: Using SIMPLE will result in different probability outputs compared to the default YAHOO mode.

  2. Install and run the OpenNSFW2 HTTP API via Docker

    main

    The recommended way to run the OpenNSFW2 HTTP service is using Docker. You can build the image manually or use Docker Compose.

    Manual Build and Run:

    docker build -t opennsfw2-api .
    docker run -p 8000:8000 opennsfw2-api

    Using Docker Compose:

    docker compose up opennsfw2-api
  3. Install opennsfw2

    main

    Install opennsfw2 using your preferred Keras backend. The package supports Keras 3 (TensorFlow or JAX backends) and tf-keras (TensorFlow-integrated Keras).

    Keras 3 (TensorFlow or JAX backend):

    python3 -m pip install "opennsfw2[keras3]"

    tf-keras (TensorFlow-integrated Keras):

    python3 -m pip install "opennsfw2[tf-keras]"

    If both versions are installed, Keras 3 is used by default. To force tf-keras, set the OPENNSFW2_KERAS environment variable before running your script:

    OPENNSFW2_KERAS=tf-keras python3 your_script.py

    Note: While the model can run on a PyTorch backend via Keras 3, it is not recommended as inference is slower and output differs from TensorFlow/JAX due to channel ordering differences.

    python3 -m pip install "opennsfw2[keras3]"
  4. Install and run the OpenNSFW2 HTTP API directly

    main

    If you prefer not to use Docker, you can install the dependencies via pip and run the service using uvicorn.

    1. Install dependencies: pip install -r requirements-api.txt
    2. Run the API: uvicorn app.main:app --host 0.0.0.0 --port 8000
    pip install -r requirements-api.txt
    uvicorn app.main:app --host 0.0.0.0 --port 8000
  5. Deploy OpenNSFW2 API using Docker Compose

    main

    You can deploy the OpenNSFW2 API as a containerized service using Docker Compose. The service exposes the API on port 8000. To ensure model weights are persisted across container restarts, a named volume model_weights is mapped to /home/appuser/.opennsfw2 inside the container.

    Service Details:

    • Service Name: opennsfw2-api
    • Port Mapping: 8000:8000
    • Healthcheck Endpoint: http://localhost:8000/health/
    • Persistence: Uses the model_weights volume to store model data in /home/appuser/.opennsfw2.
    version: "3.8"
    
    services:
      opennsfw2-api:
        build:
          context: .
          dockerfile: Dockerfile
        ports:
          - "8000:8000"
        volumes:
          - model_weights:/home/appuser/.opennsfw2
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:8000/health/"]
          interval: 30s
          timeout: 10s
          retries: 3
          start_period: 40s
    
    volumes:
      model_weights:
  6. Fine-tune the model with TensorFlow

    main

    The model can be fine-tuned using a tf.data.Dataset. Use n2.preprocess_image_tensor within your dataset mapping function to ensure compatibility with the TensorFlow pipeline.

    Note: The YAHOO preprocessing pipeline in preprocess_image_tensor intentionally omits the JPEG round-trip used in the standard PIL-based preprocess_image.

    import opennsfw2 as n2
    import tensorflow as tf
    
    image_paths = ["path/to/your/image1.jpg", "path/to/your/image2.jpg"]
    labels = [0, 1]
    
    dataset = tf.data.Dataset.from_tensor_slices((image_paths, labels))
    
    def load_and_preprocess(image_path, label):
      image = tf.io.read_file(image_path)
      image = tf.io.decode_jpeg(image, channels=3)
      image = n2.preprocess_image_tensor(image, n2.Preprocessing.YAHOO)
      return image, label
    
    dataset = (
      dataset
      .map(load_and_preprocess, num_parallel_calls=tf.data.AUTOTUNE)
      .batch(32)
      .prefetch(tf.data.AUTOTUNE)
    )
    
    model = n2.make_open_nsfw_model()
    model.compile(
      optimizer="adam",
      loss="sparse_categorical_crossentropy",
      metrics=["accuracy"],
    )
    model.fit(dataset, epochs=10)
  7. Use the low-level Keras API for inference

    main

    For more control, you can manually preprocess images and use the Keras model directly.

    1. Preprocess: Use n2.preprocess_image (for PIL images) or n2.preprocess_image_tensor (for tensors).
    2. Model Creation: Use n2.make_open_nsfw_model(). By default, it looks for weights in $HOME/.opennsfw2/weights/open_nsfw_weights.h5 and downloads them if missing. You can customize the location using the OPENNSFW2_HOME environment variable.
    3. Inference: Pass a NumPy array with a batch dimension to model.predict().
    import numpy as np
    import opennsfw2 as n2
    from PIL import Image
    
    # Load and preprocess
    image_path = "path/to/your/image.jpg"
    pil_image = Image.open(image_path)
    image = n2.preprocess_image(pil_image, n2.Preprocessing.YAHOO)
    
    # Create model
    model = n2.make_open_nsfw_model()
    
    # Predict
    inputs = np.expand_dims(image, axis=0)
    predictions = model.predict(inputs)
    
    # predictions shape is (num_images, 2) -> [sfw_prob, nsfw_prob]
    sfw_probability, nsfw_probability = predictions[0]
  8. Predict NSFW probability for multiple images

    main

    To process multiple images in one request, use the POST /predict/images endpoint. The request body should contain an inputs array containing objects with type and data fields.

    curl -X POST "http://localhost:8000/predict/images" \
      -H "Content-Type: application/json" \
      -d '{
        "inputs": [
          {
            "type": "url",
            "data": "https://example.com/image1.jpg"
          },
          {
            "type": "url", 
            "data": "https://example.com/image2.jpg"
          }
        ],
        "options": {
          "preprocessing": "YAHOO"
        }
      }'
  9. Predict NSFW probability for video

    main

    Use the POST /predict/video endpoint to analyze video content. You can configure how frames are sampled and aggregated.

    Video Options:

    • frame_interval: Process every Nth frame (default: 8).
    • aggregation_size: Number of frames to aggregate (default: 8).
    • aggregation: Aggregation method. Options: MEAN (default), MEDIAN, MAX, MIN.
    curl -X POST "http://localhost:8000/predict/video" \
      -H "Content-Type: application/json" \
      -d '{
        "input": {
          "type": "url",
          "data": "https://example.com/video.mp4"
        },
        "options": {
          "preprocessing": "YAHOO",
          "frame_interval": 8,
          "aggregation_size": 8,
          "aggregation": "MEAN"
        }
      }'
  10. Predict NSFW probability for images

    main

    Use predict_image for a single image or predict_images for a batch of images. predict_images is more efficient as it instantiates the model once and performs batch inference.

    Input handles can be either a file path (str) or a PIL.Image.Image object.

    import opennsfw2 as n2
    
    # Single image
    image_handle = "path/to/your/image.jpg"
    nsfw_probability = n2.predict_image(image_handle)
    
    # List of images (batch inference)
    image_handles = [
      "path/to/your/image1.jpg",
      "path/to/your/image2.jpg",
    ]
    nsfw_probabilities = n2.predict_images(image_handles)