Βαθιά Μάθηση
Reading time: 24 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Βαθιά Μάθηση
Η βαθιά μάθηση είναι ένα υποσύνολο της μηχανικής μάθησης που χρησιμοποιεί νευρωνικά δίκτυα με πολλαπλά επίπεδα (βαθιά νευρωνικά δίκτυα) για να μοντελοποιήσει πολύπλοκα μοτίβα στα δεδομένα. Έχει επιτύχει αξιοσημείωτη επιτυχία σε διάφορους τομείς, συμπεριλαμβανομένης της υπολογιστικής όρασης, της επεξεργασίας φυσικής γλώσσας και της αναγνώρισης ομιλίας.
Νευρωνικά Δίκτυα
Τα νευρωνικά δίκτυα είναι τα δομικά στοιχεία της βαθιάς μάθησης. Αποτελούνται από διασυνδεδεμένους κόμβους (νευρώνες) οργανωμένους σε επίπεδα. Κάθε νευρώνας λαμβάνει εισόδους, εφαρμόζει ένα σταθμισμένο άθροισμα και περνά το αποτέλεσμα μέσω μιας συνάρτησης ενεργοποίησης για να παραγάγει μια έξοδο. Τα επίπεδα μπορούν να κατηγοριοποιηθούν ως εξής:
- Επίπεδο Εισόδου: Το πρώτο επίπεδο που λαμβάνει τα δεδομένα εισόδου.
- Κρυφά Επίπεδα: Ενδιάμεσα επίπεδα που εκτελούν μετασχηματισμούς στα δεδομένα εισόδου. Ο αριθμός των κρυφών επιπέδων και των νευρώνων σε κάθε επίπεδο μπορεί να διαφέρει, οδηγώντας σε διαφορετικές αρχιτεκτονικές.
- Επίπεδο Έξοδου: Το τελικό επίπεδο που παράγει την έξοδο του δικτύου, όπως οι πιθανότητες κατηγορίας σε καθήκοντα ταξινόμησης.
Συναρτήσεις Ενεργοποίησης
Όταν ένα επίπεδο νευρώνων επεξεργάζεται δεδομένα εισόδου, κάθε νευρώνας εφαρμόζει ένα βάρος και μια προκατάθεση στην είσοδο (z = w * x + b
), όπου w
είναι το βάρος, x
είναι η είσοδος και b
είναι η προκατάθεση. Η έξοδος του νευρώνα περνά στη συνέχεια μέσω μιας συνάρτησης ενεργοποίησης για να εισάγει μη γραμμικότητα στο μοντέλο. Αυτή η συνάρτηση ενεργοποίησης υποδεικνύει αν ο επόμενος νευρώνας "πρέπει να ενεργοποιηθεί και πόσο". Αυτό επιτρέπει στο δίκτυο να μάθει πολύπλοκα μοτίβα και σχέσεις στα δεδομένα, επιτρέποντάς του να προσεγγίσει οποιαδήποτε συνεχής συνάρτηση.
Επομένως, οι συναρτήσεις ενεργοποίησης εισάγουν μη γραμμικότητα στο νευρωνικό δίκτυο, επιτρέποντάς του να μάθει πολύπλοκες σχέσεις στα δεδομένα. Κοινές συναρτήσεις ενεργοποίησης περιλαμβάνουν:
- Sigmoid: Χαρτογραφεί τις τιμές εισόδου σε μια περιοχή μεταξύ 0 και 1, συχνά χρησιμοποιούμενη σε δυαδική ταξινόμηση.
- ReLU (Rectified Linear Unit): Εξάγει την είσοδο απευθείας αν είναι θετική; διαφορετικά, εξάγει μηδέν. Χρησιμοποιείται ευρέως λόγω της απλότητάς της και της αποτελεσματικότητάς της στην εκπαίδευση βαθιών δικτύων.
- Tanh: Χαρτογραφεί τις τιμές εισόδου σε μια περιοχή μεταξύ -1 και 1, συχνά χρησιμοποιούμενη σε κρυφά επίπεδα.
- Softmax: Μετατρέπει τις ακατέργαστες βαθμολογίες σε πιθανότητες, συχνά χρησιμοποιούμενη στο επίπεδο εξόδου για πολυκατηγορική ταξινόμηση.
Οπισθοδιάδοση
Η οπισθοδιάδοση είναι ο αλγόριθμος που χρησιμοποιείται για την εκπαίδευση νευρωνικών δικτύων προσαρμόζοντας τα βάρη των συνδέσεων μεταξύ των νευρώνων. Λειτουργεί υπολογίζοντας το βαθμωτό της συνάρτησης απώλειας σε σχέση με κάθε βάρος και ενημερώνοντας τα βάρη στην αντίθετη κατεύθυνση του βαθμού για να ελαχιστοποιήσει την απώλεια. Τα βήματα που εμπλέκονται στην οπισθοδιάδοση είναι:
- Προώθηση: Υπολογίστε την έξοδο του δικτύου περνώντας την είσοδο μέσω των επιπέδων και εφαρμόζοντας συναρτήσεις ενεργοποίησης.
- Υπολογισμός Απώλειας: Υπολογίστε την απώλεια (σφάλμα) μεταξύ της προβλεπόμενης εξόδου και του αληθινού στόχου χρησιμοποιώντας μια συνάρτηση απώλειας (π.χ., μέσο τετραγωνικό σφάλμα για παλινδρόμηση, διασταυρούμενη εντροπία για ταξινόμηση).
- Οπισθοδρόμηση: Υπολογίστε τους βαθμούς της απώλειας σε σχέση με κάθε βάρος χρησιμοποιώντας τον κανόνα αλυσίδας του λογισμού.
- Ενημέρωση Βαρών: Ενημερώστε τα βάρη χρησιμοποιώντας έναν αλγόριθμο βελτιστοποίησης (π.χ., στοχαστική καθοδική κλίση, Adam) για να ελαχιστοποιήσετε την απώλεια.
Συγκεντρωτικά Νευρωνικά Δίκτυα (CNNs)
Τα Συγκεντρωτικά Νευρωνικά Δίκτυα (CNNs) είναι ένας εξειδικευμένος τύπος νευρωνικού δικτύου σχεδιασμένος για την επεξεργασία δεδομένων σε μορφή πλέγματος, όπως οι εικόνες. Είναι ιδιαίτερα αποτελεσματικά σε καθήκοντα υπολογιστικής όρασης λόγω της ικανότητάς τους να μαθαίνουν αυτόματα χωρικές ιεραρχίες χαρακτηριστικών.
Τα κύρια συστατικά των CNNs περιλαμβάνουν:
- Συγκεντρωτικά Επίπεδα: Εφαρμόζουν λειτουργίες σύγκλισης στα δεδομένα εισόδου χρησιμοποιώντας εκπαιδευόμενα φίλτρα (πυρήνες) για να εξάγουν τοπικά χαρακτηριστικά. Κάθε φίλτρο γλιστρά πάνω από την είσοδο και υπολογίζει ένα εσωτερικό γινόμενο, παράγοντας έναν χάρτη χαρακτηριστικών.
- Επίπεδα Πίεσης: Μειώνουν τις διαστάσεις των χαρτών χαρακτηριστικών για να διατηρήσουν σημαντικά χαρακτηριστικά. Κοινές λειτουργίες πίεσης περιλαμβάνουν τη μέγιστη πίεση και τη μέση πίεση.
- Πλήρως Συνδεδεμένα Επίπεδα: Συνδέουν κάθε νευρώνα σε ένα επίπεδο με κάθε νευρώνα στο επόμενο επίπεδο, παρόμοια με τα παραδοσιακά νευρωνικά δίκτυα. Αυτά τα επίπεδα χρησιμοποιούνται συνήθως στο τέλος του δικτύου για καθήκοντα ταξινόμησης.
Μέσα σε ένα CNN Συγκεντρωτικά Επίπεδα
, μπορούμε επίσης να διακρίνουμε μεταξύ:
- Αρχικού Συγκεντρωτικού Επιπέδου: Το πρώτο συγκεντρωτικό επίπεδο που επεξεργάζεται τα ακατέργαστα δεδομένα εισόδου (π.χ., μια εικόνα) και είναι χρήσιμο για την αναγνώριση βασικών χαρακτηριστικών όπως οι άκρες και οι υφές.
- Ενδιάμεσων Συγκεντρωτικών Επιπέδων: Επόμενα συγκεντρωτικά επίπεδα που βασίζονται στα χαρακτηριστικά που έχουν μάθει από το αρχικό επίπεδο, επιτρέποντας στο δίκτυο να μάθει πιο πολύπλοκα μοτίβα και αναπαραστάσεις.
- Τελικού Συγκεντρωτικού Επιπέδου: Τα τελευταία συγκεντρωτικά επίπεδα πριν από τα πλήρως συνδεδεμένα επίπεδα, τα οποία συλλαμβάνουν χαρακτηριστικά υψηλού επιπέδου και προετοιμάζουν τα δεδομένα για ταξινόμηση.
tip
Τα CNNs είναι ιδιαίτερα αποτελεσματικά για την ταξινόμηση εικόνας, την ανίχνευση αντικειμένων και τις εργασίες τμηματοποίησης εικόνας λόγω της ικανότητάς τους να μαθαίνουν χωρικές ιεραρχίες χαρακτηριστικών σε δεδομένα πλέγματος και να μειώνουν τον αριθμό των παραμέτρων μέσω κοινοποίησης βαρών. Επιπλέον, λειτουργούν καλύτερα με δεδομένα που υποστηρίζουν την αρχή τοπικότητας χαρακτηριστικών όπου τα γειτονικά δεδομένα (πίξελ) είναι πιο πιθανό να σχετίζονται από τα απομακρυσμένα πίξελ, κάτι που μπορεί να μην ισχύει για άλλους τύπους δεδομένων όπως το κείμενο. Επιπλέον, σημειώστε πώς τα CNNs θα είναι σε θέση να αναγνωρίσουν ακόμη και πολύπλοκα χαρακτηριστικά αλλά δεν θα είναι σε θέση να εφαρμόσουν κανένα χωρικό πλαίσιο, πράγμα που σημαίνει ότι το ίδιο χαρακτηριστικό που βρίσκεται σε διαφορετικά μέρη της εικόνας θα είναι το ίδιο.
Παράδειγμα ορισμού ενός CNN
Εδώ θα βρείτε μια περιγραφή για το πώς να ορίσετε ένα Συγκεντρωτικό Νευρωνικό Δίκτυο (CNN) στο PyTorch που ξεκινά με μια παρτίδα RGB εικόνων ως σύνολο δεδομένων μεγέθους 48x48 και χρησιμοποιεί συγκεντρωτικά επίπεδα και maxpool για να εξάγει χαρακτηριστικά, ακολουθούμενα από πλήρως συνδεδεμένα επίπεδα για ταξινόμηση.
Αυτός είναι ο τρόπος με τον οποίο μπορείτε να ορίσετε 1 συγκεντρωτικό επίπεδο στο PyTorch: self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=1)
.
-
in_channels
: Αριθμός εισερχόμενων καναλιών. Στην περίπτωση των RGB εικόνων, αυτό είναι 3 (ένα για κάθε χρωματικό κανάλι). Αν εργάζεστε με εικόνες σε κλίμακα του γκρι, αυτό θα είναι 1. -
out_channels
: Αριθμός εξερχόμενων καναλιών (φίλτρων) που θα μάθει το συγκεντρωτικό επίπεδο. Αυτό είναι μια υπερπαράμετρος που μπορείτε να προσαρμόσετε με βάση την αρχιτεκτονική του μοντέλου σας. -
kernel_size
: Μέγεθος του φίλτρου σύγκλισης. Μια κοινή επιλογή είναι 3x3, που σημαίνει ότι το φίλτρο θα καλύψει μια περιοχή 3x3 της εισόδου εικόνας. Αυτό είναι σαν ένα χρώμα σφραγίδας 3×3×3 που χρησιμοποιείται για να παραγάγει τα εξερχόμενα κανάλια από τα εισερχόμενα κανάλια:
- Τοποθετήστε αυτή τη σφραγίδα 3×3×3 στην επάνω αριστερή γωνία του κύβου εικόνας.
- Πολλαπλασιάστε κάθε βάρος με το πίξελ από κάτω του, προσθέστε τα όλα, προσθέστε την προκατάθεση → παίρνετε έναν αριθμό.
- Γράψτε αυτόν τον αριθμό σε έναν κενό χάρτη στη θέση (0, 0).
- Γλιστρήστε τη σφραγίδα ένα πίξελ προς τα δεξιά (stride = 1) και επαναλάβετε μέχρι να γεμίσετε ολόκληρο το πλέγμα 48×48.
padding
: Αριθμός πίξελ που προστίθενται σε κάθε πλευρά της εισόδου. Η προσθήκη βοηθά στη διατήρηση των χωρικών διαστάσεων της εισόδου, επιτρέποντας περισσότερη έλεγχο στο μέγεθος της εξόδου. Για παράδειγμα, με έναν πυρήνα 3x3 και μια είσοδο 48x48 πίξελ, η προσθήκη 1 θα διατηρήσει το μέγεθος της εξόδου το ίδιο (48x48) μετά τη λειτουργία σύγκλισης. Αυτό συμβαίνει επειδή η προσθήκη προσθέτει ένα περίγραμμα 1 πίξελ γύρω από την είσοδο εικόνας, επιτρέποντας στον πυρήνα να γλιστρήσει πάνω από τις άκρες χωρίς να μειώσει τις χωρικές διαστάσεις.
Στη συνέχεια, ο αριθμός των εκπαιδευόμενων παραμέτρων σε αυτό το επίπεδο είναι:
- (3x3x3 (μέγεθος πυρήνα) + 1 (προκατάθεση)) x 32 (εξερχόμενα κανάλια) = 896 εκπαιδευόμενες παράμετροι.
Σημειώστε ότι μια προκατάθεση (+1) προστίθεται ανά πυρήνα που χρησιμοποιείται επειδή η λειτουργία κάθε συγκεντρωτικού επιπέδου είναι να μάθει μια γραμμική μετατροπή της εισόδου, η οποία αναπαρίσταται από την εξίσωση:
Y = f(W * X + b)
όπου το W
είναι ο πίνακας βαρών (τα μαθημένα φίλτρα, 3x3x3 = 27 παράμετροι), το b
είναι το διάνυσμα προκατάληψης το οποίο είναι +1 για κάθε κανάλι εξόδου.
Σημειώστε ότι η έξοδος του self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=1)
θα είναι ένας τανυστής σχήματος (batch_size, 32, 48, 48)
, επειδή το 32 είναι ο νέος αριθμός παραγόμενων καναλιών μεγέθους 48x48 εικονοστοιχείων.
Στη συνέχεια, θα μπορούσαμε να συνδέσουμε αυτή την συνελικτική στρώση με μια άλλη συνελικτική στρώση όπως: self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)
.
Αυτό θα προσθέσει: (32x3x3 (μέγεθος πυρήνα) + 1 (προκατάληψη)) x 64 (κανάλια εξόδου) = 18,496 παραμέτρους που μπορούν να εκπαιδευτούν και μια έξοδο σχήματος (batch_size, 64, 48, 48)
.
Όπως μπορείτε να δείτε, ο αριθμός των παραμέτρων αυξάνεται γρήγορα με κάθε επιπλέον συνελικτική στρώση, ειδικά καθώς αυξάνεται ο αριθμός των καναλιών εξόδου.
Μια επιλογή για να ελέγξουμε την ποσότητα των δεδομένων που χρησιμοποιούνται είναι να χρησιμοποιήσουμε max pooling μετά από κάθε συνελικτική στρώση. Το max pooling μειώνει τις χωρικές διαστάσεις των χαρτών χαρακτηριστικών, γεγονός που βοηθά στη μείωση του αριθμού των παραμέτρων και της υπολογιστικής πολυπλοκότητας ενώ διατηρεί σημαντικά χαρακτηριστικά.
Μπορεί να δηλωθεί ως: self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
. Αυτό ουσιαστικά υποδεικνύει τη χρήση ενός πλέγματος 2x2 εικονοστοιχείων και την επιλογή της μέγιστης τιμής από κάθε πλέγμα για να μειωθεί το μέγεθος του χάρτη χαρακτηριστικών στο μισό. Επιπλέον, το stride=2
σημαίνει ότι η λειτουργία pooling θα μετακινείται 2 εικονοστοιχεία κάθε φορά, σε αυτή την περίπτωση, αποτρέποντας οποιαδήποτε επικάλυψη μεταξύ των περιοχών pooling.
Με αυτή τη στρώση pooling, το σχήμα εξόδου μετά την πρώτη συνελικτική στρώση θα είναι (batch_size, 64, 24, 24)
μετά την εφαρμογή του self.pool1
στην έξοδο του self.conv2
, μειώνοντας το μέγεθος στο 1/4 του προηγούμενου στρώματος.
tip
Είναι σημαντικό να κάνετε pooling μετά τις συνελικτικές στρώσεις για να μειώσετε τις χωρικές διαστάσεις των χαρτών χαρακτηριστικών, γεγονός που βοηθά στον έλεγχο του αριθμού των παραμέτρων και της υπολογιστικής πολυπλοκότητας ενώ επιτρέπει στις αρχικές παραμέτρους να μάθουν σημαντικά χαρακτηριστικά.
Μπορείτε να δείτε τις συνελίξεις πριν από μια στρώση pooling ως έναν τρόπο εξαγωγής χαρακτηριστικών από τα εισερχόμενα δεδομένα (όπως γραμμές, άκρες), αυτή η πληροφορία θα είναι ακόμα παρούσα στην έξοδο του pooling, αλλά η επόμενη συνελικτική στρώση δεν θα μπορεί να δει τα αρχικά εισερχόμενα δεδομένα, μόνο την έξοδο του pooling, η οποία είναι μια μειωμένη έκδοση του προηγούμενου στρώματος με αυτή την πληροφορία.
Στη συνήθη σειρά: Conv → ReLU → Pool
κάθε παράθυρο pooling 2×2 τώρα ανταγωνίζεται με τις ενεργοποιήσεις χαρακτηριστικών (“παρούσα άκρη / όχι”), όχι με τις ακατέργαστες εντάσεις εικονοστοιχείων. Η διατήρηση της ισχυρότερης ενεργοποίησης πραγματικά διατηρεί την πιο σημαντική απόδειξη.
Στη συνέχεια, μετά την προσθήκη όσων περισσότερων συνελικτικών και στρωμάτων pooling χρειάζεται, μπορούμε να ισοπεδώσουμε την έξοδο για να την τροφοδοτήσουμε σε πλήρως συνδεδεμένες στρώσεις. Αυτό γίνεται με την αναδιάταξη του τανυστή σε ένα 1D διάνυσμα για κάθε δείγμα στη δέσμη:
x = x.view(-1, 64*24*24)
Και με αυτό το 1D διάνυσμα με όλες τις παραμέτρους εκπαίδευσης που δημιουργήθηκαν από τα προηγούμενα συνελικτικά και pooling επίπεδα, μπορούμε να ορίσουμε ένα πλήρως συνδεδεμένο επίπεδο όπως:
self.fc1 = nn.Linear(64 * 24 * 24, 512)
Το οποίο θα πάρει την επίπεδη έξοδο του προηγούμενου επιπέδου και θα την αντιστοιχίσει σε 512 κρυμμένες μονάδες.
Σημειώστε πώς αυτό το επίπεδο πρόσθεσε (64 * 24 * 24 + 1 (bias)) * 512 = 3,221,504
εκπαιδευόμενες παραμέτρους, οι οποίες είναι μια σημαντική αύξηση σε σύγκριση με τα συνελικτικά επίπεδα. Αυτό συμβαίνει επειδή τα πλήρως συνδεδεμένα επίπεδα συνδέουν κάθε νευρώνα σε ένα επίπεδο με κάθε νευρώνα στο επόμενο επίπεδο, οδηγώντας σε μεγάλο αριθμό παραμέτρων.
Τέλος, μπορούμε να προσθέσουμε ένα επίπεδο εξόδου για να παραγάγουμε τους τελικούς λογισμούς κλάσης:
self.fc2 = nn.Linear(512, num_classes)
Αυτό θα προσθέσει (512 + 1 (bias)) * num_classes
εκπαιδεύσιμες παραμέτρους, όπου num_classes
είναι ο αριθμός των κατηγοριών στην εργασία ταξινόμησης (π.χ., 43 για το σύνολο δεδομένων GTSRB).
Μια άλλη κοινή πρακτική είναι να προστεθεί ένα dropout layer πριν από τα πλήρως συνδεδεμένα layers για να αποτραπεί η υπερβολική προσαρμογή. Αυτό μπορεί να γίνει με:
self.dropout = nn.Dropout(0.5)
Αυτό το επίπεδο ρυθμίζει τυχαία ένα κλάσμα των μονάδων εισόδου σε μηδέν κατά τη διάρκεια της εκπαίδευσης, το οποίο βοηθά στην πρόληψη της υπερπροσαρμογής μειώνοντας την εξάρτηση από συγκεκριμένους νευρώνες.
CNN Code example
import torch
import torch.nn as nn
import torch.nn.functional as F
class MY_NET(nn.Module):
def __init__(self, num_classes=32):
super(MY_NET, self).__init__()
# Initial conv layer: 3 input channels (RGB), 32 output channels, 3x3 kernel, padding 1
# This layer will learn basic features like edges and textures
self.conv1 = nn.Conv2d(
in_channels=3, out_channels=32, kernel_size=3, padding=1
)
# Output: (Batch Size, 32, 48, 48)
# Conv Layer 2: 32 input channels, 64 output channels, 3x3 kernel, padding 1
# This layer will learn more complex features based on the output of conv1
self.conv2 = nn.Conv2d(
in_channels=32, out_channels=64, kernel_size=3, padding=1
)
# Output: (Batch Size, 64, 48, 48)
# Max Pooling 1: Kernel 2x2, Stride 2. Reduces spatial dimensions by half (1/4th of the previous layer).
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
# Output: (Batch Size, 64, 24, 24)
# Conv Layer 3: 64 input channels, 128 output channels, 3x3 kernel, padding 1
# This layer will learn even more complex features based on the output of conv2
# Note that the number of output channels can be adjusted based on the complexity of the task
self.conv3 = nn.Conv2d(
in_channels=64, out_channels=128, kernel_size=3, padding=1
)
# Output: (Batch Size, 128, 24, 24)
# Max Pooling 2: Kernel 2x2, Stride 2. Reduces spatial dimensions by half again.
# Reducing the dimensions further helps to control the number of parameters and computational complexity.
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
# Output: (Batch Size, 128, 12, 12)
# From the second pooling layer, we will flatten the output to feed it into fully connected layers.
# The feature size is calculated as follows:
# Feature size = Number of output channels * Height * Width
self._feature_size = 128 * 12 * 12
# Fully Connected Layer 1 (Hidden): Maps flattened features to hidden units.
# This layer will learn to combine the features extracted by the convolutional layers.
self.fc1 = nn.Linear(self._feature_size, 512)
# Fully Connected Layer 2 (Output): Maps hidden units to class logits.
# Output size MUST match num_classes
self.fc2 = nn.Linear(512, num_classes)
# Dropout layer configuration with a dropout rate of 0.5.
# This layer is used to prevent overfitting by randomly setting a fraction of the input units to zero during training.
self.dropout = nn.Dropout(0.5)
def forward(self, x):
"""
The forward method defines the forward pass of the network.
It takes an input tensor `x` and applies the convolutional layers, pooling layers, and fully connected layers in sequence.
The input tensor `x` is expected to have the shape (Batch Size, Channels, Height, Width), where:
- Batch Size: Number of samples in the batch
- Channels: Number of input channels (e.g., 3 for RGB images)
- Height: Height of the input image (e.g., 48 for 48x48 images)
- Width: Width of the input image (e.g., 48 for 48x48 images)
The output of the forward method is the logits for each class, which can be used for classification tasks.
Args:
x (torch.Tensor): Input tensor of shape (Batch Size, Channels, Height, Width)
Returns:
torch.Tensor: Output tensor of shape (Batch Size, num_classes) containing the class logits.
"""
# Conv1 -> ReLU -> Conv2 -> ReLU -> Pool1 -> Conv3 -> ReLU -> Pool2
x = self.conv1(x)
x = F.relu(x)
x = self.conv2(x)
x = F.relu(x)
x = self.pool1(x)
x = self.conv3(x)
x = F.relu(x)
x = self.pool2(x)
# At this point, x has shape (Batch Size, 128, 12, 12)
# Flatten the output to feed it into fully connected layers
x = torch.flatten(x, 1)
# Apply dropout to prevent overfitting
x = self.dropout(x)
# First FC layer with ReLU activation
x = F.relu(self.fc1(x))
# Apply Dropout again
x = self.dropout(x)
# Final FC layer to get logits
x = self.fc2(x)
# Output shape will be (Batch Size, num_classes)
# Note that the output is not passed through a softmax activation here, as it is typically done in the loss function (e.g., CrossEntropyLoss)
return x
CNN Code training example
Ο παρακάτω κώδικας θα δημιουργήσει κάποια δεδομένα εκπαίδευσης και θα εκπαιδεύσει το μοντέλο MY_NET
που ορίστηκε παραπάνω. Ορισμένες ενδιαφέρουσες τιμές που πρέπει να σημειωθούν:
EPOCHS
είναι ο αριθμός των φορών που το μοντέλο θα δει ολόκληρο το σύνολο δεδομένων κατά τη διάρκεια της εκπαίδευσης. Αν το EPOCH είναι πολύ μικρό, το μοντέλο μπορεί να μην μάθει αρκετά; αν είναι πολύ μεγάλο, μπορεί να υπερβολικά προσαρμοστεί.LEARNING_RATE
είναι το μέγεθος βήματος για τον βελτιστοποιητή. Ένα μικρό learning rate μπορεί να οδηγήσει σε αργή σύγκλιση, ενώ ένα μεγάλο μπορεί να υπερβεί τη βέλτιστη λύση και να αποτρέψει τη σύγκλιση.WEIGHT_DECAY
είναι ένας όρος κανονικοποίησης που βοηθά στην αποφυγή της υπερπροσαρμογής ποινικοποιώντας τα μεγάλα βάρη.
Σχετικά με τον βρόχο εκπαίδευσης, αυτή είναι μερικές ενδιαφέρουσες πληροφορίες που πρέπει να γνωρίζετε:
- Ο
criterion = nn.CrossEntropyLoss()
είναι η συνάρτηση απώλειας που χρησιμοποιείται για καθήκοντα πολυκατηγορίας. Συνδυάζει την ενεργοποίηση softmax και την απώλεια cross-entropy σε μία μόνο συνάρτηση, καθιστώντας την κατάλληλη για την εκπαίδευση μοντέλων που εξάγουν logits κατηγορίας. - Αν το μοντέλο αναμενόταν να εξάγει άλλους τύπους εξόδων, όπως δυαδική κατηγοριοποίηση ή παλινδρόμηση, θα χρησιμοποιούσαμε διαφορετικές συναρτήσεις απώλειας όπως
nn.BCEWithLogitsLoss()
για δυαδική κατηγοριοποίηση ήnn.MSELoss()
για παλινδρόμηση. - Ο
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE, weight_decay=WEIGHT_DECAY)
αρχικοποιεί τον βελτιστοποιητή Adam, ο οποίος είναι μια δημοφιλής επιλογή για την εκπαίδευση μοντέλων βαθιάς μάθησης. Προσαρμόζει το learning rate για κάθε παράμετρο με βάση τις πρώτες και δεύτερες στιγμές των κλίσεων. - Άλλοι βελτιστοποιητές όπως
optim.SGD
(Στοχαστική Καθόδου Κλίσης) ήoptim.RMSprop
θα μπορούσαν επίσης να χρησιμοποιηθούν, ανάλογα με τις συγκεκριμένες απαιτήσεις της εργασίας εκπαίδευσης. - Η μέθοδος
model.train()
θέτει το μοντέλο σε λειτουργία εκπαίδευσης, επιτρέποντας σε στρώματα όπως το dropout και η κανονικοποίηση παρτίδας να συμπεριφέρονται διαφορετικά κατά τη διάρκεια της εκπαίδευσης σε σύγκριση με την αξιολόγηση. optimizer.zero_grad()
καθαρίζει τις κλίσεις όλων των βελτιστοποιημένων τενσορών πριν από την οπίσθια διέλευση, κάτι που είναι απαραίτητο επειδή οι κλίσεις συσσωρεύονται από προεπιλογή στο PyTorch. Αν δεν καθαριστούν, οι κλίσεις από προηγούμενες επαναλήψεις θα προστεθούν στις τρέχουσες κλίσεις, οδηγώντας σε λανθασμένες ενημερώσεις.loss.backward()
υπολογίζει τις κλίσεις της απώλειας σε σχέση με τις παραμέτρους του μοντέλου, οι οποίες στη συνέχεια χρησιμοποιούνται από τον βελτιστοποιητή για να ενημερώσουν τα βάρη.optimizer.step()
ενημερώνει τις παραμέτρους του μοντέλου με βάση τις υπολογισμένες κλίσεις και το learning rate.
import torch, torch.nn.functional as F
from torch import nn, optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from tqdm import tqdm
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
# ---------------------------------------------------------------------------
# 1. Globals
# ---------------------------------------------------------------------------
IMG_SIZE = 48 # model expects 48×48
NUM_CLASSES = 10 # MNIST has 10 digits
BATCH_SIZE = 64 # batch size for training and validation
EPOCHS = 5 # number of training epochs
LEARNING_RATE = 1e-3 # initial learning rate for Adam optimiser
WEIGHT_DECAY = 1e-4 # L2 regularisation to prevent overfitting
# Channel-wise mean / std for MNIST (grayscale ⇒ repeat for 3-channel input)
MNIST_MEAN = (0.1307, 0.1307, 0.1307)
MNIST_STD = (0.3081, 0.3081, 0.3081)
# ---------------------------------------------------------------------------
# 2. Transforms
# ---------------------------------------------------------------------------
# 1) Baseline transform: resize + tensor (no colour/aug/no normalise)
transform_base = transforms.Compose([
transforms.Resize((IMG_SIZE, IMG_SIZE)), # 🔹 Resize – force all images to 48 × 48 so the CNN sees a fixed geometry
transforms.Grayscale(num_output_channels=3), # 🔹 Grayscale→RGB – MNIST is 1-channel; duplicate into 3 channels for convnet
transforms.ToTensor(), # 🔹 ToTensor – convert PIL image [0‒255] → float tensor [0.0‒1.0]
])
# 2) Training transform: augment + normalise
transform_norm = transforms.Compose([
transforms.Resize((IMG_SIZE, IMG_SIZE)), # keep 48 × 48 input size
transforms.Grayscale(num_output_channels=3), # still need 3 channels
transforms.RandomRotation(10), # 🔹 RandomRotation(±10°) – small tilt ⇢ rotation-invariance, combats overfitting
transforms.ColorJitter(brightness=0.2,
contrast=0.2), # 🔹 ColorJitter – pseudo-RGB brightness/contrast noise; extra variety
transforms.ToTensor(), # convert to tensor before numeric ops
transforms.Normalize(mean=MNIST_MEAN,
std=MNIST_STD), # 🔹 Normalize – zero-centre & scale so every channel ≈ N(0,1)
])
# 3) Test/validation transform: only resize + normalise (no aug)
transform_test = transforms.Compose([
transforms.Resize((IMG_SIZE, IMG_SIZE)), # same spatial size as train
transforms.Grayscale(num_output_channels=3), # match channel count
transforms.ToTensor(), # tensor conversion
transforms.Normalize(mean=MNIST_MEAN,
std=MNIST_STD), # 🔹 keep test data on same scale as training data
])
# ---------------------------------------------------------------------------
# 3. Datasets & loaders
# ---------------------------------------------------------------------------
train_set = datasets.MNIST("data", train=True, download=True, transform=transform_norm)
test_set = datasets.MNIST("data", train=False, download=True, transform=transform_test)
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_set, batch_size=256, shuffle=False)
print(f"Training on {len(train_set)} samples, validating on {len(test_set)} samples.")
# ---------------------------------------------------------------------------
# 4. Model / loss / optimiser
# ---------------------------------------------------------------------------
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MY_NET(num_classes=NUM_CLASSES).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE, weight_decay=WEIGHT_DECAY)
# ---------------------------------------------------------------------------
# 5. Training loop
# ---------------------------------------------------------------------------
for epoch in range(1, EPOCHS + 1):
model.train() # Set model to training mode enabling dropout and batch norm
running_loss = 0.0 # sums batch losses to compute epoch average
correct = 0 # number of correct predictions
total = 0 # number of samples seen
# tqdm wraps the loader to show a live progress-bar per epoch
for X_batch, y_batch in tqdm(train_loader, desc=f"Epoch {epoch}", leave=False):
# 3-a) Move data to GPU (if available) ----------------------------------
X_batch, y_batch = X_batch.to(device), y_batch.to(device)
# 3-b) Forward pass -----------------------------------------------------
logits = model(X_batch) # raw class scores (shape: [B, NUM_CLASSES])
loss = criterion(logits, y_batch)
# 3-c) Backward pass & parameter update --------------------------------
optimizer.zero_grad() # clear old gradients
loss.backward() # compute new gradients
optimizer.step() # gradient → weight update
# 3-d) Statistics -------------------------------------------------------
running_loss += loss.item() * X_batch.size(0) # sum of (batch loss × batch size)
preds = logits.argmax(dim=1) # predicted class labels
correct += (preds == y_batch).sum().item() # correct predictions in this batch
total += y_batch.size(0) # samples processed so far
# 3-e) Epoch-level metrics --------------------------------------------------
epoch_loss = running_loss / total
epoch_acc = 100.0 * correct / total
print(f"[Epoch {epoch}] loss = {epoch_loss:.4f} | accuracy = {epoch_acc:.2f}%")
print("\n✅ Training finished.\n")
# ---------------------------------------------------------------------------
# 6. Evaluation on test set
# ---------------------------------------------------------------------------
model.eval() # Set model to evaluation mode (disables dropout and batch norm)
with torch.no_grad():
logits_all, labels_all = [], []
for X, y in test_loader:
logits_all.append(model(X.to(device)).cpu())
labels_all.append(y)
logits_all = torch.cat(logits_all)
labels_all = torch.cat(labels_all)
preds_all = logits_all.argmax(1)
test_loss = criterion(logits_all, labels_all).item()
test_acc = (preds_all == labels_all).float().mean().item() * 100
print(f"Test loss: {test_loss:.4f}")
print(f"Test accuracy: {test_acc:.2f}%\n")
print("Classification report (precision / recall / F1):")
print(classification_report(labels_all, preds_all, zero_division=0))
print("Confusion matrix (rows = true, cols = pred):")
print(confusion_matrix(labels_all, preds_all))
Αναδρομικά Νευρωνικά Δίκτυα (RNNs)
Αναδρομικά Νευρωνικά Δίκτυα (RNNs) είναι μια κατηγορία νευρωνικών δικτύων που έχουν σχεδιαστεί για την επεξεργασία διαδοχικών δεδομένων, όπως σειρές χρόνου ή φυσική γλώσσα. Σε αντίθεση με τα παραδοσιακά νευρωνικά δίκτυα τροφοδοσίας, τα RNNs έχουν συνδέσεις που επιστρέφουν στον εαυτό τους, επιτρέποντάς τους να διατηρούν μια κρυφή κατάσταση που καταγράφει πληροφορίες σχετικά με τις προηγούμενες εισόδους στη σειρά.
Τα κύρια συστατικά των RNNs περιλαμβάνουν:
- Αναδρομικά Επίπεδα: Αυτά τα επίπεδα επεξεργάζονται τις εισόδους μία χρονική στιγμή τη φορά, ενημερώνοντας την κρυφή τους κατάσταση με βάση την τρέχουσα είσοδο και την προηγούμενη κρυφή κατάσταση. Αυτό επιτρέπει στα RNNs να μαθαίνουν χρονικές εξαρτήσεις στα δεδομένα.
- Κρυφή Κατάσταση: Η κρυφή κατάσταση είναι ένα διάνυσμα που συνοψίζει τις πληροφορίες από προηγούμενα χρονικά βήματα. Ενημερώνεται σε κάθε χρονικό βήμα και χρησιμοποιείται για να κάνει προβλέψεις για την τρέχουσα είσοδο.
- Επίπεδο Εξόδου: Το επίπεδο εξόδου παράγει τις τελικές προβλέψεις με βάση την κρυφή κατάσταση. Σε πολλές περιπτώσεις, τα RNNs χρησιμοποιούνται για εργασίες όπως η μοντελοποίηση γλώσσας, όπου η έξοδος είναι μια κατανομή πιθανότητας για την επόμενη λέξη σε μια σειρά.
Για παράδειγμα, σε ένα μοντέλο γλώσσας, το RNN επεξεργάζεται μια σειρά λέξεων, για παράδειγμα, "Η γάτα κάθισε πάνω στο" και προβλέπει την επόμενη λέξη με βάση το πλαίσιο που παρέχεται από τις προηγούμενες λέξεις, σε αυτή την περίπτωση, "χαλί".
Μακροχρόνια Μνήμη (LSTM) και Μονάδα Επαναλαμβανόμενης Πύλης (GRU)
Τα RNNs είναι ιδιαίτερα αποτελεσματικά για εργασίες που περιλαμβάνουν διαδοχικά δεδομένα, όπως η μοντελοποίηση γλώσσας, η μηχανική μετάφραση και η αναγνώριση ομιλίας. Ωστόσο, μπορεί να δυσκολεύονται με μακροχρόνιες εξαρτήσεις λόγω προβλημάτων όπως οι φθίνουσες κλίσεις.
Για να αντιμετωπιστεί αυτό, αναπτύχθηκαν εξειδικευμένες αρχιτεκτονικές όπως η Μακροχρόνια Μνήμη (LSTM) και η Μονάδα Επαναλαμβανόμενης Πύλης (GRU). Αυτές οι αρχιτεκτονικές εισάγουν μηχανισμούς πύλης που ελέγχουν τη ροή των πληροφοριών, επιτρέποντάς τους να καταγράφουν μακροχρόνιες εξαρτήσεις πιο αποτελεσματικά.
- LSTM: Τα δίκτυα LSTM χρησιμοποιούν τρεις πύλες (πύλη εισόδου, πύλη λήθης και πύλη εξόδου) για να ρυθμίζουν τη ροή των πληροφοριών μέσα και έξω από την κατάσταση του κελιού, επιτρέποντάς τους να θυμούνται ή να ξεχνούν πληροφορίες σε μακρές ακολουθίες. Η πύλη εισόδου ελέγχει πόσες νέες πληροφορίες να προσθέσει με βάση την είσοδο και την προηγούμενη κρυφή κατάσταση, η πύλη λήθης ελέγχει πόσες πληροφορίες να απορρίψει. Συνδυάζοντας την πύλη εισόδου και την πύλη λήθης, αποκτούμε τη νέα κατάσταση. Τέλος, συνδυάζοντας τη νέα κατάσταση του κελιού με την είσοδο και την προηγούμενη κρυφή κατάσταση, αποκτούμε επίσης τη νέα κρυφή κατάσταση.
- GRU: Τα δίκτυα GRU απλοποιούν την αρχιτεκτονική LSTM συνδυάζοντας τις πύλες εισόδου και λήθης σε μια ενιαία πύλη ενημέρωσης, καθιστώντας τα υπολογιστικά πιο αποδοτικά ενώ εξακολουθούν να καταγράφουν μακροχρόνιες εξαρτήσεις.
LLMs (Μεγάλα Μοντέλα Γλώσσας)
Τα Μεγάλα Μοντέλα Γλώσσας (LLMs) είναι ένας τύπος μοντέλου βαθιάς μάθησης που έχει σχεδιαστεί ειδικά για εργασίες επεξεργασίας φυσικής γλώσσας. Εκπαιδεύονται σε τεράστιες ποσότητες δεδομένων κειμένου και μπορούν να παράγουν κείμενο παρόμοιο με αυτό των ανθρώπων, να απαντούν σε ερωτήσεις, να μεταφράζουν γλώσσες και να εκτελούν διάφορες άλλες γλωσσικές εργασίες. Τα LLMs βασίζονται συνήθως σε αρχιτεκτονικές μετασχηματιστών, οι οποίες χρησιμοποιούν μηχανισμούς αυτοπροσοχής για να καταγράψουν σχέσεις μεταξύ λέξεων σε μια σειρά, επιτρέποντάς τους να κατανοούν το πλαίσιο και να παράγουν συνεκτικό κείμενο.
Αρχιτεκτονική Μετασχηματιστή
Η αρχιτεκτονική μετασχηματιστή είναι η βάση πολλών LLMs. Αποτελείται από μια δομή κωδικοποιητή-αποκωδικοποιητή, όπου ο κωδικοποιητής επεξεργάζεται τη σειρά εισόδου και ο αποκωδικοποιητής παράγει τη σειρά εξόδου. Τα κύρια συστατικά της αρχιτεκτονικής μετασχηματιστή περιλαμβάνουν:
- Μηχανισμός Αυτοπροσοχής: Αυτός ο μηχανισμός επιτρέπει στο μοντέλο να ζυγίζει τη σημασία διαφορετικών λέξεων σε μια σειρά κατά την παραγωγή αναπαραστάσεων. Υπολογίζει βαθμολογίες προσοχής με βάση τις σχέσεις μεταξύ λέξεων, επιτρέποντας στο μοντέλο να εστιάζει σε σχετικό πλαίσιο.
- Πολυκεφαλική Προσοχή: Αυτό το συστατικό επιτρέπει στο μοντέλο να καταγράφει πολλές σχέσεις μεταξύ λέξεων χρησιμοποιώντας πολλαπλές κεφαλές προσοχής, καθεμία εστιάζοντας σε διαφορετικές πτυχές της εισόδου.
- Θέση Κωδικοποίησης: Δεδομένου ότι οι μετασχηματιστές δεν έχουν μια ενσωματωμένη έννοια της σειράς των λέξεων, η θέση κωδικοποίησης προστίθεται στις ενσωματώσεις εισόδου για να παρέχει πληροφορίες σχετικά με τη θέση των λέξεων στη σειρά.
Μοντέλα Διάχυσης
Τα μοντέλα διάχυσης είναι μια κατηγορία γενετικών μοντέλων που μαθαίνουν να παράγουν δεδομένα προσομοιώνοντας μια διαδικασία διάχυσης. Είναι ιδιαίτερα αποτελεσματικά για εργασίες όπως η παραγωγή εικόνας και έχουν αποκτήσει δημοτικότητα τα τελευταία χρόνια. Τα μοντέλα διάχυσης λειτουργούν μετατρέποντας σταδιακά μια απλή κατανομή θορύβου σε μια σύνθετη κατανομή δεδομένων μέσω μιας σειράς βημάτων διάχυσης. Τα κύρια συστατικά των μοντέλων διάχυσης περιλαμβάνουν:
- Διαδικασία Πρόσθιας Διάχυσης: Αυτή η διαδικασία προσθέτει σταδιακά θόρυβο στα δεδομένα, μετατρέποντάς τα σε μια απλή κατανομή θορύβου. Η διαδικασία πρόσθιας διάχυσης ορίζεται συνήθως από μια σειρά επιπέδων θορύβου, όπου κάθε επίπεδο αντιστοιχεί σε μια συγκεκριμένη ποσότητα θορύβου που προστίθεται στα δεδομένα.
- Διαδικασία Αντίστροφης Διάχυσης: Αυτή η διαδικασία μαθαίνει να αντιστρέφει τη διαδικασία πρόσθιας διάχυσης, αποθορυβοποιώντας σταδιακά τα δεδομένα για να παράγει δείγματα από την κατανομή στόχο. Η διαδικασία αντίστροφης διάχυσης εκπαιδεύεται χρησιμοποιώντας μια συνάρτηση απώλειας που ενθαρρύνει το μοντέλο να ανακατασκευάσει τα αρχικά δεδομένα από θορυβώδη δείγματα.
Επιπλέον, για να παραχθεί μια εικόνα από μια κείμενη προτροπή, τα μοντέλα διάχυσης συνήθως ακολουθούν αυτά τα βήματα:
- Κωδικοποίηση Κειμένου: Η κείμενη προτροπή κωδικοποιείται σε μια λανθάνουσα αναπαράσταση χρησιμοποιώντας έναν κωδικοποιητή κειμένου (π.χ. ένα μοντέλο βασισμένο σε μετασχηματιστή). Αυτή η αναπαράσταση καταγράφει τη σημασιολογική έννοια του κειμένου.
- Δειγματοληψία Θορύβου: Ένα τυχαίο διάνυσμα θορύβου δειγματίζεται από μια κανονική κατανομή.
- Βήματα Διάχυσης: Το μοντέλο εφαρμόζει μια σειρά βημάτων διάχυσης, μετατρέποντας σταδιακά το διάνυσμα θορύβου σε μια εικόνα που αντιστοιχεί στην κείμενη προτροπή. Κάθε βήμα περιλαμβάνει την εφαρμογή μαθημένων μετασχηματισμών για την αποθορυβοποίηση της εικόνας.
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.