利用深度学习获得文本特征¶
让我们试着对文本做同样的事?
我们将使用现成的文字表达式模型-Word2Vec模型。就像之前的VGGnet一样,这个模型可以获得有意义的表达式。由于单词总数很小,我们甚至不需要通过网络来传递我们的样本。即使这样我们也做了,并且将结果以字典的形式保存。我们可以简单的通过查询字典获取单词的Word2Vec特征。
你可以在这下载字典-https://drive.google.com/file/d/0B7XkCwpI5KDYNlNUTTlSS21pQmM/edit
下载字典到当前同级目录下。
from gensim import models
# model2 = models.Word2Vec.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)
model2 = models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)
现在我们只需要简单的从上面的模型中查找单词就行了。比方说,我们要获取单词“King”的Word2Vec特征值只需要查找-model2[‘king’]
print model2['king'].shape
print model2['dog'].shape
(300,)
(300,)
这样一来,我们就能用这个word2vec模型代表我们概述中的单词了。然后我们可以以此作为我们的X参数。因此,我们使用的是基于单词语义表示的表示,而不是字数。从数学上讲,每个单词可以从3-4维(长度)到300维!
对于上面的电影数据集,我们试试通过概述内容预测一下类型!
len(final_movies_set)
1265
from nltk.tokenize import RegexpTokenizer
from stop_words import get_stop_words
tokenizer = RegexpTokenizer(r'\w+')
# create English stop words list
en_stop = get_stop_words('en')
movie_mean_wordvec=np.zeros((len(final_movies_set),300))
movie_mean_wordvec.shape
(1265,300)
这样,我们就可以使用这个word2vec模型来表示概述中的单词。然后,我们可以用它作为x表示。因此,我们使用的是基于单词语义表示的表示,而不是字数。从数学上讲,每个单词从3-4维(长度)到300维!
对于上面的同一组电影,让我们试着从它们的概述的深层表现来预测类型!
len(final_movies_set)
1265
from nltk.tokenize import RegexpTokenizer
from stop_words import get_stop_words
tokenizer = RegexpTokenizer(r'\w+')
# create English stop words list
en_stop = get_stop_words('en')
movie_mean_wordvec=np.zeros((len(final_movies_set),300))
movie_mean_wordvec.shape
(1265,300)
在我们对文本训练模型之前需要做一些预处理。我们要做的唯一的事就是——删除我们知道的没有特殊含义的常见单词。某种意义上来说,这对我们来说就是噪音。这些单词经常被删除并且被称为“stop words”。你可以在网上查到他们。其中包括“a”、“and”、“but”、“how”、“or”等简单单词。使用python包nltk可以很容易地删除它们。
在上述数据集中,仅包含“stop words”的电影概述的电影和仅有word2vec表达式的概述的电影会被忽略。其余的被用于构建我们的Mean word2vec表达式。简单来说,对每部电影概述——
- 获取电影概述
- 删掉其中的stop words
- 如果属于word2vec 那么取它的300维的word2vec标识
- 如果不是 输出单词
- 对每部电影来说,对所有概述中没有被输出的单词计算300维向量表达式的平均值
这意味着它将成为电影的300维表示。对于所有电影,这些都存储在一个numpy数组中。因此X矩阵变成(1263,300),而且Y变成(1263,20),也就是说之前说过的二值化的20中类型。
为什么取算术平均数?如果你觉得我们应该把所有的单词分开——那么你的想法是正确的,但遗憾的是,我们受到了当今神经网络工作方式的限制。我不会考虑这个问题,因为担心在其他不相关的细节上压力过大。但如果你感兴趣,请阅读这篇精彩的论文-https://jiajunwu.com/papers/dmil_cvpr.pdf
genres=[]
rows_to_delete=[]
for i in range(len(final_movies_set)):
mov=final_movies_set[i]
movie_genres=mov['genre_ids']
genres.append(movie_genres)
overview=mov['overview']
tokens = tokenizer.tokenize(overview)
stopped_tokens = [k for k in tokens if not k in en_stop]
count_in_vocab=0
s=0
if len(stopped_tokens)==0:
rows_to_delete.append(i)
genres.pop(-1)
# print overview
# print "sample ",i,"had no nonstops"
else:
for tok in stopped_tokens:
if tok.lower() in model2.vocab:
count_in_vocab+=1
s+=model2[tok.lower()]
if count_in_vocab!=0:
movie_mean_wordvec[i]=s/float(count_in_vocab)
else:
rows_to_delete.append(i)
genres.pop(-1)
# print overview
# print "sample ",i,"had no word2vec"
len(genres)
1261
mask2=[]
for row in range(len(movie_mean_wordvec)):
if row in rows_to_delete:
mask2.append(False)
else:
mask2.append(True)
X=movie_mean_wordvec[mask2]
X.shape
(1261,300)
Y=mlb.fit_transform(genres)
Y.shape
(1261,20)
textual_features=(X,Y)
f9=open('textual_features.pckl','wb')
pickle.dump(textual_features,f9)
f9.close()
# textual_features=(X,Y)
f9=open('textual_features.pckl','rb')
textual_features=pickle.load(f9)
f9.close()
(X,Y)=textual_features
X.shape
(1261,300)
Y.shape
(1261,20)
mask_text=np.random.rand(len(X))<0.8
X_train=X[mask_text]
Y_train=Y[mask_text]
X_test=X[~mask_text]
Y_test=Y[~mask_text]
我们再一次使用与之前相似的那种简单架构
from keras.models import Sequential
from keras.layers import Dense, Activation
model_textual = Sequential([
Dense(300, input_shape=(300,)),
Activation('relu'),
Dense(20),
Activation('softmax'),
])
model_textual.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
model_textual.fit(X_train, Y_train, epochs=10, batch_size=500)
Epoch 1/10
982/982 [==============================] - 0s - loss: 0.4819 - acc: 0.8520
Epoch 2/10
982/982 [==============================] - 0s - loss: 0.4642 - acc: 0.8520
Epoch 3/10
982/982 [==============================] - 0s - loss: 0.4527 - acc: 0.8520
Epoch 4/10
982/982 [==============================] - 0s - loss: 0.4456 - acc: 0.8520
Epoch 5/10
982/982 [==============================] - 0s - loss: 0.4407 - acc: 0.8520
Epoch 6/10
982/982 [==============================] - 0s - loss: 0.4367 - acc: 0.8520
Epoch 7/10
982/982 [==============================] - 0s - loss: 0.4332 - acc: 0.8520
Epoch 8/10
982/982 [==============================] - 0s - loss: 0.4295 - acc: 0.8520
Epoch 9/10
982/982 [==============================] - 0s - loss: 0.4260 - acc: 0.8520
Epoch 10/10
982/982 [==============================] - 0s - loss: 0.4227 - acc: 0.8520
<keras.callbacks.History at 0x4e27e3850>
model_textual.fit(X_train, Y_train, epochs=10000, batch_size=500,verbose=0)
<keras.callbacks.History at 0x4e27e3a10>
score = model_textual.evaluate(X_test, Y_test, batch_size=249)
249/279 [=========================>….] - ETA: 0s
print("%s: %.2f%%" % (model_textual.metrics_names[1], score[1]*100))
acc: 86.52%
Y_preds=model_textual.predict(X_test)
genre_list.append(10769)
print "Our predictions for the movies are - \n"
precs=[]
recs=[]
for i in range(len(Y_preds)):
row=Y_preds[i]
gt_genres=Y_test[i]
gt_genre_names=[]
for j in range(20):
if gt_genres[j]==1:
gt_genre_names.append(Genre_ID_to_name[genre_list[j]])
top_3=np.argsort(row)[-3:]
predicted_genres=[]
for genre in top_3:
predicted_genres.append(Genre_ID_to_name[genre_list[genre]])
(precision,recall)=precision_recall(gt_genre_names,predicted_genres)
precs.append(precision)
recs.append(recall)
if i%50==0:
print "Predicted: ",predicted_genres," Actual: ",gt_genre_names
Our predictions for the movies are -
Predicted: [u’Science Fiction’, u’Action’, u’Adventure’] Actual: [u’Adventure’, u’Action’, u’Comedy’, u’Romance’]
Predicted: [u’Thriller’, u’Crime’, u’Mystery’] Actual: [u’Drama’, u’Thriller’, u’Science Fiction’]
Predicted: [u’Action’, u’Crime’, u’Thriller’] Actual: [u’Adventure’, u’Action’, u’Comedy’, u’Thriller’, u’Crime’]
Predicted: [u’Family’, u’Horror’, u’Comedy’] Actual: [u’Horror’, u’Action’, u’Thriller’]
Predicted: [u’Crime’, u’Thriller’, u’Drama’] Actual: [u’Action’, u’Science Fiction’]
Predicted: [u’Drama’, u’Thriller’, u’Mystery’] Actual: [u’Drama’, u’Thriller’, u’Mystery’, u’Romance’]
print np.mean(np.asarray(precs)),np.mean(np.asarray(recs))
0.519713261649 0.563918757467
即使对上面的模型没有太多调整,这些结果也能够超越我们之前的结果。
注-当我对从维基百科中的爬取的情节进行分类时,我的准确率高达78%。大量的信息非常适合用深度模型对电影类型进行分类。强烈建议您尝试使用这种架构。