Xây dựng Công cụ Đề xuất Phim dựa trên Tâm trạng với Voyage-4-nano, Hugging Face và MongoDB Atlas Vector Search

Hướng dẫn cách xây dựng công cụ đề xuất phim dựa trên tâm trạng sử dụng Voyage-4-nano, Hugging Face và MongoDB Atlas Vector Search.

  • 16 min read
Xây dựng Công cụ Đề xuất Phim dựa trên Tâm trạng với Voyage-4-nano, Hugging Face và MongoDB Atlas Vector Search
Hướng dẫn cách xây dựng công cụ đề xuất phim dựa trên tâm trạng sử dụng Voyage-4-nano, Hugging Face và MongoDB Atlas Vector Search.

Xây dựng công cụ gợi ý phim dựa trên tâm trạng với Voyage-4-nano, Hugging Face và MongoDB Atlas Vector Search

Các công cụ tìm kiếm phim truyền thống thường lọc theo thể loại, diễn viên hoặc tên phim. Nhưng điều gì sẽ xảy ra nếu bạn có thể tìm kiếm dựa trên tâm trạng của mình? Hãy tưởng tượng bạn có thể nhập:

  • “Thứ gì đó mang lại sự phấn chấn sau một ngày làm việc tồi tệ”
  • “Một bộ phim khiến tôi phải rơi lệ”
  • “Tôi cần sự hứng khởi, dù sao cũng không ngủ được”
  • “Thứ gì đó để xem cùng bà, người ghét bạo lực”

Đây là tìm kiếm ngữ nghĩa dựa trên tâm trạng: kết hợp trạng thái cảm xúc của bạn với mô tả cốt truyện phim bằng cách sử dụng các embedding AI.

Trong hướng dẫn này, bạn sẽ xây dựng một công cụ gợi ý phim dựa trên tâm trạng bằng cách sử dụng ba công nghệ mạnh mẽ: Voyage-4-nano (một mô hình embedding nguồn mở hiện đại), Hugging Face (để lưu trữ mô hình và tập dữ liệu), và MongoDB Atlas Vector Search (để lưu trữ và truy vấn embedding ở quy mô lớn).

Tại sao tìm kiếm dựa trên tâm trạng?

Các thẻ thể loại chỉ mang tính tương đối. Một bộ phim “chính kịch” có thể ấm áp lòng người hoặc bi thương. Một bộ phim “hài” có thể là sự giải trí nhẹ nhàng hoặc châm biếm sâu cay. Các bộ lọc truyền thống không thể nắm bắt được những sắc thái này.

Tìm kiếm ngữ nghĩa giải quyết vấn đề này bằng cách hiểu ý nghĩa. Khi bạn tìm kiếm “bộ phim tạo cảm giác tốt cho một ngày chủ nhật mưa”, hệ thống sẽ không tìm kiếm chính xác các từ đó. Nó hiểu ý định và khớp nó với các mô tả cốt truyện gợi lên những cảm xúc tương tự.

Tổng quan kiến trúc

Hệ thống kết hợp ba thành phần từ hệ sinh thái Hugging Face với MongoDB:

  • Voyage-4-nano (Hugging Face Hub): Chuyển đổi văn bản thành embedding (tối đa 2048 chiều, chúng tôi sử dụng 1024)
  • MongoDB/embedded_movies (Hugging Face Datasets): Hơn 1500 phim với tóm tắt cốt truyện, thể loại, diễn viên

Dữ liệu phim

  • MongoDB Atlas Vector Search: Lưu trữ embedding và thực hiện tìm kiếm tương tự

Hiểu về Voyage-4-nano

Voyage-4-nano là mô hình nhỏ nhất trong loạt mô hình embedding mới nhất của Voyage AI, được phát hành dưới dạng nguồn mở theo giấy phép Apache 2.0. Voyage AI đã được MongoDB mua lại, và các mô hình loạt Voyage 4 hiện có sẵn thông qua MongoDB Atlas.

Tất cả các mô hình trong loạt (voyage-4-large, voyage-4, voyage-4-lite và voyage-4-nano) đều tạo ra các embedding tương thích trong một không gian embedding chung, cho phép bạn kết hợp các mô hình cho các trường hợp sử dụng khác nhau.

