Seq vs Seq- Bộ Ettin gồm các bộ mã hóa và giải mã ghép nối

  • 18 min read
Seq vs Seq- Bộ Ettin gồm các bộ mã hóa và giải mã ghép nối

Ettin Suite: Các Bộ Mã hóa và Giải mã theo Cặp SoTA

TL;DR

Điều gì sẽ xảy ra nếu bạn lấy công thức ModernBERT và áp dụng nó cho một mô hình chỉ giải mã? Hóa ra, một mô hình ngôn ngữ giải mã hiện đại đã đánh bại Llama 3.2 1B và SmolLM2!

Chúng tôi giới thiệu một công thức đào tạo dữ liệu mở mới để tái tạo mô hình ModernBERT chỉ mã hóa (và thực sự đánh bại nó!). Sau đó, chúng tôi áp dụng chính công thức đó cho các mô hình chỉ giải mã. Lần đầu tiên, chúng tôi có hai mô hình hiện đại được đào tạo trong cùng một thiết lập nhưng với hai mục tiêu đào tạo khác nhau: mô hình hóa ngôn ngữ bị che lấp (MLM) và mô hình hóa ngôn ngữ nhân quả (CLM).

Bài đăng trên blog này giới thiệu Ettin, bộ đầu tiên các mô hình chỉ mã hóa và chỉ giải mã theo cặp SoTA (tham số 17M-1B) được đào tạo với dữ liệu giống hệt nhau (2T token), kiến trúc và công thức đào tạo. Ettin cho phép so sánh thực sự giữa các kiến trúc và mang lại hiệu suất hiện đại cho các mô hình dữ liệu mở trong cả hai loại. Sau đó, chúng tôi tiếp tục khám phá liệu có thể có được một bộ mã hóa cạnh tranh bắt đầu từ bộ giải mã và ngược lại hay không.

Nếu bạn quan tâm đến việc dùng thử các mô hình, một số mẫu có sẵn ở cuối bài đăng trên blog này!

So sánh các mẫu chú ý giữa các mô hình mã hóa và giải mã

Bộ mã hóa so với Bộ giải mã: Sự khác biệt về kiến trúc

Cộng đồng LLM phần lớn đã hội tụ vào các mô hình chỉ giải mã như GPT, Llama và Qwen. Khả năng tạo sinh của chúng rất ấn tượng, nhưng sự tập trung này đang làm giảm sự chú ý đến các danh mục khác, chẳng hạn như các mô hình chỉ mã hóa như BERT.

Tuy nhiên, các mô hình BERT giống bộ mã hóa vẫn là con ngựa thồ của các hệ thống sản xuất cho các tác vụ phân loại, truy xuất và nhúng. Chúng nhanh hơn, tiết kiệm bộ nhớ hơn và thường chính xác hơn cho các tác vụ phân biệt. Sự khác biệt chính nằm ở các mẫu chú ý của chúng:

  • Mô hình mã hóa sử dụng chú ý hai chiều, cho phép mỗi token “nhìn thấy” tất cả các token khác trong chuỗi (hoàn toàn có thể nhìn thấy)
  • Mô hình giải mã sử dụng chú ý nhân quả, trong đó các token chỉ có thể “nhìn thấy” các token trước đó để cho phép tạo tự hồi quy

Trong khi các mô hình giải mã đã chứng kiến sự đổi mới nhanh chóng, thì sự phát triển của mô hình mã hóa đã bị đình trệ - cho đến gần đây, với những nỗ lực như ModernBERT hiện đại hóa chúng. Nhưng kiến trúc nào tốt hơn? Các so sánh trước đây giữa bộ mã hóa và bộ giải mã sử dụng các tập dữ liệu, kiến trúc và công thức đào tạo khác nhau, vì vậy rất khó để biết.

Được đặt theo tên người khổng lồ hai đầu Bắc Âu, Ettin cung cấp một so sánh được kiểm soát bằng cách đào tạo với cả hai kiến trúc trên dữ liệu giống hệt nhau, hình dạng mô hình giống hệt nhau và công thức đào tạo giống hệt nhau. Chúng chỉ khác nhau về mẫu chú ý và mục tiêu đào tạo!

