dinsdag 14 april 2020

Leren met letters 11 - En dus nu ook met woorden !!! (84%)

Het was even lastig maar het is nu gelukt! Het trainen met zowel karakters naar vectoren en vervolgens deze vectoren naar 'word2vec' vectoren. En dan toepassen in het 'vertrouwde' film sentiment model.

De eerste stap was het trainen van de 'word-embeddings'. Ook daarvoor heb ik alle woorden uit de filmsentiment data genomen en ze getraind op 'omliggende woorden':

Train on 12000000 samples, validate on 3000000 samples
Epoch 1/60
12000000/12000000 [==============================] - 1828s 152us/step - loss: 0.2814 - accuracy: 0.0412 - val_loss: 0.2790 - val_accuracy: 0.0398
Epoch 2/60
12000000/12000000 [==============================] - 1716s 143us/step - loss: 0.2790 - accuracy: 0.0415 - val_loss: 0.2790 - val_accuracy: 0.0386
Epoch 3/60
12000000/12000000 [==============================] - 1496s 125us/step - loss: 0.2790 - accuracy: 0.0416 - val_loss: 0.2790 - val_accuracy: 0.0458
Epoch 4/60
12000000/12000000 [==============================] - 1346s 112us/step - loss: 0.2790 - accuracy: 0.0414 - val_loss: 0.2790 - val_accuracy: 0.0425
Epoch 5/60
12000000/12000000 [==============================] - 1290s 107us/step - loss: 0.2790 - accuracy: 0.0416 - val_loss: 0.2790 - val_accuracy: 0.0456 

Met 12 miljoen woorden leek me 6 epochs wel genoeg. Je ziet de validation loss nauwelijks bewegen.

Eerst heb ik de c2w2v vectoren apart willen converteren maar dat gaf memory errors. Gek genoeg niet bij de conversie zelf maar pas bij de poging om de data (met numpy) op te slaan. Blijkbaar heeft die dan tijdelijk meer memory nodig.

Het lukt mij nu echter om de 2e conversie als 'layer' op te nemen.

Eerst maak ik een 'hulpmodel' van de getrainde woord embeddings.

c2w2v_model = load_model(path + 'model-best-c2w2v.h5')
get_1st_layer_output = K.function([c2w2v_model.layers[0].input],
                                  [c2w2v_model.layers[0].output])
hmodel = Model(c2w2v_model.inputs,c2w2v_model.layers[0].output)

En dan kan ik dat hulpmodel als layer opnemen in de Keras 'api - versie' van mijn eerdere model:

def Model_attention_conv_api():
    input_shape = Input(shape = (max_sent * max_words, max_vec))
    x = hmodel (input_shape)
    x = Dense(512) (x)
    x = Conv1D(512, 2, activation='relu') (x)
    x = AveragePooling1D() (x)
    x = SeqSelfAttention(attention_activation='relu') (x)
    x = Flatten() (x)
    x = Dense(128) (x)
    x = Dense(label_size-1, activation='sigmoid') (x)
    model = Model(inputs = input_shape,outputs=x)
    return model

Wow, daar ben ik best wel trots op. Nu eens kijken wat het resultaat gaat zijn. Misschien lukt het zo ook nog wel om ook de chars2vec zo op te nemen zodat data conversie niet nodig is.


Dat is heel niet slecht, lijkt mij. Welliswaar nog niet bij de 85% val acc die ik zou willen maar voor een eerste test ben ik verre van ontevreden.

En na even door trainen bijna 83% !!!



Een, iets hogere trainings rate (van 0.00001 to .0001) geeft een score van meer dan 84% in 16 epochs! We naderen de beoogde 85%!!!


This is the result with chars2vec size 100 (instead of 50)  



maandag 6 april 2020

Leren met letters 10 -chars2words2vec ?

Hoewel het 'leren met letters' al behoorlijke resultaten heeft gegeven geeft het chars2vec vooral 'kennis' over gelijksoortige woorden zoasl hier:

De kennis van een word2vec lijkt meer (onderlinge) betekenis vast te leggen.

En is daarmee dus een krachtige opstap voor elk NLP algoritme.  Nadeel van word2vec is, zoals eerder beschreven, van elk woord in principe door een getal wordt vertegenwoordigd en dus, stam,  hoofdletter en spelfout ongevoelig is. Zie hier voor meer informatie.

