Récemment, j'ai essayé d'implémenter un classificateur binaire qui juge le positif et le négatif d'un document en utilisant Chainer, qui est un sujet brûlant. Depuis que j'ai utilisé Chainer pour la première fois, c'est un modèle simple car c'est pour la pratique. Pour ceux qui veulent implémenter un réseau neuronal profond avec Chainer et faire quelque chose comme l'auteur.
Il serait utile que vous puissiez signaler les erreurs dans la section des commentaires.
Veuillez consulter ici pour le code complet.
--Installation de chainer, gensim, scikit-learn
--Série Python 2.7
Les données utilisées sont un document sur un examen de quelque chose en anglais. Chaque ligne correspond à un document et chaque mot du document est séparé par un espace demi-largeur. Le numéro au début de chaque ligne (par exemple 1, 0) est l'étiquette.
0 each scene drags , underscoring the obvious , and sentiment is slathered on top . 0 afraid to pitch into farce , yet only half-hearted in its spy mechanics , all the queen's men is finally just one long drag . 1 clooney directs this film always keeping the balance between the fantastic and the believable . . . 1 just about the best straight-up , old-school horror film of the last 15 years .
Vectorisez avec un sac de mots pour traiter chaque document comme une entrée dans le réseau neuronal. Pour la vectorisation, j'ai utilisé la fonction de gensim. Veuillez consulter cet article pour plus de détails. → Classer les articles de presse par scikit-learn et gensim
La fonction load_data
lit les données d'entrée et divise l'étiquette et la chaîne de mots de chaque document par l.strip (). Split (" ", 1)
.
L'étiquette du document est stockée dans «cible» et le vecteur de document est stocké dans «source».
corpora.Dictionary (document_list)
crée un dictionnaire de mots en passant une liste de listes de documents (document_list
) avec chaque mot comme élément.
À l'origine, je devais créer un dictionnaire de mots en utilisant uniquement des données de formation, mais je voulais omettre le traitement de texte inconnu, j'ai donc créé un dictionnaire de mots en utilisant tous les documents.
Où «vocab_size» est le nombre de vocabulaire dans tout le document et correspond au nombre de dimensions du vecteur de document. Par conséquent, le nombre d'unités dans la couche d'entrée du réseau neuronal mis en œuvre cette fois est égal à «vocab_size».
def load_data(fname):
source = []
target = []
f = open(fname, "r")
document_list = [] #Un document sur chaque ligne.Les éléments du document sont des mots
for l in f.readlines():
sample = l.strip().split(" ", 1) #Libellés et chaînes de mots séparés
label = int(sample[0]) #étiquette
target.append(label)
document_list.append(sample[1].split()) #Diviser les mots et les ajouter à la liste des documents
#Créer un dictionnaire de mots
dictionary = corpora.Dictionary(document_list)
dictionary.filter_extremes(no_below=5, no_above=0.8)
# no_below:Le document utilisé est non_Ignorer les mots ci-dessous
# no_above:Le pourcentage de phrases utilisées est non_Ignorer ci-dessus ci-dessus
#Vectorisation de documents
for document in document_list:
tmp = dictionary.doc2bow(document) #Représentation BoW du document
vec = list(matutils.corpus2dense([tmp], num_terms=len(dictionary)).T[0])
source.append(vec)
dataset = {}
dataset['target'] = np.array(target)
dataset['source'] = np.array(source)
print "vocab size:", len(dictionary.items()) #Nombre de vocabulaire=Nombre d'unités dans la couche d'entrée
return dataset, dictionary
Cette fois c'était pour la pratique, j'ai donc implémenté un modèle simple.
(Le dataset
reçu de la fonction précédenteload_data
est divisé en données d'entraînement et données de test à l'aide de la fonction train_test_split
contenue dans scikit-learn.)
Le nombre d'unités dans la couche d'entrée ʻin_units contient le nombre de dimensions du vecteur de document (
x_train.shape [1]`).
La couche cachée (couche intermédiaire) peut être définie de manière appropriée. Cette fois, j'essaye de passer 500 par défaut.
Étant donné que la couche de sortie utilise la fonction softmax, le nombre d'unités est de 2, ce qui correspond au nombre de types d'étiquettes.
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)
n_units = args.units #Nombre d'unités de calque masquées
n_label = 2 #Nombre d'unités dans la couche de sortie
#Définition du modèle
model = chainer.Chain(l1=L.Linear(in_units, n_units),
l2=L.Linear(n_units, n_units),
l3=L.Linear(n_units, n_label))
La fonction «forward» effectue une propagation vers l'avant. Couche d'entrée-> couche cachée, couche cachée-> fonction d'activation de couche cachée utilisée fonction sigmoïde.
def forward(x, t, train=True):
h1 = F.sigmoid(model.l1(x))
h2 = F.sigmoid(model.l2(h1))
y = model.l3(h2)
return F.softmax_cross_entropy(y, t), F.accuracy(y, t)
Dans l'ensemble,
Chaque époque calcule l'erreur pour les données d'apprentissage et l'erreur pour les données de test. De plus, puisqu'il s'agit d'un problème de classification, le taux d'exactitude de classification «précision» est également calculé.
# Setup optimizer
optimizer = optimizers.Adam()
optimizer.setup(model)
# Learning loop
for epoch in six.moves.range(1, n_epoch + 1):
print 'epoch', 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
model.zerograds() #Zéro initialisation du gradient
loss, acc = forward(x, t) #Propagation vers l'avant
sum_train_loss += float(cuda.to_cpu(loss.data)) * len(t) #Pour le calcul de l'erreur moyenne
sum_train_accuracy += float(cuda.to_cpu(acc.data )) * len(t) #Pour calculer le taux de précision moyen
loss.backward() #Erreur de propagation de retour
optimizer.update() #optimisation
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, acc = forward(x, t, train=False)
sum_test_loss += float(cuda.to_cpu(loss.data)) * len(t)
sum_test_accuracy += float(cuda.to_cpu(acc.data)) * len(t)
print(' test mean loss={}, accuracy={}'.format(
sum_test_loss / N_test, sum_test_accuracy / N_test)) #Erreur moyenne
#Enregistrer le modèle et l'optimiseur
print 'save the model'
serializers.save_npz('pn_classifier_ffnn.model', model)
print 'save the optimizer'
serializers.save_npz('pn_classifier_ffnn.state', optimizer)
Le taux d'exactitude de classification pour les données d'essai finales était «précision = 0,716875001788». Cependant, à mesure que l'apprentissage progresse, l'erreur de test augmente et un surapprentissage se produit ...
Probablement à cause du fait que le modèle a finalement été construit.
>python train.py --gpu 1 --data input.dat --units 1000
vocab size: 4442
epoch 1
train mean loss=0.746377664579, accuracy=0.554684912523
test mean loss=0.622971419245, accuracy=0.706875003874
epoch 2
train mean loss=0.50845754933, accuracy=0.759408453399
test mean loss=0.503996372223, accuracy=0.761249992996
epoch 3
train mean loss=0.386604680468, accuracy=0.826067760105
test mean loss=0.506066314876, accuracy=0.769374992698
epoch 4
train mean loss=0.301527346359, accuracy=0.870433726909
test mean loss=0.553729468957, accuracy=0.774999994785
epoch 5
train mean loss=0.264981631757, accuracy=0.889085094432
test mean loss=0.599407823756, accuracy=0.766874998808
epoch 6
train mean loss=0.231274759588, accuracy=0.901114668847
test mean loss=0.68350501731, accuracy=0.755625002086
...
epoch 95
train mean loss=0.0158744356008, accuracy=0.993598945303
test mean loss=5.08019682765, accuracy=0.717499997467
epoch 96
train mean loss=0.0149783944279, accuracy=0.994261124581
test mean loss=5.30629962683, accuracy=0.723749995232
epoch 97
train mean loss=0.00772037562047, accuracy=0.997351288256
test mean loss=5.49559159577, accuracy=0.720624998212
epoch 98
train mean loss=0.00569957431572, accuracy=0.99834455516
test mean loss=5.67661693692, accuracy=0.716875001788
epoch 99
train mean loss=0.00772406136085, accuracy=0.997240925267
test mean loss=5.63734056056, accuracy=0.720000002533
epoch 100
train mean loss=0.0125463016702, accuracy=0.995916569395
test mean loss=5.23713605106, accuracy=0.716875001788
save the model
save the optimizer
J'ai utilisé Chainer pour implémenter un réseau neuronal feedforward pour la classification de documents. Je voudrais améliorer le modèle pour qu'il n'y ait pas de surentraînement.
Si vous souhaitez voir le code pour étudier Chainer, veuillez vous référer à ici.
Recommended Posts