Công thức đào tạo: Các kỹ thuật hiện đại cho cả hai kiến trúc

Chúng tôi xây dựng dựa trên công thức ModernBERT, công thức này mượn các kỹ thuật hiện đại từ các mô hình chỉ giải mã và đưa chúng vào đào tạo mã hóa. Điều này cung cấp một cơ sở vững chắc để đào tạo cả hai kiến trúc.

Kích thước

Chúng tôi đào tạo sáu kích thước khác nhau, từ 17M đến 1B tham số. Điều này cho phép chúng tôi kiểm tra tác động của quy mô và cung cấp nhiều mô hình khác nhau để bạn sử dụng! Cho dù bạn cần một mô hình trên thiết bị nhanh chóng hay một mô hình mạnh mẽ nhưng chậm hơn, chúng tôi đều có thể đáp ứng!

Kích thước của các mô hình Ettin

Quy trình đào tạo ba giai đoạn

Chúng tôi sử dụng một phương pháp đào tạo ba giai đoạn toàn diện để tối đa hóa hiệu suất:

Giai đoạn 1 - Đào tạo trước (1.7T token): Chúng tôi bắt đầu với một hỗn hợp đa dạng các nguồn dữ liệu chất lượng cao, đào tạo trên các ngữ cảnh ngắn hơn (1024 token) để thiết lập kiến thức nền tảng vững chắc.

Giai đoạn 2 - Mở rộng ngữ cảnh (250B token): Chúng tôi tăng độ dài ngữ cảnh lên 8K token bằng cách sử dụng dữ liệu được lọc chất lượng cao hơn, cho phép các mô hình hiểu các tài liệu dài hơn và các mối quan hệ phức tạp hơn.

Giai đoạn 3 - Phân rã (100B token): Chúng tôi hoàn thành với các nguồn dữ liệu cao cấp bao gồm các bài báo khoa học, sách giáo khoa và nội dung được tuyển chọn đồng thời giảm dần tốc độ học tập.

Các thành phần kiến trúc hiện đại

Các mô hình bộ mã hóa của chúng tôi có được tất cả lợi ích về tốc độ của ModernBERT, cho phép chúng nhanh hơn đáng kể so với các thế hệ bộ mã hóa trước.

Nguồn và chất lượng dữ liệu

Không giống như ModernBERT, tất cả dữ liệu đào tạo của chúng tôi đều công khai và có thể tái tạo:

Dữ liệu được sử dụng để đào tạo các mô hình Ettin

Bạn có thể tiếp tục đào tạo các mô hình này trên dữ liệu mới hoặc đề xuất một công thức mới để cải thiện hơn nữa kết quả!

Kết quả mã hóa: Đánh bại ModernBERT

Các mô hình bộ mã hóa của chúng tôi vượt trội hơn ModernBERT trên tất cả các tác vụ và kích thước mô hình, đồng thời sử dụng dữ liệu đào tạo hoàn toàn mở. Vì chúng tôi cung cấp một loạt các kích thước lớn, giờ đây bạn có thể sử dụng các mô hình kiểu ModernBERT ở kích thước nhỏ hơn (tuyệt vời cho các thiết bị trên thiết bị hoặc cho suy luận nhanh) hoặc tăng sức mạnh bằng bộ mã hóa có kích thước 1B đánh bại đối thủ.

So sánh hiệu suất mã hóa cho thấy các mô hình Ettin đánh bại ModernBERT

Kết quả giải mã: Đánh bại Llama 3.2 và SmolLM2

Áp dụng cùng một công thức cho các mô hình giải mã mang lại kết quả ấn tượng không kém, với các mô hình của chúng tôi vượt trội hơn hoặc phù hợp với các đường cơ sở đã thiết lập như Llama 3.2 và SmolLM2:

So sánh hiệu suất giải mã cho thấy các mô hình Ettin đánh bại Llama 3.2 và SmolLM2

