Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

classificazione testo di base

View on TensorFlow.org Eseguire in Google Colab Visualizza sorgente su GitHub Scarica notebook

Questa esercitazione dimostra classificazione testo a partire da file di testo memorizzati su disco. Ti alleni un classificatore binario per eseguire l'analisi sentiment su un set di dati IMDB. Alla fine del notebook, v'è un esercizio per provare, in cui si allena un classificatore multiclasse per predire il tag per una questione di programmazione su Stack Overflow.

 import matplotlib.pyplot as plt
import os
import re
import shutil
import string
import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import losses
from tensorflow.keras import preprocessing
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
 
 print(tf.__version__)
 
2.3.0

sentiment analysis

Questo notebook si allena un modello di sentiment analysis per recensioni di film classificare come positivo o negativo, in base al testo della revisione. Questo è un esempio di binario -o due classi-classificazione, un tipo importante e ampiamente applicabile della macchina problema di apprendimento.

Potrai utilizzare il Grande Movie Review dataset che contiene il testo di 50.000 recensioni di film dalla Internet Movie Database . Questi sono divisi in 25.000 recensioni per la formazione e 25.000 recensioni per il test. I set di allenamento e test sono equilibrati, nel senso che contengono un uguale numero di recensioni positive e negative.

Scaricare ed esplorare il set di dati IMDB

Diamo scaricare ed estrarre il set di dati, quindi esplorare la struttura di directory.

 url = "https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz"

dataset = tf.keras.utils.get_file("aclImdb_v1.tar.gz", url,
                                    untar=True, cache_dir='.',
                                    cache_subdir='')

dataset_dir = os.path.join(os.path.dirname(dataset), 'aclImdb')
 
Downloading data from https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
84131840/84125825 [==============================] - 7s 0us/step

 os.listdir(dataset_dir)
 
['imdb.vocab', 'train', 'test', 'README', 'imdbEr.txt']
 train_dir = os.path.join(dataset_dir, 'train')
os.listdir(train_dir)
 
['urls_pos.txt',
 'neg',
 'labeledBow.feat',
 'pos',
 'urls_neg.txt',
 'unsup',
 'unsupBow.feat',
 'urls_unsup.txt']

I aclImdb/train/pos e aclImdb/train/neg directory contengono molti file di testo, ognuna delle quali è una sola recensione film. Diamo uno sguardo a uno di loro.

 sample_file = os.path.join(train_dir, 'pos/1181_9.txt')
with open(sample_file) as f:
  print(f.read())
 
Rachel Griffiths writes and directs this award winning short film. A heartwarming story about coping with grief and cherishing the memory of those we've loved and lost. Although, only 15 minutes long, Griffiths manages to capture so much emotion and truth onto film in the short space of time. Bud Tingwell gives a touching performance as Will, a widower struggling to cope with his wife's death. Will is confronted by the harsh reality of loneliness and helplessness as he proceeds to take care of Ruth's pet cow, Tulip. The film displays the grief and responsibility one feels for those they have loved and lost. Good cinematography, great direction, and superbly acted. It will bring tears to all those who have lost a loved one, and survived.

Caricare il set di dati

Successivamente, si caricherà i dati dal disco e preparare in un formato adatto per la formazione. Per fare ciò, si utilizzerà l'utile text_dataset_from_directory utility, che prevede una struttura di directory come segue.

 main_directory/
...class_a/
......a_text_1.txt
......a_text_2.txt
...class_b/
......b_text_1.txt
......b_text_2.txt
 

Per preparare un set di dati per la classificazione binaria, avrete bisogno di due cartelle sul disco, corrispondente a class_a e class_b . Queste saranno le recensioni di film positivi e negativi, che possono essere trovati in aclImdb/train/pos e aclImdb/train/neg . Come l'insieme di dati IMDB contiene altre cartelle, verrà rimosso prima di usare questa utility.

 remove_dir = os.path.join(train_dir, 'unsup')
shutil.rmtree(remove_dir)
 

