Πώς μπορείτε να εκπαιδεύσετε ένα AI για να μετατρέψετε τα mockups σχεδιασμού σας σε HTML και CSS

Μέσα σε τρία χρόνια, η βαθιά εκμάθηση θα αλλάξει την ανάπτυξη του μετώπου. Θα αυξήσει την ταχύτητα του πρωτοτύπου και θα μειώσει το εμπόδιο για την κατασκευή του λογισμικού.

Το πεδίο απογειώθηκε πέρυσι, όταν ο Tony Beltramelli εισήγαγε το χαρτί pix2code και ο Airbnb ξεκίνησε το sketch2code.

Φωτογραφία από τον Wesson Wang στο Unsplash

Επί του παρόντος, ο μεγαλύτερος φραγμός στην αυτοματοποίηση της ανάπτυξης είναι η υπολογιστική ισχύς. Ωστόσο, μπορούμε να χρησιμοποιήσουμε τους τρέχοντες αλγορίθμους βαθιάς μάθησης, μαζί με τα συνθετικά δεδομένα εκπαίδευσης, για να ξεκινήσουμε την εξερεύνηση της τεχνητής μεθόδου front-end αυτή τη στιγμή.

Σε αυτήν την ανάρτηση, θα διδάξουμε ένα νευρωνικό δίκτυο πώς να κωδικοποιήσετε έναν βασικό ιστότοπο HTML και CSS βασισμένο σε μια εικόνα ενός μακέτου σχεδιασμού. Ακολουθεί μια γρήγορη επισκόπηση της διαδικασίας:

1) Δώστε μια εικόνα σχεδιασμού στο εκπαιδευμένο νευρωνικό δίκτυο

2) Το νευρωνικό δίκτυο μετατρέπει την εικόνα σε σήμανση HTML

3) Παραγόμενη απόδοση

Θα δημιουργήσουμε το νευρικό δίκτυο σε τρεις επαναλήψεις.

Πρώτον, θα κάνουμε μια ελάχιστη εκδοχή για να πάρουμε ένα κρέμονται από τα κινούμενα μέρη. Η δεύτερη έκδοση, HTML, θα επικεντρωθεί στην αυτοματοποίηση όλων των βημάτων και στην εξήγηση των στρώσεων του νευρικού δικτύου. Στην τελική έκδοση, το Bootstrap, θα δημιουργήσουμε ένα μοντέλο που μπορεί να γενικεύσει και να εξερευνήσει το στρώμα LSTM.

Όλος ο κώδικας είναι προετοιμασμένος σε GitHub και FloydHub σε σημειωματάρια Jupyter. Όλοι οι φορητοί υπολογιστές FloydHub βρίσκονται μέσα στον κατάλογο floydhub και τα τοπικά ισοδύναμα είναι τοπικά.

Τα μοντέλα βασίζονται στο χαρτί pix2code του Beltramelli και στα tutorials της εικόνας του Jason Brownlee. Ο κώδικας είναι γραμμένος σε Python και Keras, ένα πλαίσιο πάνω από το TensorFlow.

Εάν είστε νέοι στη βαθιά εκμάθηση, θα συνιστούσα να πάρετε μια αίσθηση για την Python, backpropagation και συνελικτικά νευρωνικά δίκτυα. Οι τρεις προηγούμενες αναρτήσεις μου στο blog του FloydHub θα σας ξεκινήσουν:

  • Το πρώτο μου Σαββατοκύριακο της βαθιάς μάθησης
  • Κωδικοποίηση της ιστορίας της βαθιάς μάθησης
  • Χρωματίζοντας ασπρόμαυρες φωτογραφίες με νευρωνικά δίκτυα

Core Logic

Ας ανακεφαλαιώσουμε το στόχο μας. Θέλουμε να δημιουργήσουμε ένα νευρωνικό δίκτυο που θα δημιουργεί σήμανση HTML / CSS που αντιστοιχεί σε ένα στιγμιότυπο οθόνης.

Όταν εκπαιδεύετε το νευρωνικό δίκτυο, του δίνετε αρκετές εικόνες οθόνης με αντίστοιχη HTML.

Μαθαίνει προβλέποντας όλες τις αντίστοιχες ετικέτες σήμανσης HTML μία προς μία. Όταν προβλέπει την επόμενη ετικέτα σήμανσης, λαμβάνει το στιγμιότυπο οθόνης καθώς και όλες τις σωστές ετικέτες σήμανσης μέχρι εκείνο το σημείο.

Ακολουθεί ένα απλό παράδειγμα δεδομένων εκπαίδευσης σε ένα φύλλο Google.

Η δημιουργία ενός μοντέλου που προβλέπει λέξη με λέξη είναι η πιο κοινή προσέγγιση σήμερα. Υπάρχουν και άλλες προσεγγίσεις, αλλά αυτή είναι η μέθοδος που θα χρησιμοποιήσουμε σε όλο αυτό το σεμινάριο.

Παρατηρήστε ότι για κάθε πρόβλεψη παίρνει το ίδιο screenshot. Έτσι, αν πρέπει να προβλέψει 20 λέξεις, θα πάρει το ίδιο σχέδιο mockup είκοσι φορές. Προς το παρόν, μην ανησυχείτε για το πώς λειτουργεί το νευρικό δίκτυο. Εστιάστε στο να πιάσετε την είσοδο και την έξοδο του νευρικού δικτύου.

Ας επικεντρωθούμε στην προηγούμενη σήμανση. Ας πούμε ότι εκπαιδεύουμε το δίκτυο για να προβλέψουμε την πρόταση "Μπορώ να κωδικοποιήσω". Όταν λαμβάνει "εγώ", τότε προβλέπει "μπορεί." Την επόμενη φορά θα λάβει "μπορώ" και να προβλέψω τον "κώδικα." Λαμβάνει όλες τις προηγούμενες λέξεις και πρέπει μόνο να προβλέψει την επόμενη λέξη.

Το νευρικό δίκτυο δημιουργεί χαρακτηριστικά από τα δεδομένα. Το δίκτυο δημιουργεί χαρακτηριστικά για τη σύνδεση των δεδομένων εισόδου με τα δεδομένα εξόδου. Πρέπει να δημιουργήσει παραστάσεις για να καταλάβει τι είναι σε κάθε στιγμιότυπο οθόνης, τη σύνταξη HTML, που έχει προβλέψει. Αυτό δημιουργεί τη γνώση για την πρόβλεψη της επόμενης ετικέτας.

Όταν θέλετε να χρησιμοποιήσετε το εκπαιδευμένο μοντέλο για χρήση σε πραγματικό κόσμο, είναι παρόμοιο με αυτό όταν εκπαιδεύετε το μοντέλο. Το κείμενο δημιουργείται μία προς μία με το ίδιο στιγμιότυπο κάθε φορά. Αντί να το τροφοδοτεί με τις σωστές ετικέτες HTML, λαμβάνει τη σήμανση που έχει δημιουργήσει μέχρι στιγμής. Στη συνέχεια, προβλέπει την επόμενη ετικέτα σήμανσης. Η πρόβλεψη ξεκινάει με μια "ετικέτα έναρξης" και σταματά όταν προβλέπει μια "τελική ετικέτα" ή φτάνει ένα μέγιστο όριο. Ακολουθεί ένα άλλο παράδειγμα σε ένα φύλλο Google.

Έκδοση "Hello World"

Ας οικοδομήσουμε μια έκδοση "hello world". Θα τροφοδοτήσουμε ένα νευρωνικό δίκτυο με ένα στιγμιότυπο οθόνης με έναν ιστότοπο με το "Hello World!" Και θα το διδάξουμε για να δημιουργήσουμε τη σήμανση.

Πρώτον, το νευρικό δίκτυο χαρτογραφεί το μοτίβο του σχεδίου σε μια λίστα με τις τιμές των εικονοστοιχείων. Από 0-255 σε τρία κανάλια - κόκκινο, μπλε και πράσινο.

Προκειμένου να αντιπροσωπεύει τη σήμανση με τρόπο που κατανοεί το νευρωνικό δίκτυο, χρησιμοποιώ μία θερμή κωδικοποίηση. Έτσι, η πρόταση "Μπορώ να κωδικοποιήσω" θα μπορούσε να χαρτογραφηθεί όπως παρακάτω.

Στο παραπάνω γραφικό, συμπεριλαμβάνουμε την ετικέτα έναρξης και λήξης. Αυτές οι ετικέτες είναι ενδείξεις για το πότε το δίκτυο ξεκινά τις προβλέψεις του και πότε πρέπει να σταματήσει.

Για τα δεδομένα εισόδου, θα χρησιμοποιήσουμε προτάσεις, ξεκινώντας από την πρώτη λέξη και στη συνέχεια προσθέτοντας κάθε λέξη μία προς μία. Τα δεδομένα εξόδου είναι πάντα μία λέξη.

