Αν ανοίξετε το LinkedIn ή το Twitter (ή X, αν επιμένετε) αυτή τη στιγμή, θα βομβαρδιστείτε από όρους όπως “Generative AI”, “Transformers” και “LLMs”. Όλοι ξαφνικά έγιναν ειδικοί.
Αλλά αν ξύσουμε λίγο την επιφάνεια, αν κοιτάξουμε κάτω από το καπό του ChatGPT ή του Midjourney, τι βρίσκουμε; Βρίσκουμε τα καλά, παλιά (εντάξει, όχι και τόσο παλιά) Τεχνητά Νευρωνικά Δίκτυα (Artificial Neural Networks – ANNs).
Γράφω κώδικα και στήνω αρχιτεκτονικές εδώ και χρόνια, και μπορώ να σας πω το εξής: τα νευρωνικά δίκτυα δεν είναι μαγεία.
Είναι γραμμική άλγεβρα με λίγο λογισμό (calculus) και πολλή στατιστική, πασπαλισμένα με υπολογιστική ισχύ που καίει όσο μια μικρή πόλη.
Σκοπός μου σήμερα δεν είναι να σας κάνω άλλη μια βαρετή διάλεξη πανεπιστημιακού τύπου.
Θέλω να σας δώσω την ουσία, την τεχνική “καρδιά” του συστήματος, μιλώντας σας όπως θα μιλούσα σε έναν συνάδελφο πάνω από έναν καφέ (ή μια μπύρα), εξηγώντας πως στο καλό αυτοί οι πίνακες αριθμών μαθαίνουν να ξεχωρίζουν μια γάτα από έναν σκύλο.
Ετοιμαστείτε. Θα βουτήξουμε βαθιά.
Η βιολογική αναλογία (και πότε να την αγνοήσετε)
Ξεκινάμε πάντα από εδώ, και συνήθως είναι το σημείο που γίνονται οι περισσότερες παρεξηγήσεις. Ναι, τα νευρωνικά δίκτυα είναι εμπνευσμένα από τον ανθρώπινο εγκέφαλο.
Όχι, δεν λειτουργούν ακριβώς όπως ο ανθρώπινος εγκέφαλος.
Στον εγκέφαλό μας, έχουμε νευρώνες που συνδέονται με συνάψεις. Όταν ένας νευρώνας δεχτεί αρκετό ηλεκτρικό ερέθισμα, “πυροδοτείται” (fires) και στέλνει σήμα στους επόμενους. Στην επιστήμη των υπολογιστών, κάναμε μια αφηρημένη μαθηματική προσομοίωση αυτού του φαινομένου.
Η βασική διαφορά; Ο εγκέφαλός μας είναι ένα αναλογικό, χημικό και εξαιρετικά παράλληλο σύστημα με απίστευτη πλαστικότητα.
Ένα τεχνητό νευρωνικό δίκτυο είναι ουσιαστικά ένας κατευθυνόμενος γράφος (directed graph) όπου η “γνώση” αποθηκεύεται με τη μορφή αριθμητικών βαρών (weights).
Μην σκέφτεστε λοιπόν βιολογία. Σκεφτείτε ροή πληροφορίας και μετασχηματισμό δεδομένων.
Αν κολλήσετε στη βιολογική μεταφορά, θα δυσκολευτείτε να κατανοήσετε έννοιες όπως το Backpropagation, που δεν έχει άμεσο βιολογικό αντίστοιχο.
Το Perceptron – Ο θεμέλιος λίθος
Πριν χτίσουμε ουρανοξύστες (Deep Neural Networks), πρέπει να μάθουμε να φτιάχνουμε τούβλα. Το “τούβλο” μας είναι το Perceptron. Επινοήθηκε το 1957 από τον Frank Rosenblatt και, στην ουσία του, είναι μια μαθηματική συνάρτηση που παίρνει εισόδους, τις επεξεργάζεται και βγάζει μια έξοδο.
Ας το δούμε μαθηματικά, γιατί εκεί κρύβεται η ομορφιά. Έστω ότι έχουμε ένα διάνυσμα εισόδου $x$ και ένα διάνυσμα βαρών $w$.
Η λειτουργία ενός νευρώνα περιγράφεται ως εξής:
$$z = \sum_{i=1}^{n} w_i \cdot x_i + b$$
Τι βλέπουμε εδώ;
- $x_i$ (Inputs): Τα δεδομένα μας. Μπορεί να είναι η τιμή ενός pixel, η λέξη σε μια πρόταση, ή η θερμοκρασία δωματίου.
- $w_i$ (Weights): Η “σημαντικότητα” της κάθε εισόδου. Αν το δίκτυο προσπαθεί να αποφασίσει αν θα αγοράσετε σπίτι, το $x$ της “τιμής” θα έχει μεγάλο βάρος $w$, ενώ το $x$ του “χρώματος της πόρτας” θα έχει ελάχιστο ή μηδενικό βάρος.
- $b$ (Bias): Η μεροληψία. Είναι ένας σταθερός όρος που επιτρέπει στο μοντέλο να μετατοπίζει τη συνάρτηση ενεργοποίησης. Σκεφτείτε το σαν το κατώφλι: πόσο “εύκολα” θέλουμε να ενεργοποιηθεί ο νευρώνας ανεξάρτητα από την είσοδο.
Αν αυτό σας θυμίζει την εξίσωση της ευθείας ($y = ax + b$), συγχαρητήρια. Ένας μεμονωμένος νευρώνας είναι, στην ουσία, ένας γραμμικός ταξινομητής.
Συναρτήσεις ενεργοποίησης (Activation Functions)
Αν μέναμε μόνο στην παραπάνω εξίσωση, όσα επίπεδα (layers) και να στοιβάζαμε, το τελικό αποτέλεσμα θα ήταν πάλι ένας γραμμικός συνδυασμός των εισόδων.
Με λίγα λόγια, χωρίς μη-γραμμικότητα, το νευρωνικό δίκτυο δεν είναι τίποτα παραπάνω από μια μπερδεμένη Γραμμική Παλινδρόμηση. Δεν θα μπορούσε να λύσει περίπλοκα προβλήματα, όπως η αναγνώριση προσώπου.
Εδώ μπαίνουν οι Συναρτήσεις Ενεργοποίησης. Εφαρμόζουμε μια μη γραμμική συνάρτηση $f(z)$ στο αποτέλεσμα του αθροίσματος.
Οι πιο σημαντικές που χρησιμοποιούμε σήμερα (και γιατί):
- Sigmoid: $\sigma(z) = \frac{1}{1 + e^{-z}}$.
- Παλιά σχολή. Συμπιέζει τα πάντα μεταξύ 0 και 1. Χρήσιμη για πιθανότητες στην έξοδο, αλλά καταστροφική στα ενδιάμεσα στρώματα λόγω του προβλήματος του Vanishing Gradient (θα μιλήσουμε γι’ αυτό παρακάτω).
- ReLU (Rectified Linear Unit): $f(z) = \max(0, z)$.
- Ο Βασιλιάς. Αν η είσοδος είναι θετική, την περνάει ως έχει. Αν είναι αρνητική, γίνεται μηδέν. Είναι υπολογιστικά πανάλαφρη και λύνει πολλά προβλήματα εκπαίδευσης. Το 90% των δικτύων που φτιάχνω ξεκινάνε με ReLU.
- Leaky ReLU: Παρόμοιο με το ReLU, αλλά αντί για 0 στα αρνητικά, έχει μια μικρή κλίση (π.χ. 0.01). Αυτό αποτρέπει το φαινόμενο των “νεκρών νευρώνων” (dying ReLU problem).
- Softmax: Χρησιμοποιείται σχεδόν αποκλειστικά στο τελευταίο επίπεδο για προβλήματα ταξινόμησης πολλών κλάσεων, μετατρέποντας τις εξόδους σε κατανομή πιθανότητας που αθροίζει στο 1.
Αρχιτεκτονική δικτύου – Στήνοντας το οικοδόμημα
Όταν συνδέουμε πολλούς νευρώνες μαζί, φτιάχνουμε ένα Layer (Επίπεδο). Όταν συνδέουμε πολλά Layers, φτιάχνουμε ένα Deep Neural Network. Η κλασική δομή που πρέπει να έχετε στο μυαλό σας είναι το Multi-Layer Perceptron (MLP).
Η δομή είναι ιεραρχική:
- Input Layer: Παραλαμβάνει τα ακατέργαστα δεδομένα (raw data). Δεν κάνει υπολογισμούς.
- Hidden Layers: Εδώ γίνεται η μαγεία. Κάθε στρώμα προσπαθεί να εξάγει χαρακτηριστικά (features) από τα προηγούμενα. Τα πρώτα στρώματα εντοπίζουν απλά μοτίβα (π.χ. ακμές σε μια εικόνα), ενώ τα βαθύτερα στρώματα συνδυάζουν αυτά τα μοτίβα σε πολύπλοκες έννοιες (π.χ. ένα μάτι ή μια ρόδα).
- Output Layer: Η τελική πρόβλεψη.
Στη σύγχρονη εποχή, ο όρος “Deep Learning” αναφέρεται απλώς στο πλήθος αυτών των κρυφών επιπέδων. Όσο πιο βαθύ το δίκτυο, τόσο πιο αφαιρετικές έννοιες μπορεί να κατανοήσει, αλλά τόσο πιο δύσκολο γίνεται να εκπαιδευτεί.
Μια κρίσιμη παράμετρος εδώ είναι η συνδεσιμότητα. Στα Dense (Fully Connected) επίπεδα, κάθε νευρώνας συνδέεται με όλους τους νευρώνες του επόμενου επιπέδου. Αυτό σημαίνει τεράστιο αριθμό παραμέτρων. Για παράδειγμα, δύο επίπεδα των 1000 νευρώνων το καθένα έχουν $1.000 \times 1.000 = 1.000.000$ συνδέσεις (βάρη).
Forward Propagation & Loss Functions – Πόσο λάθος κάναμε;
Η διαδικασία ξεκινάει με το Forward Propagation. Τα δεδομένα ρέουν από την είσοδο προς την έξοδο. Το δίκτυο κάνει μια πρόβλεψη.
Στην αρχή, επειδή τα βάρη $w$ αρχικοποιούνται τυχαία (συνήθως με Gaussian κατανομή), η πρόβλεψη θα είναι σκουπίδια.
Για να μάθει το δίκτυο, πρέπει να ποσοτικοποιήσουμε πόσο χάλια ήταν η πρόβλεψη. Αυτό το κάνει η Loss Function (Συνάρτηση Κόστους). Είναι ο κριτής μας.
- Για Regression (Παλινδρόμηση): Χρησιμοποιούμε συνήθως το MSE (Mean Squared Error).$$MSE = \frac{1}{n} \sum (y_{true} – y_{pred})^2$$Τιμωρεί βαριά τα μεγάλα λάθη λόγω του τετραγώνου.
- Για Classification (Ταξινόμηση): Χρησιμοποιούμε το Cross-Entropy Loss.$$L = – \sum y_{true} \cdot \log(y_{pred})$$Αυτό μετράει την απόκλιση μεταξύ της πραγματικής κατανομής και της προβλεπόμενης.
Σκεφτείτε το Loss Function σαν ένα τοπίο με βουνά και κοιλάδες. Στόχος μας είναι να βρεθούμε στο βαθύτερο σημείο της κοιλάδας (το ελάχιστο λάθος).
Το πρόβλημα είναι ότι βρισκόμαστε στην κορυφή του βουνού με δεμένα μάτια.
Backpropagation – Η μηχανή της μάθησης
Εδώ είναι το σημείο που ξεχωρίζουν οι ερασιτέχνες από τους επαγγελματίες. Το Backpropagation (Οπισθοδιάδοση) είναι ο αλγόριθμος που επιτρέπει στο δίκτυο να μάθει.
Δημοσιεύτηκε (στη μορφή που το ξέρουμε) από τους Rumelhart, Hinton και Williams το 1986 και άλλαξε τα πάντα.
Η λογική είναι η εξής: Αφού υπολογίσουμε το λάθος (Loss) στο τέλος, πρέπει να βρούμε ποιος νευρώνας φταίει και πόσο, ώστε να διορθώσουμε τα βάρη του.
Επειδή όμως έχουμε πολλά επίπεδα, πρέπει να διαδώσουμε το λάθος προς τα πίσω, από την έξοδο προς την είσοδο.
Μαθηματικά, αυτό βασίζεται στον Κανόνα της Αλυσίδας (Chain Rule) του διαφορικού λογισμού.
Θέλουμε να βρούμε την κλίση (gradient) της συνάρτησης κόστους ως προς κάθε βάρος $w$:
$$\frac{\partial L}{\partial w} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial z} \cdot \frac{\partial z}{\partial w}$$
Υπολογίζοντας αυτή τη μερική παράγωγο, βρίσκουμε προς ποια κατεύθυνση πρέπει να αλλάξουμε το βάρος $w$ για να μειώσουμε το λάθος.
Αν η παράγωγος είναι θετική, μειώνουμε το βάρος. Αν είναι αρνητική, το αυξάνουμε.
Αυτό επαναλαμβάνεται για εκατομμύρια παραμέτρους ταυτόχρονα. Είναι ένας υπολογιστικός άθλος που κατέστη εφικτός χάρη στις GPUs.
Optimizers – Κατεβαίνοντας το βουνό
Αφού το Backpropagation μας δώσει τα gradients (την κλίση του εδάφους), κάποιος πρέπει να αποφασίσει πώς θα κινηθούμε. Αυτή είναι η δουλειά του Optimizer.
Ο πιο απλός είναι ο Stochastic Gradient Descent (SGD).
$$w_{new} = w_{old} – \eta \cdot \nabla L$$
Όπου $\eta$ είναι το Learning Rate. Αν το $\eta$ είναι πολύ μικρό, θα κάνουμε αιώνες να κατεβούμε το βουνό. Αν είναι πολύ μεγάλο, μπορεί να πηδήξουμε στην απέναντι πλαγιά και να μην βρούμε ποτέ τον πάτο.
Όμως, ο σκέτος SGD έχει προβλήματα. Κολλάει σε τοπικά ελάχιστα (local minima) ή σε σαμαράκια (saddle points). Γι’ αυτό έχουμε πιο έξυπνους αλγορίθμους:
Πίνακας Σύγκρισης Optimizers
| Optimizer | Χαρακτηριστικό | Πλεονέκτημα | Μειονέκτημα |
| SGD | Απλή αφαίρεση gradient | Απλός, κατανοητός | Αργή σύγκλιση, κολλάει εύκολα |
| SGD + Momentum | Προσθέτει “ορμή” από προηγούμενα βήματα | Ξεπερνάει μικρά εμπόδια | Χρειάζεται ρύθμιση παραμέτρου momentum |
| RMSprop | Προσαρμόζει το Learning Rate ανά παράμετρο | Καλό για Recurrent Networks | Μπορεί να “σβήσει” το learning rate νωρίς |
| Adam | Συνδυασμός Momentum & RMSprop | The Gold Standard. Γρήγορος, σταθερός | Μερικές φορές γενικεύει χειρότερα από SGD |
Στην πράξη; Ξεκινήστε πάντα με Adam και learning rate 0.001 (ή 3e-4, το λεγόμενο “Andrej Karpathy constant”).
Αν δεν δουλέψει αυτό, τότε ψαχτείτε αλλού.
Overfitting & Regularization – Η παπαγαλία vs. Η γνώση
Ένα από τα μεγαλύτερα προβλήματα στην εκπαίδευση νευρωνικών δικτύων είναι το Overfitting (Υπερπροσαρμογή).
Φανταστείτε έναν μαθητή που μαθαίνει απέξω τις απαντήσεις των θεμάτων των προηγούμενων ετών. Στις εξετάσεις (training set) θα αριστεύσει. Αν όμως του βάλεις ένα νέο θέμα (test set), θα πατώσει.
Το δίκτυο έχει μάθει το “θόρυβο” των δεδομένων και όχι τη γενική αρχή. Πως το καταπολεμάμε; Με τεχνικές Regularization:
- Dropout: Κατά τη διάρκεια της εκπαίδευσης, απενεργοποιούμε τυχαία ένα ποσοστό νευρώνων (π.χ. 20%) σε κάθε πέρασμα. Αυτό αναγκάζει το δίκτυο να μην βασίζεται σε συγκεκριμένους νευρώνες και να δημιουργεί πιο στιβαρές συνδέσεις. Είναι σαν να αφαιρείς παίκτες από μια ομάδα μπάσκετ στην προπόνηση για να μάθουν οι υπόλοιποι να συνεργάζονται καλύτερα.
- L1/L2 Regularization (Weight Decay): Προσθέτουμε έναν όρο στο Loss Function που τιμωρεί τα μεγάλα βάρη. Θέλουμε το δίκτυο να λύνει το πρόβλημα με τις μικρότερες δυνατές τιμές βαρών, γιατί αυτό οδηγεί συνήθως σε απλούστερα και πιο γενικεύσιμα μοντέλα.
- Early Stopping: Παρακολουθούμε την απόδοση στο Validation Set. Μόλις το λάθος αρχίσει να αυξάνεται (ενώ στο training set πέφτει), σταματάμε την εκπαίδευση.
Εξειδικευμένες αρχιτεκτονικές – Πέρα από τα Dense Layers
Μέχρι τώρα μιλούσαμε για Dense δίκτυα. Στον πραγματικό κόσμο, σπάνια χρησιμοποιούμε μόνο αυτά. Ανάλογα με τα δεδομένα, έχουμε εξειδικευμένους “παίκτες”.
Convolutional Neural Networks (CNNs)
Αν δουλεύετε με εικόνα, τα Dense layers είναι καταστροφή. Μια εικόνα 1000×1000 pixels θα απαιτούσε 1 εκατομμύριο εισόδους.
Τα CNNs χρησιμοποιούν Φίλτρα (Kernels) που σαρώνουν την εικόνα για να εντοπίσουν μοτίβα, διατηρώντας τη χωρική συσχέτιση των pixels.
- Key Concepts: Convolution, Pooling (Max/Average), Stride, Padding.
Recurrent Neural Networks (RNNs) & LSTMs
Για δεδομένα ακολουθίας (σειρές χρόνου, κείμενο, ήχος), όπου η σειρά έχει σημασία. Τα RNNs έχουν “μνήμη”, μεταφέροντας πληροφορία από το προηγούμενο βήμα στο επόμενο.
- Το πρόβλημα: Ξεχνάνε εύκολα σε μεγάλες ακολουθίες.
- Η λύση: LSTM (Long Short-Term Memory) και GRU.
Transformers
Εδώ ζούμε σήμερα. Οι Transformers (όπως το BERT, GPT) πέταξαν την αναδρομικότητα των RNNs και βασίστηκαν εξ ολοκλήρου στον μηχανισμό Attention.
Επιτρέπουν στο μοντέλο να εστιάζει σε διαφορετικά μέρη της εισόδου ταυτόχρονα, ανεξάρτητα από την απόσταση μεταξύ τους.
Είναι ο λόγος που τα LLMs καταλαβαίνουν το context τόσο καλά. Αν θέλετε να είστε “in”, πρέπει να καταλάβετε το Self-Attention mechanism.
Υλοποίηση – Από τη θεωρία στην πράξη (PyTorch Edition)
Αρκετά με τη θεωρία. Πως μοιάζει αυτό στον κώδικα; Θα χρησιμοποιήσω PyTorch, γιατί είναι το standard στην έρευνα και την βιομηχανία αυτή τη στιγμή (συγγνώμη TensorFlow, σε αγαπάμε ακόμα, αλλά…).
Ας φτιάξουμε ένα απλό δίκτυο που ταξινομεί δεδομένα.
Python
import torch
import torch.nn as nn
import torch.optim as optim
# 1. Ορισμός της Αρχιτεκτονικής
class SimpleNet(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(SimpleNet, self).__init__()
# Πρώτο επίπεδο: Input -> Hidden
self.fc1 = nn.Linear(input_size, hidden_size)
# Συνάρτηση ενεργοποίησης
self.relu = nn.ReLU()
# Dropout για regularization
self.dropout = nn.Dropout(p=0.2)
# Δεύτερο επίπεδο: Hidden -> Output
self.fc2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.dropout(out)
out = self.fc2(out)
return out
# 2. Υπερπαράμετροι (Hyperparameters)
input_dim = 784 # π.χ. εικόνα 28x28
hidden_dim = 128
output_dim = 10 # π.χ. 10 ψηφία
learning_rate = 0.001
# 3. Initialization
model = SimpleNet(input_dim, hidden_dim, output_dim)
criterion = nn.CrossEntropyLoss() # Loss function
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# 4. Training Loop (Ψευδοκώδικας για συντομία)
# for epoch in range(num_epochs):
# for images, labels in train_loader:
# # Forward pass
# outputs = model(images)
# loss = criterion(outputs, labels)
#
# # Backward and optimize
# optimizer.zero_grad() # Καθαρισμός προηγούμενων gradients
# loss.backward() # Backpropagation
# optimizer.step() # Ενημέρωση βαρών
Τι βλέπουμε εδώ; Η δομή είναι καθαρή. Ορίζουμε τα layers στο __init__ και τη ροή των δεδομένων στο forward. Το loss.backward() είναι εκεί που το PyTorch κάνει τη βαριά δουλειά του διαφορικού λογισμού αυτόματα (Autograd). Εσείς δεν χρειάζεται να υπολογίσετε καμία παράγωγο με το χέρι. Ευτυχώς.
Τα επόμενα βήματα
Η κατανόηση των νευρωνικών δικτύων είναι σαν να μαθαίνεις μια νέα γλώσσα. Στην αρχή, η σύνταξη (τα μαθηματικά) φαίνεται τρομακτική.
Μετά αρχίζεις να φτιάχνεις προτάσεις (απλά μοντέλα).
Και ξαφνικά, συνειδητοποιείς ότι μπορείς να γράψεις ποίηση (πολύπλοκες αρχιτεκτονικές).
Βρισκόμαστε σε μια εποχή που τα εργαλεία είναι πιο προσβάσιμα από ποτέ. Δεν χρειάζεστε PhD για να εκπαιδεύσετε ένα ισχυρό μοντέλο. Χρειάζεστε όμως διαίσθηση (intuition).
Και αυτή χτίζεται μόνο λερώνοντας τα χέρια σας με δεδομένα, αποτυγχάνοντας, βλέποντας το Loss να μην πέφτει (“Not a Number” errors, ο εφιάλτης μας) και διορθώνοντας τις υπερπαραμέτρους.
Το επόμενο βήμα για εσάς; Μην μείνετε στο διάβασμα. Κατεβάστε ένα dataset από το Kaggle (ξεκινήστε με το Titanic ή το MNIST), ανοίξτε ένα Jupyter Notebook και στήστε το πρώτο σας δίκτυο.
Η αίσθηση όταν το accuracy αρχίζει να ανεβαίνει είναι εθιστική.
Καλώς ήρθατε στο κλαμπ.
