Les réseaux de neurones convolutifs (CNN) sont également utilisés pour le traitement d'image et le traitement du langage naturel, mais pourquoi ne pas le combiner avec un mécanisme d'attention? Alors j'ai essayé.
En termes simples, c'est une fonctionnalité qui vous permet de vous concentrer davantage sur les parties importantes de votre saisie (ici la phrase).
Elle est belle et a un bon style, mais elle a la pire personnalité.
Par exemple, lorsque vous voulez décider de la polarité d'évaluation (positive ou négative) de cette phrase, les êtres humains la jugent négative en regardant la section suivante contenant le pire ''
.
De même, le mécanisme Attention peut mettre davantage l'accent sur la partie pire '' que sur
beauté '', `` (style) bien ''.
Il a été initialement publié en traduction automatique. Traduction automatique neuronale par l'apprentissage conjoint de l'alignement et de la traduction [Bahdanau et al., ICLR2015] Pour ceux qui veulent en savoir plus, l'article ici est facile à comprendre.
Le mécanisme Attention a été utilisé dans diverses tâches de traitement du langage naturel depuis son annonce dans la traduction automatique. Cependant, la plupart d'entre eux sont des méthodes RNN qui appliquent LSTM et GRU. Donc, cette fois, j'ai essayé d'utiliser le mécanisme Attention pour CNN dans la tâche de classification de la polarité d'évaluation. L'évaluation de la classification de la polarité consiste à prédire si une phrase d'entrée a une signification positive ou négative lorsqu'elle est donnée, comme dans l'exemple ci-dessus.
Il est basé sur Convolutional Neural Networks for Sentence Classification [Kim, EMNLP2014].
Introduction d'un mécanisme d'attention à RNN utilisant GRU pour la classification des documents [Hierarchical Attention Networks for Document Classification] (https://www.cs.cmu.edu/~diyiy/docs/naacl16.pdf) [Yang et al., NAACL2016] Je l'ai mentionné. Carte des caractéristiques $ \ boldsymbol {c} \ in \ mathcal {R} ^ {l-k + 1} $
\boldsymbol{c} = [c_1, c_2,\cdots,c_{l-k+1}]
$ l $ est la longueur de la phrase et $ k $ est la taille de la fenêtre. Calcule l'importance dans cette carte de caractéristiques $ \ boldsymbol {c} $. Cette partie est le mécanisme Attention.
\begin{align}
p & = \sum_{i} a_i \odot c_i \\
a_i & = \frac{\exp(W^{(C2)} \tanh(W^{(C1)} c_i))} {\sum_{j} \exp(W^{(C2)} \tanh(W^{(C1)} c_j))}
\end{align}
$ \ Odot $ est le produit d'éléments. $ W ^ {(C1)} \ in \ mathcal {R} ^ {{d} \ times 1} $, $ W ^ {(C2)} \ in \ mathcal {R} ^ {1 \ times {d}} $ D $ dans $ est un hyper paramètre. Quel est ce nom? .. $ a_i $ est calculé pour avoir des nombres réels de 0 à 1, et plus $ a_i $ est proche de 1, plus le $ c_i $ correspondant est important. Un résultat de mise en commun $ p $ est généré par une carte d'entités. À partir de maintenant, c'est le même que le modèle Kim CNN présenté ci-dessus. Combinez plusieurs $ p $, compressez dimensionnellement le vecteur résultant $ v $ et classifiez-le avec un classificateur softmax.
v = p^1\oplus p^2\oplus \cdots p^m
$ m $ est le nombre de cartes de caractéristiques. Ici, il est réglé à 100 comme Kim.
J'ai l'impression d'avoir essayé d'utiliser Attention au lieu de pooling maximum dans la couche de pooling de CNN. Cela ressemble à ceci sur la figure.
Lors de l'utilisation de Attention dans RNN, il calcule l'importance du vecteur de calque caché, C'est un formulaire qui calcule l'importance du scalaire obtenu par pliage (avez-vous des informations ngram?), Donc si cela fonctionnera ou non. .. ..
cnn_attention.py
class CNN_attention(Chain):
def __init__(self, vocab_size, embedding_size, input_channel, output_channel_1, output_channel_2, output_channel_3, k1size, k2size, k3size, pooling_units, atten_size=20, output_size=args.classtype, train=True):
super(CNN_attention, self).__init__(
w2e = L.EmbedID(vocab_size, embedding_size),
conv1 = L.Convolution2D(input_channel, output_channel_1, (k1size, embedding_size)),
conv2 = L.Convolution2D(input_channel, output_channel_2, (k2size, embedding_size)),
conv3 = L.Convolution2D(input_channel, output_channel_3, (k3size, embedding_size)),
l1 = L.Linear(pooling_units, output_size),
#Attention
a1 = L.Linear(1, atten_size),
a2 = L.Linear(atten_size, 1),
)
self.output_size = output_size
self.train = train
self.embedding_size = embedding_size
self.ignore_label = 0
self.w2e.W.data[self.ignore_label] = 0
self.w2e.W.data[1] = 0 #Non-caractère
self.input_channel = input_channel
def initialize_embeddings(self, word2id):
#w_vector = word2vec.Word2Vec.load_word2vec_format('./vector/glove.840B.300d.txt', binary=False) # GloVe
w_vector = word2vec.Word2Vec.load_word2vec_format('./vector/GoogleNews-vectors-negative300.bin', binary=True) # word2vec
for word, id in sorted(word2id.items(), key=lambda x:x[1])[1:]:
if word in w_vector:
self.w2e.W.data[id] = w_vector[word]
else:
self.w2e.W.data[id] = np.reshape(np.random.uniform(-0.25,0.25,self.embedding_size),(self.embedding_size,))
def __call__(self, x):
h_list = list()
ox = copy.copy(x)
if args.gpu != -1:
ox.to_gpu()
x = xp.array(x.data)
x = F.tanh(self.w2e(x))
b, max_len, w = x.shape # batch_size, max_len, embedding_size
x = F.reshape(x, (b, self.input_channel, max_len, w))
c1 = self.conv1(x)
b, outputC, fixed_len, _ = c1.shape
tf = self.set_tfs(ox, b, outputC, fixed_len) # true&flase
h1 = self.attention_pooling(F.relu(c1), b, outputC, fixed_len, tf)
h1 = F.reshape(h1, (b, outputC))
h_list.append(h1)
c2 = self.conv2(x)
b, outputC, fixed_len, _ = c2.shape
tf = self.set_tfs(ox, b, outputC, fixed_len) # true&flase
h2 = self.attention_pooling(F.relu(c2), b, outputC, fixed_len, tf)
h2 = F.reshape(h2, (b, outputC))
h_list.append(h2)
c3 = self.conv3(x)
b, outputC, fixed_len, _ = c3.shape
tf = self.set_tfs(ox, b, outputC, fixed_len) # true&flase
h3 = self.attention_pooling(F.relu(c3), b, outputC, fixed_len, tf)
h3 = F.reshape(h3, (b, outputC))
h_list.append(h3)
h4 = F.concat(h_list)
y = self.l1(F.dropout(h4, train=self.train))
return y
def set_tfs(self, x, b, outputC, fixed_len):
TF = Variable(x[:,:fixed_len].data != 0, volatile='auto')
TF = F.reshape(TF, (b, 1, fixed_len, 1))
TF = F.broadcast_to(TF, (b, outputC, fixed_len, 1))
return TF
def attention_pooling(self, c, b, outputC, fixed_len, tf):
reshaped_c = F.reshape(c, (b*outputC*fixed_len, 1))
scala = self.a2(F.tanh(self.a1(reshaped_c)))
reshaped_scala = F.reshape(scala, (b, outputC, fixed_len, 1))
reshaped_scala = F.where(tf, reshaped_scala, Variable(-10*xp.ones((b, outputC, fixed_len, 1)).astype(xp.float32), volatile='auto'))
rereshaped_scala = F.reshape(reshaped_scala, (b*outputC, fixed_len)) # reshape for F.softmax
softmax_scala = F.softmax(rereshaped_scala)
atten = F.reshape(softmax_scala, (b*outputC*fixed_len, 1))
a_h = F.scale(reshaped_c, atten, axis=0)
reshaped_a_h = F.reshape(a_h, (b, outputC, fixed_len, 1))
p = F.sum(reshaped_a_h, axis=2)
return p
Nous avons utilisé SST pour comparer le taux de précision de la classification avec la mise en commun maximale. Nous avons expérimenté deux tâches: SST-5, qui classe les cinq valeurs de très négatif, négatif, neutre, positif et très positif, et SST-2, qui classe le positif et le négatif sans neutre.
method | SST-2 | SST-5 |
---|---|---|
max | 86.3 (0.27) | 46.5 (1.13) |
attention | 86.0 (0.20) | 47.2 (0.37) |
La valeur est la valeur moyenne essayée 5 fois et la valeur entre parenthèses est l'écart type. Il faut faire attention pour la classification à 5 valeurs, mais le résultat est que la valeur 2 ne change pas beaucoup. À propos, la valeur maximale (SST-5) sur 5 était de 48,2% pour la mise en commun maximale et de 47,7% pour Attention, ce qui est mieux pour la mise en commun maximale. C'est juste facile à secouer. .. ..
Si vous examinez de plus près comment se trouve Attention dans la carte des caractéristiques, Il s'est avéré que l'un d'entre eux était fortement accentué par environ 0,9, et les autres étaient presque 0, ce qui était similaire à la mise en commun maximale. Cependant, contrairement à la mise en commun maximale, la valeur de l'ensemble de la carte des caractéristiques est prise en considération, je me demande donc s'il est difficile de faire une erreur. .. ..
Intuitivement, j'ai senti que Attention, qui examine l'importance globale, est meilleur que le pooling max, qui n'utilise que la valeur maximale. Ce n'est pas mal car la précision de la classification à 5 valeurs est supérieure à celle de la classification à 2 valeurs. .. Je pense que cela dépend de la tâche, alors j'aimerais également essayer d'autres tâches.
L'article ici présente également la classification de texte à l'aide de CNN d'une manière facile à comprendre.