• Home
  • About Us
  • Contact Us
  • Disclaimer
  • Privacy Policy
Friday, July 10, 2026
newsaiworld
  • Home
  • Artificial Intelligence
  • ChatGPT
  • Data Science
  • Machine Learning
  • Crypto Coins
  • Contact Us
No Result
View All Result
  • Home
  • Artificial Intelligence
  • ChatGPT
  • Data Science
  • Machine Learning
  • Crypto Coins
  • Contact Us
No Result
View All Result
Morning News
No Result
View All Result
Home Data Science

Native Video Summarization Pipeline: Processing Frames with SmolVLM2-2.2B

Admin by Admin
July 10, 2026
in Data Science
0
KDN Shittu Local Video Summarization Pipeline scaled.png
0
SHARES
1
VIEWS
Share on FacebookShare on Twitter


Local Video Summarization Pipeline: Processing Frames with SmolVLM2-2.2B
 

# Introduction

 
Most video understanding instruments fall into one among two camps. The primary camp requires a cloud API; your footage is uploaded, processed on another person’s servers, and billed per minute of video. The second camp runs domestically however calls for the type of GPU cluster most builders should not have: 70B+ fashions that want a number of A100s and take minutes per clip. Neither possibility works for a developer who needs to course of a day’s value of assembly recordings, a lecture collection, or safety footage on a workstation they already personal.

SmolVLM2-2.2B-Instruct, launched by Hugging Face on February 20, 2025, adjustments the calculation. It runs on 5.2 GB of GPU RAM, an RTX 3060, a MacBook Professional M2, and the free Google Colab T4 tier. On Video-MME, the usual long-form video understanding benchmark, it outperforms each current 2B-scale mannequin. That mixture, shopper {hardware} paired with outcomes that really maintain up, is what this text is constructed round.

The mission we’ll construct on this article: a neighborhood pipeline that takes any video file, extracts frames at configurable intervals, analyzes them in batches with SmolVLM2-2.2B, and outputs a structured JSON abstract, together with per-frame scene descriptions, key moments with timestamps, motion gadgets, and a remaining narrative. The identical pipeline handles assembly recordings, lectures, and surveillance footage with out altering a line of code.

 

# SmolVLM2-2.2B

 
The explanation SmolVLM2-2.2B can run on an RTX 3060 whereas outperforming bigger fashions on video duties is a design determination about how photographs are tokenized.

Most vision-language fashions tokenize photographs at excessive density. Qwen2-VL, for instance, makes use of as much as 16,000 tokens to signify a single picture. Feeding 50 frames to such a mannequin at that density would eat 800,000 tokens, far past any shopper GPU’s context price range. SmolVLM2 makes use of a pixel shuffle technique that compresses every 384×384 picture patch to 81 tokens. Fifty frames turn into roughly 4,050 picture tokens, manageable in a single inference name. That compression is why SmolVLM2’s prefill throughput runs 3.3 to 4.5 instances quicker and technology throughput runs 7.5 to 16 instances quicker than Qwen2-VL-2B, not as a advertising and marketing declare however as a direct consequence of the token price range distinction.

The mannequin is available in three sizes. The 256M and 500M variants are designed for cell and edge units; the 256M can run on a cellphone. The two.2B is the fitting alternative for this pipeline. It’s the solely dimension with robust sufficient video benchmark scores to supply dependable multi-scene summaries: Video-MME of 52.1, MLVU of 55.2, and MVBench of 46.27, towards the 500M’s 42.2, 47.3, and 39.73, respectively.

The video understanding strategy can be value understanding earlier than you write any code. SmolVLM2 doesn’t have a local video encoder; it treats video as a sequence of photographs. The official reference pipeline extracts as much as 50 evenly sampled frames per video, bypasses inside body resizing, and passes them as a multi-image sequence inside a single chat message. That strategy scored 27.14% on CinePile, positioning it between InternVL2 (2B) and Video-LLaVA (7B) on cinematic video understanding, a robust end result given the mannequin’s dimension and that video was not the one factor it was educated for.

 

# Setting Up the Atmosphere

 
{Hardware} necessities:

 

Characteristic Minimal Really useful
GPU VRAM 6 GB (RTX 3060) 12–16 GB (RTX 4080)
Apple Silicon M2 8 GB (MPS path) M2 Professional / M3 16 GB
System RAM 16 GB 32 GB
Disk 10 GB free 20 GB+ SSD
Colab T4 (free tier) A100 (Colab Professional)

 

Python packages:

# Python 3.10+ required
python --version

python -m venv smolvlm2-env
supply smolvlm2-env/bin/activate       # macOS / Linux
smolvlm2-envScriptsactivate          # Home windows

# Set up from the secure SmolVLM-2 department -- required for SmolVLM2 help
pip set up git+https://github.com/huggingface/transformers@v4.49.0-SmolVLM-2

# Core dependencies
pip set up torch torchvision --index-url https://obtain.pytorch.org/whl/cu121
pip set up 
  opencv-python 
  Pillow 
  numpy 
  num2words 
  speed up

# Flash Consideration 2 for CUDA -- considerably quicker on NVIDIA GPUs
# Skip this on Apple Silicon and CPU -- it's CUDA-only
pip set up flash-attn --no-build-isolation

# decord -- required for SmolVLM2's native video enter path (utilized in Part 5)
pip set up decord

 

Be aware: The num2words bundle is a non-obvious dependency. SmolVLM2’s processor makes use of it to transform numeric digits to phrase representations (e.g. 3 → “three”) for consistency with pure language coaching patterns, as defined on this walkthrough. Omitting it causes a silent import error when the processor hundreds.

 

Machine test (run this earlier than loading the mannequin):

# device_check.py
# Run: python device_check.py

import torch

def detect_device():
    if torch.cuda.is_available():
        title  = torch.cuda.get_device_name(0)
        vram  = torch.cuda.get_device_properties(0).total_memory / 1e9
        print(f"CUDA: {title} ({vram:.1f} GB VRAM)")
        return "cuda", torch.bfloat16, "flash_attention_2"
    elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
        print("Apple Silicon MPS detected")
        return "mps", torch.float16, "keen"
    else:
        print("CPU fallback (gradual -- take into account Colab T4)")
        return "cpu", torch.float32, "keen"

if __name__ == "__main__":
    system, dtype, attn = detect_device()
    print(f"Machine: {system} | dtype: {dtype} | attn: {attn}")

 

Run it with:

 

# Constructing the Basis of the Pipeline

 
Earlier than SmolVLM2 sees something, you want frames. The body extractor converts a video file into a listing of PIL (Python Imaging Library) photographs with timestamps connected, one pair per extracted body.

Two modes matter for various use instances. Uniform sampling distributes frames evenly throughout the total video length, guaranteeing protection of the whole lot no matter content material. That is the fitting alternative for conferences and lectures the place you can’t afford to overlook a piece. Keyframe sampling extracts frames solely the place the visible content material adjustments considerably, akin to scene cuts, a brand new slide, or a brand new speaker, which reduces the body rely and focuses consideration on distinct moments. That is higher for surveillance and spotlight extraction.

# frame_extractor.py
# Stipulations: pip set up opencv-python Pillow numpy
# Utilization: from frame_extractor import FrameExtractor

import cv2
import numpy as np
from PIL import Picture