Mức tăng đặc biệt mạnh mẽ đối với các tác vụ chuyên sâu về kiến thức như SciQ, phản ánh lợi ích của hỗn hợp dữ liệu đào tạo chất lượng cao của chúng tôi. Những kết quả này chứng minh rằng công thức đào tạo của chúng tôi tạo ra các mô hình thực sự mạnh mẽ trong cả hai mô hình kiến trúc.

Cuộc chiến công bằng: Bộ mã hóa so với Bộ giải mã trên cơ sở bình đẳng

Lần đầu tiên, chúng ta có thể so sánh công bằng các kiến trúc bộ mã hóa và bộ giải mã được đào tạo với dữ liệu và công thức giống hệt nhau. Các kết quả cho thấy những lợi thế kiến trúc cơ bản vẫn tồn tại ngay cả khi tất cả các yếu tố khác được kiểm soát:

So sánh bộ mã hóa so với bộ giải mã trên các kích thước và tác vụ của mô hình

Những lợi thế cụ thể về kiến trúc vẫn tồn tại

Kết quả cho thấy các mẫu rõ ràng:

Bộ mã hóa chiếm ưu thế trong phân loại và truy xuất: Trên phân loại MNLI, ngay cả bộ mã hóa 150M (89,2) cũng vượt trội hơn bộ giải mã 400M (88,2). Đối với các tác vụ truy xuất, khoảng cách nhỏ hơn nhưng vẫn đáng chú ý - đặc biệt khi bộ giải mã không được đào tạo với MNTP.

Bộ giải mã vượt trội trong tạo sinh: Trên các tác vụ tạo sinh, bộ giải mã duy trì những lợi thế nhất quán, với khoảng cách hiệu suất thực tế mở rộng ở kích thước mô hình lớn hơn.

Kích thước không phải lúc nào cũng quan trọng: Bộ mã hóa 400M đánh bại bộ giải mã 1B trên các tác vụ phân loại, trong khi bộ giải mã 400M đánh bại bộ mã hóa 1B trên các tác vụ tạo sinh.

Đào tạo mục tiêu chéo không thành công

Do thiếu các mô hình bộ mã hóa mới, các công trình như LLM2Vec đã đề xuất tiếp tục đào tạo trước các bộ giải mã bằng MLM. Bây giờ chúng ta có thể kiểm tra tính hiệu quả của chiến lược này!

Chúng tôi đã chuyển đổi mục tiêu và tiếp tục đào tạo các mô hình của mình với mục tiêu ngược lại cho 50B token bổ sung. Đây là những gì chúng tôi tìm thấy:

  • Bộ mã hóa từ bộ giải mã: Vẫn thường đi sau bộ mã hóa gốc trên phân loại/truy xuất
  • Bộ giải mã từ bộ mã hóa: Tệ hơn đáng kể so với bộ giải mã gốc, đặc biệt là ở quy mô lớn hơn. Điều này có thể là do bộ mã hóa được đào tạo bằng MLM thay vì MNTP (dự đoán token tiếp theo bị che khuất) như đề xuất bởi LLM2Vec (và được sử dụng trong công thức bộ mã hóa từ bộ giải mã của chúng tôi).

Điều này cho thấy sự lựa chọn kiến trúc quan trọng về cơ bản, không chỉ mục tiêu đào tạo.

Vượt xa hiệu suất: Hiểu hành vi của mô hình

Với dữ liệu đào tạo giống hệt nhau, chúng ta có thể nghiên cứu cách các mục tiêu khác nhau ảnh hưởng đến việc học. Ví dụ: phân tích độ lệch giới tính bằng cách sử dụng chuẩn WinoGender cho thấy:

  • Mô hình mã hóa thích các đại từ trung tính về giới tính thường xuyên hơn (60%+ trung tính so với 30%+ cho bộ giải mã)
  • Cả hai kiến trúc đều cho thấy độ lệch nam, nhưng bộ giải mã hơi nhiều hơn
  • Đào tạo mục tiêu chéo ảnh hưởng đến các mẫu độ lệch theo những cách có thể đo lường được

Điều này mở ra cánh cửa cho các nghiên cứu có hệ thống về cách các mục tiêu đào tạo ảnh hưởng đến hành vi của mô hình vượt ra ngoài các số liệu chính xác.

