setup uv env

#!/bin/bash
# Set up RAM+ in an isolated venv with a compatible transformers version.
# recognize-anything uses APIs removed in transformers>=4.46, so we pin to 4.45.2.
set -e

VENV=".venv-ram"
WEIGHTS_DIR="models/ram_plus"
WEIGHTS_FILE="$WEIGHTS_DIR/ram_plus_swin_large_14m.pth"

# ---------------------------------------------------------------------------
# 1. Create venv
# ---------------------------------------------------------------------------
if [ ! -d "$VENV" ]; then
    echo "Creating $VENV …"
    uv venv "$VENV" --python 3.11
else
    echo "$VENV already exists"
fi

PIP="$VENV/bin/pip"

# ---------------------------------------------------------------------------
# 2. Install PyTorch (reuse system CUDA version if available)
# ---------------------------------------------------------------------------
if ! "$VENV/bin/python" -c "import torch" 2>/dev/null; then
    echo "Installing PyTorch …"
    CUDA_VER=$(python3 -c "import torch; print('cu' + torch.version.cuda.replace('.',''))" 2>/dev/null || echo "cpu")
    if [ "$CUDA_VER" = "cpu" ]; then
        uv pip install --python "$VENV/bin/python" torch torchvision
    else
        uv pip install --python "$VENV/bin/python" torch torchvision \
            --index-url "https://download.pytorch.org/whl/$CUDA_VER"
    fi
fi

# ---------------------------------------------------------------------------
# 3. Install recognize-anything + pinned transformers
# ---------------------------------------------------------------------------
if ! "$VENV/bin/python" -c "import ram" 2>/dev/null; then
    echo "Installing recognize-anything with transformers==4.45.2 …"
    uv pip install --python "$VENV/bin/python" \
        "transformers==4.45.2" \
        timm pillow scipy fairscale \
        git+https://github.com/xinyu1205/recognize-anything.git
fi

# ---------------------------------------------------------------------------
# 4. Install Streamlit in the RAM venv
# ---------------------------------------------------------------------------
if ! "$VENV/bin/python" -c "import streamlit" 2>/dev/null; then
    echo "Installing streamlit …"
    uv pip install --python "$VENV/bin/python" streamlit
fi

# ---------------------------------------------------------------------------
# 5. Download weights
# ---------------------------------------------------------------------------
mkdir -p "$WEIGHTS_DIR"
if [ ! -f "$WEIGHTS_FILE" ]; then
    echo "Downloading RAM+ weights (~3 GB) …"
    "$VENV/bin/python" -c "
from huggingface_hub import hf_hub_download
path = hf_hub_download(
    repo_id='ma7583/ramplus',
    filename='ram_plus_swin_large_14m.pth',
    local_dir='$WEIGHTS_DIR',
)
print('Downloaded to:', path)
"
else
    echo "Weights already present at $WEIGHTS_FILE"
fi

echo ""
echo "Setup complete. Run the app with:"
echo "  $VENV/bin/streamlit run tests/explore_ram.py"

run streamlit for demo

"""RAM+ Video Object Explorer — Streamlit app.

Usage:
    streamlit run tests/explore_ram.py
"""

import json
import subprocess
import tempfile
from pathlib import Path
from PIL import Image
import streamlit as st
import torch

VIDEO_DIR  = Path(".")
WEIGHTS    = Path("models/ram_plus/ram_plus_swin_large_14m.pth")
CACHE_DIR  = Path("tests/mbs/ram_tags")
IMAGE_SIZE = 384

st.set_page_config(page_title="RAM+ Explorer", layout="wide")

# ---------------------------------------------------------------------------
# Load model
# ---------------------------------------------------------------------------

@st.cache_resource(show_spinner="Loading RAM+ model…")
def load_model(weights: str):
    from ram.models import ram_plus
    import torchvision.transforms as T

    device = "cuda" if torch.cuda.is_available() else "cpu"
    model = ram_plus(pretrained=weights, image_size=IMAGE_SIZE, vit="swin_l")
    model.eval().to(device)

    transform = T.Compose([
        T.Resize((IMAGE_SIZE, IMAGE_SIZE)),
        T.ToTensor(),
        T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ])
    return model, transform, device


if not WEIGHTS.exists():
    st.error(f"Weights not found at `{WEIGHTS}`. Run `bash run_ram_setup.sh` first.")
    st.stop()