class FrameExtractor:
    """
    Extracts video frames as PIL Photos for SmolVLM2 inference.
    Every extracted body is paired with its timestamp in seconds.

    SmolVLM2 makes use of ~81 visible tokens per picture. At 50 frames that's
    roughly 4,050 picture tokens -- the sensible higher restrict earlier than VRAM
    stress impacts technology high quality on shopper GPUs.
    """

    MAX_FRAMES = 50

    def __init__(self, max_frames: int = MAX_FRAMES):
        """
        Args:
            max_frames: Onerous cap on extracted frames. Default 50 matches
                        the SmolVLM2 reference pipeline's examined higher restrict.
        """
        self.max_frames = max_frames

    def uniform_sample(self, video_path: str) -> record[tuple[float, Image.Image]]:
        """
        Extract evenly spaced frames throughout the total video length.
        Finest for: assembly recordings, lectures, tutorials, course content material.

        Returns:
            Listing of (timestamp_seconds, PIL_Image) in chronological order.
        """
        cap = cv2.VideoCapture(video_path)
        if not cap.isOpened():
            elevate IOError(f"Can not open video: {video_path}")

        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        fps          = cap.get(cv2.CAP_PROP_FPS) or 30.0
        n_extract    = min(self.max_frames, total_frames)

        # Construct body indices unfold evenly from first to final body
        indices = np.linspace(0, total_frames - 1, n_extract, dtype=int)
        outcomes = []

        for idx in indices:
            cap.set(cv2.CAP_PROP_POS_FRAMES, int(idx))
            ret, body = cap.learn()
            if not ret:
                proceed
            timestamp = spherical(idx / fps, 2)
            rgb = cv2.cvtColor(body, cv2.COLOR_BGR2RGB)
            outcomes.append((timestamp, Picture.fromarray(rgb)))

        cap.launch()
        return outcomes

    def keyframe_sample(
        self, video_path: str, diff_threshold: float = 30.0
    ) -> record[tuple[float, Image.Image]]:
        """
        Extract frames the place visible content material adjustments considerably.
        Finest for: surveillance, occasion detection, spotlight extraction.

        Makes use of imply absolute pixel distinction between consecutive grayscale frames
        because the change sign. When the diff exceeds diff_threshold, a brand new
        keyframe is recorded.

        Args:
            diff_threshold: Imply pixel distinction to deal with as a scene change.
                            30.0 works for many business content material.
                            Decrease = extra delicate, larger = fewer frames.

        Returns:
            Listing of (timestamp_seconds, PIL_Image) in chronological order,
            capped at self.max_frames.
        """
        cap = cv2.VideoCapture(video_path)
        if not cap.isOpened():
            elevate IOError(f"Can not open video: {video_path}")

        fps       = cap.get(cv2.CAP_PROP_FPS) or 30.0
        outcomes   = []
        prev_gray = None
        idx       = 0

        whereas len(outcomes) < self.max_frames:
            ret, body = cap.learn()
            if not ret:
                break

            grey = cv2.cvtColor(body, cv2.COLOR_BGR2GRAY)

            if prev_gray is None:
                # At all times seize the primary body as a baseline
                rgb = cv2.cvtColor(body, cv2.COLOR_BGR2RGB)
                outcomes.append((spherical(idx / fps, 2), Picture.fromarray(rgb)))
            else:
                diff = np.imply(np.abs(grey.astype(float) - prev_gray.astype(float)))
                if diff > diff_threshold:
                    rgb = cv2.cvtColor(body, cv2.COLOR_BGR2RGB)
                    outcomes.append((spherical(idx / fps, 2), Picture.fromarray(rgb)))

            prev_gray = grey
            idx += 1

        cap.launch()
        return outcomes

 

Begin each new video kind with uniform_sample. Should you discover too many redundant frames (5 nearly-identical slides in a row), change to keyframe_sample and tune diff_threshold down from 30 to twenty till the extracted set feels consultant with out being redundant.

 

# Loading SmolVLM2 and Working Single-Body Inference

 
With frames in hand, right here is the entire mannequin loading and first-inference sample. The essential particulars: AutoModelForImageTextToText is the proper class (not the generic AutoModelForCausalLM), and on CUDA, you must allow Flash Consideration 2, which gives significant latency enhancements on multi-image inputs.

# smolvlm2_loader.py
# Stipulations: transformers from v4.49.0-SmolVLM-2 department, torch, flash-attn (CUDA solely)
# Run: python smolvlm2_loader.py your_video.mp4

import sys
import torch
from PIL import Picture
from transformers import AutoProcessor, AutoModelForImageTextToText

MODEL_ID = "HuggingFaceTB/SmolVLM2-2.2B-Instruct"


def load_model():
    """
    Load SmolVLM2-2.2B and its processor.
    Robotically selects Flash Consideration 2 on CUDA, keen mode elsewhere.
    First run downloads ~4.5 GB of weights to ~/.cache/huggingface/hub.
    """
    if torch.cuda.is_available():
        dtype  = torch.bfloat16
        system = "cuda"
        attn   = "flash_attention_2"
    elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
        dtype  = torch.float16
        system = "mps"
        attn   = "keen"
    else:
        dtype  = torch.float32
        system = "cpu"
        attn   = "keen"

    print(f"Loading {MODEL_ID} on {system}...")

    processor = AutoProcessor.from_pretrained(MODEL_ID)

    mannequin = AutoModelForImageTextToText.from_pretrained(
        MODEL_ID,
        torch_dtype=dtype,
        _attn_implementation=attn,
    ).to(system)

    mannequin.eval()
    print(f"Mannequin prepared on {system}")
    return mannequin, processor


