[PYTHON] [Chainer] Classification des documents par réseau de neurones convolutifs

introduction

Réseaux de neurones convolutifs (CNN), largement utilisés pour la reconnaissance d'images, etc. Récemment, il est également utilisé dans le domaine du traitement du langage naturel [Kim, EMNLP2014]. Cette fois, j'ai construit un réseau simple en utilisant CNN avec Chainer et je l'ai appliqué à la tâche de classification de documents.

Stockage de données

--Code source implémenté cette fois - ichiroex@github

Préparation préalable

--Installation de Chainer, scikit-learn, gensim

environnement

--Série Python 2.7

Créer un vecteur de document

Cette fois, le document d'entrée est vectorisé à l'aide de word2vec, et le document vectorisé est alambiqué. La vectorisation du document se fait avec def load_data (fname) défini dans ʻuitl.py`.

En tant qu'image, une chaîne de mots d'entrée (document) $ x_1 $, $ x_2 $, $ x_3 $, ...., $ x_n $ pour chaque mot $ x_i $ Convertit en un vecteur $ N $ à dimension fixe et crée un vecteur de document bidimensionnel avec eux côte à côte.

[Exemple] word_vector.png

De plus, comme la longueur de la phrase est différente pour chaque document, le remplissage est effectué pour correspondre à la longueur de phrase maximale $ maxlen $ dans le document d'entrée. Autrement dit, la dimension du vecteur de document bidimensionnel généré est $ N * maxlen $.

À propos, dans le modèle word2vec publié par Google cette fois, la dimension de chaque vecteur de mot est de 300.

util.py


def load_data(fname):
    #Charger le modèle word2vec entraîné
    model =  word2vec.Word2Vec.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)

    target = [] #étiquette
    source = [] #Vecteur de document

    #Créer une liste de documents
    document_list = []
    for l in open(fname, 'r').readlines():
        sample = l.strip().split(' ',  1)
        label = sample[0]
        target.append(label) #étiquette
        document_list.append(sample[1].split()) #Liste de mots pour chaque document
    
    max_len = 0
    rev_document_list = [] #Liste de documents après traitement de texte inconnu
    for doc in document_list:
        rev_doc = []
        for word in doc:
            try:
                word_vec = np.array(model[word]) #Dans le cas de mots inconnus,KeyError se produit
                rev_doc.append(word)
            except KeyError:
                rev_doc.append('<unk>') #Mot inconnu
        rev_document_list.append(rev_doc)
        #Trouver la longueur maximale d'un document(Pour le rembourrage)
        if len(rev_doc) > max_len:
            max_len = len(rev_doc)
    
    #Faire correspondre la longueur du document par remplissage
    rev_document_list = padding(rev_document_list, max_len)
    
    width = 0 #Nombre de dimensions de chaque mot
    #Vectorisation des fonctionnalités du document
    for doc in rev_document_list:
        doc_vec = []
        for word in doc:
            try:
                vec = model[word.decode('utf-8')]
            except KeyError:
                vec = model.seeded_vector(word)
            doc_vec.extend(vec)
            width = len(vec)
        source.append(doc_vec)

    dataset = {}
    dataset['target'] = np.array(target)    
    dataset['source'] = np.array(source)    

    return dataset, max_len, width

Définition du modèle

Cette fois, j'ai défini un modèle avec une structure de couche de convolution-> couche de regroupement-> couche entièrement connectée. J'ai aussi un abandon en cours de route.

cnn_network_architecture.png

net.py


class SimpleCNN(Chain):
    
    def __init__(self, input_channel, output_channel, filter_height, filter_width, mid_units, n_units, n_label):
        super(SimpleCNN, self).__init__(
            conv1 = L.Convolution2D(input_channel, output_channel, (filter_height, filter_width)),
            l1    = L.Linear(mid_units, n_units),
            l2    = L.Linear(n_units,  n_label),
        )
    
    #Appelé par le classificateur
    def __call__(self, x):
        h1 = F.max_pooling_2d(F.relu(self.conv1(x)), 3)
        h2 = F.dropout(F.relu(self.l1(h1)))
        y = self.l2(h2)
        return y

Apprentissage

Lors de l'apprentissage, le taux de réponse correct et la perte sont calculés et affichés pour chaque époque de données d'apprentissage et de données de test. Le code est presque le même que lorsque Classification des documents à l'aide du réseau de neurones feedforward.

Une fois plié, la taille du filtre est de 3 x 300 (le nombre de dimensions de chaque vecteur de mot).

train_cnn.py


# Prepare dataset
dataset, height, width = util.load_data(args.data)
print 'height:', height
print 'width:', width

dataset['source'] = dataset['source'].astype(np.float32) #Valeur de la fonctionnalité
dataset['target'] = dataset['target'].astype(np.int32) #étiquette

x_train, x_test, y_train, y_test = train_test_split(dataset['source'], dataset['target'], test_size=0.15)
N_test = y_test.size         # test data size
N = len(x_train)             # train data size
in_units = x_train.shape[1]  #Nombre d'unités dans la couche d'entrée(Nombre de vocabulaire)

# (nsample, channel, height, width)Converti en tenseur à 4 dimensions
input_channel = 1
x_train = x_train.reshape(len(x_train), input_channel, height, width) 
x_test  = x_test.reshape(len(x_test), input_channel, height, width)

#Nombre d'unités de calque masquées
n_units = args.nunits
n_label = 2
filter_height = 3
output_channel = 50

#Définition du modèle
model = L.Classifier( SimpleCNN(input_channel, output_channel, filter_height, width, 950, n_units, n_label))

#Utiliser ou non le GPU
if args.gpu > 0:
    cuda.check_cuda_available()
    cuda.get_device(args.gpu).use()
    model.to_gpu()
    xp = np if args.gpu <= 0 else cuda.cupy #args.gpu <= 0: use cpu, otherwise: use gpu

batchsize = args.batchsize
n_epoch = args.epoch

# Setup optimizer
optimizer = optimizers.AdaGrad()
optimizer.setup(model)

# Learning loop
for epoch in six.moves.range(1, n_epoch + 1):

    print 'epoch', epoch, '/', n_epoch
    
    # training)
    perm = np.random.permutation(N) #Obtenez une liste aléatoire de colonnes entières
    sum_train_loss     = 0.0
    sum_train_accuracy = 0.0
    for i in six.moves.range(0, N, batchsize):

        #x en utilisant perm_train, y_Sélectionnez un jeu de données du train(Les données cibles sont différentes à chaque fois)
        x = chainer.Variable(xp.asarray(x_train[perm[i:i + batchsize]])) #source
        t = chainer.Variable(xp.asarray(y_train[perm[i:i + batchsize]])) #target
        
        optimizer.update(model, x, t)

        sum_train_loss      += float(model.loss.data) * len(t.data)   #Pour le calcul de l'erreur moyenne
        sum_train_accuracy  += float(model.accuracy.data ) * len(t.data)   #Pour calculer le taux de précision moyen

    print('train mean loss={}, accuracy={}'.format(sum_train_loss / N, sum_train_accuracy / N)) #Erreur moyenne

    # evaluation
    sum_test_loss     = 0.0
    sum_test_accuracy = 0.0
    for i in six.moves.range(0, N_test, batchsize):

        # all test data
        x = chainer.Variable(xp.asarray(x_test[i:i + batchsize]))
        t = chainer.Variable(xp.asarray(y_test[i:i + batchsize]))

        loss = model(x, t)

        sum_test_loss     += float(loss.data) * len(t.data)
        sum_test_accuracy += float(model.accuracy.data)  * len(t.data)

    print(' test mean loss={}, accuracy={}'.format(
        sum_test_loss / N_test, sum_test_accuracy / N_test)) #Erreur moyenne

    if epoch > 10:
        optimizer.lr *= 0.97
        print 'learning rate: ', optimizer.lr

    sys.stdout.flush()

Résultat expérimental

Le taux de réponse correcte final était «précision = 0,775624996424». Lorsqu'il est classé par réseau de neurones feedforward était ʻexactitude = 0,716875001788`, donc le taux de précision s'est considérablement amélioré. (Dans le cas du réseau neuronal à réaction directe, word2vec n'a pas été utilisé et le vecteur de document a été créé en utilisant un vecteur de mot chaud, les conditions expérimentales sont donc différentes.)

