本文介绍了三种无监督的深度学习表示句子的方法:自编码器、语言模型和Skip-think向量模型,并与基线模型AverageWord2Vec进行了比较。
近年来,由于用连续向量代替稀疏的一热编码向量(Word2Vec)来表示单词的发展,使得在自然语言处理领域的性能有了很大的提高。
Word2Vec示例
虽然word2vec性能很好,创造了非常好的语义,比如King-ManWoman=Queen,但是我们有时候不';我不在乎词语的表达。,而是句子的表征。
本文将介绍几种无监督的句子表示深度学习方法,并分享相关代码。我们将在具体的文本分类任务中展示这些方法作为预处理步骤的效果。
分类任务
用于显示不同句子表示方法的数据基于从万维网抓取的10,000篇新闻文章。分类任务是将每篇文章分类到10个可能的主题中的一个(数据有主题标签,所以这是一个监督任务)。出于演示目的。我会用一个逻辑回归模型,每次都用不同的预处理方法来处理文章标题。基线模型——平均word2vec
我们从一个简单的基线模型开始。。我们将通过要求标题词的Word2Vec表的平均值来表征文章的标题。如前所述,Word2Vec是一种将单词表示为向量的机器学习方法。。利用浅层神经网络训练Word2Vec模型,预测与目标词接近的词。你可以阅读更多关于这个算法是如何工作的。
我们可以使用Gensim来训练我们自己的Word2Vec模型,但在这个示例中,我们将使用Google预先训练的Word2Vec模型,该模型基于Google新闻数据。。在将每个单词表示为一个向量后,我们将一个句子(文章标题)表示为其单词(向量)的平均值,然后运行logistic回归对文章进行分类。
#加载数据和Word2vec模型
df=PD。read_CSV(';新闻_数据集。CSV')
data=df[[';正文';'头条';'类别';]]
w2v=gensim。模特。键控向量。load_word2vec_format(';/谷歌新闻-向量-负300。斌';二进制=真)
#内部版本X和Y
X=NP。随机的。rand(len(data),300)
用于范围内的I(len(data)):
k=0
non=0
值=NP。零(300)
用于数据中的j[';头条';]。国际劳工组织.拆分(';):
如果w2v中的j:
值=w2v[j]
k=1
ifk
0:
x[I,]=values/k
else:non=1
y=LabelEncoder().fit_transform(data[';类别';]。值)
MSK=NP。随机的。rand(len(data))0.8X_train,y_train,X_test,y_test=x[msk],y[msk],x[~msk],y[~MSK]
#训练模型
lr=LogisticRegression().拟合(X_train,y_train)
lr。score(X_test,y_test)
我们的基线平均Word2Vec模型达到了68%的准确率。这很好,所以让';让我们看看是否能做得更好。
一般的word2vec方法有两个弱点:它是词袋模型,与词序无关,所有词的权重都一样。对于句子表示我们将使用RNN架构以下列方法解决这些问题。
自编码器
自编码器是一种无监督的深度学习模型,它试图将自己的输入复制到输出中。。自编码器的诀窍在于中间隐藏层的维数低于输入数据的维数。因此,这种神经网络必须以一种智能和紧凑的方式来表示输入,以完成成功的重构。在许多情况下,使用自编码器的特征提取被证明是非常有效的。
我们的自编码器是一个简单的序列到序列结构,由输入层、嵌入层、LSTM层和softmax层组成。整个结构的输入和输出都是标题。我们将使用LSTM的输出来描述标题。在获得自编码器的表征之后,我们将使用逻辑回归来预测类别。为了得到更多的数据,我们将使用文章中的所有句子来训练自编码器,而不仅仅是文章的标题。
#解析所有句子
senses=[]
forIindata[';正文';]。值:
nltk.sent_tokenize(i)中j的:
句子。append(j)
#keras的预处理
num_words=2000
maxlen=20
Tokenizer=Tokenizer(num_words=num_words,split='')
记号赋予器。fit_on_texts(sentenses)
seqs=tokenizer。文本到序列(句子)
seqs中I的pad_seqs=[]
iflen(I)
4:
pad_seqs。追加(I)
pad_seqs=pad_sequences(pad_seqs,maxlen)
#型号
embed_dim=150
latent_dim=128
batch_size=64
###编码器型号###
Encoder_inputs=Input(shape=(maxlen,),name='编码器-输入';)
emb_layer=Embedding(num_words,embed_dim,input_length=maxlen,name='body-Word-Embedding';mask_zero=False)
#Encoderembeddedword(e.g.publishedtext)
x=emb_layer(encoder_inputs)
state_h=GRU(latent_dim,name='编码器-最后一个-GRU';)(x)
Encoder_Model=Model(inputs=Encoder_inputs,outputs=state_h,name='编码器-型号';)
序列2seq_encoder_out=encoder_Model(encoder_inputs)
###解码器型号###
解码=重复向量(最大长度)(序列2seq_encoder_out)
Decoder_gru=GRU(latent_dim,return_sequences=True,name='解码器-GRU-之前';)
decoder_gru_output=decoder_gru(已解码)
decoder_Dense=Dense(num_words,activation='softmax',name='最终输出-密集-之前';)
decoder_outputs=decoder_dense(decoder_gru_output)
####seqModel###
#seq2seq_decoder_out=decoder_model([decoder_inputs,seq2seq_encoder_out])
seq2seq_Model=Model(encoder_input,decoder_output)
序列2序列_模型。编译(优化器=优化器.那达慕(lr=0.001),loss='稀疏_分类_交叉熵')
历史记录=序列2序列_模型。fit(pad_seqs,np.expand_dims(pad_seqs,-1),
batch_size=batch_size,
epoch=5,
validation_split=0.12]
#特征提取
headlines=tokenizer。texts_to_sequences(数据[';头条';]。值)
headlines=pad_sequences(headlines,maxlen=maxlen)x=encoder_model。预测(头条)
#分类器
X_train,y_train,X_test,y_test=x[msk],y[msk],x[~msk],y[~msk]
lr=LogisticRegression().拟合(X_train,y_train)
lr。score(X_test,y_test)
我们实现了60%的准确率它比基线模型更差。我们可以通过优化超参数、增加训练历元数或在更多数据上训练模型来提高分数。
语言模型
我们的第二个方法是训练语言模型来表示句子。。语言模型描述了一段文本以某种语言存在的概率。例如,句子"我喜欢吃香蕉。比句子"我喜欢吃油炸圈饼。。我们通过划分n个单词的窗口并预测文本中的下一个单词来训练语言模型。你可以在这里了解更多关于基于RNN的语言模型。通过建立一个语言模型我们知道新闻英语是如何建立的,这个模式应该集中在重要的词和它们的表达上。
我们的架构类似于自编码器,但我们只预测一个字,而不是一个字序列。输入将包含一个由新闻文章中的20个单词组成的窗口,标签为第21个单词。在训练语言模型之后我们将从LSTM的输出隐藏状态中得到标题表示,然后运行逻辑回归模型来预测类别。
#X楼和Y楼
num_words=2000
maxlen=20
Tokenizer=Tokenizer(num_words=num_words,split='')
记号赋予器。fit_on_texts(df[';正文';]。值)
seqs=tokenizer。texts_to_sequences(df[';正文';]。序列中我的值)
seq=[]
:
tqdm中I的seq=I
X=[]
Y=[]
(range(len(seq)-maxlen-1)):
X.append(seq[I:Imaxlen])
y.append(seq[Imaxlen1])
X=PD.数据帧(X)
Y=pd.数据帧(Y)Y[0]=Y[0].astype(';类别';)
Y=PD。get_dummies(Y)
#构建网络
embed_dim=150
lstm_out=128
batch_size=128
模型=顺序()
模型。add(Embedding(num_words,embed_dim,input_length=maxlen))
model.add(双向(LSTM(lstm_out)))
模型。add(Dense(y.shape[1],activation='softmax'))
Adam=Adam(lr=0.001,beta_1=0.7,beta_2=0.99,epsilon=None,decay=0.0,amsgrad=False)
型号。编译(loss='类别_交叉熵';optimizer=Adam)
模型。summary()
打印(';飞腾';)
型号。fit(X,Y,batch_size=batch_size,validation_split=0.1,epochs=5,verbose=1)
#特征提取
headlines=tokenizer。texts_to_sequences(数据[';头条';]。值)
headlines=pad_sequences(headlines,maxlen=maxlen)
InP=model。输入
输出=[model.layers[1].输出]
函子=k.function([InP][k.learning_phase()],outputs)
x=函子([headlines,1.])[0]
#分类器
X_train,y_train,X_test,y_test=x[msk],y[msk],x[~msk],y[~msk]
lr=LogisticRegression().拟合(X_train,y_train)
lr。score(X_test,y_test)
这次我们获得了72%的准确率,比基线模型要好。我们能做得更好吗?跳过思维向量模型
在2015年关于skip-thought的论文《Skip-ThoughtVectors》中,作者从语言模型中得到了同样的直观认识。然而,在跳跃思维中,我们不';不要预测下一个单词,而是预测前后的句子。这给了模型更多关于句子的上下文,因此我们可以构造更好的句子表示。你可以阅读这个博客来了解更多关于这个模型的信息。
skip-thoughtpaper中的例子]
我们将构造一个类似于自编码器的序列到序列结构,但它与自编码器有两个主要区别。第一我们有两个LSTM输出层:一个用于上一句,一个用于下一句;第二,我们将在输出LSTM时使用教师强制。。这意味着我们不仅为输出LSTM提供先前的隐藏状态,还提供实际的先前单词(参见上图中的输入和输出的最后一行)。
#构建x和y
num_words=2000
maxlen=20
Tokenizer=Tokenizer(num_words=num_words,split='')
记号赋予器。fit_on_texts(sentenses)
seqs=tokenizer。文本到序列(句子)
pad_seqs=pad_sequences(seqs,maxlen)
x_skip=[]
y_before=[]
y_after=[]tqdm中我的
(range(1,len(seqs)-1)):
iflen(seqs[I])
4:
x_skip。append(pad_seqs[I].tolist())
y_before。append(pad_seqs[I-1]).tolist())
y_after。append(pad_seqs[I1].tolist())
x_before=NP。矩阵([[0]I[:-1]forIiny_before])
x_after=NP。矩阵([[0]I[:-1]forIiny_after])
x_skip=NP。矩阵(x_skip)
y_before=NP。matrix(y_before)
y_after=NP。matrix(y_after)
#建立模型
embed_dim=150
latent_dim=128
batch_size=64
###编码器型号###
Encoder_inputs=Input(shape=(maxlen,),name='编码器-输入';)
emb_layer=Embedding(num_words,embed_dim,input_length=maxlen,name='body-Word-Embedding';mask_zero=False)
x=emb_layer(编码器_输入)
_,state_h=GRU(latent_dim,return_state=True,name='编码器-最后-GRU';)(x)
Encoder_Model=Model(inputs=Encoder_inputs,outputs=state_h,name='编码器-型号';)
序列2seq_encoder_out=encoder_Model(encoder_inputs)
###解码器型号###
Decoder_inputs_before=Input(shape=(None,),name='解码器-输入-之前';)#用于教师强制
dec_emb_before=emb_layer(decoder_inputs_before)
Decoder_gru_before=GRU(latent_dim,return_state=True,return_sequences=True,name='解码器-GRU-之前';)
decoder_gru_output_before,_=decoder_gru_before(dec_emb_before,initial_state=seq2seq_编码器_out)
decoder_Dense_before=Dense(num_words,activation='softmax',name='最终输出-密集-之前';)
Beforedecoder_output_=beforedecoder_dense_(beforedecoder_gru_output_)
Decoder_inputs_after=Input(shape=(None,),name='解码器输入后';)#对于老师逼问
dec_emb_after=emb_layer(decoder_inputs_after)
Decoder_gru_after=GRU(latent_dim,return_state=True,return_sequences=True,name='解码器-GRU-后';)
decoder_gru_output_after,_=decoder_gru_after(dec_emb_after,initial_state=seq2seq_编码器_out)
decoder_Dense_after=Dense(num_words,activation='softmax',name='最终输出密集后';)
Afterdecoder_output_=Afterdecoder_dense_(afterdecoder_gru_output_)
####序号型号###
seq2seq_Model=Model([encoder_input,decoder_input_before,decoder_input_after],[decoder_output_before,decoder_output_after])
序列2序列_模型。编译(优化器=优化器.那达慕(lr=0.001),loss='稀疏_分类_交叉熵')
序列2序列_模型。summary()
历史=序列2序列_模型。fit([x_skip,x_before,x_after],[np.expand_dims(y_before,-1),np.expand_dims(y_after,-1)],
batch_size=batch_size,
epochs=10,
validation_split=0.12]
#特征提取
headlines=tokenizer。texts_to_sequences(数据[';头条';]。值)
headlines=pad_sequences(headlines,maxlen=maxlen)x=encoder_model。预测(头条)
#分类器
X_train,y_train,X_test,y_test=x[msk],y[msk],x[~msk],y[~msk]
lr=LogisticRegression().拟合(X_train,y_train)
lr。score(X_test,y_test)
这一次,我们达到了74%的准确率。这是目前为止最好的准确率。
摘要
在本文中,我们介绍了三种使用RNN创建句子向量表示的无监督方法。并且在解决一个监督任务的过程中,他们显示了自己的效率。自编码器的结果比我们的基线模型差(这可能是因为使用的数据集相对较小)。跳过思维向量模型语言模型都使用上下文来预测句子表示。并得到最好的结果。
可以提高我们展示的方法的性能的可用方法有:调整超参数、训练更多的历元时间、使用预训练嵌入矩阵、改变神经网络架构等等。理论上这些高级调整可能会在一定程度上改变结果。不过我觉得利用上面分享的例子就可以实现对每种预处理方法的基本直观认识。
- 版权所属:理财信息网
- 文章作者:angula
- 本文地址:http://www.bjbookbinding.com/qhjj/1517.html
- 版权声明:版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 931614094@qq.com 举报,一经查实,本站将立刻删除。