Γεια σε όλους!
Στο άρθρο αυτό θα δούμε πως μπορείς εύκολα και γρήγορα να κατεβάσεις, setάρεις, τρέξεις και να κάνεις interface με το πιο δημοφιλές Open Source Large Language Model (LLM) της αγοράς, το Llama 2 της Meta χρησιμοποιόντας Python.
Προσπάθησα να γράψω επίσης και τα common pitfalls που θα συναντήσεις κατά την διάρκεια του ταξιδιού σου, για να μην φας μία ολόκληρη μέρα κάνοντας debugging σαν εμένα…
But first:
whoami
:
Ονομάζομαι Κυριάκος Γιαννάκης και είμαι επαγγελματίας πληροφορικής. Έχω μια εταιρία ανάπτυξης Λογισμικών & Marketing, την Flare. Στο παρελθόν έχω συμμετάσχει σε αρκετά συνέδρια ανοικτού λογισμικού και open source projects. Αν συχνάζατε στις FOSSCOMM ή σε καμία FOSDEM, πολύ πιθανόν να γνωριζόμαστε!
Credits:
Ένα μεγάλο ευχαριστώ στον φίλο μου, Αλέξανδρο Μπαμπούνη-Τσάτσο που μου έδωσε το έναυσμα να ασχοληθώ με το llama, ένα βράδυ υπό την επίρροια μπύρας!
Που μπορώ να βρω τον κώδικα αυτού του tutorial;
Μα, βεβαίως, στο GitHub! Το παρόν άρθρο διατίθεται υπό την άδεια Creative Commons Attribution-ShareAlike 4.0 International.
Τι είναι τα Large Language Models;
Τα LLM είναι ένα πρόγραμμα που έχει μία δουλειά: να διαβάζει είσοδο από τον χρήστη και να προβλέπει και να γράφει κείμενο βάσει της εισόδου. Τα LLM είναι εκπαιδευμένα σε μεγάλο όγκο κειμένων. Μπορούν να διαβάζουν και να γράφουν άρθρα, ποιήματα, ιστορίες, ακόμα και κώδικα. Το πιο γνωστό LLM στην αγορά αυτή την στιγμή είναι το ChatGPT. Ίσως να το γνωρίζεις ;)!
Γιατί να τρέξω ένα LLM στον υπολογιστή μου; Δώσε μου 3 λόγους…
- Ασφάλεια και ιδιοτικότητα: Τα online LLMs, είτε το θέλουμε είτε όχι, χρησιμοποιούν τις εισόδους μας για να επανεκπαιδεύονται. Αυτό, σε συγκεκριμένες περιπτώσεις (αν θέλουμε, πχ να του εμπιστευτούμε πολύ προσωπικά μας δεδομένα) δυσχαιρένει την χρήση τους.
- Μελέτη και έρευνα: Τα Open Source LLMs γίνεται να τα μελετήσεις και να τα κάνεις fine tune με τα δικά σου δεδομένα.
- Φθηνό στην χρήση (σχετικά…): Αν δεν θες να πληρώσεις την OpenAI για να χρησιμοποιήσεις το GPT, στο σημερινό άρθρο θα μάθεις οτι μπορείς (σχετικά) εύκολα να τρέξεις το δικό σου LLM.
Οι εκδόσεις του Llama 2:
Το LLama 2 κυκλοφορεί σε 3 εκδόσεις, ανάλογα με το πλήθος των παραμέτρων που χρησιμοποίησαν όταν το εκπαίδευαν:
- 7b: 7 Δισεκατομμύρια παράμετροι.
- 13b: 13 Δισεκατομμύρια παράμετροι.
- 70b: 70 Δισεκατομμύρια παράμετροι.
Μπορείς να διαβάσεις για τις απαιτήσεις των 3 εκδόσεων εδώ. Στο παρόν θα μιλήσουμε για την 7b έκδοση, καθώς οι απαιτήσεις hardware αυξάνονται γρήγορα στην 13b και την 70b…
Οι μορφές και το Quantization (ΔΙΑΒΑΣΕ ΜΕ)
To Llama2 θα το κατεβάσουμε από μία από τις μεγαλύτερες κοινότητες σχετικά με το machine learning στον κόσμο, την HuggingFace. Πριν να το κατεβάσεις, όμως, καλό είναι να ξέρεις για το τι εκδόσεις υπάρχουν και τι μορφές υπάρχουν:
- Το μοντέλο hf: Το μοντέλο στην “μαμίσια” έκδοσή του, προσαρμοσμένο να λειτουργεί με τους HuggingFace transformers και είναι πλήρως συμβατό με το οικοσύστημα της HuggingFace. Δεν χρησιμοποιεί κβάντιση (Quantization, σκέψου το σαν ένα είδος compression) και, ως εκ τούτου, απαιτεί ΠΟΛΥ περισσότερη RAM για να εκτελεστεί σε σχέση με το GGUF format που θα δούμε παρακάτω. Αν θες να κάνεις έρευνα πάνω στο μοντέλο και να το επανεκπαιδεύσεις, θες αυτή την έκδοση! Αν θες απλά να το εκτελέσεις, λόγω του τεράστιου όγκου του, σου προτείνω να πας στην GGUF version!
- Το μοντέλο σε μορφή GGUF: Η GGUF μορφή αναπτύχθηκε από τους δημιουργούς του llama.cpp. Είναι ήδη κβαντισμένη και απαιτεί λιγότερη RAM για να εκτελεστεί. Σε αυτό το άρθρο θα χρησιμοποιήσω αυτή την έκδοση.
Απαιτήσεις Συστήματος (ΔΙΑΒΑΣΕ ΜΕ):
Ανάλογα την κβάντιση που θα επιλέξεις, το LLama απαιτεί διαφορετικό μέγεθος RAM για να εκτελεστεί σωστά και γρήγορα.
Minimum Requirements (δεν θα έχεις καλά αποτελέσματα και οι διάλογοι σου με αυτό θα έχουν quality loss):
- 6GB RAM (στην Q2_K έκδοση)
- CPU: Όσο πιο δυνατός, τόσο το καλύτερο. Προτείνω τουλάχιστον 4 cores.
- GPU: Δεν χρειάζεται, αλλά αν θες μπορείς να χρησιμοποιήσεις για να έχεις γρηγορότερη επεξεργασία. Πρέπει να έχει τουλάχιστον 6GB VRAM (όσο και το RAM requirement)
- OS: Linux (στο linux user είσαι, τι περίμενες;;; Εγώ θα χρησιμοποιήσω Ubuntu/Debian)
- Python Version: 3.9, 3.10, 3.11
- HDD Space: 10GB
Recommended Requirements:
- 8GB RAM (Q5_K_M version)
- 8-Core CPU
Γενικά, αν θες να μάθεις περισσότερα για τις απαιτήσεις συστήματως των LLM, μπορείς να διαβάσεις το άρθρο του @nikaskonstantinos, εδώ.
Κατέβασμα του LLama 2:
- Μπαίνεις στο HuggingFace, στο αποθετήριο του TheBloke για το μοντέλο Llama-2-7Β-Chat-GGUF.
- Επιλέγεις την κβάντιση που θες.
- Από τα tabs στο πάνω μέρος, επιλέγεις files.
- Επιλέγεις το αρχείο που αντιστοιχεί στην κβάντιση που θες. Κλικάρεις download.
- Φτιάξε ένα directory κάπου και βάλε το μέσα.
Προετοιμασία του περιβάλλοντος Python:
Φτιάξε ένα directory κάπου για να βάλεις το έργο σου και κάνε cd
μέσα σε αυτό.
mkdir llama_project
cd llama_project
Δημιούργησε το αρχείο requirements.txt
και βάλε μέσα σε αυτό το παρακάτω περιεχόμενο:
llama-cpp-python
Εγκατάστησε τα build-essentials:
sudo apt update
sudo apt install build-essentials
Έπειτα, δημιούργησε ένα virtual environment για την Python, κάνε activate και εγκατάστησε τα requirements:
python3 -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
Coding time!
Φτιάξε το llama_cli.py
και ξεκινάμε!
Ξεκινάμε με τα imports μας:
from llama_cpp import Llama, llama_types
from sys import stderr
Σετάρουμε το LLM και φτιάχνουμε το chat history:
MODEL_PATH = "/to_path_pou_evales_to_llama/llama-2-7b-chat.Q5_K_M.gguf"
model = Llama(
model_path=MODEL_PATH,
# n_gpu_layers=-1, # Κάνε uncomment για να χρησιμοποιήσεις την GPU.
chat_format="llama-2",
# Το context window. 0 = χρησιμοποίησε όσο όρίζει το model
# Όσο μεγαλύτερο, τόσα περισσότερα "θυμάται" το μοντέλο,
# αλλά αυξάνει και τον χρόνο εκτέλεσης...
n_ctx=0
)
chat_history: list[llama_types.ChatCompletionRequestMessage] = []
To chat_history
είναι της παρακάτω μορφής:
[
{
"role": "user",
"content": "Write a summary of Game of Thrones' first season."
},
{
"role": "assistant",
"content": "The first season of Game of Thrones, based on George R. R. Martin's novel A Game of Thrones, premiered in 2011..."
},
{
"role": "user",
"content": "OK. Now write a summary for season 2."
},
...
]
Για όσους έχετε ξαναδιαδράσει με LLMs, ξέρετε οτι αυτή η μορφή είναι η ίδια που χρησιμοποιεί και το ChatGPT API.
role
: Τι είδους μήνυμα είναι.user
: Τι λέει ο χρήστης στο AIassistant
: Τι απαντάει το AI στον χρήστη.system
: Μπαίνει μόνο σαν πρώτο μήνυμα και σετάρει την συμπεριφορά του AI.
content
: Το περιεχόμενο του chat.
Σετάρουμε την συνάρτηση εισόδου από τον χρήστη:
def get_user_input() -> str:
while True:
user_input = input("> ").strip()
if user_input:
return user_input
print("Chat message empty. Please retry.", file=stderr)
Τώρα σειρά έχει η συνάρτηση που αλληλεπιδρά με το LLM:
def get_llm_output(chat_history):
response = model.create_chat_completion(
messages=chat_history,
# max_new_tokens=150 # Κάνε uncomment για να περιορίσεις το μέγεθος των απαντήσεων
)
chat_history.append(response["choices"][0]["message"])
return chat_history
Και, τέλος, η κύρια loop:
if __name__ == "__main__":
# Το πρώτο message μπορεί να είναι τύπου system.
# Πχ. "You're a scientist"
# Αυτό ρυθμίζει την συμπεριφορά του μοντέλου.
system_msg = input("SYS (leave empty to not use a system message)> ")
if system_msg.strip():
chat_history.append({
"role": "system",
"content": system_msg
})
while True:
try:
user_msg = chat_history.append({
"role": "user",
"content": get_user_input()
})
chat_history = get_llm_output(chat_history)
print("AI> " + chat_history[-1]["content"])
except KeyboardInterrupt:
print("Exiting...", file=stderr)
exit(0)
Final Code:
llama_cli.py
:
from llama_cpp import Llama, llama_types
from sys import stderr
MODEL_PATH = "/to_path_pou_evales_to_llama/llama-2-7b-chat.Q5_K_M.gguf"
model = Llama(
model_path=MODEL_PATH,
# n_gpu_layers=-1, # Κάνε uncomment για να χρησιμοποιήσεις την GPU.
chat_format="llama-2",
# Το context window. 0 = χρησιμοποίησε όσο όρίζει το model
# Όσο μεγαλύτερο, τόσα περισσότερα "θυμάται" το μοντέλο,
# αλλά αυξάνει και τον χρόνο εκτέλεσης...
n_ctx=0
)
chat_history: list[llama_types.ChatCompletionRequestMessage] = []
def get_llm_output(chat_history):
response = model.create_chat_completion(
messages=chat_history,
# max_new_tokens=150 # Κάνε uncomment για να περιορίσεις το μέγεθος των απαντήσεων
)
chat_history.append(response["choices"][0]["message"])
return chat_history
def get_user_input() -> str:
while True:
user_input = input("> ")
if user_input.strip():
return user_input
print("Chat message empty. Please retry.", file=stderr)
if __name__ == "__main__":
# Το πρώτο message μπορεί να είναι τύπου system.
# Πχ. "You're a scientist"
# Αυτό ρυθμίζει την συμπεριφορά του μοντέλου.
system_msg = input("SYS (leave empty to not use a system message)> ")
if system_msg.strip():
chat_history.append({
"role": "system",
"content": system_msg
})
while True:
try:
user_msg = chat_history.append({
"role": "user",
"content": get_user_input()
})
chat_history = get_llm_output(chat_history)
print("AI> " + chat_history[-1]["content"])
except KeyboardInterrupt:
print("Exiting...", file=stderr)
exit(0)
Usage:
python3 llama_cli.py
Μπορεί να νιώσεις οτι freezeάρει στην εκκίνηση. Be patient, θα λειτουργήσει ύστερα από λίγο.
Επίλογος / Μελλοντικές Επεκτάσεις:
Αυτό ήταν;
Ναι! Αυτό ήταν ένα πολύ μικρό παράδειγμα για το τι μπορείς να κάνεις με το Llama 2 και την Python. Μπορείς αν θες να χρησιμοποιήσεις και να αλλάξεις τον κώδικα για να το κάνεις integrate σε ένα μεγαλύτερο project λχ, ένα chatbot service ή ένα μεγαλύτερο infrastructure.
How about Docker?
Ολο αυτό το άρθρο ήταν μια προσπάθεια ενός ΣΚ οπότε δεν είχα χρόνο να κάνω και docker. Θα το αφήσω με ένα TODO
για την ώρα…
Αν θέλει κάποιος να κάνει contribute ένα dockerfile και το dockerization procedure, θα εκτιμηθεί πολύ! :D
Αν θες να το βάλεις σε docker, σου προτείνω να μην βάλεις το gguf
αρχείο μέσα στο image γιατί το αποτέλεσμα θα είναι ένα image ~6GB… Καλύτερα να βάλεις bind mount και να το περάσεις έτσι στο container.
Διορθώσεις / Βελτιώσεις:
Αν θέλετε να προσθέσετε ή να διορθώσετε κάτι, by all means! Όποιες διορθώσεις θα εκτιμηθούν!