SenseNova-Vision Unified Vision Model Deep Dive: One Model for Detection, Segmentation, Depth, 3D Reconstruction — Zero Architecture Changes, Surpassing All Specialized Models

Introduction

Computer vision has long suffered from the “one task, one model” fragmentation — DETR for detection, SAM for segmentation, MoGe for depth, VGGT for 3D reconstruction. Each model has a different architecture, different data format, and they are mutually incompatible. Autonomous driving requires running 3-4 separate models for detection, depth estimation, and scene understanding. Robotic grasping demands joint detection, segmentation, and depth reasoning.

In July 2026, SenseTime, in collaboration with Nanyang Technological University, Chinese University of Hong Kong, Peking University, Shanghai Jiao Tong University, and Zhejiang University, released SenseNova-Vision — a unified multimodal generation model that simultaneously handles detection, OCR, segmentation, depth estimation, normal prediction, multi-view 3D reconstruction, and camera pose estimation — surpassing the best specialized model in every single task.

Most critically: it adds no task-specific modules. Zero architectural changes.


1. Core Idea: All Vision Tasks Are “Look and Tell”

1.1 Unified Paradigm

SenseNova-Vision’s core approach is straightforward: convert all vision tasks into “look at the image and talk/generate.”

Whether outputting text coordinates like “wine glass at [100,200,300,400]”, generating a depth map, or producing mixed text-image grounded segmentation results, everything falls within the same multimodal generation framework. This is equivalent to transplanting ChatGPT’s “text-in → text-out” paradigm to the vision domain: input an image and a natural language instruction, and the output can be text, an image, or both — no task-specific prediction heads required.

1.2 Three Output Modes

SenseNova-Vision defines three unified output modes:

  1. Text QA mode: Outputs text results (detection coordinates, OCR text, classification labels)
  2. Image generation mode: Outputs images (depth maps, normal maps, segmentation masks)
  3. Mixed mode: Simultaneously outputs text and images (referring segmentation → mask + label)

2. Core Technology: Data Redefinition

2.1 SN-VC Dataset

The key to unification is not architecture modification, but redefining the input-output space. The team built the SenseNova-Vision Corpus (SN-VC), converting all heterogeneous CV annotations into “instruction-response” pairs.

"""
SenseNova-Vision Corpus: Unified task format conversion.
Transforms heterogeneous CV annotations into instruction-response pairs.
"""

import json
import numpy as np
from typing import Dict, List, Tuple, Union
from PIL import Image
import base64
from io import BytesIO

class UnifiedTaskFormatter:
    """
    Converts task-specific CV annotations into unified instruction-response format.
    Supports: detection, segmentation, depth, normal, OCR, 3D reconstruction, pose.
    """
    
    def __init__(self, image_size: Tuple[int, int] = (1024, 1024)):
        self.image_size = image_size
    
    def detection_to_instruction(
        self, image_path: str, bboxes: List[Dict],
        task_prompt: str = "Detect all objects in the image and output coordinates"
    ) -> Dict:
        """Convert COCO-style detection annotations to instruction-response pair."""
        response_parts = []
        for bbox in bboxes:
            x1, y1, x2, y2 = bbox['bbox']
            label = bbox['category_name']
            response_parts.append(f"{label} at [{x1:.3f},{y1:.3f},{x2:.3f},{y2:.3f}]")
        
        return {
            "image": image_path,
            "instruction": task_prompt,
            "response": ", ".join(response_parts),
            "task_type": "detection",
            "output_mode": "text"
        }
    
    def segmentation_to_instruction(
        self, image_path: str, mask: np.ndarray, label: str,
        task_prompt: str = "Segment the {label} in the image"
    ) -> Dict:
        """Convert segmentation mask to instruction-response pair."""
        mask_img = Image.fromarray((mask * 255).astype(np.uint8))
        buffer = BytesIO()
        mask_img.save(buffer, format='PNG')
        mask_b64 = base64.b64encode(buffer.getvalue()).decode()
        
        return {
            "image": image_path,
            "instruction": task_prompt.format(label=label),
            "response": f"<image>{mask_b64}</image>",
            "response_image": mask_b64,
            "task_type": "segmentation",
            "output_mode": "image"
        }
    
    def depth_to_instruction(
        self, image_path: str, depth_map: np.ndarray,
        task_prompt: str = "Estimate the depth map of this image"
    ) -> Dict:
        """Convert depth map to instruction-response pair."""
        depth_norm = ((depth_map - depth_map.min()) / 
                     (depth_map.max() - depth_map.min() + 1e-8) * 255)
        depth_img = Image.fromarray(depth_norm.astype(np.uint8))
        buffer = BytesIO()
        depth_img.save(buffer, format='PNG')
        depth_b64 = base64.b64encode(buffer.getvalue()).decode()
        
        return {
            "image": image_path,
            "instruction": task_prompt,
            "response": f"<image>{depth_b64}</image>",
            "response_image": depth_b64,
            "task_type": "depth_estimation",
            "output_mode": "image"
        }

2.2 Data Unification Principles

The SN-VC dataset follows three principles:

  1. Lossless conversion: All annotation information is fully preserved
  2. Natural language alignment: Every sample includes a natural language instruction
  3. Unified output format: All outputs collapse to three formats — text only, image only, or mixed

3. Model Architecture: Zero Changes

3.1 Backbone Selection