Successivamente, si utilizzerà il text_dataset_from_directory utility per creare una etichetta tf.data.Dataset . tf.data è un potente insieme di strumenti per lavorare con i dati.

Quando si esegue un esperimento di apprendimento automatico, è una pratica migliore per dividere il set di dati in tre divisioni: treno , validazione e test di .

Il set di dati IMDB è già stato diviso in treno e di prova, ma manca un set di validazione. Creiamo un set di validazione con un 80:20 spaccatura dei dati di addestramento utilizzando il validation_split argomento di seguito.

 batch_size = 32
seed = 42

raw_train_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='training', 
    seed=seed)
 
Found 25000 files belonging to 2 classes.
Using 20000 files for training.

Come potete vedere sopra, ci sono 25.000 esempi nella cartella di formazione, di cui verrà utilizzato l'80% (o 20.000) per la formazione. Come si vedrà in un attimo, si può formare un modello passando un set di dati direttamente a model.fit . Se siete nuovi a tf.data , è anche possibile scorrere i set di dati e stampare alcuni esempi come segue.

 for text_batch, label_batch in raw_train_ds.take(1):
  for i in range(3):
    print("Review", text_batch.numpy()[i])
    print("Label", label_batch.numpy()[i])
 
Review b'"Pandemonium" is a horror movie spoof that comes off more stupid than funny. Believe me when I tell you, I love comedies. Especially comedy spoofs. "Airplane", "The Naked Gun" trilogy, "Blazing Saddles", "High Anxiety", and "Spaceballs" are some of my favorite comedies that spoof a particular genre. "Pandemonium" is not up there with those films. Most of the scenes in this movie had me sitting there in stunned silence because the movie wasn\'t all that funny. There are a few laughs in the film, but when you watch a comedy, you expect to laugh a lot more than a few times and that\'s all this film has going for it. Geez, "Scream" had more laughs than this film and that was more of a horror film. How bizarre is that?<br /><br />*1/2 (out of four)'
Label 0
Review b"David Mamet is a very interesting and a very un-equal director. His first movie 'House of Games' was the one I liked best, and it set a series of films with characters whose perspective of life changes as they get into complicated situations, and so does the perspective of the viewer.<br /><br />So is 'Homicide' which from the title tries to set the mind of the viewer to the usual crime drama. The principal characters are two cops, one Jewish and one Irish who deal with a racially charged area. The murder of an old Jewish shop owner who proves to be an ancient veteran of the Israeli Independence war triggers the Jewish identity in the mind and heart of the Jewish detective.<br /><br />This is were the flaws of the film are the more obvious. The process of awakening is theatrical and hard to believe, the group of Jewish militants is operatic, and the way the detective eventually walks to the final violent confrontation is pathetic. The end of the film itself is Mamet-like smart, but disappoints from a human emotional perspective.<br /><br />Joe Mantegna and William Macy give strong performances, but the flaws of the story are too evident to be easily compensated."
Label 0
Review b'Great documentary about the lives of NY firefighters during the worst terrorist attack of all time.. That reason alone is why this should be a must see collectors item.. What shocked me was not only the attacks, but the"High Fat Diet" and physical appearance of some of these firefighters. I think a lot of Doctors would agree with me that,in the physical shape they were in, some of these firefighters would NOT of made it to the 79th floor carrying over 60 lbs of gear. Having said that i now have a greater respect for firefighters and i realize becoming a firefighter is a life altering job. The French have a history of making great documentary\'s and that is what this is, a Great Documentary.....'
Label 1

Notare le recensioni contengono testo grezzo (con punteggiatura e tag HTML occasionali come <br/> ). Si mostrerà come gestire questi nella sezione seguente.

Le etichette sono 0 o 1. Per vedere quali di questi corrispondono alle recensioni positive e negative di film, è possibile controllare la class_names proprietà sul set di dati.

 print("Label 0 corresponds to", raw_train_ds.class_names[0])
print("Label 1 corresponds to", raw_train_ds.class_names[1])
 
