Κατέβασε και τρέξε το προσωπικό σου LLM με Python: Llama 2

Γεια σε όλους!

Στο άρθρο αυτό θα δούμε πως μπορείς εύκολα και γρήγορα να κατεβάσεις, 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:

  1. Μπαίνεις στο HuggingFace, στο αποθετήριο του TheBloke για το μοντέλο Llama-2-7Β-Chat-GGUF.
  2. Επιλέγεις την κβάντιση που θες.
  3. Από τα tabs στο πάνω μέρος, επιλέγεις files.
  4. Επιλέγεις το αρχείο που αντιστοιχεί στην κβάντιση που θες. Κλικάρεις download.
  5. Φτιάξε ένα 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: Τι λέει ο χρήστης στο AI
    • assistant: Τι απαντάει το 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! Όποιες διορθώσεις θα εκτιμηθούν!

Άλλα άρθρα σχετικά με τα LLM:

15 «Μου αρέσει»

@kgiannakis
Ευχαριστούμε πολύ, για την πολύ αναλυτική παρουσίαση!!!
Βέβαια, πρέπει να τονίσουμε ότι τα LLM για να τρέξουν τοπικά στον υπολογιστή μας θέλουν πάνω από 8GB ram και ιδανικά 64 έως 128GB ram και GPU ιδανικά πάνω από 12GB,
ἐξ οὗ, και το άρθρο:
https://linux-user.gr/t/technikes-apaithseis-ypologistwn-gia-th-chrhsh-ths-technhths-nohmosynhs-kai-alloi-periorismoi/5193
Ευτυχώς, όμως όπως μας ανέλυσες, μιας και είναι το αντικείμενό σου(ο προγραμματισμός ) και δεν γράφεις απλά από χόμπι, υπάρχει το HuggingFace, με τη μόνη διαφορά ότι εκεί τα δεδομένα που εισάγουμε θεωρούνται δημόσια, αν δεν απατώμαι.
Με τη χρήση της Python από ότι βλέπουμε οι απαιτήσεις περιορίζονται στα 6GB ram.
Mε τον τρόπο αυτό που μας παρουσιάζεις ίσως ανοίγεται ο δρόμος στους προγραμματιστές της κοινότητας να αναπτύξουν τα δικά τους μοντέλα.
Νομίζω έχουμε ανάγκη από LLM με ελληνικά ανοικτά δεδομένα.
Μια επίσης προσιτή λύση για τον υπολογιστή μας μπορεί να είναι το Ollama, επιλέγοντας μοντέλα με λιγότερες από 3Β(δισεκατομύρια) παραμέτρους, αλλά και πάλι τα 16GB ram θα τα χρειαστούμε και θα έχουμε πιο αργό αποτέλεσμα από το Huggingface, όμως αξίζει τον κόπο για να δούμε ιδίοις όμμασι, αυτή την αλληλεπίδραση με τις τελευταίες ανακαλύψεις στον χώρο της τεχνητής νοημοσύνης και της πληροφορικής ευρύτερα.

5 «Μου αρέσει»

Κωνσταντίνε, σε ευχαριστώ πολύ για τα καλά σου λόγια!

Θα κάνω attach και τα δύο άρθρα σου σχετικά με τα LLM για όποιον άλλον θέλει να τα διαβάσει. Και τα δύο είναι εξαιρετικά :smile:. Ειδικά το Ollama είναι πολύ πρακτικό για πειραματισμό!

1 «Μου αρέσει»