Οι προτάσεις ακολουθούν την ίδια λογική με τις λέξεις. Χρειάζονται επίσης το ίδιο μήκος εισόδου. Αντί να καλύπτονται από το λεξιλόγιο, δεσμεύονται από το μέγιστο μήκος ποινής. Αν είναι μικρότερη από το μέγιστο μήκος, γεμίζετε με κενά λόγια, μια λέξη με μόνο μηδενικά.

Όπως βλέπετε, οι λέξεις εκτυπώνονται από δεξιά προς τα αριστερά. Αυτό αναγκάζει κάθε λέξη να αλλάξει θέση για κάθε γύρο εκπαίδευσης. Αυτό επιτρέπει στο μοντέλο να μαθαίνει την ακολουθία αντί να απομνημονεύει τη θέση κάθε λέξης.

Στο παρακάτω γραφικό υπάρχουν τέσσερις προβλέψεις. Κάθε σειρά είναι μια πρόβλεψη. Αριστερά οι εικόνες απεικονίζονται στα τρία κανάλια χρώματος: κόκκινο, πράσινο και μπλε και οι προηγούμενες λέξεις. Έξω από τις αγκύλες υπάρχουν οι προβλέψεις μία προς μία, τελειώνοντας με ένα κόκκινο τετράγωνο για να σημειώσετε το τέλος.

πράσινα μπλοκ = μάρκες αρχής | κόκκινο μπλοκ = end token
#Length της μεγαλύτερης περιόδου
max_caption_len = 3
#Αριθμός λεξιλογίου
vocab_size = 3
# Τοποθετήστε ένα στιγμιότυπο οθόνης για κάθε λέξη και μετατρέψτε τα σε ψηφία
εικόνες = []
για το i στην περιοχή (2):
    εικόνες.append (img_to_array (load_img ('screenshot.jpg', target_size = (224, 224))))
εικόνες = np.array (εικόνες, dtype = float)
# Εισαγωγή προεπεξεργασίας για το μοντέλο VGG16
images = preprocess_input (εικόνες)
# Ξεκινήστε τα tokens σε μία θερμή κωδικοποίηση
html_input = np.array (
            [[[0., 0.], #start
             [0., 0., 0.],
             [1., 0., 0.]],
             [[0., 0., 0.], #Start  Hello World! 
             [1., 0., 0.],
             [0., 1., 0.]]])
# Μεταβείτε στην επόμενη λέξη σε μια θερμή κωδικοποίηση
next_words = np.array (
            [[0., 1., 0.], #  Hello World! 
             [0., 0., 1.]]) # τέλος
# Τοποθετήστε το μοντέλο VGG16 εκπαιδευμένο στο imagenet και εξάγετε τη λειτουργία ταξινόμησης
VGG = VGG16 (βάρη = 'imagenet', include_top = True)
# Εξαγωγή των χαρακτηριστικών από την εικόνα
Χαρακτηριστικά = VGG.predict (εικόνες)
# Τοποθετήστε τη λειτουργία στο δίκτυο, εφαρμόστε ένα πυκνό στρώμα και επαναλάβετε το διάνυσμα
vgg_feature = Εισαγωγή (σχήμα = (1000,))
vgg_feature_dense = Πυκνό (5) (vgg_feature)
vgg_feature_repeat = RepeatVector (max_caption_len) (vgg_feature_dense)
# Εξαγωγή πληροφοριών από την είσοδο seqence
language_input = Εισαγωγή (σχήμα = (vocab_size, vocab_size))
language_model = LSTM (5, return_sequences = True) (γλώσσα_αναφορά)
# Συνδέστε τις πληροφορίες από την εικόνα και την είσοδο
αποκωδικοποιητής = συγκόλληση ([vgg_feature_repeat, γλώσσα_μονάδα])
# Εξαγωγή πληροφοριών από τη συνεργαζόμενη έξοδο
αποκωδικοποιητής = LSTM (5, return_sequences = False) (αποκωδικοποιητής)
# Προβλέψτε ποια λέξη έρχεται στη συνέχεια
decoder_output = Πυκνό (vocab_size, activation = 'softmax') (αποκωδικοποιητής)
# Σύνταξη και εκτέλεση του νευρικού δικτύου
μοντέλο = Μοντέλο (είσοδοι = [vgg_feature, language_input], outputs = decoder_output)
model.compile (απώλεια = 'categorical_crossentropy', optimizer = 'rmsprop')
# Εκπαιδεύστε το νευρωνικό δίκτυο
model.fit ([χαρακτηριστικά, html_input], next_words, batch_size = 2, shuffle = False, epochs = 1000)

Στην hello world version, χρησιμοποιούμε τρία μάρκες: ξεκινήστε και τελειώστε.

Hello World! Ένα διακριτικό μπορεί να είναι οτιδήποτε. Μπορεί να είναι ένας χαρακτήρας, μια λέξη ή μια πρόταση. Οι εκδόσεις χαρακτήρων απαιτούν μικρότερο λεξιλόγιο, αλλά περιορίζουν το νευρωνικό δίκτυο. Τα μάρκες επιπέδου λέξεων τείνουν να αποδίδουν καλύτερα.

Εδώ κάνουμε την πρόβλεψη:

# Δημιουργήστε μια κενή πρόταση και εισαγάγετε το διακριτικό έναρξης
πρόταση = np.zeros ((1, 3, 3)) # [[0,0,0], [0,0,0], [0,0,0]]
start_token = [1., 0., 0.] # εκκίνηση
πρόταση [0] [2] = start_token # θέση ξεκινά σε κενή πρόταση
    
# Πραγματοποίηση της πρώτης πρόβλεψης με το αναγνωριστικό έναρξης
second_word = model.predict ([np.array ([χαρακτηριστικά [1]]), πρόταση])
    
# Τοποθετήστε τη δεύτερη λέξη στην πρόταση και κάντε την τελική πρόβλεψη
πρόταση [0] [1] = start_token
πρόταση [0] [2] = np.round (δεύτερη λέξη)
third_word = μοντέλο.predict ([np.array ([χαρακτηριστικά [1]]), πρόταση])
    
# Τοποθετήστε το διακριτικό έναρξης και τις δύο προβλέψεις μας στην πρόταση
πρόταση [0] [0] = start_token
πρόταση [0] [1] = np.round (δεύτερη λέξη)
πρόταση [0] [2] = np.round (third_word)
    