def describe_frame(
    mannequin,
    processor,
    body: Picture.Picture,
    immediate: str = "Describe what is going on on this body intimately. Be aware any textual content, individuals, objects, or actions seen.",
    max_new_tokens: int = 256,
) -> str:
    """
    Run SmolVLM2 inference on a single PIL Picture.

    The chat template expects picture content material earlier than textual content content material within the
    message -- this mirrors the coaching information format and is essential
    for dependable output.

    Args:
        body:          A PIL Picture (from FrameExtractor)
        immediate:         What to ask the mannequin about this body
        max_new_tokens: Most response size in tokens

    Returns:
        Mannequin response as a plain string
    """
    messages = [
        {
            "role": "user",
            "content": [
                # Image placed before text -- matches SmolVLM2 training format
                {"type": "image"},
                {"type": "text", "text": prompt},
            ],
        }
    ]

    # apply_chat_template codecs the message and injects visible token placeholders
    input_text = processor.apply_chat_template(
        messages,
        add_generation_prompt=True,
    )

    inputs = processor(
        photographs=[frame],
        textual content=input_text,
        return_tensors="pt",
    ).to(mannequin.system)

    with torch.no_grad():
        output_ids = mannequin.generate(
            **inputs,
            max_new_tokens=max_new_tokens,
            do_sample=False,   # Grasping decoding for constant structured output
        )

    # Decode solely the newly generated tokens -- strip the enter immediate
    new_tokens = output_ids[0][inputs["input_ids"].form[-1]:]
    return processor.decode(new_tokens, skip_special_tokens=True).strip()


# ── Fast sanity test ────────────────────────────────────────────────────────

if __name__ == "__main__":
    from frame_extractor import FrameExtractor

    if len(sys.argv) < 2:
        print("Utilization: python smolvlm2_loader.py ")
        sys.exit(1)

    mannequin, processor = load_model()
    extractor = FrameExtractor(max_frames=5)

    frames = extractor.uniform_sample(sys.argv[1])
    ts, first_frame = frames[0]

    print(f"nDescribing body at {ts}s...")
    description = describe_frame(mannequin, processor, first_frame)
    print(f"n{description}")

 

run:

python smolvlm2_loader.py your_video.mp4

 

The outline you get again is your sanity test. If the mannequin appropriately identifies seen textual content, individuals, objects, and actions within the first body, the pipeline is working. Should you get a really brief or clearly mistaken response, confirm that the transformers model is from the v4.49.0-SmolVLM-2 department; the secure Hugging Face launch doesn’t but embody SmolVLM2 help on the time of writing.

 

# Constructing the Actual-World Venture (Assembly Recording Summarizer)

 
Right here is the total pipeline. The VideoSummarizer class ties collectively the body extractor, the mannequin, and a two-pass inference technique: the primary cross generates per-frame descriptions, and the second cross synthesizes these descriptions right into a structured JSON report with a story abstract and extracted motion gadgets.

The 2-pass design is deliberate. Asking the mannequin to explain a single body at a time is a centered, achievable activity; it produces correct, concrete descriptions. Asking it to synthesize 30 body descriptions right into a coherent narrative is a distinct activity, and it handles that higher as a separate name with the concatenated descriptions as enter than should you tried to do each in a single cross.

# video_summarizer.py
# Stipulations: frame_extractor.py and smolvlm2_loader.py in the identical listing
# Run: python video_summarizer.py meeting_recording.mp4 --output abstract.json

import re
import json
import argparse
from dataclasses import dataclass, area
import cv2
import torch

from frame_extractor import FrameExtractor
from smolvlm2_loader import load_model, describe_frame


# ── Knowledge fashions ───────────────────────────────────────────────────────────────

@dataclass
class FrameDescription:
    timestamp: float
    frame_index: int
    description: str

@dataclass
class VideoSummary:
    video_path: str
    duration_seconds: float
    frames_analyzed: int
    frame_descriptions: record[FrameDescription]
    narrative_summary: str
    action_items: record[str] = area(default_factory=record)
    key_moments: record[dict] = area(default_factory=record)


# ── Per-frame immediate ──────────────────────────────────────────────────────────

FRAME_PROMPT = """You're analyzing a body from a recorded assembly.

Describe what you see concisely however utterly:
- Who or what's seen (individuals, whiteboards, screens, slides)
- Any readable textual content (slide titles, whiteboard content material, display screen content material)
- The obvious exercise (presenting, discussing, writing, listening)

Preserve your response to 2-3 sentences."""

# ── Synthesis immediate ──────────────────────────────────────────────────────────