Label 0 corresponds to neg
Label 1 corresponds to pos

Successivamente, si creerà una validazione e test di set di dati. Si utilizzerà i restanti 5.000 recensioni dal training set per la convalida.

 raw_val_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='validation', 
    seed=seed)
 
Found 25000 files belonging to 2 classes.
Using 5000 files for validation.

 raw_test_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/test', 
    batch_size=batch_size)
 
Found 25000 files belonging to 2 classes.

Preparare il set di dati per la formazione

Successivamente, si sarà standardizzare, tokenize, e vettorizzare i dati utilizzando l'utile preprocessing.TextVectorization layer.

Normalizzazione si riferisce alla pre-elaborazione testo, tipicamente per rimuovere elementi di punteggiatura o HTML per semplificare il set di dati. Tokenizzazione riferisce a suddividere stringhe in token (per esempio, dividere una frase in singole parole, suddividendo su spazi). Vettorizzazione riferisce a convertire i token in numeri in modo che possano essere inseriti in una rete neurale. Tutti questi compiti può essere realizzato con questo strato.

Come si è visto sopra, le recensioni contengono vari tag HTML come <br /> . Questi tag non verranno rimossi dal standardizer default nel TextVectorization strato (che converte il testo in lowecase e strisce punteggiatura di default, ma non elimina HTML). Potrai scrivere una funzione di standardizzazione personalizzata per rimuovere il codice HTML.

 def custom_standardization(input_data):
  lowercase = tf.strings.lower(input_data)
  stripped_html = tf.strings.regex_replace(lowercase, '<br />', ' ')
  return tf.strings.regex_replace(stripped_html,
                                  '[%s]' % re.escape(string.punctuation),
                                  '')
 

Successivamente, si creerà un TextVectorization layer. si intende utilizzare questo livello per standardizzare, tokenize, e vettorizzare i nostri dati. Si imposta output_mode per int per creare indici interi unici per ogni gettone.

Si noti che si sta utilizzando la funzione predefinita di divisione, e la funzione di standardizzazione personalizzato definito in precedenza. Potrai anche definire alcune costanti per il modello, come una massima esplicita sequence_length , che farà sì che lo strato di pad o Tronca sequenze esattamente sequence_length valori.

 max_features = 10000
sequence_length = 250

vectorize_layer = TextVectorization(
    standardize=custom_standardization,
    max_tokens=max_features,
    output_mode='int',
    output_sequence_length=sequence_length)
 

Successivamente, si chiamerà adapt per adattare lo stato dello strato di pre-elaborazione per il set di dati. Questo farà sì che il modello per costruire un indice di stringhe di numeri interi.

 # Make a text-only dataset (without labels), then call adapt
train_text = raw_train_ds.map(lambda x, y: x)
vectorize_layer.adapt(train_text)
 

Creiamo una funzione per vedere il risultato dell'utilizzo di questo strato di pre-elaborare alcuni dati.

 def vectorize_text(text, label):
  text = tf.expand_dims(text, -1)
  return vectorize_layer(text), label
 
 # retrieve a batch (of 32 reviews and labels) from the dataset
text_batch, label_batch = next(iter(raw_train_ds))
first_review, first_label = text_batch[0], label_batch[0]
print("Review", first_review)
print("Label", raw_train_ds.class_names[first_label])
print("Vectorized review", vectorize_text(first_review, first_label))
 
