2016-05-18 33 views
11

Sono relativamente nuovo alle reti neurali quindi scusate la mia ignoranza. Sto cercando di adattare l'esempio di keras BLSTM here. L'esempio legge i testi e li classifica come 0 o 1. Voglio un BLSTM che faccia qualcosa di molto simile ai tag POS, anche se extra come il lemmatizing o altre funzionalità avanzate non sono necessarie, voglio solo un modello di base. I miei dati sono una lista di frasi e ogni parola è data una categoria 1-8. Voglio addestrare un BLSTM in grado di utilizzare questi dati per prevedere la categoria per ogni parola in una frase non vista.keras BLSTM per l'etichettatura sequenziale

ad es. input = ['Il', 'cane', 'è', 'rosso'] restituisce output = [2, 4, 3, 7]

Se l'esempio di keras non è il percorso migliore, sono aperto a altri suggerimenti.

Al momento ho questo:

'''Train a Bidirectional LSTM.''' 

from __future__ import print_function 
import numpy as np 
from keras.preprocessing import sequence 
from keras.models import Model 
from keras.layers import Dense, Dropout, Embedding, LSTM, Input, merge 
from prep_nn import prep_scan 


np.random.seed(1337) # for reproducibility 
max_features = 20000 
batch_size = 16 
maxlen = 18 

print('Loading data...') 
(X_train, y_train), (X_test, y_test) = prep_scan(nb_words=max_features, 
               test_split=0.2) 
print(len(X_train), 'train sequences') 
print(len(X_test), 'test sequences') 

print("Pad sequences (samples x time)") 
# type issues here? float/int? 
X_train = sequence.pad_sequences(X_train, value=0.) 
X_test = sequence.pad_sequences(X_test, value=0.) # pad with zeros 

print('X_train shape:', X_train.shape) 
print('X_test shape:', X_test.shape) 

# need to pad y too, because more than 1 ouput value, not classification? 
y_train = sequence.pad_sequences(np.array(y_train), value=0.) 
y_test = sequence.pad_sequences(np.array(y_test), value=0.) 

print('y_train shape:', X_train.shape) 
print('y_test shape:', X_test.shape) 

# this is the placeholder tensor for the input sequences 
sequence = Input(shape=(maxlen,), dtype='int32') 

# this embedding layer will transform the sequences of integers 
# into vectors of size 128 
embedded = Embedding(max_features, 128, input_length=maxlen)(sequence) 

# apply forwards LSTM 
forwards = LSTM(64)(embedded) 
# apply backwards LSTM 
backwards = LSTM(64, go_backwards=True)(embedded) 

# concatenate the outputs of the 2 LSTMs 
merged = merge([forwards, backwards], mode='concat', concat_axis=-1) 
after_dp = Dropout(0.5)(merged) 
# number after dense has to corresponse to output matrix? 
output = Dense(17, activation='sigmoid')(after_dp) 

model = Model(input=sequence, output=output) 

# try using different optimizers and different optimizer configs 
model.compile('adam', 'categorical_crossentropy', metrics=['accuracy']) 

print('Train...') 
model.fit(X_train, y_train, 
      batch_size=batch_size, 
      nb_epoch=4, 
      validation_data=[X_test, y_test]) 

X_test_new = np.array([[0,0,0,0,0,0,0,0,0,12,3,55,4,34,5,45,3,9],[0,0,0,0,0,0,0,1,7,65,34,67,34,23,24,67,54,43,]]) 

classes = model.predict(X_test_new, batch_size=16) 
print(classes) 

La mia uscita è la dimensione giusta, ma mi sta dando galleggia 0-1. Penso che sia perché è ancora alla ricerca della classificazione binaria. Qualcuno sa come risolvere questo?

risolto

Basta fare in modo che le etichette siano ogni matrici binarie:

(X_train, y_train), (X_test, y_test), maxlen, word_ids, tags_ids = prep_model(
    nb_words=nb_words, test_len=75) 

W = (y_train > 0).astype('float') 

print(len(X_train), 'train sequences') 
print(int(len(X_train)*val_split), 'validation sequences') 
print(len(X_test), 'heldout sequences') 

# this is the placeholder tensor for the input sequences 
sequence = Input(shape=(maxlen,), dtype='int32') 

# this embedding layer will transform the sequences of integers 
# into vectors of size 256 
embedded = Embedding(nb_words, output_dim=hidden, 
        input_length=maxlen, mask_zero=True)(sequence) 

# apply forwards LSTM 
forwards = LSTM(output_dim=hidden, return_sequences=True)(embedded) 
# apply backwards LSTM 
backwards = LSTM(output_dim=hidden, return_sequences=True, 
       go_backwards=True)(embedded) 

# concatenate the outputs of the 2 LSTMs 
merged = merge([forwards, backwards], mode='concat', concat_axis=-1) 
after_dp = Dropout(0.15)(merged) 

# TimeDistributed for sequence 
# change activation to sigmoid? 
output = TimeDistributed(
    Dense(output_dim=nb_classes, 
      activation='softmax'))(after_dp) 

model = Model(input=sequence, output=output) 

# try using different optimizers and different optimizer configs 
# loss=binary_crossentropy, optimizer=rmsprop 
model.compile(loss='categorical_crossentropy', 
       metrics=['accuracy'], optimizer='adam', 
       sample_weight_mode='temporal') 

print('Train...') 
model.fit(X_train, y_train, 
      batch_size=batch_size, 
      nb_epoch=epochs, 
      shuffle=True, 
      validation_split=val_split, 
      sample_weight=W) 
+0

Potresti per favore caricare un piccolo campione dei tuoi dati? Aiuta a capire meglio come funziona il modello. Se non è possibile, potresti spiegare un po 'come sono fatti i dati grezzi e cosa hai fatto per la pre-elaborazione dei dati prima di alimentare il modello? –

risposta

4

risolto. Il problema principale consisteva nel ridisegnare i dati per le categorie di classificazione come array binari. Utilizzato anche TimeDistributed e set return_sequences su True.

+0

è possibile aggiungere il codice funzionante? grazie – PSNR

+0

Certo, basta vedere sopra le modifiche. – ChrisDH

+0

Grazie! Quando usiamo 'mask_zero = True' nel livello di incorporamento, immagino che tutti i seguenti livelli ignoreranno questa classe per calcolare la perdita, la precisione, ecc.? E suppongo che 'nb_classes 'nel livello di output debba essere # di classe + 1 (vale a dire, per il problema di classificazione in binario è 3)? Grazie ancora! – PSNR