Llama CPP là một công cụ mới được thiết kế để thực thi các mô hình ngôn ngữ trực tiếp trong C/C++. Công cụ này được tối ưu đặc biệt cho các bộ xử lý Apple Silicon thông qua việc sử dụng công nghệ ARM NEON và khung làm việc Accelerate. Nó cũng đảm bảo tính tương thích AVX2 cho các hệ thống dựa trên kiến trúc x86. Hoạt động chủ yếu trên CPU, Llama CPP cũng tích hợp khả năng lượng tử hóa 4 bit, cải thiện đáng kể hiệu quả của nó. Ưu điểm là nó cho phép bạn thực thi một mô hình ngôn ngữ ngay trên máy tính cá nhân mà không cần GPU với dung lượng VRAM lớn. Đơn giản là, bạn không cần phải bán xe hơi để thử nghiệm những mô hình mới nhất đang thịnh hành. Cho dù công cụ cho phép bạn lao vào thế giới LLM với chi phí thấp, bạn sẽ cần kiên nhẫn. Bởi vì thời gian xử lý đôi khi rất lâu. Bạn có muốn thử không? Bạn sẽ thấy rằng, việc phải đợi 5 phút để nhận được phản hồi không phải là hiếm. Và không sao, ý tưởng ở đây là để hệ thống hoạt động trên máy tính của bạn. Bạn sẽ hiểu tại sao các gã khổng lồ lưu trữ yêu cầu bạn chi hàng trăm/ngàn euro để chạy mô hình của bạn trong đám mây. Đến nay, đây là danh sách các mô hình tương thích:

  • LLaMA 🦙
  • LLaMA 2 🦙🦙
  • Falcon
  • Alpaca
  • GPT4All
  • Trung Quốc LLaMA / Alpaca và Trung Quốc LLaMA-2 / Alpaca-2
  • Vigogne (Tiếng Pháp)
  • Vicuna
  • Koala
  • OpenBuddy 🐶 (Đa ngôn ngữ)
  • Pygmalion/Metharme
  • WizardLM
  • Baichuan 1 & 2 + dẫn xuất
  • Aquila 1 & 2
  • Mô hình Starcoder
  • Mistral AI v0.1
  • Refact
  • Persimmon 8B
  • MPT
  • Bloom
  • StableLM-3b-4e1t

Bước đầu tiên, do đó, sẽ là cài đặt và biên dịch Llama cpp. Chúng ta giả định rằng bạn là một nhà phát triển, và như bất kỳ nhà phát triển giỏi nào, bạn sử dụng Linux. Không phải vậy? Không vấn đề gì, hãy sử dụng Docker để mô phỏng máy tính chạy cùng hệ điều hành với bài viết này, tức là Ubuntu 22.04. Ví dụ, bạn có thể sử dụng docker-compose.yml này:

version: '3.8'
services:
  ubuntu:
    image: ubuntu:22.04
    command: /bin/bash
    stdin_open: true
    tty: true
    working_dir: /workspace
Docker compose up
Docker compose exec ubuntu bash

Ok, chúng ta đã sẵn sàng chưa? Tiếp tục nào. Điều kiện tiên quyết: cài đặt các công cụ cần thiết để thực thi chương trình. Bạn sẽ cần các công cụ biên dịch, cũng như các công cụ cho phép bạn clone các dự án GitHub cũng như một token cho phép bạn truy cập vào Hugingface, kho lưu trữ nổi tiếng của LLM nguồn mở.

apt-get update
apt-get install -y git  cmake g++ make curl gh python3-pip

curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 

sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg 
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.g
pg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null 


pip install numpy
pip install sentencepiece
pip install -U "huggingface_hub[cli]"

Để tạo token truy cập Hugging Face, đây là liên kết (nó có thể hơi khó tìm trong giao diện): https://huggingface.co/settings/tokens

Nếu bạn vẫn chưa có token trên GitHub, đây cũng là một liên kết: https://github.com/settings/tokens/new

Bây giờ, chúng ta sẽ clone và biên dịch llama.cpp.

# Cloner le dépôt Git de llama-cpp
gh repo clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp

# Compiler le projet
mkdir build
cd build
cmake ..
cmake --build . --config Release

Bây giờ, chúng ta sẽ tải xuống mô hình mới nhất được chế tạo bởi MistralAi. Bạn có thể tìm thấy mô hình trên Huggingface ở đây: https://huggingface.co/mistralai