def build_synthesis_prompt(descriptions: record[FrameDescription], length: float) -> str:
    """Construct the second-pass immediate that synthesizes body descriptions right into a report."""
    frames_text = "n".be part of(
        f"[{int(d.timestamp // 60):02d}:{int(d.timestamp % 60):02d}] {d.description}"
        for d in descriptions
    )
    return f"""Under are time-stamped descriptions of frames from a {length:.0f}-second assembly recording.

{frames_text}

Based mostly on these descriptions, present:

1. NARRATIVE SUMMARY: A 3-5 sentence abstract of what the assembly lined, who participated (if seen), and what choices or conclusions had been reached.

2. ACTION ITEMS: A bullet record of concrete duties or follow-ups talked about or implied within the assembly. Begin every with a splash (-).

3. KEY MOMENTS: A bullet record of the 3-5 most important moments with their timestamps in [MM:SS] format.

Format your response with clear headings for every part."""


# ── Output parser ─────────────────────────────────────────────────────────────

def parse_action_items(textual content: str) -> record[str]:
    """Extract bullet-point motion gadgets from the synthesis output."""
    gadgets = []
    for line in textual content.break up("n"):
        stripped = line.strip()
        if re.match(r"^[-*•]s+", stripped) or re.match(r"^d+.s+", stripped):
            clear = re.sub(r"^[-*•d.]+s*", "", stripped).strip()
            if clear and len(clear) > 5:
                gadgets.append(clear)
    return gadgets

def parse_key_moments(textual content: str) -> record[dict]:
    """Extract key moments with timestamps from the synthesis output."""
    moments = []
    sample = re.compile(r"[(d{2}:d{2})]s*(.+)")
    for match in sample.finditer(textual content):
        moments.append({
            "timestamp_label": match.group(1),
            "description": match.group(2).strip()
        })
    return moments


# ── Principal summarizer class ─────────────────────────────────────────────────────

class VideoSummarizer:
    """
    Finish-to-end native video summarizer utilizing SmolVLM2-2.2B.
    Two-pass technique: per-frame descriptions + synthesis narrative.
    Works on scanned, digital, and live-recorded movies alike.
    """

    def __init__(self, batch_size: int = 8):
        """
        Args:
            batch_size: Frames to explain per inference batch.
                        Tune primarily based on VRAM: 8 for 8 GB, 16 for 16 GB.
                        Every body makes use of ~81 visible tokens; decrease batch = much less peak VRAM.
        """
        self.mannequin, self.processor = load_model()
        self.extractor = FrameExtractor(max_frames=50)
        self.batch_size = batch_size

    def _get_duration(self, video_path: str) -> float:
        cap = cv2.VideoCapture(video_path)
        frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
        fps    = cap.get(cv2.CAP_PROP_FPS) or 30.0
        cap.launch()
        return spherical(frames / fps, 2)

    def summarize(self, video_path: str, mode: str = "uniform") -> VideoSummary:
        """
        Summarize a video file.

        Args:
            video_path: Path to the video file (mp4, avi, mov, mkv)
            mode:       "uniform" for even protection, "keyframe" for scene adjustments

        Returns:
            VideoSummary with per-frame descriptions, narrative, and motion gadgets
        """
        length = self._get_duration(video_path)
        print(f"Video: {video_path} ({length:.0f}s)")

        # ── Cross 1: Extract frames ─────────────────────────────────────────
        if mode == "keyframe":
            frames = self.extractor.keyframe_sample(video_path)
        else:
            frames = self.extractor.uniform_sample(video_path)

        print(f"Extracted {len(frames)} frames -- describing in batches of {self.batch_size}...")

        # ── Cross 2: Describe every body ────────────────────────────────────
        descriptions: record[FrameDescription] = []

        for batch_start in vary(0, len(frames), self.batch_size):
            batch = frames[batch_start : batch_start + self.batch_size]

            for local_idx, (timestamp, img) in enumerate(batch):
                global_idx = batch_start + local_idx
                print(f"  [{global_idx + 1}/{len(frames)}] Describing body at {timestamp}s...")

                desc = describe_frame(
                    self.mannequin,
                    self.processor,
                    img,
                    immediate=FRAME_PROMPT,
                    max_new_tokens=128,   # Preserve body descriptions concise
                )
                descriptions.append(FrameDescription(
                    timestamp=timestamp,
                    frame_index=global_idx,
                    description=desc,
                ))

        # ── Cross 3: Synthesis ──────────────────────────────────────────────
        print("nRunning synthesis cross...")

        synthesis_prompt = build_synthesis_prompt(descriptions, length)
        synthesis_messages = [
            {
                "role": "user",
                "content": [{"type": "text", "text": synthesis_prompt}],
            }
        ]
        synthesis_text_input = self.processor.apply_chat_template(
            synthesis_messages,
            add_generation_prompt=True,
        )
        # Synthesis is text-only -- no photographs on this cross
        synthesis_inputs = self.processor(
            textual content=synthesis_text_input,
            return_tensors="pt",
        ).to(self.mannequin.system)

        with torch.no_grad():
            synthesis_ids = self.mannequin.generate(
                **synthesis_inputs,
                max_new_tokens=512,
                do_sample=False,
            )

        synthesis_new = synthesis_ids[0][synthesis_inputs["input_ids"].form[-1]:]
        synthesis_output = self.processor.decode(synthesis_new, skip_special_tokens=True).strip()

        action_items = parse_action_items(synthesis_output)
        key_moments  = parse_key_moments(synthesis_output)

        return VideoSummary(
            video_path=video_path,
            duration_seconds=length,
            frames_analyzed=len(descriptions),
            frame_descriptions=descriptions,
            narrative_summary=synthesis_output,
            action_items=action_items,
            key_moments=key_moments,
        )

    def to_json(self, abstract: VideoSummary) -> str:
        """Serialize a VideoSummary to formatted JSON."""
        return json.dumps({
            "video":            abstract.video_path,
            "duration_seconds": abstract.duration_seconds,
            "frames_analyzed":  abstract.frames_analyzed,
            "narrative":        abstract.narrative_summary,
            "action_items":     abstract.action_items,
            "key_moments":      abstract.key_moments,
            "frame_descriptions": [
                {
                    "timestamp":    d.timestamp,
                    "timestamp_label": f"{int(d.timestamp // 60):02d}:{int(d.timestamp % 60):02d}",
                    "description":  d.description,
                }
                for d in summary.frame_descriptions
            ],
        }, indent=2, ensure_ascii=False)