Wellicht is een combinatie van die 2 een goede oplossing. Word2vec wordt in principe getraind door voor elk woord de meest waarschijnlijke omliggende woorden te voorspellen. Dat moet, denk ik, ook te doen zijn voor de chars2vec vectoren. Neem bijvoorbeeld een woord dat met chars2vec in 50 'features' wordt beschreven. Er moet een NN te trainen zijn dat de meest waarschijnlijke, omliggende 6 * 50 woordfeatures kan voorspellen. (of meer/minder). De vectoren die hierbij ontstaan zijn dan, denk ik, de chars2word2vec vectoren. Met hopelijk de voordelen van beide ineen verpakt.
Wel zullen deze vrij groot uitpakken, neem ik aan. Als in een normale word2vec vaak minimaal zo'n 100 vectoren worden getraind en we voor chars2vec uitgaan van het huidige kleinste model zijn dat al 5000 vectoren per woord. (Bert base heeft er bijvoorbeeld 768).

Voor de test eerst maar eens uitgaan van bijvoorbeeld 30 woordvectoren dus een totaal van 50*30. Het gaat er tenslotte eerst om om aan te tonen of 'chars2words2vec' kan werken. Ik denk dat ik maar eens terug ga naar mijn filmrecentie experimenten.


 


donderdag 2 april 2020

Leren met letters 09 - Zelf een NL chars2vec netwerk trainen.

Nee, deze keer nog geen nieuwe resultaten in het verder optimaliseren van het deeplearning met chars2vec. Maar wel een start met iets nieuws: Kijken of ik ook zelf een chars2vec embedding network kan trainen. Met name ook met Nederlandse woorden. En wellicht later een keer met hoofd- en kleine letters. (Daar was het tenslotte allemaal (ondermeer) om te doen. Om de 'betekenis' in een zin van hoofdletters mee te kunnen nemen zonder daarbij een volledig nieuw 'woord' te hoeven maken. Zie toelichting hier.

Ik heb al eens eerder Nederlandse wiki artikelen gedownload en die staan nog 'braaf' te wachten om verder van nut te zijn. Dat komt nu goed uit.

Ik moet blijkbaar trainingsdata maken in deze vorm:

X_train = [('mecbanizing', 'mechanizing'), # similar words, target is equal 0
           ('dicovery', 'dis7overy'), # similar words, target is equal 0
           ('prot$oplasmatic', 'prtoplasmatic'), # similar words, target is equal 0
           ('copulateng', 'lzateful'), # not similar words, target is equal 1
           ('estry', 'evadin6'), # not similar words, target is equal 1
           ('cirrfosis', 'afear') # not similar words, target is equal 1
          ]

y_train = [0, 0, 0, 1, 1, 1]

Dat zou moeten lukken. De NL wiki beval genoeg woorden zou ik zeggen om een stevige hoeveelheid materiaal aan te maken.

Het gaat om 211.674 wiki artikelen en dat blijkt al snel veel te veel voor mijn (computers) geheugen. Ik neem de eerste 5.000 en kom daarmee op 222948 verschillende woorden als uitganspunt. Dat is best veul!



Van deze woorden maak ik 1 x een paar met random letter vervanging, 1 x met letter verwisseling en 2 x met een random ander woord. Na 'schudden' selecteer ik de eerste 100.000 paren om de training mee te doen. Hier een voorbeeld:

[('Engelsche', 'Engelscje'), ('visual', 'Lichenology'), ('Inhoudsopgave', 'Ministre'), ('Dandelion', 'Dandeilon'), ('tombe', 'tobme'), ('woningcrisis', 'tollenaar'), ('gallicisme', 'gallicisem'), ('Boekhoorn', 'Boekhoorn'), ('bouwster', 'richtinggetrouw'), ('Reu', 'eRu')]

Grappig dat het eerste woord van deze NL selectie 'Engelsche' is.

Standaard traint het model 200 epochs met 10 'patience' d.w.z. dat er maximaal 10x geen verbetring in de costfunctie te zien mag zijn. Ik ben ongeduldig en verander dat laatste naar 3x.
Hij draait nu in ongeveer 316 seconden 1 epoch en ik moet er 17 wachten tot hij vanzelf stopt.

Epoch 17/200
95000/95000 [==============================] - 281s 3ms/step - loss: 4.2194e-04 - val_loss: 0.0023

Een nette validatie loss, lijkt mij, en hij saved netjes he model in de door mij opgegevn directory.
Nu gaat het erom spannen of ik er ook redelijke resultaten mee ga halen. Wordt vervolgd!