데이터 과학자가 야생동물의 행동을 연구하고 외딴 숲에 있는 카메라에서 촬영된 수백 시간 분량의 비디오 영상을 분석한다고 상상해 보세요. 또는 새로운 전략을 개발하기 위해 전체 시즌 경기에서 주요 플레이를 식별해야 하는 스포츠 코치도 있습니다. 또는 대규모 비디오 갤러리에서 특정 장면을 검색하여 다큐멘터리를 구성하는 영화 제작자를 생각해 보세요.
전통적으로 이러한 전문가들은 모두 시간이 많이 걸리고 오류가 발생하기 쉬우며 끝없는 시간의 영상을 수동으로 분류해야 하는 압도적인 과제에 직면해 있습니다.
그러나 인공 지능과 기계 학습의 발전은 비디오 검색 애플리케이션을 극적으로 변화시켰습니다. 이제 이러한 기술을 통해 우리는 광범위한 비디오 데이터 세트 내에서 믿을 수 없을 만큼 정교하게 특정 개체와 이벤트를 검색할 수 있습니다. 데이터 과학자와 연구자는 탁월한 정확성과 효율성으로 관련 비디오 세그먼트를 정확히 찾아낼 수 있습니다.
목표는 사용자가 매우 큰 비디오 데이터 세트에서 특정 콘텐츠나 속성이 포함된 영상을 쉽게 찾을 수 있도록 고급 검색 기능을 제공하여 연구 프로세스를 단순화하는 것이었습니다.
OpenOrigins는 정교한 검색 알고리즘과 사용자 친화적인 인터페이스를 사용하여 플랫폼을 이 커뮤니티의 중요한 도구로 만드는 것을 목표로 했습니다.
OpenOrigins는 이 비디오 검색 서비스를 구축하기 위해 이미지 임베딩을 사용한 프레임 검색과 다중 모드 임베딩이라는 두 가지 기술적 접근 방식을 고려했습니다. 각 옵션을 살펴보겠습니다.
"자연 서식지에 있는 사슴을 보여주는 비디오 콘텐츠가 몇 분 정도 있습니까?"와 같은 복잡한 질문에 답하기 위해 비디오에 대한 의미 검색을 활성화합니다. 기본적인 키워드 메타데이터 매칭을 넘어 영상의 내용을 이해하고 해석할 수 있는 정교한 검색 기능이 필요합니다. 이것을 달성하는 열쇠는 무엇입니까? 다중 모드 임베딩.
다중 모드 임베딩 모델과 다중 모드 대형 언어 모델(LLM)은 유사한 솔루션으로 볼 수 있습니다. CLIP 및 Google 멀티모달 임베딩과 같은 모델은 텍스트, 이미지, 비디오와 같은 데이터 유형에 대한 임베딩을 생성하여 의미론적 의미를 포착하는 고차원 벡터를 생성합니다. 이를 통해 의미 검색, 콘텐츠 검색, 유사성 감지와 같은 애플리케이션이 가능해집니다.
반면, GPT-4(다중 모드 기능 포함), Flamingo 및 Gemini와 같은 다중 모드 LLM은 다양한 유형의 데이터에서 콘텐츠를 이해하고 생성하도록 설계되었습니다.
이러한 모델은 다중 모드 입력(예: 텍스트 및 이미지)을 사용하고 다중 모드 출력을 생성하여 대화형 AI 및 콘텐츠 생성과 같은 복잡한 작업을 효과적으로 수행하여 의미 있고 상황에 따라 풍부한 응답을 제공합니다.
임베딩 모델은 효율적인 검색 및 검색에 중점을 두는 반면, 다중 모드 LLM은 다양한 콘텐츠를 생성하고 이해하는 데 적합하므로 챗봇, 대화형 도우미 및 다중 모드 상호 작용에 이상적입니다.
| 다중 모달 임베딩 모델 | 다중 모드 대형 언어 모델(LLM) |
---|---|---|
주목적 | 텍스트, 이미지 등 다양한 데이터 형식에 걸쳐 검색 및 검색이 가능합니다. | 다양한 양식에 걸쳐 콘텐츠 생성 및 이해 |
핵심 사용 사례 | 의미론적 검색, 콘텐츠 검색 및 유사성 | 대화형 AI, 콘텐츠 생성 및 대화 시스템 |
예시 모델 | CLIP, Google 멀티모달 임베딩 모델 | GPT-4(다중 모드 기능 포함), Llava, Gemini, Flamingo, LaMDA |
검색 및 검색 | 빠르고 정확한 검색 및 유사성을 위해 최적화되었습니다. | 다양한 데이터 유형에 대한 포괄적인 이해 및 생성을 위해 최적화되었습니다. |
응용 | 콘텐츠 조정, 추천 시스템, 의미 검색 | 대화형 에이전트, 콘텐츠 생성, 다중 모드 상호 작용 |
OpenOrigins가 살펴본 첫 번째 방법은 이미지 임베딩을 사용한 비디오의 프레임별 분석이었습니다. 이 접근 방식은 비디오를 개별 프레임으로 나누고 각 프레임은 다음을 사용하여 벡터 임베딩으로 변환됩니다.
CLIP은 설명과 함께 수백만 개의 웹 이미지를 연구함으로써 인간이 세상을 인식하고 설명하는 방식과 유사한 방식으로 시각적 개념을 이해합니다. 훈련에는 이미지를 올바른 설명과 일치시키는 방법을 학습하는 "대조 학습"이 포함되며, 이를 통해 우리가 보는 것과 사용하는 단어 사이의 연관성을 이해함으로써 다양한 작업을 처리할 수 있는 고유한 능력을 제공합니다.
따라서 CLIP은 이미지와 언어에 대한 깊은 이해가 필요한 애플리케이션에 적응력이 뛰어나고 유용합니다.
이러한 임베딩은 벡터 데이터베이스에 저장되어 의미론적 유사성을 기반으로 텍스트와 텍스트, 텍스트와 이미지, 이미지와 이미지를 일치시켜 빠르고 정확한 검색이 가능합니다.
프레임 추출은 지정된 간격으로 비디오를 프레임으로 분해합니다. 각 프레임은 이미지 임베딩 모델을 통해 처리되어 고차원 벡터 표현을 생성합니다. 이러한 벡터는 DataStax Astra DB와 같은 벡터 저장소에 저장되어 효율적인 유사성 검색이 가능합니다.
이 방법은 다중 모드 의미 검색에서 높은 정확도를 제공하며 특정 개체나 장면을 검색하는 데 매우 적합합니다. 그러나 특히 긴 비디오의 경우 계산 집약적이며 시간적 맥락이나 프레임 간 변경 사항을 놓칠 수 있습니다.
두 번째 접근 방식은 특히 Google의
이러한 임베딩은 비디오를 숫자로 표현함으로써 고급 기계 학습 작업을 가능하게 하여 비디오 콘텐츠를 더 쉽게 검색, 분석 및 분류할 수 있게 해줍니다.
이러한 임베딩을 다음과 통합
Google의 다중 모드 임베딩과 CLIP 방법은 각각 다중 모드 데이터를 공통 임베딩 공간에 포함합니다. 주요 차이점은 Google의 다중 모드 임베딩은 비디오를 지원하지만 CLIP은 지원하지 않는다는 것입니다.
우리는 프레임 검색 비디오 분석과 다중 모드 임베딩 모두에 대한 예를 조명하고 적용하기 위해 아래 저장소를 구성했습니다. 이러한 예는 각 접근 방식을 효과적으로 구현하고 평가하는 데 도움이 되는 실제 데모와 자세한 지침을 제공합니다.
이 접근 방식에서는 다음을 소개합니다.
get_single_frame_from_scene
함수는 프레임 ID를 계산하고 비디오 캡처를 이 프레임으로 설정하고 읽습니다.
def get_single_frame_from_scene(scene, video_capture): frame_id = (scene[1] - scene[0]).frame_num // 2 + scene[0].frame_num video_capture.set(cv2.CAP_PROP_POS_FRAMES, frame_id) _, frame = video_capture.read() return Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
get_frames_from_video
함수는 비디오를 처리하고 AdaptiveDetector를 사용하여 장면을 감지하고 get_single_frame_from_scene을 호출하여 각 장면에서 단일 프레임을 추출하고 이러한 프레임을 목록에 저장합니다.
def get_frames_from_video(video_path): res = [] video_capture = cv2.VideoCapture(video_path) content_list = detect(video_path, AdaptiveDetector()) for scene in content_list: res.append(get_single_frame_from_scene(scene, video_capture)) return res
get_image_embedding 함수는
def get_image_embedding(image): inputs = clip_processor(images=image, return_tensors="pt") image_embeddings = model.get_image_features(**inputs) return list(image_embeddings[0].detach().numpy().astype(float))
이 코드는 Astra DB 데이터베이스에 연결하고, 벡터 임베딩이 포함된 JSON 개체 컬렉션을 생성하고, 이러한 개체를 데이터베이스의 "비디오" 컬렉션에 삽입합니다.
import json from astrapy import DataAPIClient client = DataAPIClient(ASTRA_DB_TOKEN) database = client.get_database(ASTRA_DB_API_ENDPOINT) collectiondb = database.video json_embedding = [ {"id": f"{i+1}", "$vector": values} for i, values in enumerate(image_embeddings) ] response = collectiondb.insert_many(json_embedding)
OpenAI Clip 임베딩을 사용하여 특정 텍스트를 검색합니다.
query_text = "men with white hair" query_embedding = get_text_embedding(query_text) result = collectiondb.find_one({}, vector=query_embedding)
여기에서는 Google의 멀티모달 임베딩 모델을 사용하여 비디오 임베딩을 생성하고 start_offset_sec 및 end_offset_sec와 같은 메타데이터 정보를 포함하여 Astra DB에 저장하는 방법을 확인할 수 있습니다.
import vertexai from vertexai.vision_models import MultiModalEmbeddingModel, Video from astrapy import DataAPIClient import streamlit as st # Initialize Vertex AI vertexai.init(project=st.secrets['PROJECT'], location=st.secrets['REGION']) # Initialize the client client = DataAPIClient(st.secrets['ASTRA_TOKEN']) database = client.get_database(st.secrets['ASTRA_API_ENDPOINT']) my_collection = database.create_collection( "videosearch", dimension=1408, metric=astrapy.constants.VectorMetric.COSINE, ) collectiondb = database.videosearch # Load the pre-trained model and video model = MultiModalEmbeddingModel.from_pretrained("multimodalembedding") video = Video.load_from_file(st.secrets['PATH']) # Get embeddings with the specified contextual text embeddings = model.get_embeddings( video=video, contextual_text="Mixed Content", dimension=1408, ) # Video Embeddings are segmented based on the video_segment_config. for video_embedding in embeddings.video_embeddings: # Check if embedding is a numpy array or a tensor and convert accordingly if isinstance(video_embedding.embedding, (list, tuple)): embedding_list = video_embedding.embedding else: embedding_list = video_embedding.embedding.tolist() embedding_data = { "metadata": { "start_offset_sec": video_embedding.start_offset_sec, "end_offset_sec": video_embedding.end_offset_sec }, "$vector": embedding_list # Ensure embedding is in list format } response = collectiondb.insert_one(embedding_data)
여기서는
import vertexai from vertexai.vision_models import MultiModalEmbeddingModel, Video from vertexai.vision_models import Image as img from astrapy import DataAPIClient import streamlit as st from PIL import Image st.title("Video Search App") user_input_placeholder = st.empty() user_input = user_input_placeholder.text_input( "Describe the content you're looking for:", key="user_input" ) uploaded_file = st.file_uploader("Choose an image file that is similar you're looking for", type="png") if uploaded_file is not None: image = Image.open(uploaded_file) image_path = st.secrets['IMAGE_PATH'] image.save(image_path) saved_image = Image.open(image_path) st.image(saved_image, caption='', use_column_width=True) # Initialize Vertex AI vertexai.init(project=st.secrets['PROJECT'], location=st.secrets['REGION']) # Initialize the client client = DataAPIClient(st.secrets['ASTRA_TOKEN']) database = client.get_database(st.secrets['ASTRA_API_ENDPOINT']) collectiondb = database.videosearch # Load the pre-trained model and video model = MultiModalEmbeddingModel.from_pretrained("multimodalembedding") video = Video.load_from_file(st.secrets['PATH']) # Search action trigger if st.button("Search"): if user_input: embeddings = model.get_embeddings( contextual_text=user_input ) result = collectiondb.find_one({}, vector=embeddings.text_embedding) start_offset_value = result['metadata']['start_offset_sec'] end_offset_value = result['metadata']['end_offset_sec'] st.write("Text input result found between: " + str(start_offset_value) + "-" + str(end_offset_value)) video_file = open(st.secrets['PATH'], 'rb') video_bytes = video_file.read() st.video(video_bytes, start_time=start_offset_value) if uploaded_file is not None: embimage = img.load_from_file(image_path) embeddingsimg = model.get_embeddings( image=embimage ) imgresult = collectiondb.find_one({}, vector=embeddingsimg.image_embedding) start_offset_value = imgresult['metadata']['start_offset_sec'] end_offset_value = imgresult['metadata']['end_offset_sec'] st.write("Image input result found between: " + str(start_offset_value) + "-" + str(end_offset_value)) video_file = open(st.secrets['PATH'], 'rb') video_bytes = video_file.read() st.video(video_bytes, start_time=start_offset_value)
결과는 다음과 같습니다.
이 두 가지 접근 방식을 살펴보면 비디오 검색 애플리케이션에서 최신 AI 기술의 상당한 잠재력이 강조됩니다. 이미지 임베딩을 사용한 프레임 검색은 특정 시각적 검색에 높은 정확도를 제공하지만 다중 모드 임베딩의 유연성과 강력함 덕분에 복잡한 다중 모드 검색 요구 사항에 탁월한 선택이 됩니다.
Astra DB를 사용하면 비디오 검색 플랫폼은 사용자에게 고급 검색 기능을 제공하여 대규모 데이터 세트에서 특정 비디오 콘텐츠를 정확하고 효율적으로 검색할 수 있습니다. 이를 통해 비디오 데이터를 분석하고 해석하는 능력이 크게 향상되어 더 빠르고 정확한 통찰력을 얻을 수 있습니다.
앞으로도 지속적인 연구와 개발을 통해 비디오 검색의 미래는 밝을 것입니다. AI와 머신러닝의 발전은 이러한 기술을 지속적으로 개선하여 접근성과 효율성을 더욱 높여줄 것입니다. 증강 현실, 실시간 비디오 분석 등 다른 신기술과의 통합으로 그 역량이 더욱 확장될 것입니다.
작성자: Matthew Pendlebury (OpenOrigins 엔지니어링 책임자) 및 Betul O'Reilly (DataStax 솔루션 설계자)