Review tf.Tensor(b'Silent Night, Deadly Night 5 is the very last of the series, and like part 4, it\'s unrelated to the first three except by title and the fact that it\'s a Christmas-themed horror flick.<br /><br />Except to the oblivious, there\'s some obvious things going on here...Mickey Rooney plays a toymaker named Joe Petto and his creepy son\'s name is Pino. Ring a bell, anyone? Now, a little boy named Derek heard a knock at the door one evening, and opened it to find a present on the doorstep for him. Even though it said "don\'t open till Christmas", he begins to open it anyway but is stopped by his dad, who scolds him and sends him to bed, and opens the gift himself. Inside is a little red ball that sprouts Santa arms and a head, and proceeds to kill dad. Oops, maybe he should have left well-enough alone. Of course Derek is then traumatized by the incident since he watched it from the stairs, but he doesn\'t grow up to be some killer Santa, he just stops talking.<br /><br />There\'s a mysterious stranger lurking around, who seems very interested in the toys that Joe Petto makes. We even see him buying a bunch when Derek\'s mom takes him to the store to find a gift for him to bring him out of his trauma. And what exactly is this guy doing? Well, we\'re not sure but he does seem to be taking these toys apart to see what makes them tick. He does keep his landlord from evicting him by promising him to pay him in cash the next day and presents him with a "Larry the Larvae" toy for his kid, but of course "Larry" is not a good toy and gets out of the box in the car and of course, well, things aren\'t pretty.<br /><br />Anyway, eventually what\'s going on with Joe Petto and Pino is of course revealed, and as with the old story, Pino is not a "real boy". Pino is probably even more agitated and naughty because he suffers from "Kenitalia" (a smooth plastic crotch) so that could account for his evil ways. And the identity of the lurking stranger is revealed too, and there\'s even kind of a happy ending of sorts. Whee.<br /><br />A step up from part 4, but not much of one. Again, Brian Yuzna is involved, and Screaming Mad George, so some decent special effects, but not enough to make this great. A few leftovers from part 4 are hanging around too, like Clint Howard and Neith Hunter, but that doesn\'t really make any difference. Anyway, I now have seeing the whole series out of my system. Now if I could get some of it out of my brain. 4 out of 5.', shape=(), dtype=string)
Label neg
Vectorized review (<tf.Tensor: shape=(1, 250), dtype=int64, numpy=
array([[1287,  313, 2380,  313,  661,    7,    2,   52,  229,    5,    2,
         200,    3,   38,  170,  669,   29, 5492,    6,    2,   83,  297,
         549,   32,  410,    3,    2,  186,   12,   29,    4,    1,  191,
         510,  549,    6,    2, 8229,  212,   46,  576,  175,  168,   20,
           1, 5361,  290,    4,    1,  761,  969,    1,    3,   24,  935,
        2271,  393,    7,    1, 1675,    4, 3747,  250,  148,    4,  112,
         436,  761, 3529,  548,    4, 3633,   31,    2, 1331,   28, 2096,
           3, 2912,    9,    6,  163,    4, 1006,   20,    2,    1,   15,
          85,   53,  147,    9,  292,   89,  959, 2314,  984,   27,  762,
           6,  959,    9,  564,   18,    7, 2140,   32,   24, 1254,   36,
           1,   85,    3, 3298,   85,    6, 1410,    3, 1936,    2, 3408,
         301,  965,    7,    4,  112,  740, 1977,   12,    1, 2014, 2772,
           3,    4,  428,    3, 5177,    6,  512, 1254,    1,  278,   27,
         139,   25,  308,    1,  579,    5,  259, 3529,    7,   92, 8981,
          32,    2, 3842,  230,   27,  289,    9,   35,    2, 5712,   18,
          27,  144, 2166,   56,    6,   26,   46,  466, 2014,   27,   40,
        2745,  657,  212,    4, 1376, 3002, 7080,  183,   36,  180,   52,
         920,    8,    2, 4028,   12,  969,    1,  158,   71,   53,   67,
          85, 2754,    4,  734,   51,    1, 1611,  294,   85,    6,    2,
        1164,    6,  163,    4, 3408,   15,   85,    6,  717,   85,   44,
           5,   24, 7158,    3,   48,  604,    7,   11,  225,  384,   73,
          65,   21,  242,   18,   27,  120,  295,    6,   26,  667,  129,
        4028,  948,    6,   67,   48,  158,   93,    1]])>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)

Come potete vedere sopra, ogni token è stato sostituito da un numero intero. Si può cercare il token (stringa) che ogni intero corrisponde chiamando .get_vocabulary() sullo strato.

 print("1287 ---> ",vectorize_layer.get_vocabulary()[1287])