# ── Entry level ───────────────────────────────────────────────────────────────

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Summarize a video with SmolVLM2-2.2B")
    parser.add_argument("video",   assist="Path to the enter video file")
    parser.add_argument("--output", default="abstract.json", assist="Output JSON file path")
    parser.add_argument("--mode",   default="uniform", selections=["uniform", "keyframe"])
    parser.add_argument("--batch-size", kind=int, default=8)
    args = parser.parse_args()

    summarizer = VideoSummarizer(batch_size=args.batch_size)
    end result = summarizer.summarize(args.video, mode=args.mode)

    output_str = summarizer.to_json(end result)
    with open(args.output, "w", encoding="utf-8") as f:
        f.write(output_str)

    print(f"nSummary saved to {args.output}")
    print(f"Frames analyzed: {end result.frames_analyzed}")
    print(f"Motion gadgets discovered: {len(end result.action_items)}")
    for merchandise in end result.action_items:
        print(f"  - {merchandise}")

 

run:

# Uniform sampling (default) -- finest for conferences and lectures
python video_summarizer.py meeting_2026_06_14.mp4 --output meeting_summary.json

# Keyframe sampling -- finest for occasion detection, surveillance
python video_summarizer.py security_footage.mp4 --mode keyframe --output occasions.json

# Alter batch dimension on your VRAM (8 for 8 GB VRAM, 16 for 16 GB)
python video_summarizer.py long_lecture.mp4 --batch-size 4 --output lecture.json

 

Pattern output (abstract.json):

{
  "video": "meeting_2026_06_14.mp4",
  "duration_seconds": 3247.0,
  "frames_analyzed": 50,
  "narrative": "The assembly centered on Q3 product planning ...",
  "action_items": [
    "Finalize API design document by end of June",
    "Schedule testing sprint kickoff for July 1",
    "Share updated Gantt chart with stakeholders"
  ],
  "key_moments": [
    {"timestamp_label": "00:00", "description": "Team introductions and agenda overview"},
    {"timestamp_label": "12:30", "description": "API architecture diagram reviewed on screen"},
    {"timestamp_label": "41:15", "description": "Action items summarized on whiteboard"}
  ]
}

 

# Batching Frames with VRAM Consciousness

 
The batch dimension in VideoSummarizer is the first knob for staying inside your VRAM price range. Too giant and also you hit out-of-memory errors. Too small and also you decelerate unnecessarily. Right here is the calculation:

SmolVLM2-2.2B weights occupy roughly 4.5 GB in bfloat16. Every body contributes roughly 81 picture tokens to the inference name, and at 2.2B scale, KV cache overhead is roughly 0.5 MB per token. Leaving 20% VRAM as headroom:

# vram_calculator.py
# Estimate a protected batch dimension on your GPU earlier than operating the pipeline