height: 59
width: 300
epoch 1 / 100
train mean loss=0.68654858897, accuracy=0.584814038988
 test mean loss=0.673290403187, accuracy=0.674374999106
epoch 2 / 100
train mean loss=0.653146019086, accuracy=0.678733030628
 test mean loss=0.626838338375, accuracy=0.695624998212
epoch 3 / 100
train mean loss=0.604344114544, accuracy=0.717580840894
 test mean loss=0.582373640686, accuracy=0.713124997914

...

epoch 98 / 100
train mean loss=0.399981137426, accuracy=0.826288489978
 test mean loss=0.460177404433, accuracy=0.775625003874
learning rate:  6.85350312961e-05
epoch 99 / 100
train mean loss=0.400466494895, accuracy=0.822536144887
 test mean loss=0.464013618231, accuracy=0.773749999702
learning rate:  6.64789803572e-05
epoch 100 / 100
train mean loss=0.399539747416, accuracy=0.824081227461
 test mean loss=0.466326575726, accuracy=0.775624996424
learning rate:  6.44846109465e-05
save the model
save the optimizer

en conclusion

J'ai essayé la classification de documents (classification positive / négative) en utilisant un réseau neuronal convolutif. C'était un modèle simple, mais il semble avoir une certaine précision.

Ensuite, j'ai également implémenté le modèle de Yoon Kim avec chainer, donc Je publierai un article.