model, transform, device = load_model(str(WEIGHTS))

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def extract_frames(video_path: Path, fps: float) -> list[tuple[float, Path]]:
    tmp = Path(tempfile.mkdtemp(prefix="ram-frames-"))
    subprocess.run(
        ["ffmpeg", "-y", "-i", str(video_path), "-vf", f"fps={fps}", "-q:v", "2",
         str(tmp / "frame_%05d.jpg")],
        capture_output=True, check=True, timeout=300,
    )
    frames = sorted(tmp.glob("frame_*.jpg"))
    return [(i / fps, p) for i, p in enumerate(frames)]


@torch.inference_mode()
def tag_frame(img_path: Path, threshold: float) -> list[str]:
    img = Image.open(img_path).convert("RGB")
    tensor = transform(img).unsqueeze(0).to(device)
    model.threshold = threshold
    tags, _ = model.generate_tag(tensor)
    return [t.strip() for t in tags[0].split("|") if t.strip()]


CACHE_DIR.mkdir(parents=True, exist_ok=True)

def cache_path(video_name: str, fps: float, threshold: float) -> Path:
    return CACHE_DIR / f"{Path(video_name).stem}_{fps}fps_t{threshold:.2f}.json"


@st.cache_data(show_spinner=False)
def get_tags(video_name: str, fps: float, threshold: float, video_dir: str) -> list[dict]:
    cp = cache_path(video_name, fps, threshold)
    if cp.exists():
        return json.loads(cp.read_text())

    frames = extract_frames(Path(video_dir) / video_name, fps)
    results = []
    bar = st.progress(0, text=f"Tagging {len(frames)} frames…")
    for i, (ts, fp) in enumerate(frames):
        results.append({"timestamp": round(ts, 2), "tags": tag_frame(fp, threshold), "frame": str(fp)})
        bar.progress((i + 1) / len(frames), text=f"Frame {i+1}/{len(frames)}")
    bar.empty()

    cp.write_text(json.dumps(results, ensure_ascii=False))
    return results

# ---------------------------------------------------------------------------
# UI
# ---------------------------------------------------------------------------

with st.sidebar:
    st.header("Settings")
    video_dir_input = st.text_input("Video directory", value=str(VIDEO_DIR))
    video_dir = Path(video_dir_input)

videos = sorted(p.name for p in video_dir.glob("*.mp4")) if video_dir.exists() else []
if not videos:
    st.error(f"No .mp4 files found in `{video_dir}`")
    st.stop()

with st.sidebar:
    video_name = st.selectbox(f"Video ({len(videos)} total)", videos)

col_search, col_fps, col_thresh = st.columns([4, 1, 1])
with col_search:
    tag_filter = st.text_input("Search tags", placeholder="e.g. person, shelf, phone")
with col_fps:
    fps = st.select_slider("Sampling fps", [0.25, 0.5, 1.0, 2.0], value=0.5)
with col_thresh:
    threshold = st.slider("RAM Threshold", 0.1, 0.95, 0.68, step=0.05)

cached = cache_path(video_name, fps, threshold).exists()
st.caption(f"{'✓ cached' if cached else '⚡ will run inference'}")

with st.spinner(f"Processing {video_name}…"):
    frames = get_tags(video_name, fps, threshold, str(video_dir))

# Filter by tag
if tag_filter.strip():
    needles = [n.strip().lower() for n in tag_filter.split(",") if n.strip()]
    frames = [f for f in frames if any(
        any(n in t.lower() for t in f["tags"]) for n in needles
    )]
    st.info(f"{len(frames)} frames match **{tag_filter}**")
else:
    # Show tag cloud when no filter active
    all_tags: dict[str, int] = {}
    for f in frames:
        for t in f["tags"]:
            all_tags[t] = all_tags.get(t, 0) + 1
    top = sorted(all_tags.items(), key=lambda x: -x[1])[:60]
    st.write("**All tags:** " + "  ·  ".join(f"`{t}` ({n})" for t, n in top))
    st.divider()

# Frame grid
if frames:
    cols = st.columns(4)
    for i, frame in enumerate(frames):
        with cols[i % 4]:
            st.image(frame["frame"], use_container_width=True)
            ts = frame["timestamp"]
            m, s = divmod(int(ts), 60)
            st.caption(f"**{m}:{s:02d}**  {' · '.join(frame['tags'][:5])}")
else:
    st.warning("No frames match the search.")
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support