# Μεταμορφώστε τις προφορικές μας προβλέψεις σε τελικές μάρκες
λεξιλόγιο = ["έναρξη", " <κέντρο> 

Hello World! ", "τέλος"] για το i στην πρόταση [0]: εκτύπωση (λεξιλόγιο [np.argmax (i)], τέλος = '')

Παραγωγή

  • 10 εποχές: έναρξη εκκίνησης εκκίνησης
  • 100 εποχές: αρχίστε <κέντρο>

    Hello World!

  • 300 εποχές: έναρξη <κέντρο>

    Hello World! end

Λάθη που έκανα:

  • Δημιουργήστε την πρώτη έκδοση εργασίας πριν συλλέξετε τα δεδομένα. Αρχικά σε αυτό το έργο, κατάφερα να βρω ένα αντίγραφο ενός παλιού αρχείου της ιστοσελίδας φιλοξενίας Geocities. Έχει 38 εκατομμύρια ιστοσελίδες. Τυφλωμένος από τις δυνατότητες, αγνόησα τον τεράστιο φόρτο εργασίας που θα χρειαζόταν για να μειώσω το λεξιλόγιο μεγέθους 100Κ.
  • Η ενασχόληση με ένα δεδομένο terabyte δεδομένων απαιτεί καλό υλικό ή πολλή υπομονή. Αφού έκανα το mac μου σε πολλά προβλήματα, κατέληξα να χρησιμοποιώ έναν ισχυρό απομακρυσμένο διακομιστή. Αναμείνετε να νοικιάσετε μια εξέδρα με 8 σύγχρονους πυρήνες CPU και μια σύνδεση 1GPS στο διαδίκτυο για να έχετε μια αξιοπρεπή ροή εργασίας.
  • Τίποτα δεν είχε νόημα μέχρι να καταλάβω τα δεδομένα εισόδου και εξόδου. Η είσοδος, X, είναι ένα στιγμιότυπο οθόνης και οι προηγούμενες ετικέτες σήμανσης. Η έξοδος, Y, είναι η επόμενη ετικέτα σήμανσης. Όταν το έκανα αυτό, έγινε ευκολότερο να κατανοήσουμε τα πάντα μεταξύ τους. Επίσης έγινε ευκολότερο να πειραματιστείτε με διαφορετικές αρχιτεκτονικές.
  • Να γνωρίζετε τις τρύπες του κουνελιού. Επειδή αυτό το έργο διασταυρώνεται με πολλά πεδία στη βαθιά εκμάθηση, έχω κολλήσει σε πολλές τρύπες κουνελιών κατά μήκος του δρόμου. Πέρασα μια εβδομάδα προγραμματισμό RNNs από το μηδέν, πήρε πολύ γοητευμένος από την ενσωμάτωση διανυσματικών χώρων, και αποπλανήθηκε από εξωτικές εφαρμογές.
  • Τα δίκτυα "Εικόνα-προς-κωδικό" είναι μοντέλα υποτίτλων εικόνας σε μεταμφίεση. Ακόμη και όταν έμαθα αυτό, αγνοούσα ακόμα πολλά από τα χαρτιά υποτίτλων εικόνας, απλώς και μόνο επειδή ήταν λιγότερο δροσερά. Μόλις έχω κάποια προοπτική, επιτάχυνα την εκμάθηση του χώρου προβλημάτων.

Εκτέλεση του κώδικα στο FloydHub

Το FloydHub είναι μια πλατφόρμα εκπαίδευσης για βαθιά εκμάθηση. Τους έχω συναντήσει όταν άρχισα να μαθαίνω για πρώτη φορά τη βαθιά εκμάθηση και τους έχω χρησιμοποιήσει για να εκπαιδεύσω και να διαχειριστώ τα βαθιά μου πειράματα μάθησης. Μπορείτε να χρησιμοποιήσετε το πρώτο σας μοντέλο μέσα σε 30 δευτερόλεπτα πατώντας εδώ.

Ανοίγει ένα χώρο εργασίας στο FloydHub όπου θα βρείτε το ίδιο περιβάλλον και το σύνολο δεδομένων που χρησιμοποιείται για την έκδοση Bootstrap. Μπορείτε επίσης να βρείτε τα εκπαιδευμένα μοντέλα για δοκιμές.

Ή μπορείτε να εκτελέσετε μια χειροκίνητη εγκατάσταση ακολουθώντας τα εξής βήματα: Εγκατάσταση 2 λεπτών ή 5 λεπτά περπάτημα μου.

Κλωνοποιήστε το αποθετήριο

git κλώνος https://github.com/emilwallner/Screenshot-to-code-in-Keras.git

Συνδεθείτε και ξεκινήστε το εργαλείο γραμμής εντολών FloydHub

cd Screenshot-to-code-in-Keras
Σύνδεση floyd
floyd init s2c

Εκτελέστε ένα σημειωματάριο Jupyter σε μια μηχανή GPU του cloud FloydHub:

floyd εκτέλεση - gpu --env tensorflow-1.4 - ημερομηνία emilwallner / datasets / imagetocode / 2: jupyter-mode δεδομένων

Όλα τα σημειωματάρια είναι έτοιμα μέσα στον κατάλογο του FloydHub. Τα τοπικά ισοδύναμα είναι τοπικά. Μόλις τρέξει, μπορείτε να βρείτε το πρώτο σημειωματάριο εδώ: floydhub / Helloworld / helloworld.ipynb.

Αν θέλετε πιο λεπτομερείς οδηγίες και μια εξήγηση για τις σημαίες, ελέγξτε την προηγούμενη ανάρτησή μου.

Έκδοση HTML

Σε αυτήν την έκδοση, θα αυτοματοποιήσουμε πολλά από τα βήματα από το μοντέλο Hello World. Αυτή η ενότητα θα επικεντρωθεί στη δημιουργία μιας κλιμακούμενης εφαρμογής και των κινούμενων τεμαχίων στο νευρωνικό δίκτυο.

Αυτή η έκδοση δεν θα είναι σε θέση να προβλέψει HTML από τυχαίες ιστοσελίδες, αλλά εξακολουθεί να είναι μια μεγάλη εγκατάσταση για να εξερευνήσετε τη δυναμική του προβλήματος.

ΣΦΑΙΡΙΚΗ ΕΙΚΟΝΑ

Εάν επεκτείνουμε τα στοιχεία του προηγούμενου γραφικού, μοιάζει με αυτό.

Υπάρχουν δύο σημαντικά τμήματα. Πρώτον, ο κωδικοποιητής. Εδώ δημιουργούμε χαρακτηριστικά εικόνας και προηγούμενα χαρακτηριστικά σήμανσης. Τα χαρακτηριστικά γνωρίσματα είναι τα δομικά στοιχεία που δημιουργεί το δίκτυο για να συνδέσει τα mockups του σχεδίου με τη σήμανση. Στο τέλος του κωδικοποιητή, κόβουμε τις λειτουργίες εικόνας σε κάθε λέξη της προηγούμενης σήμανσης.

Στη συνέχεια, ο αποκωδικοποιητής λαμβάνει τη συνδυασμένη λειτουργία σχεδιασμού και σήμανσης και δημιουργεί μια επόμενη λειτουργία ετικέτας. Αυτή η λειτουργία εκτελείται μέσω ενός πλήρως συνδεδεμένου νευρικού δικτύου για την πρόβλεψη της επόμενης ετικέτας.

Σχεδιαστικά χαρακτηριστικά μακέτας

Δεδομένου ότι πρέπει να εισαγάγουμε ένα στιγμιότυπο οθόνης για κάθε λέξη, αυτό γίνεται εμπόδιο κατά την εκπαίδευση του δικτύου (παράδειγμα). Αντί να χρησιμοποιούμε τις εικόνες, εξάγουμε τις πληροφορίες που χρειάζονται για τη δημιουργία της σήμανσης.

Οι πληροφορίες κωδικοποιούνται σε χαρακτηριστικά εικόνας. Αυτό γίνεται χρησιμοποιώντας ένα ήδη προ-εκπαιδευμένο συνεργατικό νευρωνικό δίκτυο (CNN). Το μοντέλο είναι προ-εκπαιδευμένο στην Imagenet.

Εξάγουμε τα χαρακτηριστικά από το στρώμα πριν από την τελική ταξινόμηση.

Καταλήγουμε με 1536 οκτώ έως οκτώ εικόνες εικονοστοιχείων γνωστές ως χαρακτηριστικά. Αν και είναι δύσκολο να κατανοήσουν για εμάς, ένα νευρωνικό δίκτυο μπορεί να εξάγει τα αντικείμενα και τη θέση των στοιχείων από αυτά τα χαρακτηριστικά.

Χαρακτηριστικά σήμανσης

Στην έκδοση hello world, χρησιμοποιήσαμε ένα κωδικοποιημένο ένα καυτό για να αντιπροσωπεύσουμε την σήμανση. Σε αυτήν την έκδοση, θα χρησιμοποιήσουμε μια λέξη ενσωμάτωσης για την είσοδο και θα διατηρήσουμε την κωδικοποίηση για την έξοδο.

Ο τρόπος με τον οποίο δομείται κάθε πρόταση παραμένει ο ίδιος, αλλά αλλάζει ο τρόπος με τον οποίο χαρτογραφούμε κάθε διακριτικό. Η κωδικοποίηση ενός καυτού αντιμετωπίζει κάθε λέξη ως απομονωμένη μονάδα. Αντίθετα, μετατρέπουμε κάθε λέξη στα δεδομένα εισόδου σε λίστες με ψηφία. Αυτά αντιπροσωπεύουν τη σχέση μεταξύ των ετικετών σήμανσης.

Η διάσταση αυτής της ενσωμάτωσης λέξεων είναι οκτώ, αλλά συχνά κυμαίνεται μεταξύ 50-500, ανάλογα με το μέγεθος του λεξιλογίου.

Τα οκτώ ψηφία για κάθε λέξη είναι βάρη παρόμοια με ένα νευρικό δίκτυο βανίλιας. Είναι συντονισμένοι για να χαρτογραφούν πώς οι λέξεις σχετίζονται μεταξύ τους (Mikolov et al., 2013).

Έτσι ξεκινάμε να αναπτύσσουμε χαρακτηριστικά σήμανσης. Χαρακτηριστικά είναι αυτά που αναπτύσσει το νευρικό δίκτυο για να συνδέσει τα δεδομένα εισόδου με τα δεδομένα εξόδου. Προς το παρόν, μην ανησυχείτε για το τι είναι, θα το σκάψουμε βαθύτερα σε αυτό στο επόμενο τμήμα.

Ο κωδικοποιητής

Θα λάβουμε τις ενσωματωμένες λέξεις και θα τις εκτελέσουμε μέσω ενός LSTM και θα επιστρέψουμε μια σειρά χαρακτηριστικών σήμανσης. Αυτά τρέχουν μέσα από ένα Χρόνου κατανεμημένο πυκνό στρώμα - σκεφτείτε το ως ένα πυκνό στρώμα με πολλαπλές εισόδους και εξόδους.

Παράλληλα, τα χαρακτηριστικά της εικόνας αρχικοποιούνται. Ανεξάρτητα από το πώς δομήθηκαν τα ψηφία, μετατρέπονται σε μία μεγάλη λίστα αριθμών. Στη συνέχεια, εφαρμόζουμε ένα πυκνό στρώμα σε αυτό το στρώμα για να διαμορφώσουμε ένα χαρακτηριστικό υψηλού επιπέδου. Αυτές οι λειτουργίες εικόνας συνδέονται στη συνέχεια με τις δυνατότητες σήμανσης.

Αυτό μπορεί να είναι δύσκολο να τυλίξετε το μυαλό σας γύρω - γι 'αυτό ας το σπάσουμε.

Χαρακτηριστικά σήμανσης

Εδώ τρέχουμε τη λέξη embeddings μέσω του στρώματος LSTM. Σε αυτό το γραφικό, όλες οι προτάσεις είναι γεμισμένες για να φτάσουν το μέγιστο μέγεθος τριών μαρκών.

Για να συνδυάσουμε σήματα και να βρούμε μοτίβα υψηλότερου επιπέδου, εφαρμόζουμε ένα πυκνό στρώμα TimeDistributed για τα χαρακτηριστικά σήμανσης. ΧρόνοςΔιανομής πυκνό είναι το ίδιο με ένα πυκνό στρώμα, αλλά με πολλαπλές εισόδους και εξόδους.

Χαρακτηριστικά εικόνας

Παράλληλα προετοιμάζουμε τις εικόνες. Παίρνουμε όλα τα χαρακτηριστικά μίνι εικόνας και τα μετατρέπουμε σε μια μακρά λίστα. Οι πληροφορίες δεν αλλάζουν, απλά αναδιοργανώνονται.

Και πάλι, για να αναμίξουμε σήματα και να εξάγουμε υψηλότερες έννοιες, εφαρμόζουμε ένα πυκνό στρώμα. Δεδομένου ότι ασχολούμαστε μόνο με μια τιμή εισόδου, μπορούμε να χρησιμοποιήσουμε ένα κανονικό πυκνό στρώμα. Για να συνδέσετε τις λειτουργίες εικόνας με τις λειτουργίες σήμανσης, αντιγράφετε τις λειτουργίες εικόνας.

Σε αυτήν την περίπτωση, έχουμε τρία χαρακτηριστικά σήμανσης. Έτσι, καταλήγουμε σε ίσες ποσότητες χαρακτηριστικών εικόνας και χαρακτηριστικών σήμανσης.

Συγχρονισμός των χαρακτηριστικών εικόνας και σήμανσης

Όλες οι προτάσεις είναι γεμισμένες για να δημιουργήσουν τρία χαρακτηριστικά σήμανσης. Δεδομένου ότι έχουμε ετοιμάσει τις λειτουργίες εικόνας, μπορούμε τώρα να προσθέσουμε μία λειτουργία εικόνας για κάθε δυνατότητα σήμανσης.

Μετά την προσκόλληση ενός χαρακτηριστικού εικόνας σε κάθε δυνατότητα σήμανσης, καταλήγουμε με τρία χαρακτηριστικά σήμανσης εικόνας. Αυτή είναι η είσοδος που τροφοδοτούμε στον αποκωδικοποιητή.

Ο αποκωδικοποιητής

Εδώ χρησιμοποιούμε τις συνδυασμένες λειτουργίες σήμανσης εικόνας για να προβλέψουμε την επόμενη ετικέτα.

Στο παρακάτω παράδειγμα, χρησιμοποιούμε τρία ζευγάρια χαρακτηριστικών εικόνας και εξάγουμε ένα επόμενο χαρακτηριστικό ετικέτας.

Σημειώστε ότι το στρώμα LSTM έχει την σειρά που έχει οριστεί ως ψευδής. Αντί να επιστρέφει το μήκος της ακολουθίας εισόδου, προβλέπει μόνο μία δυνατότητα. Στην περίπτωσή μας, είναι μια λειτουργία για την επόμενη ετικέτα. Περιέχει τις πληροφορίες για την τελική πρόβλεψη.

Η τελική πρόβλεψη

Το πυκνό στρώμα λειτουργεί σαν ένα παραδοσιακό ανεστραμμένο δίκτυο. Συνδέει τα 512 ψηφία στην επόμενη λειτουργία ετικέτας με τις 4 τελικές προβλέψεις. Πείτε ότι έχουμε 4 λέξεις στο λεξιλόγιό μας: αρχή, γειά σου, κόσμος και τέλος.

Η πρόβλεψη του λεξιλογίου θα μπορούσε να είναι [0,1, 0,1, 0,1, 0,7]. Η ενεργοποίηση softmax στο πυκνό στρώμα κατανέμει μια πιθανότητα από 0-1, με το άθροισμα όλων των προβλέψεων ίσο με 1. Στην περίπτωση αυτή, προβλέπει ότι η 4η λέξη είναι η επόμενη ετικέτα. Στη συνέχεια, μεταφράζετε την κωδικοποίηση ενός καυτού [0, 0, 0, 1] στην αντιστοιχισμένη τιμή, δηλ. "Τέλος".

# Φορτώστε τις εικόνες και επεξεργαστείτε τις για εκκίνηση-resnet
εικόνες = []
all_filenames = listdir ('εικόνες /')
all_filenames.sort ()
για το όνομα αρχείου σε όλα τα_φιλικά:
    images.append (img_to_array (load_img ('images /' + όνομα αρχείου, target_size = (299, 299))))
εικόνες = np.array (εικόνες, dtype = float)
images = preprocess_input (εικόνες)
# Εκτελέστε τις εικόνες μέσω της δημιουργίας-επανασύνδεσης και εξαγάγετε τα χαρακτηριστικά χωρίς το επίπεδο ταξινόμησης
IR2 = InceptionResNetV2 (weights = 'imagenet', include_top = False)
χαρακτηριστικά = IR2.predict (εικόνες)
# Θα καλύψουμε κάθε ακολουθία εισόδου σε 100 μάρκες
max_caption_len = 100
# Αρχικοποιήστε τη λειτουργία που θα δημιουργήσει το λεξιλόγιό μας
tokenizer = Tokenizer (φίλτρα = '', διαίρεση = "", χαμηλότερα = ψευδή)
# Διαβάστε ένα έγγραφο και επιστρέψτε μια συμβολοσειρά
def load_doc (όνομα αρχείου):
    αρχείο = ανοιχτό (όνομα αρχείου, 'r')
    text = file.read ()
    file.close ()
    επιστροφή κειμένου
# Φορτώστε όλα τα αρχεία HTML
Χ = []
all_filenames = listdir ('html /')
all_filenames.sort ()
για το όνομα αρχείου σε όλα τα_φιλικά:
    X.append (load_doc ('html /' + όνομα αρχείου))
# Δημιουργήστε το λεξιλόγιο από τα αρχεία html
tokenizer.fit_on_texts (X)
# Προσθέστε +1 για να αφήσετε χώρο για κενές λέξεις
vocab_size = len (tokenizer.word_index) + 1
# Μεταφράστε κάθε λέξη σε αρχείο κειμένου στο αντίστοιχο ευρετήριο λεξιλογίου
ακολουθίες = tokenizer.texts_to_sequences (X)
# Το μεγαλύτερο αρχείο HTML
max_length = μέγιστο (len (s) για s σε ακολουθίες)
# Αρχικοποιήστε την τελική μας εισαγωγή στο μοντέλο
X, y, image_data = λίστα (), λίστα (), λίστα ()
για img_no, seq σε απαριθμήσεις (ακολουθίες):
    για i στην περιοχή (1, len (seq)):
        # Προσθέστε ολόκληρη την ακολουθία στην είσοδο και διατηρήστε μόνο την επόμενη λέξη για την έξοδο
        in_seq, out_seq = seq [: i], ακολουθία [i]
        # Αν η πρόταση είναι μικρότερη από το max_length, συμπληρώστε την με κενές λέξεις
        in_seq = pad_sequences ([in_seq], maxlen = max_length) [0]
        # Χάρτης της εξόδου σε μία θερμή κωδικοποίηση
        out_seq = to_categorical ([out_seq], num_classes = vocab_size) [0]
        # Προσθήκη και εικόνα που αντιστοιχεί στο αρχείο HTML
        image_data.append (χαρακτηριστικά [img_no])
        # Αποκόψτε την πρόταση εισαγωγής σε 100 μάρκες και προσθέστε τα στα δεδομένα εισόδου
        X.append (in_seq [-100:])
        y.append (out_seq)
X, y, image_data = np.array (X), np.array (y), np.array (image_data)
# Δημιουργήστε τον κωδικοποιητή
image_features = Εισαγωγή (σχήμα = (8, 8, 1536,))
image_flat = Ομαλοποίηση () (image_features)
image_flat = Πυκνό (128, ενεργοποίηση = 'relu') (image_flat)
ir2_out = RepeatVector (max_caption_len) (image_flat)
language_input = Εισαγωγή (σχήμα = (max_caption_len,))
language_model = Ενσωμάτωση (vocab_size, 200, input_length = max_caption_len) (language_input)
language_model = LSTM (256, return_sequences = True) (language_model)
language_model = LSTM (256, return_sequences = True) (language_model)
language_model = Χρόνος Διανομής (Dense (128, ενεργοποίηση = 'relu')) (γλώσσα_μονάδα)
# Δημιουργήστε τον αποκωδικοποιητή
αποκωδικοποιητής = συνδιαλλαγή ([ir2_out, γλώσσα_μονάδα])
αποκωδικοποιητής = LSTM (512, return_sequences = False) (αποκωδικοποιητής)
decoder_output = Πυκνό (vocab_size, activation = 'softmax') (αποκωδικοποιητής)
# Καταρτίστε το μοντέλο
μοντέλο = Μοντέλο (είσοδο = [image_features, language_input], outputs = decoder_output)
model.compile (απώλεια = 'categorical_crossentropy', optimizer = 'rmsprop')
# Εκπαιδεύστε το νευρωνικό δίκτυο
μοντέλοfit ([image_data, X], y, batch_size = 64, shuffle = ψευδές, epochs = 2)
# χαρτογραφήστε έναν ακέραιο σε μια λέξη
def word_for_id (ακέραιος αριθμός, tokenizer):
    για λέξη, ευρετήριο στο tokenizer.word_index.items ():
        αν δείκτης == ακέραιος:
            επιστροφή λέξη
    επιστροφή Δεν υπάρχει
# δημιουργεί μια περιγραφή για μια εικόνα
def generate_desc (μοντέλο, tokenizer, φωτογραφία, max_length):
    # σπορά τη διαδικασία παραγωγής
    in_text = 'START'
    # επαναλάβετε καθ 'όλο το μήκος της ακολουθίας
    για i στην περιοχή (900):
        # integer κωδικοποιεί την ακολουθία εισόδου
        ακολουθία = tokenizer.texts_to_sequences ([in_text]) [0] [- 100:]
        # input pad
        ακολουθία = συμβολοσειρές ([ακολουθία], maxlen = max_length)
        # πρόβλεψη επόμενης λέξης
        yhat = model.predict ([φωτογραφία, ακολουθία], verbose = 0)
        # μετατρέπουν την πιθανότητα σε ακέραιο
        yhat = np.argmax (yhat)
        # ακέραιος αριθμός λέξεων
        λέξη = word_for_id (yhat, tokenizer)
        # stop αν δεν μπορούμε να χαρτογραφήσουμε τη λέξη
        αν η λέξη είναι Καμία:
            Διακοπή
        # προσθήκη ως είσοδος για τη δημιουργία της επόμενης λέξης
        in_text + = '' + λέξη
        # Εκτυπώστε την πρόβλεψη
        εκτύπωση ('' + λέξη, τέλος = '')
        # stop αν προβλέψουμε το τέλος της ακολουθίας
        αν λέξη == 'END':
            Διακοπή
    ΕΠΙΣΤΡΟΦΗ
# Φόρτωση και εικόνα, προεπεξεργαστείτε το για IR2, εξαγάγετε τις λειτουργίες και δημιουργήστε το HTML
test_image = img_to_array (φόρτωση_img ('images / 87.jpg', target_size = (299, 299)))
test_image = np.array (test_image, dtype = float)
test_image = preprocess_input (test_image)
test_features = IR2.predict (np.array ([test_image]))
generate_desc (μοντέλο, tokenizer, np.array (test_features), 100)

Παραγωγή

Σύνδεσμοι σε ιστοτόπους που δημιουργούνται

  • 250 εποχές
  • 350 εποχές
  • 450 εποχές
  • 550 εποχές

Εάν δεν μπορείτε να δείτε τίποτα όταν κάνετε κλικ σε αυτούς τους συνδέσμους, μπορείτε να κάνετε δεξί κλικ και να κάνετε κλικ στο "Προβολή προέλευσης σελίδας". Εδώ είναι ο αρχικός ιστότοπος για αναφορά.

Λάθη που έκανα:

  • Τα LSTM είναι πολύ πιο βαρύ για τη γνώση μου σε σύγκριση με τα CNN. Όταν ξεπήδησα όλα τα LSTM, έγιναν ευκολότερα κατανοητά. Το βίντεο του Fast.ai για τα RNNs ήταν εξαιρετικά χρήσιμο. Επίσης, εστιάστε στις λειτουργίες εισόδου και εξόδου πριν προσπαθήσετε να καταλάβετε πώς λειτουργούν.
  • Η οικοδόμηση ενός λεξιλογίου από το έδαφος είναι πολύ πιο εύκολη από τη μείωση ενός τεράστιου λεξιλογίου. Αυτό περιλαμβάνει τα πάντα, από τις γραμματοσειρές, τα μεγέθη div και τα hex χρώματα έως τα μεταβλητά ονόματα και τις κανονικές λέξεις.
  • Οι περισσότερες βιβλιοθήκες δημιουργούνται για την ανάλυση εγγράφων κειμένου και όχι για κωδικό. Στα έγγραφα, όλα χωρίζονται από ένα διάστημα, αλλά στον κώδικα χρειάζεστε προσαρμοσμένη ανάλυση.
  • Μπορείτε να εξαγάγετε χαρακτηριστικά με ένα μοντέλο που εκπαιδεύεται στην Imagenet. Αυτό μπορεί να φαίνεται αντίθετο από τότε που η Imagenet έχει λίγες εικόνες στο διαδίκτυο. Ωστόσο, η απώλεια είναι 30% υψηλότερη σε σύγκριση με ένα μοντέλο pix2code, το οποίο εκπαιδεύεται από το μηδέν. Θα ήταν ενδιαφέρον να χρησιμοποιήσετε ένα πρότυπο πρόωρης εκκίνησης-resnet τύπου μοντέλου με βάση screenshots web.

Έκδοση Bootstrap

Στην τελική μας έκδοση, θα χρησιμοποιήσουμε ένα σύνολο δεδομένων από τους ιστότοπους δημιουργίας bootstrap από το χαρτί pix2code. Χρησιμοποιώντας το bootstrap του Twitter, μπορούμε να συνδυάσουμε HTML και CSS και να μειώσουμε το μέγεθος του λεξιλογίου.

Θα του επιτρέψουμε να δημιουργήσει τη σήμανση για ένα στιγμιότυπο οθόνης που δεν έχει ξαναδεί. Θα ανακαλύψουμε επίσης πώς δημιουργεί γνώση σχετικά με το στιγμιότυπο οθόνης και τη σήμανση.

Αντί να το εκπαιδεύσουμε στο markup bootstrap, θα χρησιμοποιήσουμε 17 απλοποιημένα tokens που μεταφράζουμε στη συνέχεια σε HTML και CSS. Το σύνολο δεδομένων περιλαμβάνει 1500 στιγμιότυπα οθόνης και 250 εικόνες επικύρωσης. Για κάθε στιγμιότυπο οθόνης υπάρχουν κατά μέσο όρο 65 μάρκες, με 96925 παραδείγματα εκπαίδευσης.

Με το μικροαλλαγές του μοντέλου στο χαρτί pix2code, το μοντέλο μπορεί να προβλέψει τα στοιχεία του ιστού με 97% ακρίβεια (BLEU 4-ngram άπληστη αναζήτηση, περισσότερα για αυτό αργότερα).

Μια προσέγγιση από άκρο σε άκρο

Η εξαγωγή χαρακτηριστικών από προ-εκπαιδευμένα μοντέλα λειτουργεί καλά σε μοντέλα με τίτλο εικόνας. Αλλά μετά από μερικά πειράματα, συνειδητοποίησα ότι η προσέγγιση end-to-end του pix2code λειτουργεί καλύτερα για αυτό το πρόβλημα. Τα προ-εκπαιδευμένα μοντέλα δεν έχουν εκπαιδευτεί σε δεδομένα ιστού και είναι προσαρμοσμένα για ταξινόμηση.

Σε αυτό το μοντέλο, αντικαθιστούμε τα προ-εκπαιδευμένα χαρακτηριστικά εικόνας με ένα ελαφρύ συνελικτικό νευρωνικό δίκτυο. Αντί να χρησιμοποιούμε τη μέγιστη συγκέντρωση για να αυξήσουμε την πυκνότητα πληροφοριών, αυξάνουμε τα βήματα. Αυτό διατηρεί τη θέση και το χρώμα των στοιχείων του εμπρόσθιου τμήματος.

Υπάρχουν δύο βασικά μοντέλα που επιτρέπουν αυτό: συνεστραμμένα νευρωνικά δίκτυα (CNN) και επαναλαμβανόμενα νευρωνικά δίκτυα (RNN). Το πιο συνηθισμένο επαναλαμβανόμενο νευρωνικό δίκτυο είναι η μακροπρόθεσμη μνήμη (LSTM), γι 'αυτό θα αναφερθώ.

Υπάρχουν πολλά σπουδαία μαθήματα του CNN και τα κάλυψα στο προηγούμενο άρθρο μου. Εδώ, θα επικεντρωθώ στα LSTM.

Κατανόηση των χρονομετρήσεων σε LSTMs

Ένα από τα πιο δύσκολα πράγματα που πρέπει να αντιληφθούμε για τα LSTMs είναι τα timesteps. Ένα νευρωνικό δίκτυο βανίλιας μπορεί να θεωρηθεί ως δύο χρονικά σημεία. Εάν το δώσετε "Γεια σας", προβλέπει "Παγκόσμια". Αλλά θα δυσκολευτεί να προβλέψει περισσότερα timesteps. Στο παρακάτω παράδειγμα, η είσοδος έχει τέσσερα timesteps, ένα για κάθε λέξη.

Τα LSTMs γίνονται για είσοδο με timesteps. Είναι ένα νευρωνικό δίκτυο προσαρμοσμένο για πληροφορίες στη σειρά. Εάν ξετυλίξετε το μοντέλο μας, μοιάζει με αυτό. Για κάθε βήμα προς τα κάτω, διατηρείτε τα ίδια βάρη. Εφαρμόζετε ένα σύνολο βαρών στην προηγούμενη έξοδο και ένα άλλο σύνολο στη νέα είσοδο.

Η σταθμισμένη είσοδος και έξοδος συνδυάζονται και προστίθενται μαζί με μια ενεργοποίηση. Αυτή είναι η έξοδος για αυτό το χρονικό διάστημα. Δεδομένου ότι επαναχρησιμοποιούμε τα βάρη, αντλούν πληροφορίες από διάφορες εισροές και δημιουργούν γνώσεις της ακολουθίας.

Εδώ είναι μια απλοποιημένη έκδοση της διαδικασίας για κάθε timestep σε ένα LSTM.

Για να πάρετε μια αίσθηση για αυτή τη λογική, θα συνιστούσα να φτιάξετε έναν RNN από το μηδέν με το λαμπρό φροντιστήριο του Andrew Trask.

Κατανόηση των μονάδων σε στρώματα LSTM

Ο αριθμός των μονάδων σε κάθε επίπεδο LSTM καθορίζει την ικανότητα απομνημόνευσης. Αυτό επίσης αντιστοιχεί στο μέγεθος κάθε χαρακτηριστικού εξόδου. Και πάλι, ένα χαρακτηριστικό είναι μια μακρά λίστα αριθμών που χρησιμοποιούνται για τη μεταφορά πληροφοριών μεταξύ των επιπέδων.

Κάθε μονάδα στο στρώμα LSTM μαθαίνει να παρακολουθεί τις διάφορες πτυχές της σύνταξης. Παρακάτω είναι μια απεικόνιση μιας μονάδας που κρατά κομμάτια των πληροφοριών στη σειρά div. Αυτή είναι η απλοποιημένη σήμανση που χρησιμοποιούμε για την εκπαίδευση του μοντέλου εκκίνησης.

Κάθε μονάδα LSTM διατηρεί κατάσταση κυττάρων. Σκεφτείτε την κατάσταση της κυψέλης ως τη μνήμη. Τα βάρη και οι ενεργοποιήσεις χρησιμοποιούνται για την τροποποίηση της κατάστασης με διαφορετικούς τρόπους. Αυτό επιτρέπει στα στρώματα LSTM να τελειοποιήσουν ποιες πληροφορίες πρέπει να διατηρήσουν και να απορρίψουν για κάθε είσοδο.

Εκτός από τη διέλευση από μια λειτουργία εξόδου για κάθε είσοδο, προωθεί επίσης τις καταστάσεις κυψελών, μία τιμή για κάθε μονάδα στο LSTM. Για να αποκτήσετε μια αίσθηση για το πώς αλληλεπιδρούν τα συστατικά μέρη του LSTM, προτείνω το σεμινάριο του Colah, την υλοποίηση του Numpy του Jayasiri και τη διάλεξη και την εγγραφή του Karphay.

dir_name = 'πόροι / eval_light /'
# Διαβάστε ένα αρχείο και επιστρέψτε μια συμβολοσειρά
def load_doc (όνομα αρχείου):
    αρχείο = ανοιχτό (όνομα αρχείου, 'r')
    text = file.read ()
    file.close ()
    επιστροφή κειμένου
def load_data (data_dir):
    κείμενο = []
    εικόνες = []
    # Τοποθετήστε όλα τα αρχεία και τα παραγγείλετε
    all_filenames = listdir (data_dir)
    all_filenames.sort ()
    για το όνομα αρχείου στο (all_filenames):
        εάν το όνομα αρχείου [-3:] == "npz":
            # Τοποθετήστε τις εικόνες που έχουν ήδη προετοιμαστεί σε συστοιχίες
            image = np.load (data_dir + όνομα αρχείου)
            images.append (εικόνα ['χαρακτηριστικά'])
        αλλού:
            # Φορτώστε τα μάρκες ώθησης και κάντε τα κτυπήματα σε μια ετικέτα έναρξης και λήξης
            syntax = '' + load_doc (data_dir + όνομα αρχείου) + ''
            # Ξεχωρίστε όλες τις λέξεις με ένα μόνο κενό
            syntax = '' .join (syntax.split ())
            # Προσθέστε ένα κενό μετά από κάθε κόμμα
            syntax = syntax.replace (',', ',')
            text.append (σύνταξη)
    εικόνες = np.array (εικόνες, dtype = float)
    επιστροφή εικόνων, κειμένου
train_features, texts = load_data (dir_name)
# Αρχικοποιήστε τη λειτουργία για να δημιουργήσετε το λεξιλόγιο
tokenizer = Tokenizer (φίλτρα = '', διαίρεση = "", χαμηλότερα = ψευδή)
# Δημιουργήστε το λεξιλόγιο
tokenizer.fit_on_texts ([load_doc ('bootstrap.vocab')])
# Προσθέστε ένα σημείο για την κενή λέξη στο λεξιλόγιο
vocab_size = len (tokenizer.word_index) + 1
# Χάρτης των φράσεων εισόδου στους δείκτες λεξιλογίου
train_sequences = tokenizer.texts_to_sequences (κείμενα)
# Το μεγαλύτερο σύνολο ζευγών ώθησης
max_sequence = max (len (s) για το s στην ακολουθία τρένων)
# Καθορίστε πόσες μάρκες πρέπει να έχετε σε κάθε πρόταση εισόδου
max_length = 48
def preprocess_data (ακολουθίες, χαρακτηριστικά):
    X, y, image_data = λίστα (), λίστα (), λίστα ()
    για img_no, seq σε απαριθμήσεις (ακολουθίες):
        για i στην περιοχή (1, len (seq)):
            # Προσθέστε τη φράση μέχρι την τρέχουσα μέτρηση (i) και προσθέστε την τρέχουσα μέτρηση στην έξοδο
            in_seq, out_seq = seq [: i], ακολουθία [i]
            # Τοποθετήστε όλες τις προτάσεις συμβολικών συμβόλων σε max_sequence
            in_seq = pad_sequences ([in_seq], maxlen = max_sequence) [0]
            # Γυρίστε την έξοδο σε μία θερμή κωδικοποίηση
            out_seq = to_categorical ([out_seq], num_classes = vocab_size) [0]
            # Προσθέστε την αντίστοιχη εικόνα στο αρχείο συμβολοσειράς ώθησης
            image_data.append (χαρακτηριστικά [img_no])
            # Κλείστε την πρόταση εισόδου σε 48 μάρκες και προσθέστε την
            X.append (in_seq [-48:])
            y.append (out_seq)
    επιστροφή np.array (X), np.array (y), np.array (image_data)
X, y, image_data = preprocess_data (train_sequences, train_features)
# Δημιουργήστε τον κωδικοποιητή
image_model = Διαδοχική ()
image_model.add (Conv2D (16, 3, 3), padding = 'έγκυρο', activation = 'relu', input_shape = (256, 256, 3)
image_model.add (Conv2D (16, (3,3), ενεργοποίηση = 'relu', padding = 'ίδιο', βήματα = 2))
image_model.add (Conv2D (32, (3,3), ενεργοποίηση = 'relu', padding = 'ίδιο'))
image_model.add (Conv2D (32, (3,3), ενεργοποίηση = 'relu', padding = 'ίδιο', βήματα = 2))
image_model.add (Conv2D (64, (3,3), ενεργοποίηση = 'relu', padding = 'ίδιο'))
image_model.add (Conv2D (64, (3,3), ενεργοποίηση = 'relu', padding = 'ίδιο', βήματα = 2))
image_model.add (Conv2D (128, (3,3), ενεργοποίηση = 'relu', padding = 'ίδιο'))
image_model.add (Flatten ())
image_model.add (Dense (1024, ενεργοποίηση = 'relu'))
image_model.add (Απόκλιση (0.3))
image_model.add (Dense (1024, ενεργοποίηση = 'relu'))
image_model.add (Απόκλιση (0.3))
image_model.add (RepeatVector (max_length))
visual_input = Εισαγωγή (σχήμα = (256, 256, 3,))
encoded_image = image_model (visual_input)
language_input = Εισαγωγή (σχήμα = (max_length,))
language_model = Ενσωμάτωση (vocab_size, 50, input_length = max_length, mask_zero = True) (language_input)
language_model = LSTM (128, return_sequences = True) (language_model)
language_model = LSTM (128, return_sequences = True) (language_model)
# Δημιουργήστε τον αποκωδικοποιητή
αποκωδικοποιητής = συγκολλήστε ([encoded_image, γλώσσα_μονάδα])
αποκωδικοποιητής = LSTM (512, return_sequences = True) (αποκωδικοποιητής)
αποκωδικοποιητής = LSTM (512, return_sequences = False) (αποκωδικοποιητής)
αποκωδικοποιητής = πυκνό (vocab_size, activation = 'softmax') (αποκωδικοποιητής)
# Καταρτίστε το μοντέλο
μοντέλο = Μοντέλο (είσοδοι = [οπτική_αναφορά, γλώσσα_αναφορά], εξόδους = αποκωδικοποιητής)
βελτιστοποιητής = RMSprop (lr = 0,0001, clipvalue = 1,0)
model.compile (απώλεια = 'categorical_crossentropy', optimizer = optimizer)
#Αποθηκεύστε το μοντέλο για κάθε 2η εποχή
filepath = "org-weights-epoch- {epoch: 04d} - val_loss- {val_loss: .4f} - loss- {loss: .4f} .hdf5"
checkpoint = ΜοντέλοCheckpoint (filepath, monitor = 'val_loss', verbose = 1, save_weights_only = Αληθινό, περίοδο = 2)
callbacks_list = [σημείο ελέγχου]
# Εκπαιδεύστε το μοντέλο
μοντέλοfit ([image_data, X], y, batch_size = 64, shuffle = ψευδές, validation_split = 0,1, callbacks = callbacks_list, verbose = 1, epochs = 50)

Ακρίβεια δοκιμής

Είναι δύσκολο να βρούμε έναν δίκαιο τρόπο μέτρησης της ακρίβειας. Πείτε ότι συγκρίνετε λέξη με λέξη. Εάν η πρόβλεψή σας είναι μια λέξη εκτός συγχρονισμού, μπορεί να έχετε 0% ακρίβεια. Αν αφαιρέσετε μια λέξη που συγχρονίζει την πρόβλεψη, ίσως καταλήξετε σε 99/100.

Χρησιμοποίησα τη βαθμολογία BLEU, την καλύτερη πρακτική σε μηχανήματα μετάφρασης και υποδείγματα εικόνας. Διαλύει την πρόταση σε τέσσερα n-grams, από 1-4 ακολουθίες λέξεων. Στην παρακάτω πρόβλεψη η "γάτα" υποτίθεται ότι είναι "κώδικας".

Για να λάβετε την τελική βαθμολογία πολλαπλασιάζετε κάθε βαθμολογία με 25%, (4/5) * 0.25 + (2/4) * 0.25 + (1/3) * 0.25 + (0/2) * 0.25 = 0.2 + 0,083 + 0 = 0,408. Το ποσό στη συνέχεια πολλαπλασιάζεται με ποινή μήκους ποινής. Δεδομένου ότι το μήκος είναι σωστό στο παράδειγμά μας, γίνεται το τελικό μας σκορ.

Θα μπορούσατε να αυξήσετε τον αριθμό των n-grams για να γίνει πιο δύσκολο. Ένα μοντέλο τεσσάρων n-gram είναι το μοντέλο που αντιστοιχεί καλύτερα στις ανθρώπινες μεταφράσεις. Θα πρότεινα να εκτελέσετε μερικά παραδείγματα με τον παρακάτω κώδικα και να διαβάσετε τη σελίδα wiki.

# Δημιουργήστε μια λειτουργία για να διαβάσετε ένα αρχείο και να επιστρέψετε το περιεχόμενό του
def load_doc (όνομα αρχείου):
    αρχείο = ανοιχτό (όνομα αρχείου, 'r')
    text = file.read ()
    file.close ()
    επιστροφή κειμένου
def load_data (data_dir):
    κείμενο = []
    εικόνες = []
    files_in_folder = os.listdir (data_dir)
    files_in_folder.sort ()
    για το όνομα αρχείου στο tqdm (files_in_folder):
        #Προσθέστε μια εικόνα
        εάν το όνομα αρχείου [-3:] == "npz":
            image = np.load (data_dir + όνομα αρχείου)
            images.append (εικόνα ['χαρακτηριστικά'])
        αλλού:
        # Προσθέστε κείμενο και τυλίξτε το σε μια ετικέτα έναρξης και λήξης
            syntax = '' + load_doc (data_dir + όνομα αρχείου) + ''
            #Μετάξτε κάθε λέξη με ένα κενό
            syntax = '' .join (syntax.split ())
            #Προσθέστε ένα κενό μεταξύ κάθε κόμπου
            syntax = syntax.replace (',', ',')
            text.append (σύνταξη)
    εικόνες = np.array (εικόνες, dtype = float)
    επιστροφή εικόνων, κειμένου
#Initialize τη λειτουργία για να δημιουργήσετε το λεξιλόγιο
tokenizer = Tokenizer (φίλτρα = '', διαίρεση = "", χαμηλότερα = ψευδή)
# Δημιουργήστε το λεξιλόγιο με μια συγκεκριμένη σειρά
tokenizer.fit_on_texts ([load_doc ('bootstrap.vocab')])
dir_name = '../../../../eval/'
train_features, texts = load_data (dir_name)
#load μοντέλο και βάρη
json_file = άνοιγμα ('../../../../ model.json', 'r')
loaded_model_json = json_file.read ()
json_file.close ()
loaded_model = model_from_json (loaded_model_json)
# βάρη φόρτωσης σε νέο μοντέλο
loaded_model.load_weights ("../../../../ weights.hdf5")
print ("Φορτωμένο μοντέλο από δίσκο")
# χαρτογραφήστε έναν ακέραιο σε μια λέξη
def word_for_id (ακέραιος αριθμός, tokenizer):
    για λέξη, ευρετήριο στο tokenizer.word_index.items ():
        αν δείκτης == ακέραιος:
            επιστροφή λέξη
    επιστροφή Δεν υπάρχει
εκτύπωση (word_for_id (17, tokenizer))
# δημιουργεί μια περιγραφή για μια εικόνα
def generate_desc (μοντέλο, tokenizer, φωτογραφία, max_length):
    photo = np.array ([φωτογραφία])
    # σπορά τη διαδικασία παραγωγής
    in_text = ''
    # επαναλάβετε καθ 'όλο το μήκος της ακολουθίας
    εκτύπωση ('\ nΠροβολή ----> \ n \ n ', τέλος = '')
    για i στην περιοχή (150):
        # integer κωδικοποιεί την ακολουθία εισόδου
        ακολουθία = tokenizer.texts_to_sequences ([in_text]) [0]
        # input pad
        ακολουθία = συμβολοσειρές ([ακολουθία], maxlen = max_length)
        # πρόβλεψη επόμενης λέξης
        yhat = loaded_model.predict ([φωτογραφία, ακολουθία], verbose = 0)
        # μετατρέπουν την πιθανότητα σε ακέραιο
        yhat = argmax (yhat)
        # ακέραιος αριθμός λέξεων
        λέξη = word_for_id (yhat, tokenizer)
        # stop αν δεν μπορούμε να χαρτογραφήσουμε τη λέξη
        αν η λέξη είναι Καμία:
            Διακοπή
        # προσθήκη ως είσοδος για τη δημιουργία της επόμενης λέξης
        in_text + = λέξη + ''
        # stop αν προβλέψουμε το τέλος της ακολουθίας
        εκτύπωση (λέξη + '', τέλος = '')
        αν λέξη == '':
            Διακοπή
    επιστροφή in_text
max_length = 48
# αξιολογεί την ικανότητα του μοντέλου
def evalu_model (μοντέλο, περιγραφές, φωτογραφίες, tokenizer, max_length):
    πραγματική, προβλεπόμενη = λίστα (), λίστα ()
    # βήμα πάνω από το σύνολο
    για i στην περιοχή (len (κείμενα)):
        yhat = generate_desc (μοντέλο, tokenizer, φωτογραφίες [i], max_length)
        # κατάστημα πραγματικό και προβλεπόμενο
        εκτύπωση ('\ n \ nReal ----> \ n \ n' + κείμενα [i])
        actual.append ([κείμενα [i] .split ()])
        predicted.append (yhat.split ())
    # υπολογίστε το αποτέλεσμα BLEU
    bleu = corpus_bleu (πραγματικό, προβλεπόμενο)
    επιστροφή bleu, πραγματική, προβλεπόμενη
bleu, πραγματικό, προβλεπόμενο = evaluate_model (φορτωμένο μοντέλο, κείμενα, χαρακτηριστικά τρένων, tokenizer, max_length)
#Compile τα tokens σε HTML και css
dsl_path = "compiler / assets / web-dsl-mapping.json"
compiler = Μεταγλωττιστής (dsl_path)
compiled_website = compiler.compile (προβλεπόμενη [0], 'index.html')
εκτύπωση (compiled_website)
εκτύπωση (μπλε)

Παραγωγή

Σύνδεσμοι προς την έξοδο του δείγματος

  • Δημιουργία ιστότοπου 1 - Πρωτότυπο 1
  • Δημιουργία ιστότοπου 2 - Πρωτότυπο 2
  • Δημιουργία ιστότοπου 3 - Πρωτότυπο 3
  • Δημιουργία ιστότοπου 4 - Πρωτότυπο 4
  • Δημιουργία ιστότοπου 5 - Πρωτότυπο 5

Λάθη που έκανα:

  • Κατανοήστε την αδυναμία των μοντέλων αντί να δοκιμάσετε τυχαία μοντέλα. Αρχικά, εφάρμοζα τυχαία πράγματα όπως κανονικοποίηση παρτίδων και αμφίδρομα δίκτυα και προσπάθησα να επιδείξω την προσοχή. Αφού εξέτασε τα δεδομένα των δοκιμών και βλέποντας ότι δεν μπορούσε να προβλέψει χρώμα και θέση με μεγάλη ακρίβεια, συνειδητοποίησα ότι υπήρχε αδυναμία στο CNN. Αυτό με οδήγησε να αντικαταστήσω τη συντριπτική πλειοψηφία με αυξημένους ρυθμούς. Η απώλεια επικύρωσης μεταβλήθηκε από 0,12 σε 0,02 και αύξησε τη βαθμολογία BLEU από 85% σε 97%.
  • Χρησιμοποιήστε μόνο προ-εκπαιδευμένα μοντέλα εάν είναι σχετικά. Δεδομένου του μικρού συνόλου δεδομένων, σκέφτηκα ότι ένα προ-εκπαιδευμένο μοντέλο εικόνας θα βελτίωνε την απόδοση. Από τα πειράματά μου, και το μοντέλο από άκρο σε άκρο είναι πιο αργό να εκπαιδεύσει και απαιτεί περισσότερη μνήμη, αλλά είναι 30% ακριβέστερη.
  • Σχεδιάστε ελαφρά διακύμανση κατά την εκτέλεση του μοντέλου σας σε απομακρυσμένο διακομιστή. Στη mac μου, διαβάζει τα αρχεία με αλφαβητική σειρά. Ωστόσο, στο διακομιστή, εντοπίστηκε τυχαία. Αυτό δημιούργησε μια αναντιστοιχία μεταξύ των στιγμιότυπων οθόνης και του κώδικα. Συνέχισε να συγκλίνει, αλλά τα δεδομένα επικύρωσης ήταν 50% χειρότερα από ό, τι όταν το έκανα.
  • Βεβαιωθείτε ότι γνωρίζετε τις λειτουργίες της βιβλιοθήκης. Συμπεριλάβετε χώρο για το κενό διακριτικό στο λεξιλόγιό σας. Όταν δεν το πρόσθεσα, δεν περιλάμβανε μία από τις μάρκες. Το παρατήρησα μόνο αφού έβλεπα την τελική παραγωγή αρκετές φορές και παρατήρησα ότι ποτέ δεν προέβλεπε ένα "ενιαίο" σήμα. Μετά από μια γρήγορη επιθεώρηση, συνειδητοποίησα ότι δεν ήταν καν στο λεξιλόγιο. Επίσης, χρησιμοποιήστε την ίδια σειρά στο λεξιλόγιο για εκπαίδευση και δοκιμές.
  • Χρησιμοποιήστε ελαφρύτερα μοντέλα κατά τον πειραματισμό. Η χρήση των GRU αντί των LSTM μείωσε κάθε κύκλο εποχής κατά 30% και δεν είχε μεγάλη επίδραση στην απόδοση.

Επόμενα βήματα

Η ανάπτυξη του μπροστινού τμήματος είναι ένας ιδανικός χώρος για την εφαρμογή βαθιάς μάθησης. Είναι εύκολο να δημιουργήσετε δεδομένα και οι τρέχοντες αλγόριθμοι βαθιάς εκμάθησης μπορούν να χαρτογραφήσουν το μεγαλύτερο μέρος της λογικής.

Μία από τις πιο συναρπαστικές περιοχές είναι η εφαρμογή προσοχής στα LSTMs. Αυτό δεν θα βελτιώσει μόνο την ακρίβεια, αλλά θα μας επιτρέψει να απεικονίσουμε όπου το CNN εστιάζει την προσοχή του καθώς παράγει την σήμανση.

Η προσοχή είναι επίσης το κλειδί για την επικοινωνία μεταξύ της σήμανσης, των φύλλων στυλ, των σεναρίων και τελικά του backend. Τα στρώματα προσοχής μπορούν να παρακολουθούν τις μεταβλητές, επιτρέποντας στο δίκτυο να επικοινωνεί μεταξύ των γλωσσών προγραμματισμού.

Αλλά στο κοντινό χαρακτηριστικό, ο μεγαλύτερος αντίκτυπος θα προκύψει από την οικοδόμηση ενός κλιμακούμενου τρόπου σύνθεσης δεδομένων. Στη συνέχεια, μπορείτε να προσθέσετε βήμα προς βήμα τις γραμματοσειρές, τα χρώματα, τις λέξεις και τις κινούμενες εικόνες.

Μέχρι στιγμής, η μεγαλύτερη πρόοδος συμβαίνει κατά τη λήψη σκίτσων και τη μετατροπή τους σε εφαρμογές προτύπων. Σε λιγότερο από δύο χρόνια, θα μπορέσουμε να σχεδιάσουμε μια εφαρμογή σε χαρτί και να έχουμε το αντίστοιχο front-end σε λιγότερο από ένα δευτερόλεπτο. Υπάρχουν ήδη δύο πρωτότυπα εργασίας που κατασκευάστηκαν από την ομάδα σχεδιασμού της Airbnb και την Uizard.

Ακολουθούν μερικά πειράματα για να ξεκινήσετε.

Πειράματα

Ξεκινώντας

  • Εκτελέστε όλα τα μοντέλα
  • Δοκιμάστε διαφορετικές παραμέτρους υπέρ
  • Δοκιμάστε μια διαφορετική αρχιτεκτονική CNN
  • Προσθέστε μοντέλα LSM αμφίδρομης επικοινωνίας
  • Εφαρμόστε το μοντέλο με διαφορετικό σύνολο δεδομένων. (Μπορείτε να προσαρτήσετε εύκολα αυτό το σύνολο δεδομένων στις εργασίες σας FloydHub με αυτήν τη σημαία - data emilwallner / datasets / 100k-html: data)

Περαιτέρω πειράματα

  • Δημιουργία μιας συμπαγής τυχαίας εφαρμογής / γεννήτριας ιστού με την αντίστοιχη σύνταξη.
  • Δεδομένα για ένα σκίτσο σε μοντέλο εφαρμογής. Αυτόματη μετατροπή των screenshot εφαρμογών / web σε σκίτσα και χρήση ενός GAN για τη δημιουργία ποικιλίας.
  • Εφαρμόστε ένα στρώμα προσοχής για να απεικονίσετε την εστίαση στην εικόνα για κάθε πρόβλεψη, παρόμοια με αυτό το μοντέλο.
  • Δημιουργήστε ένα πλαίσιο για μια αρθρωτή προσέγγιση. Πείτε, έχοντας μοντέλα κωδικοποιητή γραμματοσειρών, ένα για χρώμα, άλλο για διάταξη και συνδυάστε τα με έναν αποκωδικοποιητή. Ένα καλό ξεκίνημα θα μπορούσε να είναι στερεά χαρακτηριστικά εικόνας.
  • Τροφοδοτήστε τα απλά συστατικά HTML του δικτύου και μάθετε να δημιουργεί κινούμενα σχέδια χρησιμοποιώντας το CSS. Θα ήταν συναρπαστικό να έχουμε μια προσέγγιση προσοχής και να απεικονίσουμε την εστίαση και στις δύο πηγές εισόδου.

Τεράστια ευχαριστίες στον Tony Beltramelli και τον Jon Gold για την έρευνα και τις ιδέες τους και για την απάντηση σε ερωτήσεις. Χάρη στον Jason Brownlee για τα αστέρια του Keras tutorials (συμπεριλάμβανα μερικά αποσπάσματα από το σεμινάριο του στην εφαρμογή Core Keras) και το Beltramelli για την παροχή των δεδομένων. Επίσης, χάρη στον Qingping Hou, τον Charlie Harrington, τον Sai Soundararaj, τον Jannes Klaas, τον Claudio Cabral, τον Alain Demenet και τον Dylan Djian για την ανάγνωση των σχεδίων.

Σχετικά με τον Emil Wallner

Αυτό το τέταρτο μέρος μιας σειριακής σειράς blog από τον Emil καθώς μαθαίνει βαθιά μάθηση. Ο Έμιλ έχει περάσει μια δεκαετία για να διερευνήσει την ανθρώπινη μάθηση. Έχει δουλέψει στην επιχειρηματική σχολή της Οξφόρδης, έχει επενδύσει σε εκπαιδευτικές δραστηριότητες και έχει κατασκευάσει μια επιχείρηση τεχνολογίας εκπαίδευσης. Πέρυσι, εγγραφόταν στην Ecole 42 για να εφαρμόσει τις γνώσεις του για την ανθρώπινη μάθηση στη μηχανική μάθηση.

Εάν χτίσετε κάτι ή κολλήσετε, πινγκ μου κάτω ή στο twitter: emilwallner. Θα ήθελα πολύ να δω τι χτίζετε.

Αυτό δημοσιεύθηκε για πρώτη φορά ως κοινοτική δημοσίευση στο ιστολόγιο του Floydhub.