11 KiB
TVP tvp
๊ฐ์ overview
Text-Visual Prompting(TVP) ํ๋ ์์ํฌ๋ Yimeng Zhang, Xin Chen, Jinghan Jia, Sijia Liu, Ke Ding์ด ๋ฐํํ ๋ ผ๋ฌธ Text-Visual Prompting for Efficient 2D Temporal Video Grounding์์ ์ ์๋์์ต๋๋ค.
๋ ผ๋ฌธ์ ์ด๋ก์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
๋ณธ ๋ ผ๋ฌธ์์๋ ๊ธธ๊ณ , ํธ์ง๋์ง ์์ ๋น๋์ค์์ ๋ฌธ์ฅ์ผ๋ก ์ค๋ช ๋ ์๊ฐ์ ์์/์ข ๋ฃ ์์ ์ ์์ธกํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ๋ Temporal Video Grounding(TVG) ๋ฌธ์ ๋ฅผ ๋ค๋ฃน๋๋ค. ์ธ๋ฐํ 3D ์๊ฐ์ ํน์ง ๋๋ถ์ TVG ๊ธฐ์ ์ ์ต๊ทผ ๋ช ๋ ๋์ ๋๋ผ์ด ๋ฐ์ ์ ์ด๋ค์ต๋๋ค. ํ์ง๋ง 3D ํฉ์ฑ๊ณฑ ์ ๊ฒฝ๋ง(CNN)์ ๋์ ๋ณต์ก์ฑ์ผ๋ก ์ธํด ๋ฐ๋ ๋์ 3D ์๊ฐ์ ํน์ง์ ์ถ์ถํ๋ ๋ฐ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๊ณ ๊ทธ๋งํผ ๋ง์ ๋ฉ๋ชจ๋ฆฌ์ ์ฐ์ฐ ์์์ ํ์๋ก ํฉ๋๋ค. ํจ์จ์ ์ธ TVG๋ฅผ ์ํด, ๋ณธ ๋ ผ๋ฌธ์์๋ TVG ๋ชจ๋ธ์ ์๊ฐ์ ์ ๋ ฅ๊ณผ ํ ์คํธ ํน์ง ๋ชจ๋์ ์ต์ ํ๋ ๊ต๋ ํจํด('ํ๋กฌํํธ'๋ผ๊ณ ๋ถ๋ฆ)์ ํตํฉํ๋ ์๋ก์ด Text-Visual Prompting(TVP) ํ๋ ์์ํฌ๋ฅผ ์ ์ํฉ๋๋ค. 3D CNN๊ณผ ๋๋ ท์ด ๋๋น๋๊ฒ TVP๊ฐ 2D TVG ๋ชจ๋ธ์์ ๋น์ ์ธ์ฝ๋์ ์ธ์ด ์ธ์ฝ๋๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ณต๋ ํ์ตํ ์ ์๊ฒ ํ๊ณ , ๋ฎ์ ๋ณต์ก๋์ ํฌ์ํ 2D ์๊ฐ์ ํน์ง๋ง์ ์ฌ์ฉํ์ฌ ํฌ๋ก์ค ๋ชจ๋ฌ ํน์ง ์ตํฉ์ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค. ๋ ๋์๊ฐ, TVG์ ํจ์จ์ ์ธ ํ์ต์ ์ํด Temporal-Distance IoU(TDIoU) ์์ค ํจ์๋ฅผ ์ ์ํฉ๋๋ค. ๋ ๊ฐ์ ๋ฒค์น๋งํฌ ๋ฐ์ดํฐ ์ธํธ์ธ Charades-STA์ ActivityNet Captions ๋ฐ์ดํฐ์ ์ ๋ํ ์คํ์ ํตํด, ์ ์๋ TVP๊ฐ 2D TVG์ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํค๊ณ (์: Charades-STA์์ 9.79% ํฅ์, ActivityNet Captions์์ 30.77% ํฅ์) 3D ์๊ฐ์ ํน์ง์ ์ฌ์ฉํ๋ TVG์ ๋นํด 5๋ฐฐ์ ์ถ๋ก ๊ฐ์์ ๋ฌ์ฑํจ์ ์คํ์ ์ผ๋ก ์ ์ฆํฉ๋๋ค.
์ด ์ฐ๊ตฌ๋ Temporal Video Grounding(TVG)์ ๋ค๋ฃน๋๋ค. TVG๋ ๋ฌธ์ฅ์ผ๋ก ์ค๋ช ๋ ํน์ ์ด๋ฒคํธ์ ์์ ๋ฐ ์ข ๋ฃ ์์ ์ ๊ธด ๋น๋์ค์์ ์ ํํ ์ฐพ์๋ด๋ ๊ณผ์ ์ ๋๋ค. TVG ์ฑ๋ฅ์ ํฅ์์ํค๊ธฐ ์ํด Text-Visual Prompting(TVP)์ด ์ ์๋์์ต๋๋ค. TVP๋ 'ํ๋กฌํํธ'๋ผ๊ณ ์๋ ค์ง ํน๋ณํ ์ค๊ณ๋ ํจํด์ TVG ๋ชจ๋ธ์ ์๊ฐ์ (์ด๋ฏธ์ง ๊ธฐ๋ฐ) ๋ฐ ํ ์คํธ(๋จ์ด ๊ธฐ๋ฐ) ์ ๋ ฅ ๊ตฌ์ฑ ์์ ๋ชจ๋์ ํตํฉํ๋ ๊ฒ์ ๋ฐฉ์์ ๋๋ค. ์ด ํ๋กฌํํธ๋ ์ถ๊ฐ์ ์ธ ์๊ณต๊ฐ์ ์ปจํ ์คํธ๋ฅผ ์ ๊ณตํจ์ผ๋ก์จ ๋ชจ๋ธ์ด ๋น๋์ค ๋ด ์ด๋ฒคํธ ์์ ์ ์์ธก ์ ํ๋๋ฅผ ๋์ ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ 3D ์๊ฐ์ ์ ๋ ฅ ๋์ 2D ์ ๋ ฅ์ ์ฌ์ฉํฉ๋๋ค. 3D ์ ๋ ฅ์ ๋ณด๋ค ํ๋ถํ ์๊ณต๊ฐ์ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ง๋ง ์ฒ๋ฆฌํ๋ ๋ฐ ์๊ฐ์ด ๋ ๋ง์ด ๊ฑธ๋ฆฝ๋๋ค. ๋ฐ๋ผ์ ํ๋กฌํํ ๋ฉ์๋์ ํจ๊ป 2D ์ ๋ ฅ์ ์ฌ์ฉํ์ฌ ์ด์ ์ ์ฌํ ์์ค์ ์ปจํ ์คํธ์ ์ ํ๋๋ฅผ ๋ ํจ์จ์ ์ผ๋ก ์ ๊ณตํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
TVP ์ํคํ ์ฒ. ์๋ณธ ๋ ผ๋ฌธ์์ ๋ฐ์ท.
์ด ๋ชจ๋ธ์ Jiqing Feng๋์ด ๊ธฐ์ฌํ์ต๋๋ค. ์๋ณธ ์ฝ๋๋ ์ด ๊ณณ์์ ์ฐพ์ ์ ์์ต๋๋ค.
์ฌ์ฉ ํ ๋ฐ ์์ usage-tips-and-examples
ํ๋กฌํํธ๋ ์ต์ ํ๋ ๊ต๋ ํจํด์ผ๋ก ์ ๋ ฅ ๋น๋์ค ํ๋ ์์ด๋ ํ ์คํธ ํน์ง์ ์ถ๊ฐ๋๋ ํจํด์ ๋๋ค. ๋ฒ์ฉ ์ธํธ๋ ๋ชจ๋ ์ ๋ ฅ์ ๋ํด ๋์ผํ ํ๋กฌํํธ ์ธํธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋งํฉ๋๋ค. ์ฆ, ์ ๋ ฅ ๋ด์ฉ๊ณผ ๊ด๊ณ์์ด ๋ชจ๋ ๋น๋์ค ํ๋ ์๊ณผ ํ ์คํธ ํน์ง์ ์ด ํ๋กฌํํธ๋ค์ ์ผ๊ด์ ์ผ๋ก ์ถ๊ฐํฉ๋๋ค.
TVP๋ ์๊ฐ ์ธ์ฝ๋์ ํฌ๋ก์ค ๋ชจ๋ฌ ์ธ์ฝ๋๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ๋ฒ์ฉ ์๊ฐ ํ๋กฌํํธ์ ํ ์คํธ ํ๋กฌํํธ ์ธํธ๊ฐ ๊ฐ๊ฐ ์ํ๋ง๋ ๋น๋์ค ํ๋ ์๊ณผ ํ ์คํธ ํน์ง์ ํตํฉ๋ฉ๋๋ค. ํนํ, ์๋ก ๋ค๋ฅธ ์๊ฐ ํ๋กฌํํธ ์ธํธ๊ฐ ํธ์ง๋์ง ์์ ํ ๋น๋์ค์์ ๊ท ์ผํ๊ฒ ์ํ๋ง๋ ํ๋ ์์ ์์๋๋ก ์ ์ฉ๋ฉ๋๋ค.
์ด ๋ชจ๋ธ์ ๋ชฉํ๋ ํ์ต ๊ฐ๋ฅํ ํ๋กฌํํธ๋ฅผ ์๊ฐ์ ์ ๋ ฅ๊ณผ ํ ์คํธ ํน์ง ๋ชจ๋์ ํตํฉํ์ฌ Temporal Video Grounding(TVG) ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ ๋๋ค.
์์น์ ์ผ๋ก, ์ ์๋ ์ํคํ ์ฒ์๋ ์ด๋ค ์๊ฐ ์ธ์ฝ๋๋ ํฌ๋ก์ค ๋ชจ๋ฌ ์ธ์ฝ๋๋ผ๋ ์ ์ฉํ ์ ์์ต๋๋ค.
[TvpProcessor]๋ [BertTokenizer]์ [TvpImageProcessor]๋ฅผ ๋จ์ผ ์ธ์คํด์ค๋ก ๋ํํ์ฌ ํ ์คํธ๋ฅผ ์ธ์ฝ๋ฉํ๊ณ ์ด๋ฏธ์ง๋ฅผ ๊ฐ๊ฐ ์ค๋นํฉ๋๋ค.
๋ค์ ์์๋ [TvpProcessor]์ [TvpForVideoGrounding]์ ์ฌ์ฉํ์ฌ TVG๋ฅผ ์คํํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
import av
import cv2
import numpy as np
import torch
from huggingface_hub import hf_hub_download
from transformers import AutoProcessor, TvpForVideoGrounding
def pyav_decode(container, sampling_rate, num_frames, clip_idx, num_clips, target_fps):
'''
์๋ณธ fps์ ๋น๋์ค๋ฅผ ์ง์ ํ fps(target_fps)๋ก ๋ณํํ๊ณ PyAV ๋์ฝ๋๋ก ๋น๋์ค๋ฅผ ๋์ฝ๋ฉํฉ๋๋ค.
Args:
container (container): pyav ์ปจํ
์ด๋ ๊ฐ์ฒด์
๋๋ค.
sampling_rate (int): ํ๋ ์ ์ํ๋ง ์๋์
๋๋ค.(์ํ๋ง๋ ๋๊ฐ์ ํ๋ ์ ์ฌ์ด์ ๊ฐ๊ฒฉ์ ๋งํฉ๋๋ค)
num_frames (int): ์ํ๋งํ ํ๋ ์ ์์
๋๋ค.
clip_idx (int): clip_idx๊ฐ -1์ด๋ฉด ์๊ฐ ์ถ์์ ๋ฌด์์ ์ํ๋ง์ ์ํํฉ๋๋ค.
clip_idx๊ฐ -1๋ณด๋ค ํฌ๋ฉด ๋น๋์ค๋ฅผ num_clips ๊ฐ๋ก ๊ท ๋ฑ ๋ถํ ํ ํ
clip_idx๋ฒ์งธ ๋น๋์ค ํด๋ฆฝ์ ์ ํํฉ๋๋ค.
num_clips (int): ์ฃผ์ด์ง ๋น๋์ค์์ ๊ท ์ผํ๊ฒ ์ํ๋งํ ์ ์ฒด ํด๋ฆฝ ์์
๋๋ค.
target_fps (int): ์
๋ ฅ ๋น๋์ค์ fps๊ฐ ๋ค๋ฅผ ์ ์์ผ๋ฏ๋ก, ์ํ๋ง ์ ์
์ง์ ํ fps๋ก ๋ณํํฉ๋๋ค
Returns:
frames (tensor): ๋น๋์ค์์ ๋์ฝ๋ฉ๋ ํ๋ ์์
๋๋ค. ๋น๋์ค ์คํธ๋ฆผ์ ์ฐพ์ ์ ์๋ ๊ฒฝ์ฐ
None์ ๋ฐํํฉ๋๋ค.
fps (float): ๋น๋์ค์ ์ด๋น ํ๋ ์ ์์
๋๋ค.
'''
video = container.streams.video[0]
fps = float(video.average_rate)
clip_size = sampling_rate * num_frames / target_fps * fps
delta = max(num_frames - clip_size, 0)
start_idx = delta * clip_idx / num_clips
end_idx = start_idx + clip_size - 1
timebase = video.duration / num_frames
video_start_pts = int(start_idx * timebase)
video_end_pts = int(end_idx * timebase)
seek_offset = max(video_start_pts - 1024, 0)
container.seek(seek_offset, any_frame=False, backward=True, stream=video)
frames = {}
for frame in container.decode(video=0):
if frame.pts < video_start_pts:
continue
frames[frame.pts] = frame
if frame.pts > video_end_pts:
break
frames = [frames[pts] for pts in sorted(frames)]
return frames, fps
def decode(container, sampling_rate, num_frames, clip_idx, num_clips, target_fps):
'''
๋น๋์ค๋ฅผ ๋์ฝ๋ฉํ๊ณ ์๊ฐ ์ถ ์ํ๋ง์ ์ํํฉ๋๋ค.
Args:
container (container): pyav ์ปจํ
์ด๋ ๊ฐ์ฒด์
๋๋ค.
sampling_rate (int): ํ๋ ์ ์ํ๋ง ์๋์
๋๋ค.(์ํ๋ง๋ ๋๊ฐ์ ํ๋ ์ ์ฌ์ด์ ๊ฐ๊ฒฉ์ ๋งํฉ๋๋ค)
num_frames (int): ์ํ๋งํ ํ๋ ์ ์์
๋๋ค.
clip_idx (int): clip_idx๊ฐ -1์ด๋ฉด ์๊ฐ ์ถ์์ ๋ฌด์์ ์ํ๋ง์ ์ํํฉ๋๋ค.
clip_idx๊ฐ -1๋ณด๋ค ํฌ๋ฉด ๋น๋์ค๋ฅผ num_clips ๊ฐ๋ก ๊ท ๋ฑ ๋ถํ ํ ํ
clip_idx๋ฒ์งธ ๋น๋์ค ํด๋ฆฝ์ ์ ํํฉ๋๋ค.
num_clips (int): ์ฃผ์ด์ง ๋น๋์ค์์ ๊ท ์ผํ๊ฒ ์ํ๋งํ ์ ์ฒด ํด๋ฆฝ ์์
๋๋ค.
target_fps (int): ์
๋ ฅ ๋น๋์ค์ fps๊ฐ ๋ค๋ฅผ ์ ์์ผ๋ฏ๋ก, ์ํ๋ง ์ ์
์ง์ ํ fps๋ก ๋ณํํฉ๋๋ค
Returns:
frames (tensor): ๋น๋์ค์์ ๋์ฝ๋ฉ๋ ํ๋ ์์
๋๋ค.
'''
assert clip_idx >= -2, "Not a valid clip_idx {}".format(clip_idx)
frames, fps = pyav_decode(container, sampling_rate, num_frames, clip_idx, num_clips, target_fps)
clip_size = sampling_rate * num_frames / target_fps * fps
index = np.linspace(0, clip_size - 1, num_frames)
index = np.clip(index, 0, len(frames) - 1).astype(np.int64)
frames = np.array([frames[idx].to_rgb().to_ndarray() for idx in index])
frames = frames.transpose(0, 3, 1, 2)
return frames
file = hf_hub_download(repo_id="Intel/tvp_demo", filename="AK2KG.mp4", repo_type="dataset")
model = TvpForVideoGrounding.from_pretrained("Intel/tvp-base")
decoder_kwargs = dict(
container=av.open(file, metadata_errors="ignore"),
sampling_rate=1,
num_frames=model.config.num_frames,
clip_idx=0,
num_clips=1,
target_fps=3,
)
raw_sampled_frms = decode(**decoder_kwargs)
text = "a person is sitting on a bed."
processor = AutoProcessor.from_pretrained("Intel/tvp-base")
model_inputs = processor(
text=[text], videos=list(raw_sampled_frms), return_tensors="pt", max_text_length=100#, size=size
)
model_inputs["pixel_values"] = model_inputs["pixel_values"].to(model.dtype)
output = model(**model_inputs)
def get_video_duration(filename):
cap = cv2.VideoCapture(filename)
if cap.isOpened():
rate = cap.get(5)
frame_num = cap.get(7)
duration = frame_num/rate
return duration
return -1
duration = get_video_duration(file)
start, end = processor.post_process_video_grounding(output.logits, duration)
print(f"The time slot of the video corresponding to the text \"{text}\" is from {start}s to {end}s")
ํ:
- ์ด TVP ๊ตฌํ์ ํ ์คํธ ์๋ฒ ๋ฉ์ ์์ฑํ๊ธฐ ์ํด [BertTokenizer]๋ฅผ ์ฌ์ฉํ๊ณ , ์๊ฐ์ ์๋ฒ ๋ฉ์ ๊ณ์ฐํ๊ธฐ ์ํด Resnet-50 ๋ชจ๋ธ์ ์ฌ์ฉํฉ๋๋ค.
- ์ฌ์ ํ์ต๋ tvp-base์ ์ฒดํฌํฌ์ธํธ๊ฐ ๊ณต๊ฐ๋์ด ์์ต๋๋ค.
- ์๊ฐ์ ๋น๋์ค ๊ทธ๋ผ์ด๋ฉ ์์ ์ ๋ํ TVP์ ์ฑ๋ฅ์ ํ 2๋ฅผ ์ฐธ๊ณ ํ์ธ์.
TvpConfig transformers.TvpConfig
autodoc TvpConfig
TvpImageProcessor transformers.TvpImageProcessor
autodoc TvpImageProcessor - preprocess
TvpProcessor transformers.TvpProcessor
autodoc TvpProcessor - call
TvpModel transformers.TvpModel
autodoc TvpModel - forward
TvpForVideoGrounding transformers.TvpForVideoGrounding
autodoc TvpForVideoGrounding - forward