Mặc dù Voyage-4-nano hỗ trợ native các embedding có chiều lên đến 2048, chúng tôi cố tình cắt bớt chúng xuống còn 1024 chiều bằng thuộc tính embedding Matryoshka của nó. Trên thực tế, điều này mang lại sự cân bằng mạnh mẽ giữa chất lượng ngữ nghĩa, hiệu quả lưu trữ và độ trễ tìm kiếm vector, đồng thời duy trì hành vi xếp hạng ổn định.

Sentence Transformers

Hướng dẫn này sử dụng Sentence Transformers, một thư viện Python được xây dựng dựa trên Transformers của Hugging Face. Nó được thiết kế đặc biệt để làm việc với các mô hình embedding và cung cấp một API đơn giản để tạo embedding văn bản.

Tại sao lại dùng Sentence Transformers thay vì Transformers gốc? Khi làm việc với các mô hình embedding, bạn cần xử lý tokenization, pooling, chuẩn hóa và định dạng prompt. Sentence Transformers thực hiện tất cả những điều này một cách tự động trong một lần gọi phương thức. Mã rõ ràng hơn, ít lỗi tiềm ẩn hơn và bạn nhận được các tính năng tích hợp sẵn như xử lý theo lô với thanh tiến trình.

Về bản chất, Sentence Transformers vẫn sử dụng Transformers của Hugging Face để tải và chạy mô hình.

Cấu hình môi trường phát triển

Hãy bắt đầu!

Tạo cấu trúc dự án

bash mkdir mood-movie-search cd mood-movie-search mkdir src touch requirements.txt .env

Cài đặt các dependency

Tạo tệp requirements.txt:

bash cat «‘EOF’ > requirements.txt fastapi>=0.109.0 uvicorn>=0.27.0 pymongo>=4.6.1 sentence-transformers>=3.0.0 python-dotenv>=1.0.0 datasets>=2.16.0 torch EOF

Tạo môi trường ảo Python và cài đặt các dependency:

bash python -m venv venv source venv/bin/activate pip install -r requirements.txt

Chạy MongoDB Atlas cục bộ

Sử dụng Atlas CLI để tạo một triển khai cục bộ có hỗ trợ Vector Search:

bash brew install mongodb-atlas-cli atlas deployments setup

Chọn local khi được nhắc. Khi sẵn sàng, bạn sẽ nhận được một chuỗi kết nối như:

Deployment created! Connection string: “mongodb://localhost:52955/?directConnection=true”

Cấu hình biến môi trường

Tạo tệp .env:

bash cat «‘EOF’ > .env MONGO_URI=mongodb://localhost:52955/?directConnection=true DB_NAME=movies_db COLLECTION_NAME=movies MODEL_NAME=voyageai/voyage-4-nano EMBEDDING_DIM=1024 EOF

Tôi sử dụng 1024 chiều làm sự cân bằng giữa chất lượng và hiệu quả lưu trữ. Bạn có thể thử nghiệm với 2048 (chất lượng tối đa) hoặc 512 (truy vấn nhanh hơn).

Triển khai các thành phần hệ thống

Mô-đun cơ sở dữ liệu

Mô-đun cơ sở dữ liệu quản lý kết nối MongoDB và tạo chỉ mục tìm kiếm vector. Chỉ mục phải khớp với các chiều embedding được chỉ định trong cấu hình của chúng ta.

python

src/database.py

import os from pymongo import MongoClient from pymongo.operations import SearchIndexModel from dotenv import load_dotenv

load_dotenv()

class MongoManager: def init(self): self.client = MongoClient(os.getenv(“MONGO_URI”)) self.db = self.client[os.getenv(“DB_NAME”)] self.collection = self.db[os.getenv(“COLLECTION_NAME”)] self.embedding_dim = int(os.getenv(“EMBEDDING_DIM”, 1024))

def get_collection(self):
    return self.collection

