multimodalart HF Staff commited on
Commit
966ec4e
·
verified ·
1 Parent(s): 2af9d0f

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ examples/realworld_insert_cylinder.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ examples/sim_microwave_spoon.mp4 filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,13 +1,31 @@
1
  ---
2
- title: Robofac
3
- emoji: 👀
4
- colorFrom: yellow
5
- colorTo: red
6
  sdk: gradio
7
  sdk_version: 6.30.0
8
- python_version: '3.12'
9
  app_file: app.py
10
- pinned: false
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: RoboFAC-7B
3
+ emoji: 🤖
4
+ colorFrom: blue
5
+ colorTo: gray
6
  sdk: gradio
7
  sdk_version: 6.30.0
 
8
  app_file: app.py
9
+ short_description: Analyze robot manipulation videos for failures
10
+ python_version: "3.10"
11
+ startup_duration_timeout: 1h
12
  ---
13
 
14
+ # RoboFAC-7B — Robotic Failure Analysis & Correction
15
+
16
+ Demo of [`MINT-SJTU/RoboFAC-7B`](https://huggingface.co/MINT-SJTU/RoboFAC-7B), a 7B vision-language model fine-tuned from Qwen2.5-VL-7B-Instruct for analyzing robot-manipulation videos: task identification and planning, failure detection / identification / locating / explanation, and both high-level and low-level correction guidance.
17
+
18
+ Upload a video of a robot arm performing a task and ask a question about it. Following the authors' reference pipeline ([mint-sjtu/robofac](https://github.com/mint-sjtu/robofac), `evaluation/eval_utils.py`), the app samples one keyframe per second from the video, resizes each frame to 512×512, and feeds all frames to the model together with the question in a single user message.
19
+
20
+ ## Example videos
21
+
22
+ The bundled example videos are test clips from the [`MINT-SJTU/RoboFAC-dataset`](https://huggingface.co/datasets/MINT-SJTU/RoboFAC-dataset) (MIT license):
23
+
24
+ - `examples/sim_microwave_spoon.mp4` — simulation, *MicrowaveTask* (put the spoon in the mug, then both in the microwave; the grasp fails).
25
+ - `examples/realworld_insert_cylinder.mp4` — real-world SO-100 arm, *InsertCylinder* (insert a cylinder into a shelf hole; the reach is misaligned).
26
+
27
+ The example questions are the authors' own test QA prompts from the dataset's `test_qa_sim` / `test_qa_realworld` annotations.
28
+
29
+ ## Paper
30
+
31
+ [RoboFAC: A Comprehensive Framework for Robotic Failure Analysis and Correction](https://huggingface.co/papers/2505.12224) (arXiv:2505.12224).
app.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
4
+
5
+ import spaces # MUST come before torch / transformers
6
+ import time
7
+
8
+ import cv2
9
+ import gradio as gr
10
+ import numpy as np
11
+ import torch
12
+ from transformers import AutoProcessor, Qwen2_5_VLForConditionalGeneration
13
+
14
+ MODEL_ID = "MINT-SJTU/RoboFAC-7B"
15
+ FRAME_INTERVAL = 30 # sample one keyframe per second at the dataset's 30 Hz
16
+ FRAME_SIZE = 512 # frames are resized to 512x512, matching the paper's eval pipeline
17
+ MAX_FRAMES = 32 # safety cap so a very long upload cannot blow the context
18
+
19
+ processor = AutoProcessor.from_pretrained(MODEL_ID)
20
+ model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
21
+ MODEL_ID,
22
+ dtype=torch.bfloat16,
23
+ attn_implementation="sdpa",
24
+ ).to("cuda")
25
+ model.eval()
26
+
27
+
28
+ def extract_keyframes(video_path: str) -> list[np.ndarray]:
29
+ """Decode a video and return one keyframe per second, resized to 512x512 RGB.
30
+
31
+ This mirrors the authors' reference pipeline (evaluation/eval_utils.py in
32
+ mint-sjtu/robofac): cv2 decodes the stream, every FRAME_INTERVAL-th frame is
33
+ kept, resized to (512, 512), and JPEG-encoded before being sent to the model.
34
+ """
35
+ cap = cv2.VideoCapture(video_path)
36
+ if not cap.isOpened():
37
+ raise ValueError(f"Could not open video: {video_path}")
38
+ frames = []
39
+ count = 0
40
+ ok, frame = cap.read()
41
+ while ok:
42
+ if count % FRAME_INTERVAL == 0:
43
+ frame = cv2.resize(frame, (FRAME_SIZE, FRAME_SIZE))
44
+ # cv2 decodes BGR; imencode expects BGR input, so the reference pipeline
45
+ # produces correctly-colored JPEGs. We convert to RGB for the processor.
46
+ frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
47
+ frames.append(frame)
48
+ if len(frames) >= MAX_FRAMES:
49
+ break
50
+ count += 1
51
+ ok, frame = cap.read()
52
+ cap.release()
53
+ if not frames:
54
+ raise ValueError("No frames could be decoded from the video.")
55
+ return frames
56
+
57
+
58
+ @spaces.GPU(duration=120)
59
+ def analyze(
60
+ video: str | None,
61
+ question: str,
62
+ max_new_tokens: int = 512,
63
+ progress=gr.Progress(),
64
+ ) -> str:
65
+ """Analyze a robot-manipulation video with RoboFAC-7B and answer a question.
66
+
67
+ Args:
68
+ video: filepath of an uploaded robot-manipulation video.
69
+ question: the question to ask about the video (task identification,
70
+ failure detection/explanation, correction guidance, ...).
71
+ max_new_tokens: maximum number of new tokens to generate.
72
+ progress: Gradio progress bar (injected automatically).
73
+ Returns:
74
+ The model's textual analysis/answer.
75
+ """
76
+ if not question or not question.strip():
77
+ raise gr.Error("Please enter a question about the video.")
78
+ if not video:
79
+ raise gr.Error("Please upload a video first.")
80
+
81
+ t0 = time.perf_counter()
82
+ frames = extract_keyframes(video)
83
+ progress((0.2, 0.9), desc=f"Extracted {len(frames)} keyframes")
84
+
85
+ # Reference prompt format: all frames as image blocks + the question in a
86
+ # single user message (no answer-format suffixes for RoboFAC).
87
+ conversation = [
88
+ {
89
+ "role": "user",
90
+ "content": [
91
+ *[{"type": "image", "image": f} for f in frames],
92
+ {"type": "text", "text": question.strip()},
93
+ ],
94
+ }
95
+ ]
96
+ inputs = processor.apply_chat_template(
97
+ conversation,
98
+ tokenize=True,
99
+ add_generation_prompt=True,
100
+ return_dict=True,
101
+ return_tensors="pt",
102
+ ).to("cuda")
103
+
104
+ with torch.inference_mode():
105
+ generated = model.generate(
106
+ **inputs,
107
+ max_new_tokens=int(max_new_tokens),
108
+ do_sample=False,
109
+ )
110
+
111
+ generated = generated[:, inputs["input_ids"].shape[1]:]
112
+ answer = processor.batch_decode(generated, skip_special_tokens=True)[0].strip()
113
+ elapsed = time.perf_counter() - t0
114
+ return f"{answer}\n\n_({len(frames)} keyframes · {elapsed:.1f}s on GPU)_"
115
+
116
+
117
+ CSS = """
118
+ #col-container { max-width: 1100px; margin: 0 auto; }
119
+ .dark .gradio-container { color: var(--body-text-color); }
120
+ """
121
+
122
+ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
123
+ with gr.Column(elem_id="col-container"):
124
+ gr.Markdown(
125
+ """
126
+ # 🤖 RoboFAC-7B — Robotic Failure Analysis & Correction
127
+
128
+ Upload a video of a robot arm performing a manipulation task and ask
129
+ anything about it: what the task is, whether it succeeded, why it
130
+ failed, or how to correct the failure. The model samples one
131
+ keyframe per second from the video and answers in text.
132
+
133
+ **Model**: [`MINT-SJTU/RoboFAC-7B`](https://huggingface.co/MINT-SJTU/RoboFAC-7B) ·
134
+ **Paper**: [RoboFAC](https://huggingface.co/papers/2505.12224) ·
135
+ **Code**: [mint-sjtu/robofac](https://github.com/mint-sjtu/robofac)
136
+ """
137
+ )
138
+ with gr.Row():
139
+ with gr.Column(scale=1):
140
+ video_in = gr.Video(label="Robot manipulation video")
141
+ question_in = gr.Textbox(
142
+ label="Question",
143
+ placeholder="e.g. Did the robot finish the task? If not, why did it fail?",
144
+ lines=2,
145
+ )
146
+ run_btn = gr.Button("Analyze", variant="primary")
147
+ with gr.Accordion("Advanced", open=False):
148
+ max_new_tokens = gr.Slider(
149
+ minimum=64, maximum=2048, value=512, step=64,
150
+ label="Max new tokens",
151
+ )
152
+ run_btn.click(
153
+ analyze,
154
+ inputs=[video_in, question_in, max_new_tokens],
155
+ outputs=answer_out,
156
+ api_name="analyze",
157
+ )
158
+ with gr.Column(scale=1):
159
+ answer_out = gr.Textbox(
160
+ label="Analysis",
161
+ lines=14,
162
+ show_copy_button=True,
163
+ )
164
+
165
+ gr.Examples(
166
+ examples=[
167
+ ["examples/sim_microwave_spoon.mp4",
168
+ "Please describe the task the robot is performing in the video."],
169
+ ["examples/sim_microwave_spoon.mp4",
170
+ "Based on the video, provide a detailed explanation of why the robotic arm failed to complete the task."],
171
+ ["examples/realworld_insert_cylinder.mp4",
172
+ "In the video, the robotic arm executes a task, was it successful?"],
173
+ ["examples/realworld_insert_cylinder.mp4",
174
+ "Based on the video, an error happened while the robot was executing a task, give detailed low-level instructions to correct the issue and allow the task to be finished."],
175
+ ],
176
+ inputs=[video_in, question_in],
177
+ outputs=answer_out,
178
+ fn=analyze,
179
+ cache_examples=True,
180
+ cache_mode="lazy",
181
+ label="Try the authors' test questions (from the RoboFAC dataset)",
182
+ )
183
+
184
+ demo.launch(mcp_server=True)
examples/realworld_insert_cylinder.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d7462a75cb2b197c9134a880b7ec104e9b5c9f73ffbbb8074896191a5c214c21
3
+ size 2243206
examples/sim_microwave_spoon.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9dc8a0040b71daac0103357ed16cf502c9467d4badd8b0c28d0ad78928f4f13f
3
+ size 1629940
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ transformers
4
+ accelerate
5
+ opencv-python-headless
6
+ numpy
7
+ pillow