Để rõ ràng hơn, bạn có thể trực tiếp thêm llama.cpp vào môi trường của mình. Điều này sẽ giúp chúng ta tập trung vào các lệnh mà không làm ô nhiễm bảng điều khiển của chúng ta bằng đường dẫn không cung cấp thêm thông tin. Ví dụ:

export PATH="/Data/Projets/Llm/src/Llama-cpp/llama.cpp/build/bin:$PATH"

Tải xuống mô hình: thay $HUGGINGFACE_TOKEN bằng token của bạn.

mkdir /Data/Projets/Llm/Models/mistralai 

huggingface-cli login --token $HUGGINGFACE_TOKEN
huggingface-cli download mistralai/Mistral-7B-v0.1 --local-dir /Data/Projets/Llm/Models/mistralai 

Hãy pha một tách cà phê, vì có tới 15 gigabyte đang chờ bạn. Một số tệp lớn sẽ chỉ là các liên kết tượng trưng đến thư mục cache. Bạn có thể chỉ định --cache-dir để ghi chúng vào một phân vùng khác nếu cần. Điều này có thể như sau:

huggingface-cli download mistralai/Mistral-7B-v0.1 --local-dir /Data/Projets/Llm/Models/mistralai --cache-dir /Data/Projets/Llm/Models/huggingface_cache/

Sau khi chúng ta đã tải xuống các tệp theo định dạng PyTorch, chúng ta sẽ cần thực hiện một chuyển đổi nhỏ. Chúng ta quay lại thư mục llama.cpp của chúng ta và thực hiện lệnh sau:

python3 llama.cpp/convert.py /Data/Projets/Llm/Models/mistralai 
  --outfile /Data/Projets/Llm/Models/mistralai/Mistral-7B-v0.1.gguf 
  --outtype f16

Vậy tham số --outtype q8_0 là gì?? Đó là Lượng tử hóa (quantization). Lượng tử hóa là một quá trình nhằm giảm bớt kích thước và độ phức tạp của các mô hình. Hãy tưởng tượng một nhà điêu khắc bắt đầu với một khối cẩm thạch khổng lồ và điêu khắc nó để tạo ra một bức tượng. Lượng tử hóa giống như việc loại bỏ các phần của khối để làm cho nó nhẹ hơn và dễ di chuyển hơn, trong khi vẫn đảm bảo bức tượng giữ được vẻ đẹp và hình dáng của nó. Trong bối cảnh của LLMs, lượng tử hóa bao gồm việc đơn giản hóa cách thức biểu diễn trọng số của mô hình. Trọng số trong một LLM là những giá trị số đại diện cho cách mô hình phản ứng với các đầu vào khác nhau. Bằng cách giảm độ chính xác của các trọng số này (ví dụ, chuyển từ giá trị dấu phẩy động 32 bit sang giá trị 8 bit), chúng ta giảm kích thước tổng thể của mô hình và số lượng tính toán cần thiết để thực thi nó. Điều này có một số lợi ích. Thứ nhất, nó làm cho mô hình nhanh hơn và tiêu thụ ít năng lượng hơn, điều này rất quan trọng đối với các ứng dụng trên các thiết bị di động hoặc server có dung lượng thấp. Thứ hai, nó làm cho AI trở nên dễ tiếp cận hơn, vì nó có thể hoạt động trên nhiều loại thiết bị hơn, bao gồm cả những thiết bị không có phần cứng tính toán tiên tiến. Tuy nhiên, lượng tử hóa cần được quản lý cẩn thận. Sự giảm độ chính xác quá mức có thể dẫn tới mất ổn định hiệu suất, khi mô hình trở nên kém chính xác hoặc không đáng tin cậy. Do đó, cần tìm ra sự cân bằng chính xác giữa hiệu quả và hiệu suất.

  1. Lượng tử hóa 2 bit (2-Bit Quantization) - q2_k: Sử dụng Q4_K cho các tensor attention.vw và feed_forward.w2, và Q2_K cho các tensor khác. Điều này có nghĩa là một số tensor quan trọng có độ chính xác cao hơn một chút (4 bit) để duy trì hiệu suất, trong khi các tensor khác được nén mạnh hơn (2 bit).
  2. Lượng tử hóa 3 bit (3-Bit Quantization) - q3_k_l: Sử dụng Q5_K cho attention.wv, attention.wo, và feed_forward.w2, và Q3_K cho các tensor khác. Điều này cho biết một độ chính xác cao hơn (5 bit) cho một số tensor quan trọng, trong khi các tensor khác ở mức 3 bit.
    • q3_k_m: Sử dụng Q4_K cho các tensor giống như q3_k_l, nhưng với độ chính xác thấp hơn một chút (4 bit), và Q3_K cho các tensor khác.
    • q3_k_s: Áp dụng lượng tử hóa Q3_K cho tất cả các tensor, cung cấp sự thống nhất nhưng với độ chính xác thấp hơn.
  3. Lượng tử hóa 4 bit (4-Bit Quantization) - q4_0: Phương pháp lượng tử hóa ban đầu 4 bit.
    • q4_1: Cung cấp độ chính xác cao hơn so với q4_0, nhưng thấp hơn q5_0, với sự suy đoán nhanh hơn so với các mô hình q5.
    • q4_k_m: Sử dụng Q6_K cho một nửa các tensor attention.wv và feed_forward.w2, và Q4_K cho các tensor khác.
    • q4_k_s: Áp dụng Q4_K cho tất cả các tensor.
  4. Lượng tử hóa 5 bit (5-Bit Quantization) - q5_0: Cung cấp độ chính xác cao hơn nhưng yêu cầu nhiều tài nguyên hơn và làm chậm suy đoán.
    • q5_1: Cung cấp độ chính xác còn cao hơn nữa với chi phí là việc sử dụng tài nguyên nhiều hơn và suy đoán chậm hơn.
    • q5_k_m: Giống như q4_k_m, nhưng với Q6_K cho một số tensor và Q5_K cho các tensor khác.
    • q5_k_s: Sử dụng Q5_K cho tất cả các tensor.
  5. Lượng tử hóa 6 bit (6-Bit Quantization) - q6_k: Sử dụng lượng tử hóa Q8_K cho tất cả các tensor, cung cấp một độ chính xác tương đối cao.
  6. Lượng tử hóa 8 bit (8-Bit Quantization) - q8_0: Phương pháp này đạt được mức lượng tử hóa gần như không thể phân biệt với định dạng float16, nhưng yêu cầu nhiều tài nguyên và làm chậm suy đoán.