print(" 313 ---> ",vectorize_layer.get_vocabulary()[313])
print('Vocabulary size: {}'.format(len(vectorize_layer.get_vocabulary())))
 
1287 --->  silent
 313 --->  night
Vocabulary size: 10000

Sei quasi pronto per addestrare il vostro modello. Come passo di pre-elaborazione finale, si applicherà il livello TextVectorization creato in precedenza al treno, la convalida, e set di dati di test.

 train_ds = raw_train_ds.map(vectorize_text)
val_ds = raw_val_ds.map(vectorize_text)
test_ds = raw_test_ds.map(vectorize_text)
 

Configurare il set di dati per le prestazioni

Si tratta di due metodi importanti che si dovrebbero usare quando il caricamento dei dati per assicurarsi che I / O non diventa il blocco.

.cache() mantiene dati in memoria dopo che è stato caricato dal disco. Ciò garantirà l'insieme di dati non diventi un collo di bottiglia, mentre l'addestramento del vostro modello. Se il set di dati è troppo grande per entrare nella memoria, è possibile anche utilizzare questo metodo per creare un performante cache su disco, che è più efficiente da leggere rispetto a molti file di piccole dimensioni.

.prefetch() si sovrappone i dati di pre-elaborazione e l'esecuzione del modello, mentre la formazione.

Si può imparare di più su entrambi i metodi, come pure come i dati della cache su disco nella guida prestazioni dei dati .

 AUTOTUNE = tf.data.experimental.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)
 

Creare il modello

È il momento di creare la nostra rete neurale:

 embedding_dim = 16
 
 model = tf.keras.Sequential([
  layers.Embedding(max_features + 1, embedding_dim),
  layers.Dropout(0.2),
  layers.GlobalAveragePooling1D(),
  layers.Dropout(0.2),
  layers.Dense(1)])

model.summary()
 
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 16)          160016    
_________________________________________________________________
dropout (Dropout)            (None, None, 16)          0         
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 1)                 17        
=================================================================
Total params: 160,033
Trainable params: 160,033
Non-trainable params: 0
_________________________________________________________________

Gli strati sono impilati in sequenza per costruire il classificatore:

  1. Il primo strato è un Embedding strato. Questo strato prende le recensioni interi codifica e cerca un vettore incorporamento per ogni parola-index. Questi vettori sono apprese come i treni di modello. I vettori aggiungono una dimensione alla matrice di uscita. Le dimensioni risultanti sono: (batch, sequence, embedding) . Per ulteriori informazioni su incastri, vedere la parola embedding esercitazione .
  2. Successivamente, un GlobalAveragePooling1D strato restituisce un vettore di uscita di lunghezza fissa per ciascun esempio da una media su dimensione sequenza. Questo permette al modello di ingresso manico di lunghezza variabile, nel modo più semplice possibile.
  3. Questa uscita vettore a lunghezza fissa viene convogliata attraverso un (completamente collegato Dense ) strato con 16 unità nascoste.
  4. L'ultimo strato è densamente collegata con un singolo nodo di uscita.

funzione di perdita e ottimizzatore

Un modello ha bisogno di una funzione di perdita e un ottimizzatore per la formazione. Poiché questo è un problema di classificazione binaria e il modello uscite una probabilità (a strato singolo apparecchio con attivazione sigmoidale), si userà losses.BinaryCrossentropy funzione di perdita.

Ora, configurare il modello di utilizzare un una funzione di perdita ottimizzatore e:

 model.compile(loss=losses.BinaryCrossentropy(from_logits=True), optimizer='adam', metrics=tf.metrics.BinaryAccuracy(threshold=0.0))
 

Addestrare il modello

Potrete allenare il modello passando il dataset oggetto per il metodo di adattamento.

 epochs = 10
history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=epochs)
 