def compute_batch_size(vram_gb: float, tokens_per_frame: int = 81) -> int:
    """
    Estimate frames per inference batch for a given VRAM price range.

    Args:
        vram_gb:          Obtainable GPU VRAM in gigabytes
        tokens_per_frame: Visible tokens per picture (81 for SmolVLM2)

    Returns:
        Secure batch dimension, minimal 1, most 50
    """
    MODEL_GB     = 4.5      # SmolVLM2-2.2B weights in bfloat16
    HEADROOM     = 0.80     # Use at most 80% of whole VRAM
    MB_PER_TOKEN = 0.5 / 1024  # GB per KV token at 2.2B scale (tough)

    usable_gb        = vram_gb * HEADROOM
    inference_budget = max(0.0, usable_gb - MODEL_GB)
    frames           = int(inference_budget / (tokens_per_frame * MB_PER_TOKEN))

    return max(1, min(frames, 50))


if __name__ == "__main__":
    for vram in [6.0, 8.0, 12.0, 16.0, 24.0]:
        print(f"  {vram:.0f} GB VRAM → batch_size = {compute_batch_size(vram)}")

 

Working this towards a couple of frequent VRAM tiers provides a way of the ceiling:

  6 GB  VRAM → batch_size = 16
  8 GB  VRAM → batch_size = 30
 12 GB  VRAM → batch_size = 50
 16 GB  VRAM → batch_size = 50
 24 GB  VRAM → batch_size = 50

 

For lengthy movies the place you can’t afford to restart from zero if one thing fails, add a JSON Strains (JSONL) streaming author that persists every body’s description as it’s generated:

# jsonl_writer.py -- drop-in checkpoint help for long-video processing

import json

class JSONLWriter:
    """
    Writes body descriptions to a JSONL file as they're produced.
    Allows resume-from-checkpoint on lengthy movies -- if inference fails at
    body 30 of fifty, re-read the JSONL and skip already-processed frames.
    """
    def __init__(self, path: str):
        self.path = path
        self._fh  = open(path, "a", encoding="utf-8")  # Append mode for resume

    def write(self, document: dict):
        """Write one body document and flush instantly to disk."""
        self._fh.write(json.dumps(document, ensure_ascii=False) + "n")
        self._fh.flush()

    def already_processed(self) -> set[int]:
        """Return the set of body indices already within the checkpoint file."""
        processed = set()
        strive:
            with open(self.path, "r", encoding="utf-8") as f:
                for line in f:
                    document = json.hundreds(line)
                    processed.add(document.get("frame_index", -1))
        besides FileNotFoundError:
            cross
        return processed

    def shut(self):
        self._fh.shut()

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.shut()

 

# Extending the Pipeline (Timestamps and JSONL Streaming)

 
The output JSON from this pipeline is already timestamped on the body stage. Making it extra searchable requires one addition: a clear MM:SS label on each body description that maps on to the video participant’s scrubber.

Add this post-processing step to to_json() if you’d like the output to be immediately usable in a video overview interface:

def timestamp_label(seconds: float) -> str:
    """Convert decimal seconds to MM:SS or HH:MM:SS label."""
    whole = int(seconds)
    h, the rest = divmod(whole, 3600)
    m, s = divmod(the rest, 60)
    if h > 0:
        return f"{h:02d}:{m:02d}:{s:02d}"
    return f"{m:02d}:{s:02d}"

 

For long-form video output that you just need to stream right into a downstream system (a database, a Slack notification, a doc indexer), substitute the batch buffer strategy with a JSONL output the place every line is one body’s document. Which means the primary body’s description is on the market 30 seconds right into a 90-minute video’s processing, reasonably than ready for the total pipeline to finish earlier than writing something.

Pair the JSONL author with JSONLWriter.already_processed() to implement resume-from-checkpoint: if the pipeline crashes at body 35 of fifty, restart it and it’ll learn the prevailing checkpoint, skip the primary 35 frames, and proceed from body 36. On lengthy movies, this protects vital time over ranging from zero.

 

# Conclusion

 
SmolVLM2-2.2B sits at a genuinely helpful level on the capability-size trade-off curve. Sufficiently small to run on a single shopper GPU, succesful sufficient to supply video summaries which are truly helpful for actual workflows. The frame-as-image strategy retains the implementation clear: no unique video encoders, no customized consideration implementations, simply the usual transformers API with PIL photographs as enter.