def create_vector_index(self):
    """Creates a Vector Search index for mood-based queries"""
    search_index_model = SearchIndexModel(
        definition={
            "fields": [
                {
                    "type": "vector",
                    "path": "plot_embedding",
                    "numDimensions": self.embedding_dim,
                    "similarity": "cosine"
                },
                {
                    "type": "filter",
                    "path": "genres"
                },
                {
                    "type": "filter", 
                    "path": "year"
                }
            ]
        },
        name="mood_search_index",
        type="vectorSearch"
    )
    try:
        self.collection.create_search_index(model=search_index_model)
        print(f"Vector index created with {self.embedding_dim} dimensions.")
    except Exception as e:
        print(f"Index status: {e}")

Mô-đun AI với Voyage-4-nano

Mô-đun AI tải Voyage-4-nano từ Hugging Face Hub và cung cấp các phương thức để tạo embedding. Chúng tôi sử dụng thư viện sentence-transformers cho một API sạch sẽ.

python

src/ai.py

import os import torch from sentence_transformers import SentenceTransformer from dotenv import load_dotenv

load_dotenv()

class MoodEmbedder: def init(self): model_name = os.getenv(“MODEL_NAME”, “voyageai/voyage-4-nano”) self.embedding_dim = int(os.getenv(“EMBEDDING_DIM”, 1024))

    print(f"Loading {model_name} from Hugging Face Hub...")
    
    # Load with GPU optimization if available
    if torch.cuda.is_available():
        self.model = SentenceTransformer(
            model_name,
            trust_remote_code=True,
            truncate_dim=self.embedding_dim,
            model_kwargs={
                "attn_implementation": "flash_attention_2",
                "torch_dtype": torch.bfloat16
            }
        )
        print(f"Model loaded on GPU with Flash Attention 2")
    else:
        self.model = SentenceTransformer(
            model_name,
            trust_remote_code=True,
            truncate_dim=self.embedding_dim
        )
        print(f"Model loaded on CPU")
    
    print(f"Embedding dimension: {self.embedding_dim}")

def embed_query(self, mood_description: str) -> list:
    """
    Embed a mood query. Uses query-specific prompt for better retrieval.
    Example: "something uplifting after a bad day"
    """
    if not mood_description:
        return []
    embedding = self.model.encode_query(mood_description)
    return embedding.tolist()

def embed_document(self, plot: str) -> list:
    """
    Embed a movie plot description. Uses document-specific prompt.
    """
    if not plot:
        return []
    embedding = self.model.encode_document(plot)
    return embedding.tolist()

def embed_documents_batch(self, plots: list[str], batch_size: int = 32) -> list:
    """
    Embed multiple plots efficiently in batches.
    """
    embeddings = self.model.encode_document(
        plots, 
        batch_size=batch_size,
        show_progress_bar=True
    )
    return [emb.tolist() for emb in embeddings]

Voyage-4-nano sử dụng các prompt khác nhau cho truy vấn và tài liệu:

  • encode_query() thêm tiền tố: “Represent the query for retrieving supporting documents:”
  • encode_document() thêm tiền tố: “Represent the document for retrieval: "

Việc mã hóa không đối xứng này cải thiện chất lượng truy xuất.

Mô-đun lập chỉ mục dữ liệu

Bộ lập chỉ mục tải tập dữ liệu phim từ Hugging Face, tạo các embedding mới với Voyage-4-nano và lưu trữ mọi thứ vào MongoDB.

python

src/indexer.py

import os from datasets import load_dataset from src.database import MongoManager from src.ai import MoodEmbedder

def extract_year(date_str): “““Extract year from various date formats””” if not date_str: return None try: if isinstance(date_str, dict) and ‘$date’ in date_str: from datetime import datetime ts = date_str[’$date’].get(’$numberLong’, 0) return datetime.fromtimestamp(int(ts) / 1000).year return int(str(date_str)[:4]) except: return None

