Mô hình ngôn ngữ lớn (LLM) đã trở thành từ thông dụng trong phát triển phần mềm kể từ khi ChatGPT phát hành. Khả năng trò chuyện tự nhiên với con người của nó chỉ là phần nổi của tảng băng trôi. Được cải tiến bằng các công cụ như LangChain hoặc Semantic Kernel, LLM có khả năng thay đổi hoàn toàn cách người dùng tương tác với phần mềm. Nói cách khác, LLM có thể tạo ra sự phối hợp giữa các chức năng và nguồn dữ liệu, đồng thời cung cấp trải nghiệm người dùng hiệu quả và trực quan hơn.
Ví dụ: nhiều người đã sử dụng các công cụ tạo nội dung dựa trên AI cho các video lan truyền tiếp theo của họ. Một quy trình sản xuất video điển hình bao gồm viết kịch bản, hậu cần, viết kịch bản phân cảnh, chỉnh sửa và tiếp thị, chỉ kể tên một số. Để đơn giản hóa quy trình, LLM có thể giúp người sáng tạo nội dung nghiên cứu trong khi viết kịch bản, mua đạo cụ cho cảnh quay, tạo bảng phân cảnh dựa trên kịch bản (có thể cần khả năng khuếch tán ổn định để tạo hình ảnh), tạo điều kiện thuận lợi cho quá trình chỉnh sửa và viết tiêu đề bắt mắt. /mô tả video để thu hút lượt xem trên mạng xã hội. LLM là cốt lõi điều phối tất cả những điều này, nhưng có thể có một số mối lo ngại khi kết hợp LLM vào một sản phẩm phần mềm:
Nếu sử dụng API của OpenAI, liệu tôi có trở nên quá phụ thuộc vào dịch vụ này không? Lỡ họ tăng giá thì sao? Điều gì sẽ xảy ra nếu họ thay đổi tính khả dụng của dịch vụ?
Tôi không thích cách OpenAI kiểm duyệt nội dung hoặc đưa ra phản hồi không mang tính xây dựng đối với một số thông tin đầu vào nhất định của người dùng. (Hoặc ngược lại: Tôi không thích cách kiểm duyệt OpenAI bỏ qua một số điều nhạy cảm trong trường hợp sử dụng của tôi.)
Nếu khách hàng của tôi thích triển khai trên nền tảng đám mây riêng tư hoặc tại chỗ thì tôi có những lựa chọn thay thế ChatGPT nào?
Tôi chỉ muốn có quyền kiểm soát. Tôi cần tùy chỉnh LLM và tôi muốn nó rẻ.
Đối với những lo ngại này, tôi tự hỏi liệu có thể có một mô hình GPT có nguồn mở tương đương với các mô hình GPT của OpenAI hay không. May mắn thay, các cộng đồng nguồn mở tuyệt vời đã chia sẻ một số giải pháp rất hứa hẹn. Tôi quyết định dùng thử alpaca-lora , một phương pháp tinh chỉnh tham số hiệu quả để đào tạo LLM của riêng bạn. Bài đăng trên blog này thảo luận về quy trình, những vấn đề tôi gặp phải, cách tôi giải quyết chúng và những gì có thể xảy ra tiếp theo. Nếu bạn cũng muốn sử dụng kỹ thuật đào tạo LLM của riêng mình, tôi hy vọng thông tin này có thể hữu ích.
Hãy bắt đầu nào!
LLaMA là tập hợp các mô hình ngôn ngữ nền tảng từ Meta AI. Các mô hình tự hồi quy này có số lượng tham số nằm trong khoảng từ 7B đến 65B và chúng chỉ có thể được sử dụng cho mục đích nghiên cứu. Meta gần đây đã phát hành LLaMA 2 , có thể được sử dụng thương mại với một số giới hạn. Điều làm cho dòng mô hình LLaMA trở nên đặc biệt là tập dữ liệu huấn luyện và hiệu suất của nó. Meta tuyên bố rằng LLaMA được đào tạo trên các bộ dữ liệu có sẵn công khai. Biến thể 13B của nó đạt được hiệu suất tương đương với GPT-3 (mẫu 175B) trên hầu hết các điểm chuẩn.
alpaca là nỗ lực của Stanford nhằm xây dựng LLM theo hướng dẫn dựa trên LLaMA. Nó hoạt động như thế này:
Yêu cầu một mô hình ngôn ngữ tạo ra bộ ba lệnh-đầu vào-phản hồi.
Sử dụng dữ liệu được tạo để tinh chỉnh LLaMA.
Sau khi tinh chỉnh, LLaMA có thể làm theo hướng dẫn của người dùng và phản hồi tương ứng.
Dưới đây là so sánh giữa phản hồi của vanilla LLaMA và phản hồi LLaMA được tinh chỉnh:
{ "instruction": "Answer user's question.", "input": "Can you put a medium voltage circuit breaker in a low voltage switchgear? Why? Explain in detail.", "vanilla LLaMA": { "answer": "Yes, you can put a medium voltage circuit breaker in a low voltage switchgear. The medium voltage circuit breaker can be put in a low voltage switchgear because the medium voltage circuit breaker can be put in a low voltage switchgear because the medium voltage circuit breaker can be put in a low voltage switchgear because the medium voltage circuit breaker can be put....(repetition continues)" }, "fine-tuned LLaMA": { "answer": "No, it is not possible to put a medium voltage circuit breaker in a low voltage switchgear. This is because low voltage switchgear is designed to handle voltages up to 1 kV, while medium voltage switchgear is designed to handle voltages from 1 kV to 38 kV. The circuit breakers, contacts, and other components in low voltage switchgear are not suitable for the higher voltages and currents of medium voltage switchgear. Using a medium voltage circuit breaker in a low voltage switchgear could result in damage to the components and could pose a safety hazard." } }
Như bạn có thể thấy, việc tinh chỉnh thay đổi hành vi LLM khá mạnh mẽ. Mô hình vanilla bị mắc kẹt trong một vòng lặp lặp lại. Mặc dù mô hình được tinh chỉnh không mang lại phản hồi chính xác 100% nhưng ít nhất câu trả lời của nó là "Không". Tinh chỉnh là một bước cần thiết để tạo ra LLM có thể sử dụng được. Trong nhiều trường hợp, việc triển khai LLM tinh chỉnh có nguồn mở là đủ. Tuy nhiên, trong một số trường hợp sử dụng phù hợp với doanh nghiệp, có thể nên tinh chỉnh các mô hình trên các bộ dữ liệu theo miền cụ thể.
Hạn chế lớn nhất của Alpaca là yêu cầu về tài nguyên. Trang GitHub của nó nói rằng:
Ngây thơ, việc tinh chỉnh mô hình 7B cần khoảng 7 x 4 x 4 = 112 GB VRAM.
Đây là nhiều VRAM hơn mức mà GPU A100 80GB có thể xử lý. Chúng tôi có thể bỏ qua yêu cầu VRAM bằng LoRA .
LoRA hoạt động như thế này:
Trọng lượng tăng thêm có một số tính chất đặc biệt. Lấy cảm hứng từ bài báo này, Edward Hu et al. đã chỉ ra rằng đối với trọng lượng mô hình ban đầu $W_o\in R^{d \times k}$, bạn có thể tạo ra trọng số tinh chỉnh $W_o'=W_o+BA$ cho các tác vụ xuôi dòng, trong đó $B\in R^{d \times r}$ , $A \in R^{r \times k}$ và $r\ll min(d, k)$ là "thứ hạng nội tại" của trọng lượng bộ chuyển đổi. Điều quan trọng là phải đặt $r$ thích hợp cho trọng lượng bộ chuyển đổi, vì $r$ nhỏ hơn sẽ làm giảm hiệu suất mô hình và $r$ lớn hơn sẽ tăng kích thước trọng lượng bộ chuyển đổi mà không tăng hiệu suất theo tỷ lệ.
Kỹ thuật này tương tự như SVD rút gọn, xấp xỉ một ma trận bằng cách phân tách nó thành nhiều ma trận nhỏ hơn và chỉ giữ một vài giá trị số ít lớn nhất. Giả sử $W_o\in R^{100 \times 100}$, một tinh chỉnh đầy đủ sẽ thay đổi 10.000 tham số. Việc tinh chỉnh LoRA với $r=8$ sẽ phân tách trọng số được tinh chỉnh thành 2 phần, $B\in R^{100 \times 8}$ và $A\in R^{8 \times 100}$, mỗi phần phần chứa 800 tham số (tổng cộng 1600 tham số.) Số lượng tham số có thể huấn luyện giảm 6,25 lần.
Sau khi chuyển đổi mô hình bằng LoRA, chúng tôi có được một mô hình chỉ có ~1% trọng số có thể huấn luyện được, tuy nhiên hiệu suất của nó được cải thiện đáng kể trong một số lĩnh vực nhất định. Điều này sẽ cho phép chúng tôi đào tạo các mô hình 7B hoặc 13B trên phần cứng dễ tiếp cận hơn như RTX 4090 hoặc V100.
Tôi đã chạy thử nghiệm trên Huawei Cloud với phiên bản VM được tăng tốc GPU ( p2s.2xlarge
, 8vCPU, RAM 64GB, 1x V100 32GB VRAM.) Được biết, V100 không hỗ trợ kiểu dữ liệu bfloat16 và lõi tensor của nó không hỗ trợ int8 sự tăng tốc. Hai giới hạn này có thể làm chậm quá trình đào tạo có độ chính xác hỗn hợp và gây ra tình trạng tràn số trong quá trình đào tạo có độ chính xác hỗn hợp. Chúng tôi sẽ ghi nhớ điều này để thảo luận sau.
finetune.py
và generate.py
là cốt lõi của dự án. Tập lệnh đầu tiên tinh chỉnh các mô hình LLaMA và tập lệnh thứ hai sử dụng mô hình tinh chỉnh để trò chuyện với người dùng. Trước tiên chúng ta hãy xem luồng chính của finetune.py
:
model = LlamaForCausalLM.from_pretrained( base_model, # name of a huggingface compatible LLaMA model load_in_8bit=True, torch_dtype=torch.float16, device_map=device_map, )
tokenizer = LlamaTokenizer.from_pretrained(base_model) tokenizer.pad_token_id = ( 0 # unk. we want this to be different from the eos token ) tokenizer.padding_side = "left" # Allow batched inference
dựa trên mẫu đào tạo, hãy chuẩn bị đầu vào mô hình với hai hàm, tokenize
và generate_and_tokenize_prompt
.
tạo mô hình phù hợp với LoRA bằng cách sử dụng PEFT của ôm mặt
config = LoraConfig( r=lora_r, # the lora rank lora_alpha=lora_alpha, # a weight scaling factor, think of it like learning rate target_modules=lora_target_modules, # transformer modules to apply LoRA to lora_dropout=lora_dropout, bias="none", task_type="CAUSAL_LM", ) model = get_peft_model(model, config)
trainer = transformers.Trainer( model=model, train_dataset=train_data, eval_dataset=val_data, args=transformers.TrainingArguments( ...
Điều này khá đơn giản.
Cuối cùng, tập lệnh tạo ra một thư mục mô hình có các điểm kiểm tra, trọng lượng bộ điều hợp và cấu hình bộ điều hợp.
Tiếp theo, hãy xem luồng chính của generate.py
:
model = LlamaForCausalLM.from_pretrained( base_model, device_map={"": device}, torch_dtype=torch.float16, ) model = PeftModel.from_pretrained( model, lora_weights, device_map={"": device}, torch_dtype=torch.float16, )
generation_config = GenerationConfig( temperature=temperature, top_p=top_p, top_k=top_k, num_beams=num_beams, **kwargs, ) generate_params = { "input_ids": input_ids, "generation_config": generation_config, "return_dict_in_generate": True, "output_scores": True, "max_new_tokens": max_new_tokens, }
if stream_output: # streaming ... # Without streaming with torch.no_grad(): generation_output = model.generate( input_ids=input_ids, generation_config=generation_config, return_dict_in_generate=True, output_scores=True, max_new_tokens=max_new_tokens, ) s = generation_output.sequences[0] output = tokenizer.decode(s) yield prompter.get_response(output)
gr.Interface( ...
README.md
của dự án cho biết rằng các cài đặt tinh chỉnh sau đây tạo ra LLaMA 7B với hiệu suất tương đương với alpaca Stanford. Trọng lượng alpaca-lora "chính thức" đã được chia sẻ trên ôm mặt.
python finetune.py \ --base_model='decapoda-research/llama-7b-hf' \ --num_epochs=10 \ --cutoff_len=512 \ --group_by_length \ --output_dir='./lora-alpaca' \ --lora_target_modules='[q_proj,k_proj,v_proj,o_proj]' \ --lora_r=16 \ --micro_batch_size=8
Tuy nhiên, theo kinh nghiệm của tôi, nó không mang lại một mô hình có thể sử dụng được. Chạy nó trên V100 sẽ gặp phải các vấn đề dừng hiển thị sau:
load_in_8bit
gây ra lỗi kiểu dữ liệu.decapoda-research/llama-7b-hf
dường như đã sử dụng sai mã thông báo. Mã thông báo pad, mã thông báo bos và mã thông báo eos của nó khác với mã thông báo chính thức của LLaMA.training loss = 0.0
và eval loss = NaN
.
Sau khi tìm hiểu kỹ và lãng phí nhiều giờ VM, tôi đã tìm thấy những thay đổi cần thiết để thực hiện công việc đào tạo trên một chiếc V100.
... # do not use decapoda-research/llama-7b-hf as base_model. use a huggingface LLaMA model that was properly converted and has a correct tokenizer, eg, yahma/llama-7b-hf or huggyllama/llama-7b. # decapoda-research/llama-7b-hf is likely to cause overflow/underflow on V100. train loss goes to 0 and eval loss becomes NaN. using yahma/llama-7b-hf or huggyllama/llama-7b somehow mitigates this issue model = LlamaForCausalLM.from_pretrained( base_model, load_in_8bit=True, # only work for 7B LLaMA. On a V100, set True to save some VRAM at the cost of slower training; set False to speed up training at the cost of more VRAM / smaller micro batch size torch_dtype=torch.float16, device_map=device_map, ) ... # comment out the following line if load_in_8bit=False model = prepare_model_for_int8_training(model) ... # set legacy=False to avoid unexpected tokenizer behavior. make sure no tokenizer warning was raised during tokenizer instantiation tokenizer = LlamaTokenizer.from_pretrained(base_model, legacy=False) ... # the following binding script results in invalid adapter. simply comment them out old_state_dict = model.state_dict model.state_dict = ( lambda self, *_, **__: get_peft_model_state_dict( self, old_state_dict() ) ).__get__(model, type(model)) ... # if load_in_8bit=True, need to cast data type during training with torch.autocast('cuda'): trainer.train(resume_from_checkpoint=resume_from_checkpoint)
Sau khi thực hiện những thay đổi này, các đối số huấn luyện này sẽ tạo ra một mô hình có thể sử dụng được.
{ "args": [ "--base_model", "yahma/llama-7b-hf", "--num_epochs=10", "--data_path", "yahma/alpaca-cleaned", "--output_dir", "./your output dir", "--cutoff_len=512", "--lora_target_modules=[q_proj,k_proj,v_proj,o_proj]", "--lora_r=16", "--micro_batch_size=2", "--batch_size=16", "--wandb_project", "your wandb project name" ], }
Lưu ý rằng tập lệnh huấn luyện không chỉ lưu mô hình "tốt nhất" (điểm kiểm tra có mức mất đánh giá thấp nhất) mà còn lưu một số điểm kiểm tra. Tôi đã sử dụng Wandb để ghi lại các tổn thất đào tạo/đánh giá để phân tích thêm.
Tôi ném một số câu hỏi ngẫu nhiên vào mô hình đã được tinh chỉnh. Nó tạo ra một số phản ứng hợp lý.
Đây là một ví dụ:
Hướng dẫn: Trả lời câu hỏi của người dùng một cách cẩn thận.
Đầu vào: Điều gì xảy ra khi bạn sử dụng một chiếc xe tải cầu dao thiết bị đóng cắt?
Trả lời: Khi xe tải đóng cắt bị "hạ điện" có nghĩa là tất cả các cầu dao trong xe tải đã được mở và xe tải ở trạng thái không mang điện. Việc này thường được thực hiện khi xe tải đang được bảo dưỡng, sửa chữa hoặc kiểm tra. Khi cầu dao đã được tháo ra, xe tải sẽ hoạt động an toàn và có thể được cấp điện trở lại sau khi hoàn thành việc bảo trì hoặc sửa chữa cần thiết.
Ví dụ này truy vấn kiến thức nội bộ của LLM. Người mẫu dường như biết rất nhiều về thiết bị đóng cắt. Tuy nhiên, khi tôi thử kiểm tra khả năng suy luận của nó bằng thực nghiệm thì nó lại cho ra một kết quả rất kỳ lạ:
Chỉ dẫn:
Cho những thông tin dưới đây về một dự án, hãy trả lời các câu hỏi. Dự án Chinese-Llama-2 nhằm mục đích nâng cao khả năng hiểu, tạo và dịch thuật của mô hình ngôn ngữ lớn Llama-2 bằng tiếng Trung Quốc. Với việc áp dụng các phương pháp như tinh chỉnh LoRA, tinh chỉnh hướng dẫn tham số đầy đủ và đào tạo trước thứ cấp, chúng tôi trân trọng mời bạn tải xuống và sử dụng các bộ dữ liệu, hướng dẫn đào tạo và tham số mô hình liên quan.
Đầu vào: Những phương pháp nào được sử dụng trong dự án này?
Phản hồi: Dự án Chinese-Llama-2 nhằm mục đích nâng cao khả năng hiểu, tạo và dịch thuật của mô hình ngôn ngữ lớn Llama-2 bằng tiếng Trung Quốc. Với việc áp dụng các phương pháp như tinh chỉnh LoRA, tinh chỉnh hướng dẫn tham số đầy đủ và đào tạo trước thứ cấp, chúng tôi trân trọng mời bạn tải xuống và sử dụng các tập dữ liệu, hướng dẫn đào tạo và tham số mô hình liên quan.</s>
Như bạn có thể thấy, mô hình thích lặp lại lời nhắc. Tôi gọi nó là mô hình lặp lại lời nhắc và các nhà phát triển khác cũng đã báo cáo hành vi này trong các vấn đề về kho lưu trữ . Khả năng trả lời các câu hỏi của nó chỉ trở nên tốt hơn khi có những lời nhắc được thiết kế cẩn thận hơn. Hành vi này không phải là điều chúng tôi mong muốn trong hệ thống sản xuất vì chúng tôi không thể đảm bảo hiệu quả nhanh chóng trên các mô hình khác nhau. Các mô hình phải ít nhạy cảm hơn với các lời nhắc. Chúng tôi muốn bằng cách nào đó cải thiện hiệu suất của LLM này.
Trong phần tiếp theo, tôi sẽ thảo luận về nguyên nhân gây ra vấn đề này và cách cải thiện kết quả tinh chỉnh.
Dưới đây là 3 điều tôi đã cố gắng cải thiện kết quả tinh chỉnh:
Che giấu sự mất mát trên lời nhắc (giúp tránh lặp lại lời nhắc)
Tắt tùy chọn group-by-length
(giúp cải thiện hiệu suất, giúp đường cong mất mát trông mượt mà hơn)
Đừng tin vào đường cong tổn thất đánh giá. Sử dụng điểm kiểm tra có mức mất huấn luyện thấp hơn, mặc dù mức mất đánh giá của nó có thể cao hơn điểm kiểm tra "tốt nhất". (giúp cải thiện hiệu suất, vì mất eval không phải là ma trận tốt nhất ở đây)
Hãy giải thích từng điểm một.
Tôi đang tìm kiếm nguyên nhân của sự lặp lại nhanh chóng cho đến khi tôi tìm thấy bài đăng này và thông báo cam kết chính thức về trọng lượng lora . Họ gợi ý rằng nên loại trừ các lời nhắc trong tính toán tổn thất. Về cơ bản, bạn không muốn khuyến khích mô hình xuất mã thông báo nhắc nhở. Việc che giấu các lời nhắc trong quá trình đào tạo sẽ không khuyến khích mô hình lặp lại các mã thông báo nhắc nhở. Biểu đồ bên dưới giải thích điều này: trong số 3 lượt tập luyện, stoic-star-6
là lượt chạy duy nhất không che giấu những lời nhắc trong quá trình tập luyện. Do đó, tổn thất huấn luyện của nó lúc đầu cao hơn. Tôi nghi ngờ rằng nếu a) lời nhắc không bị che giấu khi tính toán tổn thất và b) đào tạo không đầy đủ thì mô hình sẽ có nhiều khả năng lặp lại lời nhắc hơn là làm theo hướng dẫn.
Trong mã nguồn, việc che dấu tổn thất được thực hiện bằng cách đặt mã thông báo nhắc thành -100:
Các mã thông báo có chỉ số được đặt thành
-100
sẽ bị bỏ qua (bị che), tổn thất chỉ được tính cho các mã thông báo có nhãn trong[0, ..., config.vocab_size]
.
group-by-length
tùy chọn group-by-length
cho phép Trainer
của ôm mặt nhóm các đầu vào có độ dài tương tự thành các đợt. Điều này giúp tiết kiệm mức sử dụng VRAM khi đệm các chuỗi đầu vào. Tuy nhiên, nó sẽ làm giảm đáng kể phương sai mẫu trong một đợt. Trong quá trình đào tạo, chúng tôi thường thích cho mô hình tiếp xúc với nhiều mẫu đào tạo khác nhau. Đặt group-by-length
False
sẽ giảm sự biến đổi của mẫu. Nó cũng gây ra sự biến động về tổn thất trong quá trình huấn luyện (Ví dụ: hai lô liên tiếp có độ dài đệm là 10 và 50. Lô ngắn hơn có tổn thất thấp hơn và lô dài hơn có tổn thất cao hơn. Điều này dẫn đến đường cong tổn thất dao động, như trong hình dưới).
Mặt khác, vì group-by-length
làm giảm sự biến đổi mẫu trong lô nên tôi nghi ngờ hiệu suất của mô hình cũng có thể bị ảnh hưởng bởi điều này. Hình dưới đây so sánh mức độ mất huấn luyện có hoặc không có group-by-length
. Rõ ràng là tổn thất trung bình cao hơn khi chạy peach-violet-19
, được bật group-by-length
.
Tôi quan sát thấy rằng mức giảm khi luyện tập và mức giảm đánh giá khác nhau trong tất cả các lần chạy của tôi.
Đây là một ví dụ:
Trong ví dụ này, điểm kiểm tra tối ưu xảy ra vào khoảng epoch=2
. Nếu bạn tải điểm kiểm tra tối ưu như được đề xuất bởi repo ban đầu, rất có thể bạn sẽ nhận được mô hình lặp lại lời nhắc như đã đề cập trong phiên trước.
Bằng cách tải điểm kiểm tra mô hình vào gần cuối khóa đào tạo, tôi đã có được một mô hình hoạt động hiệu quả hơn. Tôi đã hỏi câu hỏi tương tự như trước và người mẫu đã trả lời đúng:
Chỉ dẫn:
Cho những thông tin dưới đây về một dự án, hãy trả lời các câu hỏi. Dự án Chinese-Llama-2 nhằm mục đích nâng cao khả năng hiểu, tạo và dịch thuật của mô hình ngôn ngữ lớn Llama-2 bằng tiếng Trung Quốc. Với việc áp dụng các phương pháp như tinh chỉnh LoRA, tinh chỉnh hướng dẫn tham số đầy đủ và đào tạo trước thứ cấp, chúng tôi trân trọng mời bạn tải xuống và sử dụng các bộ dữ liệu, hướng dẫn đào tạo và tham số mô hình liên quan.
Đầu vào: Những phương pháp nào được sử dụng trong dự án này?
Phản hồi: Dự án Chinese-Llama-2 sử dụng các phương pháp như tinh chỉnh LoRA, tinh chỉnh hướng dẫn đầy đủ thông số và đào tạo trước thứ cấp.</s>
Nhưng xét theo tổn thất đánh giá, mô hình này sẽ hoạt động kém hơn. Điều gì gây ra tình trạng khó xử?
Tôi nghĩ rằng việc mất đánh giá không phải là ma trận tốt để đo lường hiệu suất của mô hình ngôn ngữ lớn. LLaMA sử dụng CrossEntropyLoss
để đào tạo và đánh giá tổn thất:
# modelling_llama.py from transformers library ... # forward function under LlamaForCausalLM class if labels is not None: # Shift so that tokens < n predict n shift_logits = logits[..., :-1, :].contiguous() shift_labels = labels[..., 1:].contiguous() # Flatten the tokens loss_fct = CrossEntropyLoss() loss = loss_fct(shift_logits.view(-1, self.config.vocab_size), shift_labels.view(-1))
Khi thử nghiệm trên một tập đánh giá, một mô hình có thể đưa ra cùng một câu trả lời nhưng có cách diễn đạt khác nhau:
{ "evaluation prompt": "What is 1 + 3?" "evaluation answer": "4." "prediction answer": "The answer is 4." }
Cả hai câu trả lời đều đúng, nhưng nếu câu trả lời dự đoán không khớp chính xác với câu trả lời đánh giá thì tổn thất đánh giá sẽ cao. Trong trường hợp này, chúng ta cần một ma trận đánh giá tốt hơn để đo lường hiệu suất của mô hình. Chúng tôi sẽ lo lắng về việc đánh giá đúng đắn sau này. Hiện tại, hãy giả sử mô hình tốt nhất là mô hình có mức tổn thất đào tạo thấp nhất.
Tôi đã thử tinh chỉnh model 13B trên V100. Mặc dù V100 có thể xử lý cả đào tạo int8 và fp16 trên mô hình 7B, nhưng đơn giản là nó không thể xử lý đào tạo int8 trên mô hình 13B. Nếu load_int_8bit = True
, mô hình 13B sẽ tạo ra training_loss = 0.0
. Chúng ta có thể sử dụng một số công cụ gỡ lỗi để hiểu lý do tại sao điều này xảy ra ( cảnh báo spoiler: nguyên nhân là do tràn/tràn).
Tôi đã sử dụng công cụ DebugUnderflowOverflow
của ôm mặt để kiểm tra các thông số trong quá trình đào tạo. Trong lần chuyển tiếp đầu tiên, nó đã phát hiện các giá trị inf/nan:
Cụ thể hơn, DebugUnderflowOverflow
đã bắt được các giá trị vô cực âm trong đầu vào thứ 2 của LlamaDecoderLayer
, như minh họa trong hình bên dưới. Đầu vào thứ 2 là attention_mask
. Tôi đã tìm hiểu sâu hơn một chút và phát hiện ra rằng attention_mask
được cho là có giá trị âm rất lớn đối với các phần tử đệm. Thật trùng hợp, các giá trị vô cực âm lại nằm ở đầu mỗi chuỗi. Quan sát này khiến tôi tin rằng các giá trị vô cực âm được cho là xảy ra ở lớp này. Nghiên cứu sâu hơn cũng cho thấy rằng các giá trị vô cực không gây ra nhiều giá trị vô cực hơn trong một số lớp tiếp theo. Do đó, tình trạng tràn LlamaDecoderLayer
rất có thể không phải là nguyên nhân sâu xa gây ra tình trạng mất huấn luyện bất thường.
Tiếp theo, tôi kiểm tra kết quả đầu ra của từng lớp. Rõ ràng là đầu ra của các lớp cuối cùng đang bị tràn, như trong hình bên dưới. Tôi tin rằng điều này là do độ chính xác hạn chế của trọng số int-8 (hoặc phạm vi giới hạn của float16
. Có khả năng là bfloat16
có thể tránh được vấn đề này).
Để giải quyết vấn đề tràn, tôi đã sử dụng float16 trong quá trình đào tạo. V100 không có đủ VRAM để huấn luyện mẫu 13B trừ khi sử dụng một số thủ thuật. Ôm mặt DeepSpeed cung cấp một số phương pháp, chẳng hạn như giảm tải CPU, để giảm mức sử dụng VRAM khi luyện tập. Nhưng thủ thuật đơn giản nhất là bật tính năng kiểm tra độ dốc bằng cách gọi model.gradient_checkpointing_enable()
trước khi bắt đầu đào tạo.
Điểm kiểm tra độ dốc đánh đổi tốc độ đào tạo để sử dụng ít VRAM hơn. Thông thường, trong quá trình chuyển tiếp, các kích hoạt được tính toán và lưu trữ trong bộ nhớ để sử dụng trong quá trình chuyển tiếp. Điều này chiếm thêm bộ nhớ. Tuy nhiên, với điểm kiểm tra độ dốc, thay vì lưu trữ các kích hoạt trong quá trình chuyển tiếp, chúng được tính toán lại trong quá trình chuyển ngược, do đó tiết kiệm VRAM. Đây là một bài viết hay về kỹ thuật này.
Tôi đã có thể huấn luyện Llama 13B khi bật tính năng kiểm tra độ dốc và float16:
python finetune.py \ --base_model=yahma/llama-13b-hf \ --num_epochs=10 \ --output_dir 'your/output/dir' \ --lora_target_modules='[q_proj,k_proj,v_proj,o_proj]' \ --cutoff_len=1024 \ --lora_r=16 \ --micro_batch_size=4 \ --batch_size=128 \ --wandb_project 'alpaca_lora_13b' \ --train_on_inputs=False
Mô hình 13B có thể xử lý một số tác vụ nâng cao như nhận dạng thực thể tên. Tôi sử dụng lời nhắc ví dụ cho bài kiểm tra và đây là phản hồi chính xác của mô hình 13B:
Tất cả đều tốt! Đây là một khởi đầu thú vị. Mô hình cho phép chúng tôi tạo các ứng dụng phức tạp với LangChain.
Tại thời điểm này, chúng tôi vẫn còn thiếu các công cụ để đánh giá mô hình tự động. Chúng tôi có thể sử dụng Khai thác đánh giá mô hình ngôn ngữ để đánh giá các mô hình của mình trên nhiều trường hợp thử nghiệm hoặc thậm chí tạo trường hợp thử nghiệm của riêng mình. Đây chính là công cụ mà Hugging Face sử dụng cho Bảng xếp hạng LLM mở. Mặc dù đánh giá là một khía cạnh quan trọng của việc phát triển LLM, bài viết này chỉ tập trung vào quá trình đào tạo. Tôi có thể thảo luận về đánh giá trong một bài viết trong tương lai.
Trong bài viết này, chúng tôi đã giới thiệu khái niệm về mô hình nền tảng lớn (LFM) và một số phương pháp tinh chỉnh giúp LFM hoạt động như mong muốn. Sau đó, chúng tôi tập trung vào LoRA, một phương pháp hiệu quả về tham số để tinh chỉnh LFM và giải thích mã tinh chỉnh cũng như các kỹ thuật cải thiện hiệu suất. Cuối cùng, chúng tôi đã tiến thêm một bước nữa và đào tạo thành công mẫu Llama 13B trên GPU V100. Mặc dù quá trình đào tạo mô hình 13B gặp phải một số vấn đề nhưng chúng tôi nhận thấy rằng những vấn đề này là do các hạn chế về phần cứng và các giải pháp được đưa ra. Cuối cùng, chúng tôi đã có được một LLM được tinh chỉnh hoạt động nhưng chúng tôi vẫn chưa đánh giá một cách định lượng hiệu suất của LLM.
Giới thiệu về tác giả
Xin chào! Tên tôi là Vĩ. Tôi là người giải quyết vấn đề tận tâm, Chuyên gia AI cấp cao và trưởng dự án phân tích tại ABB và Chuyên gia nhà phát triển máy học của Google . Tôi có bằng Thạc sĩ Kỹ thuật Cơ khí của Đại học Minnesota Twin Cities và bằng Cử nhân Kỹ thuật Cơ khí của Đại học Illinois tại Urbana-Champaign.
Nhóm công nghệ của tôi tập trung vào lập trình Python / C#, thị giác máy tính, học máy, thuật toán và dịch vụ vi mô, nhưng tôi cũng có nhiều mối quan tâm khác như phát triển trò chơi (Unity), phát triển front/back-end, lãnh đạo kỹ thuật, mày mò với máy tính bảng đơn và robot.
Tôi hy vọng bài viết này có thể giúp đỡ mọi người một cách nào đó. Cảm ơn bạn đã đọc và giải quyết vấn đề vui vẻ!