The assembly summarizer on this article is the template. Change FRAME_PROMPT with a immediate tuned to your area, change build_synthesis_prompt() to extract no matter structured fields matter on your use case, and the identical pipeline works for lecture recordings, safety footage, product demo walkthroughs, or sports activities highlights. The 2-pass sample, per-frame description first and synthesis second, holds throughout all of these as a result of the mannequin describes particular person frames precisely and synthesizes throughout descriptions reliably.

The 50-frame restrict is a place to begin, not a ceiling. On higher-VRAM {hardware}, enhance max_frames to 75 or 100 and experiment. High quality scales with body protection up to a degree, and your synthesis cross advantages from extra materials to work with.
 
 

Shittu Olumide is a software program engineer and technical author obsessed with leveraging cutting-edge applied sciences to craft compelling narratives, with a eager eye for element and a knack for simplifying complicated ideas. You may as well discover Shittu on Twitter.



READ ALSO

How Behavioral Analytics and AI Are Redefining Cybersecurity for Boca Raton Companies

Why AI’s Plumbing Retains Changing into Its Largest Assault Floor |

Tags: FrameslocalPipelineProcessingSmolVLM22.2BSummarizationVideo

Related Posts

Image 11.png
Data Science

How Behavioral Analytics and AI Are Redefining Cybersecurity for Boca Raton Companies

July 10, 2026
Ai mcp server security vulnerabilities cvss.png
Data Science

Why AI’s Plumbing Retains Changing into Its Largest Assault Floor |

July 9, 2026
Awan clean messy csv files python beginners guide 1.png
Data Science

Clear Messy CSV Information with Python: A Newbie’s Information

July 9, 2026
Chatgpt image jun 26 2026 03 02 24 pm.png
Data Science

How AI Web site Chatbots Enhance Buyer Help and Lead Technology

July 8, 2026
Open padlock keyboard synthetic data privacy risk.jpg
Data Science

Artificial Information Will not Save You From a Dangerous Privateness Technique |

July 8, 2026
Rosidi sql vs pandas vs ai agents 1.png
Data Science

SQL vs Pandas vs AI Brokers: Which Solves Analytics Issues Greatest?

July 7, 2026

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

POPULAR NEWS

Gemini 2.0 Fash Vs Gpt 4o.webp.webp

Gemini 2.0 Flash vs GPT 4o: Which is Higher?

January 19, 2025
Chainlink Link And Cardano Ada Dominate The Crypto Coin Development Chart.jpg

Chainlink’s Run to $20 Beneficial properties Steam Amid LINK Taking the Helm because the High Creating DeFi Challenge ⋆ ZyCrypto

May 17, 2025
Image 100 1024x683.png

Easy methods to Use LLMs for Highly effective Computerized Evaluations

August 13, 2025
Blog.png

XMN is accessible for buying and selling!

October 10, 2025
0 3.png

College endowments be a part of crypto rush, boosting meme cash like Meme Index

February 10, 2025

EDITOR'S PICK

Leonardo Ai Llm Battle.jpg

Sci-fi creator Neal Stephenson needs AIs combating AIs • The Register

May 16, 2025
Xrp etfs set to reach secs desk as billions ready to pour into xrp following ripple win against sec.jpg

Why XRP Worth Has Dropped Regardless of Huge Success This Week ⋆ ZyCrypto

September 27, 2025
Sara author spotlight.jpg

Constructing Techniques That Survive Actual Life

February 2, 2026
Jr Korpa Sgg6o7wdzd0 Unsplash Scaled 1.jpg

The Artwork of Noise | In the direction of Information Science

April 3, 2025

About Us

Welcome to News AI World, your go-to source for the latest in artificial intelligence news and developments. Our mission is to deliver comprehensive and insightful coverage of the rapidly evolving AI landscape, keeping you informed about breakthroughs, trends, and the transformative impact of AI technologies across industries.

Categories

  • Artificial Intelligence
  • ChatGPT
  • Crypto Coins
  • Data Science
  • Machine Learning

Recent Posts

  • Native Video Summarization Pipeline: Processing Frames with SmolVLM2-2.2B
  • The Massive Con of Agentic AI
  • USDPT is on the market for buying and selling!
  • Home
  • About Us
  • Contact Us
  • Disclaimer
  • Privacy Policy

© 2024 Newsaiworld.com. All rights reserved.

No Result
View All Result
  • Home
  • Artificial Intelligence
  • ChatGPT
  • Data Science
  • Machine Learning
  • Crypto Coins
  • Contact Us

© 2024 Newsaiworld.com. All rights reserved.

Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?