Epoch 1/10
625/625 [==============================] - 3s 5ms/step - loss: 0.6632 - binary_accuracy: 0.6931 - val_loss: 0.6135 - val_binary_accuracy: 0.7752
Epoch 2/10
625/625 [==============================] - 3s 4ms/step - loss: 0.5472 - binary_accuracy: 0.8003 - val_loss: 0.4968 - val_binary_accuracy: 0.8220
Epoch 3/10
625/625 [==============================] - 3s 4ms/step - loss: 0.4434 - binary_accuracy: 0.8459 - val_loss: 0.4187 - val_binary_accuracy: 0.8486
Epoch 4/10
625/625 [==============================] - 3s 4ms/step - loss: 0.3770 - binary_accuracy: 0.8660 - val_loss: 0.3726 - val_binary_accuracy: 0.8622
Epoch 5/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3349 - binary_accuracy: 0.8786 - val_loss: 0.3442 - val_binary_accuracy: 0.8678
Epoch 6/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3046 - binary_accuracy: 0.8889 - val_loss: 0.3253 - val_binary_accuracy: 0.8722
Epoch 7/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2807 - binary_accuracy: 0.8977 - val_loss: 0.3118 - val_binary_accuracy: 0.8726
Epoch 8/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2609 - binary_accuracy: 0.9046 - val_loss: 0.3026 - val_binary_accuracy: 0.8762
Epoch 9/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2443 - binary_accuracy: 0.9123 - val_loss: 0.2961 - val_binary_accuracy: 0.8774
Epoch 10/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2309 - binary_accuracy: 0.9163 - val_loss: 0.2915 - val_binary_accuracy: 0.8804

Valutare il modello

Vediamo come le esegue modello. Due valori saranno restituiti. Perdita (un numero che rappresenta il nostro errore, i valori più bassi sono migliori), e l'accuratezza.

 loss, accuracy = model.evaluate(test_ds)

print("Loss: ", loss)
print("Accuracy: ", accuracy)
 
782/782 [==============================] - 2s 3ms/step - loss: 0.3097 - binary_accuracy: 0.8740
Loss:  0.30967268347740173
Accuracy:  0.8740400075912476

Questo approccio abbastanza ingenuo raggiunge una precisione di circa 86%.

Creare un appezzamento di precisione e la perdita nel tempo

model.fit() restituisce uno History oggetto che contiene un dizionario con tutto ciò che è accaduto durante l'allenamento:

 history_dict = history.history
history_dict.keys()
 
dict_keys(['loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'])

Ci sono quattro voci: una per ogni monitorato metrica durante l'allenamento e la convalida. È possibile utilizzare questi per tracciare la perdita di formazione e il riconoscimento per il confronto, così come la precisione formazione e il riconoscimento:

 acc = history_dict['binary_accuracy']