SenseNova-Vision is fine-tuned from Bagel-7B-MoT, a pre-trained image-text multimodal model. No task-specific decoders are added, and no network structure is modified. The unified capability comes entirely from data-level reformulation.

3.2 Training Pipeline

import torch
from torch.utils.data import DataLoader, Dataset
from transformers import AutoModelForVision2Seq, AutoProcessor
from typing import Dict, List
from PIL import Image

class UnifiedVisionDataset(Dataset):
    """Unified dataset for all vision tasks."""
    
    def __init__(self, unified_data: List[Dict], processor):
        self.data = unified_data
        self.processor = processor
    
    def __len__(self):
        return len(self.data)
    
    def __getitem__(self, idx):
        item = self.data[idx]
        image = Image.open(item['image']).convert('RGB')
        text = f"User: {item['instruction']}\nAssistant: {item['response']}"
        
        inputs = self.processor(
            images=image, text=text,
            return_tensors="pt", padding="max_length", max_length=2048,
        )
        
        return {
            'pixel_values': inputs['pixel_values'].squeeze(0),
            'input_ids': inputs['input_ids'].squeeze(0),
            'attention_mask': inputs['attention_mask'].squeeze(0),
            'labels': inputs['input_ids'].squeeze(0).clone(),
        }


class SenseNovaVisionTrainer:
    """Trainer — no architectural changes, pure data-driven unification."""
    
    def __init__(self, model_name: str = "OpenSenseNova/Bagel-7B-MoT",
                 learning_rate: float = 2e-5, batch_size: int = 32):
        self.model = AutoModelForVision2Seq.from_pretrained(
            model_name, torch_dtype=torch.bfloat16, device_map="auto"
        )
        self.processor = AutoProcessor.from_pretrained(model_name)
        self.optimizer = torch.optim.AdamW(self.model.parameters(), lr=learning_rate)
        self.batch_size = batch_size
    
    def train_epoch(self, dataloader: DataLoader) -> float:
        self.model.train()
        total_loss = 0.0
        
        for batch in dataloader:
            pixel_values = batch['pixel_values'].to(self.model.device)
            input_ids = batch['input_ids'].to(self.model.device)
            attention_mask = batch['attention_mask'].to(self.model.device)
            labels = batch['labels'].to(self.model.device)
            
            outputs = self.model(
                pixel_values=pixel_values, input_ids=input_ids,
                attention_mask=attention_mask, labels=labels,
            )
            
            loss = outputs.loss
            loss.backward()
            self.optimizer.step()
            self.optimizer.zero_grad()
            total_loss += loss.item()
        
        return total_loss / len(dataloader)

3.3 Output Decoding

package sensenova

import (
	"image"
	"strings"
)

// DetectionResult represents parsed detection output
type DetectionResult struct {
	Label string
	BBox  [4]float64
}

// ParseDetectionOutput parses text output for detection
func ParseDetectionOutput(text string) []DetectionResult {
	var results []DetectionResult
	parts := strings.Split(text, ", ")
	
	for _, part := range parts {
		openBracket := strings.Index(part, "[")
		closeBracket := strings.Index(part, "]")
		if openBracket < 0 || closeBracket <= openBracket {
			continue
		}
		
		label := strings.TrimSpace(part[:openBracket])
		label = strings.TrimRight(label, " at")
		
		coordStr := part[openBracket+1 : closeBracket]
		coords := strings.Split(coordStr, ",")
		if len(coords) != 4 {
			continue
		}
		
		var bbox [4]float64
		for i, c := range coords {
			val, _ := parseFloat(strings.TrimSpace(c))
			bbox[i] = val
		}
		results = append(results, DetectionResult{Label: label, BBox: bbox})
	}
	return results
}

// DepthMapResult represents parsed depth estimation output
type DepthMapResult struct {
	DepthMap [][]float32
}

// DecodeDepthMap decodes image output to depth map
func DecodeDepthMap(img image.Image) *DepthMapResult {
	bounds := img.Bounds()
	height := bounds.Dy()
	width := bounds.Dx()
	
	depthMap := make([][]float32, height)
	for y := 0; y < height; y++ {
		depthMap[y] = make([]float32, width)
		for x := 0; x < width; x++ {
			r, g, b, _ := img.At(x, y).RGBA()
			gray := float32(r+g+b) / (3.0 * 65535.0)
			depthMap[y][x] = gray
		}
	}
	return &DepthMapResult{DepthMap: depthMap}
}

4. Experimental Results

Task CategoryMetricSenseNova-VisionBest SpecializedImprovement
Structured PerceptionDetection F1@mIoU56.6Rex-Omni 52.9+7.0%
Dense GeometryDepth δ193.2MoGe-2 92.6+0.6%
SegmentationGCG mIoU69.2LISA 61.9+11.8%
Multi-view 3DReconstruction F187.9VGGT 84.3+4.3%

5. Conclusion

SenseNova-Vision proves that a unified multimodal generation model can handle seven major vision tasks simultaneously and surpass specialized models. Its core contribution is not a new network architecture, but demonstrating that data redefinition matters more than architecture innovation — by converting heterogeneous vision annotations into unified “instruction-response” pairs, any pre-trained multimodal model can learn general vision capabilities.


References

  1. SenseTime, “Vision as Unified Multimodal Generation,” arXiv:2607.06560, 2026.
  2. OpenSenseNova, “SenseNova-Vision: Unified Vision Model,” GitHub, 2026.