Ví dụ sử dụng

Bạn có thể sử dụng các mô hình này chỉ với một vài dòng mã!

Bộ mã hóa

from transformers import AutoTokenizer, AutoModel

# Tải bộ mã hóa để phân loại/nhúng
tokenizer = AutoTokenizer.from_pretrained("jhu-clsp/ettin-encoder-150m")
model = AutoModel.from_pretrained("jhu-clsp/ettin-encoder-150m")

def predict_masked_token(text):
    inputs = tokenizer(text, return_tensors="pt")
    with torch.no_grad():
        outputs = model(**inputs)
    
    # Nhận dự đoán cho token [MASK]
    mask_indices = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)
    predictions = outputs.logits[mask_indices]
    
    # Nhận 5 dự đoán hàng đầu
    top_tokens = torch.topk(predictions, 5, dim=-1)
    return [tokenizer.decode(token) for token in top_tokens.indices[0]]

# Ví dụ
masked_text = "Thủ đô của Pháp là [MASK]."
predictions = predict_masked_token(masked_text)
print(f"Dự đoán: {predictions}")

Đối với các tác vụ phân loại và truy xuất, hãy sử dụng các mô hình bộ mã hóa: Bạn cũng có thể muốn sử dụng phiên bản đã được tinh chỉnh cho các tác vụ này.

Bộ giải mã

Đối với các tác vụ tạo văn bản, hãy sử dụng các mô hình giải mã:

from transformers import AutoTokenizer, AutoModelForCausalLM

# Tải bộ giải mã để tạo
tokenizer = AutoTokenizer.from_pretrained("jhu-clsp/ettin-decoder-150m")
model = AutoModelForCausalLM.from_pretrained("jhu-clsp/ettin-decoder-150m")

# Tạo văn bản
prompt = "Tương lai của trí tuệ nhân tạo là"
inputs = tokenizer(prompt, return_tensors="pt")
outputs = model.generate(inputs.input_ids, max_length=50, temperature=0.7)
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)

Ví dụ tinh chỉnh

Bộ mã hóa

import argparse

from datasets import load_dataset
from sentence_transformers import (
    SentenceTransformer,
    SentenceTransformerTrainer,
    SentenceTransformerTrainingArguments,
)
from sentence_transformers.evaluation import TripletEvaluator
from sentence_transformers.losses import CachedMultipleNegativesRankingLoss
from sentence_transformers.training_args import BatchSamplers