Độ chính xác của một phương pháp lượng tử hóa phụ thuộc vào lượng bit sử dụng để biểu diễn trọng số của mô hình.

  1. Chính xác nhất: Phương pháp q6_k (Lượng tử hóa 6 bit), sử dụng Q8_K cho tất cả các tensor, có lẽ sẽ thông dịch chính xác nhất trong số những phương pháp mà chúng ta đã bàn luận. Nó sử dụng 8 bit cho mỗi trọng số, cho phép một biểu diễn chi tiết hơn và gần với giá trị gốc hơn. Điều này dịch ra là việc bảo quản tốt những màu sắc và chi tiết của mô hình, nhưng với giá là việc sử dụng tài nguyên nhiều hơn và thời gian suy đoán có thể dài hơn.
  2. Kém chính xác nhất: Phương pháp q2_k (Lượng tử hóa 2 bit) sẽ kém chính xác nhất. Phương pháp này sử dụng chỉ 2 bit cho phần lớn các tensor, với một số ngoại lệ ở mức 4 bit (Q4_K) cho các tensor attention.vw và feed_forward.w2. Biểu diễn 2 bit rất gọn nhẹ, nhưng cũng dễ mất thông tin quan trọng hơn nhiều, vì nó chỉ có thể biểu diễn bốn giá trị khác nhau cho mỗi trọng số, so với 256 giá trị trong lượng tử hóa 8 bit.

Đó là lý thuyết, công cụ của chúng ta cung cấp ba loại chuyển đổi: --outtype {f32,f16,q8_0}

  1. f32 (Số dấu phẩy động 32-bit): Đây là định dạng tiêu chuẩn có độ chính xác cao cho các số dấu phẩy động trong nhiều tính toán máy tính, bao gồm trong LLMs. Mỗi trọng số được lưu trữ với độ chính xác 32 bit, cung cấp độ chính xác cao nhưng cũng tăng kích thước mô hình và sử dụng tài nguyên. Tùy chọn này không phải là một dạng của lượng tử hóa mà là định dạng tiêu chuẩn không lượng tử hóa.
  2. f16 (Số dấu phẩy động 16-bit): Đây là phiên bản gọn nhẹ hơn của f32, nơi mỗi trọng số được lưu trữ với độ chính xác 16 bit. Điều này giảm kích thước mô hình và số lượng tính toán cần thiết, với một chút mất độ chính xác so với f32. Mặc dù đây là dạng nén, nhưng nó không phải là lượng tử h