References

Recommended Posts

[Chainer] Classification des documents par réseau de neurones convolutifs
Implémenter un réseau neuronal convolutif
Expérience de réseau de neurones pliable
Apprentissage des classements à l'aide d'un réseau neuronal (implémentation RankNet par Chainer)
Classification d'images avec un réseau de neurones auto-fabriqué par Keras et PyTorch
[Apprentissage en profondeur] Classification d'images avec un réseau neuronal convolutif [DW jour 4]
Implémentation simple d'un réseau neuronal à l'aide de Chainer
Modèle de classification simple avec réseau neuronal
Qu'est-ce que le réseau neuronal convolutif?
[Classification de texte] J'ai essayé d'implémenter des réseaux de neurones convolutifs pour la classification des phrases avec Chainer
Essayez d'utiliser TensorFlow-Part 2-Convolution Neural Network (MNIST)
Implémentation de réseaux neuronaux "flous" avec Chainer
Une autre méthode de conversion de style utilisant le réseau neuronal convolutif
Reconnaissance des nombres manuscrits par un réseau neuronal multicouche
Réseau neuronal paramétrique
Présentation de DNC (Differentiable Neural Computers) + Implémentation par Chainer
Modèle utilisant un réseau neuronal convolutif dans le traitement du langage naturel
Mise en œuvre de l'optimisation bayésienne des hyper paramètres du réseau de neurones (Chainer + GPyOpt)
Implémentez un réseau de neurones feedforward dans Chainer pour classer les documents
Implémentation d'un réseau de neurones convolutifs utilisant uniquement Numpy
Conversion de style par style neuronal
Implémenter le réseau neuronal à partir de zéro
Construction d'un réseau neuronal qui reproduit XOR par Z3
Série d'accélération CNN ~ FCNN: Introduction du réseau neuronal convolutif de Fourier ~
Etude du réseau neuronal récurrent (RNN) par Chainer ~ Vérification de l'exactitude des nombres aléatoires dans Excel et R ~