def main():
    # phân tích cú pháp lr & tên mô hình
    parser = argparse.ArgumentParser()
    parser.add_argument("--lr", type=float, default=8e-5)
    parser.add_argument("--model_name", type=str, default="jhu-clsp/ettin-encoder-150m")
    args = parser.parse_args()
    lr = args.lr
    model_name = args.model_name
    model_shortname = model_name.split("/")[-1]

    # 1. Tải mô hình để tinh chỉnh
    model = SentenceTransformer(model_name)

    # 2. Tải một tập dữ liệu để tinh chỉnh
    dataset = load_dataset(
        "sentence-transformers/msmarco-co-condenser-margin-mse-sym-mnrl-mean-v1",
        "triplet-hard",
        split="train",
    )
    dataset_dict = dataset.train_test_split(test_size=1_000, seed=12)
    train_dataset = dataset_dict["train"].select(range(1_250_000))
    eval_dataset = dataset_dict["test"]

    # 3. Xác định hàm mất mát
    loss = CachedMultipleNegativesRankingLoss(model, mini_batch_size=16)  # Tăng mini_batch_size nếu bạn có đủ VRAM

    run_name = f"{model_shortname}-DPR-{lr}"
    # 4. (Tùy chọn) Chỉ định đối số đào tạo
    args = SentenceTransformerTrainingArguments(
        # Tham số bắt buộc:
        output_dir=f"output/{model_shortname}/{run_name}",
        # Tham số đào tạo tùy chọn:
        num_train_epochs=1,
        per_device_train_batch_size=512,
        per_device_eval_batch_size=512,
        warmup_ratio=0.05,
        fp16=False,  # Đặt thành False nếu GPU không thể xử lý FP16
        bf16=True,  # Đặt thành True nếu GPU hỗ trợ BF16
        batch_sampler=BatchSamplers.NO_DUPLICATES,  # (Cached) MultipleNegativesRankingLoss được hưởng lợi từ việc không có bản sao
        learning_rate=lr,
        # Các tham số theo dõi/gỡ lỗi tùy chọn:
        save_strategy="steps",
        save_steps=500,
        save_total_limit=2,
        logging_steps=500,
        run_name=run_name,  # Được sử dụng trong `wandb`, `tensorboard`, `neptune`, v.v. nếu được cài đặt
    )

    # 5. (Tùy chọn) Tạo bộ đánh giá & đánh giá mô hình cơ sở
    dev_evaluator = TripletEvaluator(
        anchors=eval_dataset["query"],
        positives=eval_dataset["positive"],
        negatives=eval_dataset["negative"],
        name="msmarco-co-condenser-dev",
    )
    dev_evaluator(model)

    # 6. Tạo một trình đào tạo & đào tạo
    trainer = SentenceTransformerTrainer(
        model=model,
        args=args,
        train_dataset=train_dataset,
        eval_dataset=eval_dataset,
        loss=loss,
        evaluator=dev_evaluator,
    )
    trainer.train()

    # 7. (Tùy chọn) Đánh giá mô hình đã đào tạo trên bộ đánh giá sau khi đào tạo
    dev_evaluator(model)

    # 8. Lưu mô hình
    model.save_pretrained(f"output/{model_shortname}/{run_name}/final")

    # 9. (Tùy chọn) Đẩy nó lên Hugging Face Hub
    model.push_to_hub(run_name, private=False)

if __name__ == "__main__":
    main()
from datasets import load_dataset
from pylate import losses, models, utils
from sentence_transformers import (
    SentenceTransformerTrainer,
    SentenceTransformerTrainingArguments,
)

def main():
    # Tải tập dữ liệu cần thiết cho việc chắt lọc kiến thức (đào tạo, truy vấn, tài liệu)
    train = load_dataset(
        path="lightonai/ms-marco-en-bge",
        name="train",
    )

    queries = load_dataset(
        path="lightonai/ms-marco-en-bge",
        name="queries",
    )

    documents = load_dataset(
        path="lightonai/ms-marco-en-bge",
        name="documents",
    )

    # Đặt biến đổi để tải văn bản tài liệu/truy vấn bằng cách sử dụng các id tương ứng một cách nhanh chóng
    train.set_transform(
        utils.KDProcessing(queries=queries, documents=documents).transform,
    )

    # Xác định mô hình cơ sở, tham số đào tạo và thư mục đầu ra
    num_train_epochs = 1
    lr = 8e-5
    batch_size = 16
    accum_steps = 1
    model_name = "jhu-clsp/ettin-encoder-150m"
    model_shortname = model_name.split("/")[-1]

    # Đặt tên chạy cho ghi nhật ký và thư mục đầu ra
    run_name = f"{model_shortname}-colbert-KD-{lr}"
    output_dir = f"output/{model_shortname}/{run_name}"

    # Khởi tạo mô hình ColBERT từ mô hình cơ sở
    model = models.ColBERT(model_name_or_path=model_name)

    # Định cấu hình các đối số đào tạo (ví dụ: số kỷ nguyên, kích thước lô, tốc độ học)
    args = SentenceTransformerTrainingArguments(
        output_dir=output_dir,
        num_train_epochs=num_train_epochs,
        per_device_train_batch_size=batch_size,
        fp16=False,  # Đặt thành False nếu bạn gặp lỗi rằng GPU của bạn không thể chạy trên FP16
        bf16=True,  # Đặt thành True nếu bạn có GPU hỗ trợ BF16
        run_name=run_name,
        logging_steps=10,
        learning_rate=lr,
        gradient_accumulation_steps=accum_steps,
        warmup_ratio=0.05,
    )

    # Sử dụng hàm mất mát Distillation để đào tạo
    train_loss = losses.Distillation(model=model)

    # Khởi tạo trình đào tạo
    trainer = SentenceTransformerTrainer(
        model=model,
        args=args,
        train_dataset=train,
        loss=train_loss,
        data_collator=utils.ColBERTCollator(tokenize_fn=model.tokenize),
    )

    # Bắt đầu quá trình đào tạo
    trainer.train()

    model.save_pretrained(f"{output_dir}/final")