def run_indexing(): print("=” * 60) print("🎬 MOOD-BASED MOVIE SEARCH - INDEXING") print("=" * 60)

print("\n[1/6] Connecting to MongoDB...")
db = MongoManager()
collection = db.get_collection()
print("✓ Connected")

print("\n[2/6] Loading Voyage-4-nano from Hugging Face Hub...")
embedder = MoodEmbedder()
print("✓ Model ready")

print("\n[3/6] Downloading movie dataset from Hugging Face...")
dataset = load_dataset("MongoDB/embedded_movies", split="train")
print(f"✓ Downloaded {len(dataset)} movies")

# Sample for demo (use full dataset in production)
sample_size = min(500, len(dataset))
sample_data = dataset.shuffle(seed=42).select(range(sample_size))
print(f"\n[4/6] Processing {sample_size} movies...")

collection.delete_many({})
print("✓ Cleared existing data")

# Prepare documents
movies_to_embed = []
plots_to_embed = []

for item in sample_data:
    plot = item.get("plot", "")
    if not plot or len(plot) < 50:
        continue
        
    movie = {
        "title": item.get("title", "Unknown"),
        "plot": plot,
        "genres": item.get("genres", []),
        "year": extract_year(item.get("released")),
        "runtime": item.get("runtime"),
        "cast": item.get("cast", [])[:5],
        "directors": item.get("directors", []),
        "imdb_rating": item.get("imdb", {}).get("rating") if isinstance(item.get("imdb"), dict) else None,
    }
    movies_to_embed.append(movie)
    plots_to_embed.append(plot)

print(f"  Found {len(movies_to_embed)} movies with valid plots")

print("\n[5/6] Generating embeddings with Voyage-4-nano...")
embeddings = embedder.embed_documents_batch(plots_to_embed)

for movie, embedding in zip(movies_to_embed, embeddings):
    movie["plot_embedding"] = embedding

if movies_to_embed:
    print(f"\n  Inserting {len(movies_to_embed)} movies into MongoDB...")
    collection.insert_many(movies_to_embed)
    print(f"✓ Inserted {len(movies_to_embed)} movies")

print("\n[6/6] Creating vector search index...")
db.create_vector_index()

print("\n" + "=" * 60)
print("✓ INDEXING COMPLETE!")
print(f"  Movies indexed: {len(movies_to_embed)}")
print(f"  Embedding dimensions: {embedder.embedding_dim}")
print("=" * 60)

if name == “main”: run_indexing()

API Tìm kiếm

Ứng dụng FastAPI cung cấp điểm cuối tìm kiếm dựa trên tâm trạng. Người dùng mô tả tâm trạng của họ và hệ thống trả về các phim khớp về mặt ngữ nghĩa.

python

src/main.py

from fastapi import FastAPI, HTTPException from pydantic import BaseModel, field_validator from typing import Optional from src.database import MongoManager from src.ai import MoodEmbedder

app = FastAPI(title=“Mood-Based Movie Search API”)

Initialize components

db = MongoManager() embedder = MoodEmbedder() collection = db.get_collection()

class MoodSearchRequest(BaseModel): mood: str limit: int = 5 min_rating: Optional[float] = None genre_filter: Optional[str] = None

@field_validator('mood')
@classmethod
def mood_must_not_be_empty(cls, v):
    if not v or not v.strip():
        raise ValueError('Mood description cannot be empty')
    return v.strip()

@field_validator('limit')
@classmethod
def limit_must_be_reasonable(cls, v):
    if v < 1 or v > 20:
        raise ValueError('Limit must be between 1 and 20')
    return v

@app.post("/search") def search_by_mood(request: MoodSearchRequest): """ Search for movies based on your current mood.

Examples:
- "I need something uplifting after a rough day"
- "want to cry and feel cathartic"
- "exciting adventure for movie night with friends"
- "something calm and beautiful to fall asleep to"
"""

query_embedding = embedder.embed_query(request.mood)

if not query_embedding:
    raise HTTPException(status_code=400, detail="Failed to process mood description")

vector_search_stage = {
    "$vectorSearch": {
        "index": "mood_search_index",
        "path": "plot_embedding",
        "queryVector": query_embedding,
        "numCandidates": 150,
        "limit": request.limit * 2
    }
}

match_stage = {"$match": {}}
if request.min_rating:
    match_stage["$match"]["imdb_rating"] = {"$gte": request.min_rating}
if request.genre_filter:
    match_stage["$match"]["genres"] = request.genre_filter

project_stage = {
    "$project": {
        "_id": 0,
        "title": 1,
        "plot": 1,
        "genres": 1,
        "year": 1,
        "imdb_rating": 1,
        "cast": 1,
        "directors": 1,
        "mood_match_score": {"$meta": "vectorSearchScore"}
    }
}

pipeline = [vector_search_stage]
if match_stage["$match"]:
    pipeline.append(match_stage)
pipeline.append(project_stage)
pipeline.append({"$limit": request.limit})

try:
    results = list(collection.aggregate(pipeline))
    
    return {
        "mood_query": request.mood,
        "results_count": len(results),
        "movies": results
    }
except Exception as e:
    raise HTTPException(status_code=500, detail=f"Search failed: {str(e)}")

@app.get("/examples") def get_example_queries(): “““Returns example mood queries to try””” return { “examples”: [ {“mood”: “something uplifting after a rough day at work”, “category”: “Feel Good”}, {“mood”: “I want to cry and have a good emotional release”, “category”: “Emotional”}, {“mood”: “edge-of-seat thriller I can’t pause”, “category”: “Exciting”}, {“mood”: “slow beautiful film to relax to”, “category”: “Calm”}, {“mood”: “something to watch with kids on Sunday”, “category”: “Family”}, {“mood”: “mind-bending movie that makes you think”, “category”: “Thought-provoking”}, {“mood”: “nostalgic 80s vibe adventure”, “category”: “Nostalgic”}, {“mood”: “dark and disturbing but artistic”, “category”: “Art House”}, ] }

@app.get("/") def health_check(): return { “status”: “ok”, “service”: “Mood-Based Movie Search API”, “model”: “voyage-4-nano”, “embedding_dim”: embedder.embedding_dim }

Khởi tạo gói

bash touch src/init.py

Cấu trúc dự án

Cấu trúc dự án cuối cùng của bạn sẽ trông như thế này:

mood-movie-search/ ├── src/ │ ├── init.py │ ├── ai.py # Logic embedding của Voyage-4-nano │ ├── database.py # Kết nối và lập chỉ mục MongoDB │ ├── indexer.py # Tải dữ liệu và tạo embedding │ └── main.py # Ứng dụng FastAPI ├── requirements.txt ├── .env └── venv/

Chạy và Kiểm tra

Lập chỉ mục dữ liệu

Đầu tiên, chạy bộ lập chỉ mục để tải phim từ Hugging Face và tạo embedding:

bash python -m src.indexer

Kết quả mong đợi:

======================================= 🎬 MOOD-BASED MOVIE SEARCH - INDEXING

[1/6] Connecting to MongoDB… ✓ Connected

[2/6] Loading Voyage-4-nano from Hugging Face Hub… Loading voyageai/voyage-4-nano from Hugging Face Hub… Model loaded on CPU Embedding dimension: 1024 ✓ Model ready

[3/6] Downloading movie dataset from Hugging Face… ✓ Downloaded 1525 movies

[4/6] Processing 500 movies… ✓ Cleared existing data Found 487 movies with valid plots

[5/6] Generating embeddings with Voyage-4-nano… Batches: 100%|██████████████████|

Inserting 487 movies into MongoDB… ✓ Inserted 487 movies

[6/6] Creating vector search index… Vector index created with 1024 dimensions.

==================================== ✓ INDEXING COMPLETE! Movies indexed: 487 Embedding dimensions: 1024

Khởi động máy chủ API

bash python -m uvicorn src.main:app –reload

Kiểm tra các truy vấn dựa trên tâm trạng

Truy vấn 1: Phim tạo cảm giác tốt sau một ngày làm việc khó khăn

bash curl -X POST “http://localhost:8000/search”
-H “Content-Type: application/json”
-d ‘{“mood”: “something uplifting after a rough day at work”}’

Phản hồi:

json { “mood_query”: “something uplifting after a rough day at work”, “results_count”: 5, “movies”: [ { “title”: “The Long Kiss Goodnight”, “plot”: “A woman suffering from amnesia begins to recover her memories…”, “genres”: [“Action”, “Crime”, “Drama”], “imdb_rating”: 6.7, “mood_match_score”: 0.662 }, { “title”: “Villain”, “plot”: “Shiva a bus conductor has another face of life in which he helps the physically challenged…”, “genres”: [“Action”, “Drama”, “Romance”], “imdb_rating”: 7.0, “mood_match_score”: 0.659 }, { “title”: “The Blade”, “plot”: “After the master of the Sharp Manufacturer saber factory abdicates…”, “genres”: [“Drama”, “Action”], “imdb_rating”: 7.2, “mood_match_score”: 0.656 } ] }

Hệ thống đã trả về các phim hành động với chủ đề biến đổi cá nhân và giúp đỡ người khác. Điểm số khoảng 0.65 cho thấy sự tương đồng vừa phải vì “phấn chấn” là một khái niệm trừu tượng không xuất hiện trực tiếp trong văn bản cốt truyện.

Truy vấn 2: Cảm xúc thăng hoa

bash curl -X POST “http://localhost:8000/search”
-H “Content-Type: application/json”
-d ‘{“mood”: “I want to cry and feel emotionally moved”}’

Phản hồi:

json { “mood_query”: “I want to cry and feel emotionally moved”, “results_count”: 5, “movies”: [ { “title”: “The Wedding Party”, “plot”: “Screaming, shooting, tears and blood changes the party into a nightmare.”, “genres”: [“Action”, “Comedy”, “Drama”], “imdb_rating”: 6.6, “mood_match_score”: 0.666 }, { “title”: “Split Decisions”, “plot”: “When a boxer is killed because he wouldn’t take a dive, his brother tries to find a way to avenge him…”, “genres”: [“Action”, “Drama”], “imdb_rating”: 5.2, “mood_match_score”: 0.625 }, { “title”: “Tae Guk Gi: The Brotherhood of War”, “plot”: “A drama about the fate of brothers forced to fight in the Korean War.”, “genres”: [“Action”, “Drama”, “War”], “imdb_rating”: 8.2, “mood_match_score”: 0.618 } ] }

Hệ thống đã tìm thấy các bộ phim có chủ đề cảm xúc nặng nề. “Tae Guk Gi” là một bộ phim chiến tranh về những người anh em bị buộc phải chiến đấu chống lại nhau. “Split Decisions” nói về sự mất mát và trả thù sau cái chết của một võ sĩ quyền anh. Từ “nước mắt” trong cốt truyện của “The Wedding Party” đã khớp trực tiếp với ý định cảm xúc của truy vấn.

Truy vấn 3: Với bộ lọc

bash curl -X POST “http://localhost:8000/search”
-H “Content-Type: application/json”
-d ‘{ “mood”: “exciting adventure movie”, “min_rating”: 7.5, “genre_filter”: “Action” }’

Phản hồi:

json { “mood_query”: “exciting adventure movie”, “results_count”: 1, “movies”: [ { “title”: “Project A”, “plot”: “Fighting against pirates in old Hong Kong. Chinese costume drama with plenty of over-the-top tongue in cheek action and music.”, “genres”: [“Action”, “Comedy”], “cast”: [“Jackie Chan”, “Sammo Kam-Bo Hung”], “imdb_rating”: 7.5, “mood_match_score”: 0.761 } ] }

Với các bộ lọc nghiêm ngặt (điểm đánh giá >= 7.5, thể loại = Action), chỉ có một bộ phim khớp. Lưu ý điểm số cao hơn đáng kể là 0.761 so với các truy vấn trước đó. Cụm từ “exciting adventure” đã khớp trực tiếp với “over-the-top action” trong mô tả cốt truyện. Điều này cho thấy các truy vấn tâm trạng cụ thể, mô tả rõ ràng tạo ra các kết quả khớp ngữ nghĩa mạnh mẽ hơn các truy vấn cảm xúc trừu tượng.

Quan sát chính

  • Các truy vấn tâm trạng trừu tượng (“phấn chấn”, “cảm động”) đạt điểm 0.62 đến 0.67
  • Các mô tả cụ thể (“phiêu lưu thú vị”) đạt điểm 0.75+
  • Các bộ lọc giúp tìm các kết quả khớp tốt hơn ngay cả với ít kết quả hơn
  • Hệ thống hiểu chủ đề ngay cả khi không khớp từ chính xác

So sánh các chiều embedding

Một lợi thế độc đáo của các embedding Matryoshka của Voyage-4-nano là khả năng thử nghiệm với các chiều khác nhau. Hãy so sánh cách lựa chọn chiều ảnh hưởng đến kết quả.

Tạo một tập lệnh kiểm tra:

python

test_dimensions.py

from sentence_transformers import SentenceTransformer import numpy as np

model_2048 = SentenceTransformer(“voyageai/voyage-4-nano”, trust_remote_code=True, truncate_dim=2048) model_512 = SentenceTransformer(“voyageai/voyage-4-nano”, trust_remote_code=True, truncate_dim=512) model_256 = SentenceTransformer(“voyageai/voyage-4-nano”, trust_remote_code=True, truncate_dim=256)

query = “heartwarming story about friendship” plots = [ “Two elderly men rediscover their friendship during a road trip across America.”, “A violent revenge thriller set in the criminal underworld.”, “A young girl and her robot companion explore a magical forest.”, ]

for dim, model in [(2048, model_2048), (512, model_512), (256, model_256)]: q_emb = model.encode_query(query) d_embs = model.encode_document(plots)

similarities = np.dot(d_embs, q_emb) / (np.linalg.norm(d_embs, axis=1) * np.linalg.norm(q_emb))

print(f"\n=== {dim} dimensions ===")
for plot, sim in zip(plots, similarities):
    print(f"  {sim:.4f}: {plot[:50]}...")

Chạy tập lệnh:

bash python test_dimensions.py

Kết quả:

=== 2048 dimensions === 0.4496: Two elderly men rediscover their friendship during… 0.1472: A violent revenge thriller set in the criminal und… 0.3726: A young girl and her robot companion explore a mag…

=== 512 dimensions === 0.4350: Two elderly men rediscover their friendship during… 0.0953: A violent revenge thriller set in the criminal und… 0.3487: A young girl and her robot companion explore a mag…

=== 256 dimensions === 0.4139: Two elderly men rediscover their friendship during… 0.0168: A violent revenge thriller set in the criminal und… 0.3310: A young girl and her robot companion explore a mag…

Cả ba cài đặt chiều đều xếp hạng cốt truyện theo đúng thứ tự: câu chuyện về tình bạn có điểm cao nhất, câu chuyện về người bạn đồng hành robot đứng thứ hai (liên quan về mặt chủ đề thông qua tình bạn), và bộ phim kinh dị bạo lực có điểm thấp nhất.

Sự khác biệt chính:

  • Khoảng cách phân biệt (Discrimination gap): Với 2048 chiều, khoảng cách giữa kết quả khớp tốt nhất (0.4496) và tệ nhất (0.1472) là 0.302. Với 256 chiều, khoảng cách lớn hơn ở mức 0.397 (0.4139 trừ 0.0168). Thật thú vị, các chiều thấp hơn có thể tạo ra khoảng cách lớn hơn do nén không gian embedding mạnh mẽ hơn, nhưng điều này không nhất thiết có nghĩa là chất lượng tốt hơn. Các điểm tương tự tuyệt đối thấp hơn và kém tin cậy hơn.
  • Tính ổn định xếp hạng: Tất cả các chiều đều tạo ra cùng một thứ hạng. Đối với các tác vụ truy xuất đơn giản, ngay cả 256 chiều cũng hoạt động tốt.
  • Khi các chiều quan trọng: Nếu ứng dụng của bạn yêu cầu điểm tương tự chi tiết, hãy sử dụng các chiều cao hơn. Nếu bạn chỉ cần xếp hạng chính xác, các chiều thấp hơn sẽ tiết kiệm dung lượng lưu trữ và thời gian truy vấn.
  • Khuyến nghị thực tế: Bắt đầu với 1024 chiều làm mặc định cân bằng. Giảm xuống 512 nếu dung lượng lưu trữ là mối quan tâm. Chỉ sử dụng 2048 khi bạn cần độ chính xác tối đa cho các truy vấn tinh tế.

Recommended for You

Cách Sử dụng Nhiều GPU trong Hugging Face Transformers- Device Map so với Tensor Parallelism

Cách Sử dụng Nhiều GPU trong Hugging Face Transformers- Device Map so với Tensor Parallelism

Hướng dẫn cách sử dụng nhiều GPU với Hugging Face Transformers, so sánh Device Map và Tensor Parallelism.

Forge- Khung và Thuật toán Agent RL có thể mở rộng

Forge- Khung và Thuật toán Agent RL có thể mở rộng

Một bài viết về Forge, một khung và thuật toán Agent RL có thể mở rộng.