val_acc = history_dict['val_binary_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()
 

png

 plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')

plt.show()
 

png

In questo grafico, i punti rappresentano la perdita di formazione e precisione, e le linee solide sono la perdita di validazione e precisione.

Si noti la perdita di formazione diminuisce con ogni epoca e la formazione di precisione aumenta con ogni epoca. Questo è previsto quando usando un gradiente di discesa ottimizzazione-dovrebbe minimizzare la quantità desiderata su ogni iterazione.

Questo non è il caso per la perdita di convalida e l'accuratezza, sembrano picco prima l'accuratezza di formazione. Questo è un esempio di sovradattamento: il modello esegue meglio sui dati di formazione di quanto non faccia su dati non ha mai visto prima. Dopo questo punto, il modello over-ottimizza e impara rappresentazioni specifiche per i dati di allenamento che non generalizzano a dati di test.

Per questo caso particolare, si potrebbe prevenire overfitting semplicemente fermando la formazione quando la precisione di convalida non è in aumento. Un modo per farlo è quello di utilizzare il callback EarlyStopping .

Esportare il modello

Nel codice di cui sopra, è stato applicato il TextVectorization livello per il set di dati prima di alimentare il testo al modello. Se si desidera rendere il vostro modello in grado di elaborare le stringhe prime (ad esempio, per semplificare la distribuzione di esso), è possibile includere il TextVectorization strato interno il tuo modello. Per fare ciò, è possibile creare un nuovo modello utilizzando i pesi appena addestrato.

 export_model = tf.keras.Sequential([
  vectorize_layer,
  model,
  layers.Activation('sigmoid')
])

export_model.compile(
    loss=losses.BinaryCrossentropy(from_logits=False), optimizer="adam", metrics=['accuracy']
)

# Test it with `raw_test_ds`, which yields raw strings
loss, accuracy = export_model.evaluate(raw_test_ds)
print(accuracy)
 
782/782 [==============================] - 3s 4ms/step - loss: 0.3097 - accuracy: 0.8740
0.8740400075912476

Tra cui la logica di testo pre-elaborazione all'interno del vostro modello consente di esportare un modello per la produzione che la distribuzione semplifica e riduce il rischio di treno / test skew .

V'è una differenza di prestazioni da tenere a mente quando si sceglie dove applicare il vostro strato TextVectorization. Utilizzando al di fuori del modello permette di fare di elaborazione della CPU asincrona e il buffering dei dati quando la formazione sulla GPU. Quindi, se ti alleni il tuo modello sulla GPU, probabilmente si vuole andare con questa opzione per ottenere le migliori prestazioni durante lo sviluppo del modello, quindi passare alla compreso lo strato TextVectorization all'interno del modello quando si è pronti a preparare per la distribuzione .

Visita questa esercitazione per ulteriori informazioni sul salvataggio modelli.

Esercizio: la classificazione multiclasse sulle questioni Stack Overflow

Questo tutorial ha mostrato come addestrare un classificatore binario da zero sul set di dati IMDB. Come esercizio, è possibile modificare questo notebook di formare un classificatore multiclasse per predire il tag di una questione di programmazione su Stack Overflow .

Abbiamo preparato un set di dati per l'uso contenente il corpo di diverse migliaia di domande di programmazione (ad esempio, "Come può ordinare un dizionario per valore in Python?") Inviato a Stack Overflow. Ciascuno di questi è marcato con esattamente un tag (o Python, CSharp, JavaScript o Java). Il vostro compito è quello di prendere una domanda come input, e prevedere il tag appropriato, in questo caso, Python.

Il set di dati si lavorerà con contiene diverse migliaia di domande estratte dal molto più grande pubblico Stack Overflow dataset su BigQuery , che contiene più di 17 milioni di messaggi.

Dopo aver scaricato il set di dati, troverete che ha una struttura di directory simile al set di dati IMDB hai lavorato con precedenza:

 train/
...python/
......0.txt
......1.txt
...javascript/
......0.txt
......1.txt
...csharp/
......0.txt
......1.txt
...java/
......0.txt
......1.txt
 

Per completare questo esercizio, è necessario modificare questo notebook al lavoro con il set di dati overflow dello stack effettuando le seguenti modifiche:

  1. Nella parte superiore del notebook, aggiornare il codice che scarica il DataSet IMDB con codice per scaricare il set di dati Stack Overflow abbiamo prepreared. Come il set di dati Stack Overflow ha una simile struttura di directory, non avrete bisogno di fare molte modifiche.

  2. Modificare l'ultimo strato del modello di leggere Dense(4) , come ora ci sono quattro classi di potenza.

  3. Quando si compila il proprio modello, cambiare la perdita di SparseCategoricalCrossentropy . Questa è la funzione perdita corretto da utilizzare per un problema di classificazione multiclasse, quando le etichette per ogni classe sono interi (nel nostro caso, possono essere 0, 1, 2, o 3).

  4. Una volta che questi cambiamenti sono completi, si sarà in grado di formare un classificatore multiclasse.

Se rimani bloccato, è possibile trovare una soluzione qui .

Imparare più

Questo tutorial ha introdotto la classificazione del testo da zero. Per ulteriori informazioni sul flusso di lavoro di classificazione di testi, in generale, si consiglia la lettura di questa guida da Google Developers.

 
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.