Transformers documentation
Mẫu chat
Mẫu chat
Hướng dẫn cơ bản về chat bao gồm cách lưu trữ lịch sử chat và tạo văn bản từ các mô hình chat bằng TextGenerationPipeline.
Hướng dẫn này dành cho người dùng nâng cao hơn, bao gồm các lớp và phương thức cơ bản, cũng như các khái niệm chính để hiểu những gì thực sự diễn ra khi bạn trò chuyện với một mô hình.
Insight quan trọng cần nắm để hiểu các mô hình chat là: mọi LM nhân quả, dù có được huấn luyện cho chat hay không, đều tiếp tục một chuỗi token. Khi huấn luyện các LM nhân quả, quá trình thường bắt đầu bằng “pre-training” trên một tập dữ liệu văn bản khổng lồ, tạo ra một mô hình “base”.
Các mô hình base này sau đó thường được “fine-tune” cho chat, nghĩa là huấn luyện chúng trên dữ liệu được định dạng dưới dạng một chuỗi các tin nhắn. Tuy nhiên, chat vẫn chỉ là một chuỗi token! Danh sách các từ điển role và content mà bạn truyền
vào một mô hình chat sẽ được chuyển đổi thành một chuỗi token, thường kèm theo các token điều khiển như <|user|> hoặc <|assistant|> hoặc <|end_of_message|>, cho phép mô hình nhìn thấy cấu trúc của cuộc chat.
Có nhiều định dạng chat khác nhau, và các mô hình khác nhau có thể sử dụng các định dạng hoặc token điều khiển khác nhau, ngay cả khi chúng được fine-tune từ cùng một mô hình base!
Đừng lo lắng - bạn không cần phải ghi nhớ mọi định dạng chat có thể để sử dụng các mô hình chat. Các mô hình chat đi kèm với mẫu chat, cho biết chúng kỳ vọng chat được định dạng như thế nào.
Bạn có thể truy cập chúng bằng phương thức apply_chat_template. Hãy xem hai ví dụ. Cả hai mô hình này đều được tinh chỉnh từ cùng một mô hình cơ sở Mistral-7B:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
chat = [
{"role": "user", "content": "Hello, how are you?"},
{"role": "assistant", "content": "I'm doing great. How can I help you today?"},
{"role": "user", "content": "I'd like to show off how chat templating works!"},
]
tokenizer.apply_chat_template(chat, tokenize=False)<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
chat = [
{"role": "user", "content": "Hello, how are you?"},
{"role": "assistant", "content": "I'm doing great. How can I help you today?"},
{"role": "user", "content": "I'd like to show off how chat templating works!"},
]
tokenizer.apply_chat_template(chat, tokenize=False)<|user|>\nHello, how are you?</s>\n<|assistant|>\nI'm doing great. How can I help you today?</s>\n<|user|>\nI'd like to show off how chat templating works!</s>\nMistral-7B-Instruct sử dụng các token [INST] và [/INST] để chỉ định điểm bắt đầu và kết thúc của thông điệp người dùng, trong khi Zephyr-7B sử dụng các token <|user|> và <|assistant|> để chỉ định vai trò của người nói. Đây là lý do tại sao các chat template lại quan trọng - với các token điều khiển sai, hiệu suất của các mô hình này sẽ giảm đi đáng kể.
Sử dụng apply_chat_template
Đầu vào của apply_chat_template nên được cấu trúc dưới dạng một danh sách các từ điển có các khóa role và content. Khóa role chỉ định người nói, và khóa content chứa nội dung tin nhắn. Các vai trò phổ biến là:
usercho các tin nhắn từ người dùngassistantcho các tin nhắn từ mô hìnhsystemđể chỉ định cách mô hình nên hành xử (thường được đặt ở đầu cuộc trò chuyện)
apply_chat_template nhận danh sách này và trả về một chuỗi đã được định dạng. Đặt tokenize=True nếu bạn muốn thực hiện tokenize chuỗi.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceH4/zephyr-7b-beta", device_map="auto", dtype=torch.bfloat16)
messages = [
{"role": "system", "content": "You are a friendly chatbot who always responds in the style of a pirate",},
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
]
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to(model.device)
print(tokenizer.decode(tokenized_chat["input_ids"][0]))<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>Truyền chat đã được token hóa vào generate() để tạo phản hồi.
outputs = model.generate(**tokenized_chat, max_new_tokens=128)
print(tokenizer.decode(outputs[0]))<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.Một số tokenizer thêm các token đặc biệt
<bos>và<eos>. Chat template thường đã bao gồm tất cả các token đặc biệt cần thiết, và việc thêm các token đặc biệt bổ sung thường là không chính xác hoặc bị trùng lặp, gây ảnh hưởng đến hiệu suất của model. Khi bạn định dạng văn bản bằngapply_chat_template(tokenize=False), hãy đảm bảo đặtadd_special_tokens=Falsenếu bạn tokenize sau đó để tránh trùng lặp các token này. Đây không phải là vấn đề nếu bạn sử dụngapply_chat_template(tokenize=True), điều này có nghĩa là đây thường là lựa chọn an toàn hơn!
add_generation_prompt
Bạn có thể đã nhận thấy đối số add_generation_prompt trong các ví dụ ở trên.
Đối số này thêm các token vào cuối cuộc trò chuyện để chỉ báo sự bắt đầu của một phản hồi assistant. Hãy nhớ rằng: Bên dưới tất cả các trừu tượng về chat, các mô hình chat vẫn chỉ là các mô hình ngôn ngữ tiếp nối một chuỗi token!
Nếu bạn bao gồm các token cho biết hiện đang ở trong một phản hồi assistant, mô hình sẽ viết phản hồi một cách chính xác, nhưng nếu bạn không bao gồm các token này, mô hình có thể bị nhầm lẫn và làm điều gì đó kỳ lạ, chẳng hạn như tiếp tục tin nhắn của người dùng thay vì trả lời nó!
Hãy xem một ví dụ để hiểu add_generation_prompt thực sự đang làm gì. Trước tiên, hãy định dạng một cuộc trò chuyện mà không có add_generation_prompt:
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
tokenized_chat<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>Bây giờ, hãy định dạng cùng một cuộc trò chuyện với add_generation_prompt=True:
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
tokenized_chat<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
<|im_start|>assistant
Khi add_generation_prompt=True, <|im_start|>assistant được thêm vào cuối để chỉ báo bắt đầu một thông điệp assistant. Điều này giúp mô hình biết rằng phản hồi assistant sẽ đến tiếp theo.
Không phải tất cả các model đều yêu cầu prompt sinh, và một số model, chẳng hạn như Llama, không có token đặc biệt nào trước phản hồi assistant. Trong những trường hợp này, add_generation_prompt không có tác dụng.
continue_final_message
Tham số continue_final_message kiểm soát việc tin nhắn cuối cùng trong cuộc trò chuyện có nên được tiếp tục hay không thay vì bắt đầu một tin nhắn mới. Tham số này loại bỏ các token kết thúc chuỗi để mô hình tiếp tục sinh nội dung từ tin nhắn cuối cùng.
Điều này hữu ích để “tiền nạp” (prefill) phản hồi của mô hình. Trong ví dụ bên dưới, mô hình tạo ra văn bản tiếp nối chuỗi JSON thay vì bắt đầu một tin nhắn mới. Nó có thể rất hữu ích để cải thiện độ chính xác của việc tuân theo chỉ thị khi bạn biết cách bắt đầu các phản hồi của nó.
chat = [
{"role": "user", "content": "Can you format the answer in JSON?"},
{"role": "assistant", "content": '{"name": "'},
]
formatted_chat = tokenizer.apply_chat_template(chat, tokenize=True, return_dict=True, continue_final_message=True)
model.generate(**formatted_chat)Bạn không nên sử dụng add_generation_prompt và continue_final_message cùng lúc. Tham số đầu tiên thêm các token bắt đầu một tin nhắn mới, trong khi tham số sau xóa các token kết thúc chuỗi. Việc sử dụng chúng cùng nhau sẽ gây ra lỗi.
Truyền tên trường dưới dạng chuỗi để điền trước trường đó thay vì content. Các mô hình suy luận đọc suy luận của chúng từ trường reasoning_content riêng biệt. Việc điền trước content sẽ đóng khối suy luận trước khi bắt đầu tạo, khiến mô hình không thể tiếp tục bên trong khối đó. Việc điền trước reasoning_content trực tiếp sẽ giữ cho khối mở.
chat = [
{"role": "user", "content": "Explain 1+1"},
{"role": "assistant", "reasoning_content": "The user wants a simple addition. ", "content": ""},
]
formatted_chat = tokenizer.apply_chat_template(chat, tokenize=False, continue_final_message="reasoning_content")Trường có tên phải tồn tại trong tin nhắn cuối cùng và phải được tham chiếu bởi mẫu chat. Một lỗi sẽ được ném ra khi một trong hai kiểm tra thất bại.
TextGenerationPipeline đặt add_generation_prompt thành True theo mặc định để bắt đầu một tin nhắn mới. Tuy nhiên, nếu tin nhắn cuối cùng trong cuộc trò chuyện có vai trò assistant, hệ thống sẽ coi tin nhắn đó là prefill và chuyển sang continue_final_message=True. Điều này là do hầu hết các model không hỗ trợ nhiều tin nhắn assistant liên tiếp. Để ghi đè hành vi này, hãy truyền rõ ràng đối số continue_final_message cho pipeline.
Huấn luyện mô hình
Việc huấn luyện một mô hình với chat template là cách tốt để đảm bảo template khớp với các token mà mô hình đã được huấn luyện. Áp dụng chat template như một bước tiền xử lý cho bộ dữ liệu của bạn. Đặt add_generation_prompt=False vì các token bổ sung để gợi ý phản hồi của trợ lý không hữu ích trong quá trình huấn luyện.
Dưới đây là một ví dụ về việc tiền xử lý một bộ dữ liệu với một mẫu trò chuyện.
from transformers import AutoTokenizer
from datasets import Dataset
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
chat1 = [
{"role": "user", "content": "Which is bigger, the moon or the sun?"},
{"role": "assistant", "content": "The sun."}
]
chat2 = [
{"role": "user", "content": "Which is bigger, a virus or a bacterium?"},
{"role": "assistant", "content": "A bacterium."}
]
dataset = Dataset.from_dict({"chat": [chat1, chat2]})
dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)})
print(dataset['formatted_chat'][0])<|user|>
Which is bigger, the moon or the sun?</s>
<|assistant|>
The sun.</s>Sau bước này, bạn có thể tiếp tục làm theo công thức huấn luyện cho các mô hình ngôn ngữ nhân quả bằng cách sử dụng cột formatted_chat.