Dernière fois est l'utilisation de base de Chainer, l'implémentation de MLP (perceptron multicouche) et le nombre de nœuds de la couche entièrement connectée de la couche de convolution de CNN. J'ai introduit la formule de calcul nécessaire pour cela.
Cette fois, je vais lire les données Twitter réelles et créer un CNN.
L'explication du réseau de neurones convolutifs était facile à comprendre ici.
Un filtre est appliqué aux données d'image bidimensionnelles pour compresser les caractéristiques. Après cela, la mise en commun est effectuée pour extraire davantage la quantité de fonctionnalités. Il n'y a probablement pas un type de filtre, mais différents filtres sont appliqués pour le nombre de feuilles que vous souhaitez produire.
Cet article en référence à [http://qiita.com/hogefugabar/items/93fcb2bc27d7b268cbe6) Je penserai à l'imiter.
Les grandes lignes du processus sont les suivantes.
La définition et l'apprentissage de CNN utilisent la méthode suivante décrite dans l'article.
Cette figure illustre le processus de convolution et de mise en commun pour une seule phrase, $ d $ étant la dimension du vecteur Word et $ s $ étant le nombre de mots de la phrase dans la grande matrice à l'extrême gauche. Et la taille du filtre n'est pas une matrice symétrique, mais une matrice asymétrique de dimensions $ d × m $.
Cependant, je n'ai pas compris même après avoir lu l'article, mais $ s $ est différent pour chaque phrase, donc si je me demandais comment faire cela, cet article / items / 93fcb2bc27d7b268cbe6) prend le nombre maximum de mots pour chaque phrase qui apparaît dans tous les Tweets, alors imitez ceci.
Obtenez les données du Tweet (https://raw.githubusercontent.com/satwantrana/CharSCNN/master/tweets_clean.txt). Dans les données, la première colonne est le drapeau de [0,1] et la deuxième colonne est le Tweet en anglais.
Word Embed
Je veux garder la phrase dans un format d'image bidimensionnel, donc je vais la changer en une représentation distribuée. Cette fois, l'ID intégré fourni avec Chainer n'a pas fonctionné, donc j'utiliserai Word2Vec du package gensim.
Tout d'abord, attribuez un ID à Word à partir des données texte.
#! -*- coding:utf-8 -*-
def read(inp_file,num_sent=None):
f_in = open(inp_file, 'r')
lines = f_in.readlines()
words_map = {}
word_cnt = 0
k_wrd = 5 #Fenêtre contextuelle Word
y = []
x_wrd = []
if num_sent is None:
num_sent = len(lines)
max_sen_len = 0
else:
max_sen_len, num_sent = 0, num_sent
words_vocab_mat = []
token_list = []
for line in lines[:num_sent]:
words = line[:-1].split()
tokens = words[1:]
y.append(int(float(words[0])))
max_sen_len = max(max_sen_len,len(tokens))
for token in tokens:
if token not in words_map:
words_map[token] = word_cnt
token_list.append(token)
word_cnt += 1
words_vocab_mat.append(tokens)
cnt = 0
for line in lines[:num_sent]:
words = line[:-1].split()
cnt += 1
tokens = words[1:]
word_mat = [-1] * (max_sen_len+k_wrd-1)
for i in xrange(len(tokens)):
word_mat[(k_wrd/2)+i] = words_map[tokens[i]]
x_wrd.append(word_mat)
max_sen_len += k_wrd-1
# num_sent:Nombre de documents
# word_cnt:Nombre de types de mots
# max_sen_len:Longueur maximale du document
# x_wrd:Nombre de lignes dans la colonne id du mot d'entrée:Nombre de phrases(num_sent)Le nombre de colonnes:Longueur maximale du document(max_sen_len)
# k_wrd: window size
# words_map : key = word,value = id
# y: 1 or 0 (i.e., positive or negative)
# words_vocab_mat :Phrase décomposée, le nombre de lignes correspond au nombre de phrases, le nombre de colonnes est variable et le nombre de mots
# token_list :Liste de jetons, l'index correspond à l'id
data = (num_sent, word_cnt, max_sen_len, k_wrd, x_wrd, y,words_map,words_vocab_mat,token_list)
return data
(num_sent, word_cnt, max_sen_len, k_wrd, x_wrd, y,words_map,sentences,token_list) = load.read("data/tweets_clean.txt",10000)
x_wrd est une matrice de nombre de phrases x longueur maximale du document, et chaque élément est l'ID du mot qui apparaît. Préparez words_map, token_list et words_vocab_mat car vous en aurez besoin plus tard.
Ensuite, utilisez Word2Vec pour obtenir une représentation vectorielle de chaque mot, puis créez une «matrice d'image de phrase» (attachée arbitrairement).
"""Créer un espace vectoriel de mots avec Word2Vec"""
word_dimension = 200
from gensim.models import Word2Vec
model_w2v = Word2Vec(sentences,seed=123,size=word_dimension,min_count=0,window=5)
sentence_image_matrix = np.zeros((len(sentences),1,word_dimension,max_sen_len)) #Initialisation de la matrice d'image de phrase pour la convolution
"""x_Générer un vecteur pour wrd"""
for i in range(0,len(x_wrd)):
tmp_id_list = x_wrd[i,:]
for j in range(0,len(tmp_id_list)):
"""Tourner pour une ligne"""
id = tmp_id_list[j]
if id == -1:
"""Aucune information"""
sentence_image_matrix[i,0,:,j] = [0.] * word_dimension #Insérer 0 vecteur
else:
target_word = token_list[id]
sentence_image_matrix[i,0,:,j] = model_w2v[target_word]
phrase_image_matrix est défini comme un tenseur à 4 dimensions avec la taille (nombre de phrases, 1, dimension vectorielle = 200, longueur maximale de la phrase).
Comme je l'ai appris pour la première fois, train_test_split de sklearn peut également être utilisé pour les tenseurs à 4 dimensions. Probablement parce que je ne regarde que la première dimension.
"""Divisez en données d'entraînement et en données de test"""
sentence_image_matrix = np.array(sentence_image_matrix,dtype=np.float32)
N = len(sentence_image_matrix)
t_n = 0.33
x_train,x_test,y_train,y_test = train_test_split(sentence_image_matrix,y,test_size=t_n,random_state=123)
Le problème est la définition de CNN. Dans cet article, nous utilisons un filtre asymétrique, et la mise en commun est également asymétrique, nous devons donc en tenir compte.
Alors ça ressemble à ça.
class CNNFiltRow(ChainerClassifier):
"""
Un modèle qui déplace toutes les directions de ligne de CNN dans la direction de colonne en tant que filtre
"""
def _setup_network(self, **params):
self.input_dim = params["input_dim"] #Dimensions par colonne d'une seule image
self.in_channels = params["in_channels"] #input channels : default = 1
self.out_channels = params["out_channels"] #out_channels :Tout
self.row_dim = params["row_dim"] #Dimension de direction de ligne d'une image=Cela devient le nombre de lignes de Filter
self.filt_clm = params["filt_clm"] #Nombre de colonnes de filtre
self.pooling_row = params["pooling_row"] if params.has_key("pooling_row") else 1 #Nombre de lignes de pooling: default = 1
self.pooling_clm = params["pooling_clm"] if params.has_key("pooling_clm") else int(self.input_dim - 2 * math.floor(self.filt_clm/2.)) #Nombre de colonnes de regroupement: default = math.floor((self.input_dim - 2 * math.floor(self.filt_clm/2.))
self.batch_size = params["batch_size"] if params.has_key("batch_size") else 100
self.hidden_dim = params["hidden_dim"]
self.n_classes = params["n_classes"]
self.conv1_out_dim = math.floor((self.input_dim - 2 * math.floor(self.filt_clm/2.))/self.pooling_clm)
network = FunctionSet(
conv1 = F.Convolution2D(self.in_channels,self.out_channels,(self.row_dim,self.filt_clm)), #Made Filter asymétrique
l1=F.Linear(self.conv1_out_dim*self.out_channels, self.hidden_dim),
l2=F.Linear(self.hidden_dim, self.hidden_dim),
l3=F.Linear(self.hidden_dim, self.n_classes),
)
return network
def forward(self, x, train=True):
h = F.max_pooling_2d(F.relu(self.network.conv1(x)), (self.pooling_row,self.pooling_clm))
h1 = F.dropout(F.relu(self.network.l1(h)),train=train)
h2 = F.dropout(F.relu(self.network.l2(h1)),train=train)
y = self.network.l3(h2)
return y
def output_func(self, h):
return F.softmax(h)
def loss_func(self, y, t):
return F.softmax_cross_entropy(y, t)
def fit(self, x_data, y_data):
batchsize = self.batch_size
N = len(y_data)
for loop in range(self.n_iter):
perm = np.random.permutation(N)
sum_accuracy = 0
sum_loss = 0
for i in six.moves.range(0, N, batchsize):
x_batch = x_data[perm[i:i + batchsize]]
y_batch = y_data[perm[i:i + batchsize]]
x = Variable(x_batch)
y = Variable(y_batch)
self.optimizer.zero_grads()
yp = self.forward(x)
loss = self.loss_func(yp,y)
loss.backward()
self.optimizer.update()
sum_loss += loss.data * len(y_batch)
sum_accuracy += F.accuracy(yp,y).data * len(y_batch)
if self.report > 0 and loop % self.report == 0:
print('loop={}, train mean loss={} , train mean accuracy={}'.format(loop, sum_loss / N,sum_accuracy / N))
return self
def fit_test(self, x_data, y_data,x_test,y_test):
batchsize = self.batch_size
N = len(y_data)
Nt = len(y_test)
train_ac = []
test_ac = []
for loop in range(self.n_iter):
perm = np.random.permutation(N)
permt = np.random.permutation(Nt)
sum_accuracy = 0
sum_loss = 0
sum_accuracy_t = 0
"""Phase d'apprentissage"""
for i in six.moves.range(0, N, batchsize):
x_batch = x_data[perm[i:i + batchsize]]
y_batch = y_data[perm[i:i + batchsize]]
x = Variable(x_batch)
y = Variable(y_batch)
self.optimizer.zero_grads()
yp = self.forward(x)
loss = self.loss_func(yp,y)
loss.backward()
self.optimizer.update()
sum_loss += loss.data * len(y_batch)
sum_accuracy += F.accuracy(yp,y).data * len(y_batch)
"""Phase de test"""
for i in six.moves.range(0,Nt,batchsize):
x_batch = x_test[permt[i:i + batchsize]]
y_batch = y_test[permt[i:i + batchsize]]
x = Variable(x_batch)
y = Variable(y_batch)
yp = self.forward(x,False)
sum_accuracy_t += F.accuracy(yp,y).data * len(y_batch)
if self.report > 0 and loop % self.report == 0:
print('loop={}, train mean loss={} , train mean accuracy={} , test mean accuracy={}'.format(loop, sum_loss / N,sum_accuracy / N,sum_accuracy_t / Nt))
train_ac.append(sum_accuracy / N)
test_ac.append(sum_accuracy_t / Nt)
return self,train_ac,test_ac
Veuillez vous référer à Article précédent pour Chainer Classifier.
Je voulais également voir la précision des données de test, j'ai donc ajouté la méthode fit_test.
"""Apprentissage de la ligne de filtre CNN"""
n_iter = 200
report = 5
params = {"input_dim":max_sen_len,"in_channels":1,"out_channels":20,"row_dim":word_dimension,"filt_clm":3,"batch_size":100,"hidden_dim":300,"n_classes":2}
cnn = CNNFiltRow(n_iter=n_iter,report=report,**params)
cnn,train_ac,test_ac = cnn.fit_test(x_train,y_train,x_test,y_test)
Vous trouverez ci-dessous un graphique de la précision pendant l'entraînement et de la précision des données de test. Il semble que le surapprentissage commence à partir d'environ 100. Pourtant, l'impression que les performances de généralisation sont élevées.
Si vous mettez des données de test dans le modèle final et que vous sortez chaque index, ce sera comme suit.
[CNN]P AUC: 0.80 Pres: 0.66 Recl: 0.89 Fscr: 0.76
Le score F était de 0,76 et l'ASC de 0,8, ce qui était plutôt bon.
Faites de même avec Random Forest et MLP (Multilayer Perceptron) comme points de repère. Étant donné que les données d'entrée ne sont pas bidimensionnelles dans ce cas, elles sont corrigées en unidimensionnel comme MNIST.
En conséquence, divers indicateurs pour des données de test similaires sont les suivants.
[RF ]P AUC: 0.71 Pres: 0.65 Recl: 0.60 Fscr: 0.62
[MLP]P AUC: 0.71 Pres: 0.64 Recl: 0.69 Fscr: 0.67
[CNN]P AUC: 0.80 Pres: 0.66 Recl: 0.89 Fscr: 0.76
Cette énorme différence de performance de CNN ...
Recommended Posts