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.
--Code source implémenté cette fois - ichiroex@github
--Installation de Chainer, scikit-learn, gensim
--Série Python 2.7
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]
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
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.
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
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()
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
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