if __name__ == "__main__":
    main()
import logging

from datasets import load_dataset

from sentence_transformers import (
    SparseEncoder,
    SparseEncoderModelCardData,
    SparseEncoderTrainer,
    SparseEncoderTrainingArguments,
)
from sentence_transformers.sparse_encoder.evaluation import SparseNanoBEIREvaluator
from sentence_transformers.sparse_encoder.losses import SparseMultipleNegativesRankingLoss, SpladeLoss
from sentence_transformers.training_args import BatchSamplers

logging.basicConfig(format="%(asctime)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=logging.INFO)

# 1. Tải một mô hình để tinh chỉnh với 2. (Tùy chọn) dữ liệu thẻ mô hình
model = SparseEncoder(
    "jhu-clsp/ettin-encoder-150m",
    model_card_data=SparseEncoderModelCardData(
        language="en",
        license="apache-2.0",
    )
)

# 3. Tải một tập dữ liệu để tinh chỉnh
full_dataset = load_dataset("sentence-transformers/natural-questions", split="train").select(range(100_000))
dataset_dict = full_dataset.train_test_split(test_size=1_000, seed=12)
train_dataset = dataset_dict["train"]
eval_dataset = dataset_dict["test"]

# 4. Xác định hàm mất mát
loss = SpladeLoss(
    model=model,
    loss=SparseMultipleNegativesRankingLoss(model=model),
    query_regularizer_weight=5e-5,
    document_regularizer_weight=3e-5,
)

# 5. (Tùy chọn) Chỉ định đối số đào tạo
run_name = "splade-distilbert-base-uncased-nq"
args = SparseEncoderTrainingArguments(
    # Tham số bắt buộc:
    output_dir=f"models/{run_name}",
    # Tham số đào tạo tùy chọn:
    num_train_epochs=1,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=16,
    learning_rate=2e-5,
    warmup_ratio=0.1,
    fp16=True,  # Đặt thành False nếu bạn gặp lỗi rằng GPU của bạn không thể chạy trên FP16
    bf16=False,  # Đặt thành True nếu bạn có GPU hỗ trợ BF16
    batch_sampler=BatchSamplers.NO_DUPLICATES,  # MultipleNegativesRankingLoss được hưởng lợi từ việc không có mẫu trùng lặp trong một lô
    # Các tham số theo dõi/gỡ lỗi tùy chọn:
    eval_strategy="steps",
    eval_steps=1000,
    save_strategy="steps",
    save_steps=1000,
    save_total_limit=2,
    logging_steps=200,
    run_name=run_name,  # Sẽ được sử dụng trong W&B nếu `wandb` được cài đặt
)

# 6. (Tùy chọn) Tạo bộ đánh giá & đánh giá mô hình cơ sở
dev_evaluator = SparseNanoBEIREvaluator(dataset_names=["msmarco", "nfcorpus", "nq"], batch_size=16)

# 7. Tạo một trình đào tạo & đào tạo
trainer = SparseEncoderTrainer(
    model=model,
    args=args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    loss=loss,
    evaluator=dev_evaluator,
)
trainer.train()

# 8. Đánh giá lại hiệu suất của mô hình sau khi đào tạo
dev_evaluator(model)

# 9. Lưu mô hình đã đào tạo
model.save_pretrained(f"models/{run_name}/final")

# 10. (Tùy chọn) Đẩy nó lên Hugging Face Hub
model.push_to_hub(run_name)
import logging
import traceback

import torch
from datasets import load_dataset

from sentence_transformers import SentenceTransformer
from sentence_transformers.cross_encoder import (
    CrossEncoder,
    CrossEncoderModelCardData,
    CrossEncoderTrainer,
    CrossEncoderTrainingArguments,
)
from sentence_transformers.cross_encoder.evaluation import (
    CrossEncoderNanoBEIREvaluator,
    CrossEncoderRerankingEvaluator,
)
from sentence_transformers.cross_encoder.losses import BinaryCrossEntropyLoss
from sentence_transformers.evaluation import SequentialEvaluator
from sentence_transformers.util import mine_hard_negatives

# Đặt mức nhật ký thành INFO để nhận thêm thông tin
logging.basicConfig(format="%(asctime)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=logging.INFO)


def main():
    model_name = "jhu-clsp/ettin-encoder-150m"

    train_batch_size = 64
    num_epochs = 1
    num_hard_negatives = 5  # Cần khai thác bao nhiêu số âm cứng cho mỗi cặp câu hỏi-trả lời

    # 1a. Tải một mô hình để tinh chỉnh với 1b. (Tùy chọn) dữ liệu thẻ mô hình
    model = CrossEncoder(
        model_name,
        model_card_data=CrossEncoderModelCardData(
            language="en",
            license="apache-2.0",
        ),
    )
    print("Độ dài tối đa của mô hình:", model.max_length)
    print("Số nhãn của mô hình:", model.num_labels)

    # 2a. Tải tập dữ liệu GooAQ: https://huggingface.co/datasets/sentence-transformers/gooaq
    logging.info("Đọc tập dữ liệu đào tạo gooaq")
    full_dataset = load_dataset("sentence-transformers/gooaq", split="train").select(range(100_000))
    dataset_dict = full_dataset.train_test_split(test_size=1_000, seed=12)
    train_dataset = dataset_dict["train"]
    eval_dataset = dataset_dict["test"]
    logging.info(train_dataset)
    logging.info(eval_dataset)

    # 2b. Sửa đổi tập dữ liệu đào tạo của chúng tôi để bao gồm các số âm cứng bằng cách sử dụng mô hình nhúng rất hiệu quả
    embedding_model = SentenceTransformer("sentence-transformers/static-retrieval-mrl-en-v1", device="cpu")
    hard_train_dataset = mine_hard_negatives(
        train_dataset,
        embedding_model,
        num_negatives=num_hard_negatives,  # Bao nhiêu số âm trên mỗi cặp câu hỏi-trả lời
        margin=0,  # Độ tương đồng giữa truy vấn và mẫu âm phải thấp hơn độ tương đồng truy vấn-dương
        range_min=0,  # Bỏ qua x mẫu tương tự nhất
        range_max=100,  # Chỉ xem xét x mẫu tương tự nhất
        sampling_strategy="top",  # Lấy mẫu các số âm hàng đầu từ phạm vi
        batch_size=4096,  # Sử dụng kích thước lô là 4096 cho mô hình nhúng
        output_format="labeled-pair",  # Định dạng đầu ra là (truy vấn, đoạn văn, nhãn), như BinaryCrossEntropyLoss yêu cầu
        use_faiss=True,
    )
    logging.info(hard_train_dataset)

    # 2c. (Tùy chọn) Lưu tập dữ liệu đào tạo cứng vào đĩa
    # hard_train_dataset.save_to_disk("gooaq-hard-train")
    # Tải lại với:
    # hard_train_dataset = load_from_disk("gooaq-hard-train")

    # 3. Xác định mất mát đào tạo của chúng tôi.
    # Nên đặt pos_weight là tỷ lệ giữa số dương với số âm, a.k.a. `num_hard_negatives`
    loss = BinaryCrossEntropyLoss(model=model, pos_weight=torch.tensor(num_hard_negatives))

    # 4a. Xác định bộ đánh giá. Chúng tôi sử dụng CrossEncoderNanoBEIREvaluator, là một bộ đánh giá nhẹ cho việc xếp hạng lại tiếng Anh
    nano_beir_evaluator = CrossEncoderNanoBEIREvaluator(
        dataset_names=["msmarco", "nfcorpus", "nq"],
        batch_size=train_batch_size,
    )

    # 4b. Xác định một trình đánh giá xếp hạng lại bằng cách khai thác các số âm cứng cho các cặp câu hỏi-trả lời
    # Chúng tôi bao gồm câu trả lời tích cực trong danh sách các số âm, để bộ đánh giá có thể sử dụng hiệu suất của
    # mô hình nhúng làm đường cơ sở.
    hard_eval_dataset = mine_hard_negatives(
        eval_dataset,
        embedding_model,
        corpus=full_dataset["answer"],  # Sử dụng toàn bộ tập dữ liệu làm ngữ liệu
        num_negatives=30,  # Cần xếp hạng lại bao nhiêu tài liệu
        batch_size=4096,
        include_positives=True,
        output_format="n-tuple",
        use_faiss=True,
    )
    logging.info(hard_eval_dataset)
    reranking_evaluator = CrossEncoderRerankingEvaluator(
        samples=[
            {
                "query": sample["question"],
                "positive": [sample["answer"]],
                "documents": [sample[column_name] for column_name in hard_eval_dataset.column_names[2:]],
            }
            for sample in hard_eval_dataset
        ],
        batch_size=train_batch_size,
        name="gooaq-dev",
        # Cài đặt thực tế: chỉ xếp hạng lại các số dương mà trình truy xuất đã tìm thấy
        # Đặt thành True để xếp hạng lại *tất cả* các số dương
        always_rerank_positives=False,
    )

    # 4c. Kết hợp bộ đánh giá & chạy mô hình cơ sở trên chúng
    evaluator = SequentialEvaluator([reranking_evaluator, nano_beir_evaluator])
    evaluator(model)

    # 5. Xác định các đối số đào tạo
    short_model_name = model_name if "/" not in model_name else model_name.split("/")[-1]
    run_name = f"reranker-{short_model_name}-gooaq-bce"
    args = CrossEncoderTrainingArguments(
        # Tham số bắt buộc:
        output_dir=f"models/{run_name}",
        # Tham số đào tạo tùy chọn:
        num_train_epochs=num_epochs,
        per_device_train_batch_size=train_batch_size,
        per_device_eval_batch_size=train_batch_size,
        learning_rate=2e-5,
        warmup_ratio=0.1,
        fp16=False,  # Đặt thành False nếu bạn gặp lỗi rằng GPU của bạn không thể chạy trên FP16
        bf16=True,  # Đặt thành True nếu bạn có GPU hỗ trợ BF16
        dataloader_num_workers=4,
        load_best_model_at_end=True,
        metric_for_best_model="eval_gooaq-dev_ndcg@10",
        # Các tham số theo dõi/gỡ lỗi tùy chọn:
        eval_strategy="steps",
        eval_steps=1000,
        save_strategy="steps",
        save_steps=1000,
        save_total_limit=2,
        logging_steps=200,
        logging_first_step=True,
        run_name=run_name,  # Sẽ được sử dụng trong W&B nếu `wandb` được cài đặt
        seed=12,
    )

    # 6. Tạo trình đào tạo & bắt đầu đào tạo
    trainer = CrossEncoderTrainer(
        model=model,
        args=args,
        train_dataset=hard_train_dataset,
        loss=loss,
        evaluator=evaluator,
    )
    trainer.train()

    # 7. Đánh giá mô hình cuối cùng, hữu ích để bao gồm các mô hình này trong thẻ mô hình
    evaluator(model)

    # 8. Lưu mô hình cuối cùng
    final_output_dir = f"models/{run_name}/final"
    model.save_pretrained(final_output_dir)

    # 9. (Tùy chọn) lưu mô hình vào Hugging Face Hub!
    # Nên chạy `huggingface-cli login` để đăng nhập vào tài khoản Hugging Face của bạn trước
    try:
        model.push_to_hub(run_name)
    except Exception:
        logging.error(
            f"Lỗi tải lên mô hình lên Hugging Face Hub:\n{t

### [Link bài viết gốc](https://huggingface.co/blog/ettin)

Recommended for You

Di chuyển Hub từ Git LFS sang Xet

Di chuyển Hub từ Git LFS sang Xet

SmolLM3- smol, đa ngôn ngữ, lý luận theo ngữ cảnh dài

SmolLM3- smol, đa ngôn ngữ, lý luận theo ngữ cảnh dài