CICC科普欄目 |簡述表徵句子的3種無監督深度學習方法

2021-02-21 中國指揮與控制學會

選自Medium

作者:yonatan hadar

機器之心編譯

轉自:機器之心

參與:Nurhachu Null、路

本文介紹了三種用於表徵句子的無監督深度學習方法:自編碼器、語言模型和 Skip-Thought 向量模型,並與基線模型 Average Word2Vec 進行了對比。

近年來,由於用連續向量表示詞語(而不是用稀疏的 one-hot 編碼向量(Word2Vec))技術的發展,自然語言處理領域的性能獲得了重大提升。

Word2Vec 示例

儘管 Word2Vec 性能不錯,並且創建了很不錯的語義,例如 King - Man + Woman = Queen,但是我們有時候並不在意單詞的表徵,而是句子的表徵。

本文將介紹幾個用於句子表徵的無監督深度學習方法,並分享相關代碼。我們將展示這些方法在特定文本分類任務中作為預處理步驟的效果。

分類任務

用來展示不同句子表徵方法的數據基於從全球資訊網抓取的 10000 篇新聞類文章。分類任務是將每篇文章歸類為 10 個可能的主題之一(數據具備主題標籤,所以這是一個有監督的任務)。為了便於演示,我會使用一個 logistic 回歸模型,每次使用不同的預處理表徵方法處理文章標題。

基線模型——Average Word2Vec

我們從一個簡單的基線模型開始。我們會通過對標題單詞的 Word2Vec 表徵求平均來表徵文章標題。正如之前提及的,Word2Vec 是一種將單詞表徵為向量的機器學習方法。Word2Vec 模型是通過使用淺層神經網絡來預測與目標詞接近的單詞來訓練的。你可以閱讀更多內容來了解這個算法是如何運行的:http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/。

我們可以使用 Gensim 訓練我們自己的 Word2Vec 模型,但是在這個例子中我們會使用一個 Google 預訓練 Word2Vec 模型,它基於 Google 的新聞數據而建立。在將每一個單詞表徵為向量後,我們會將一個句子(文章標題)表徵為其單詞(向量)的均值,然後運行 logistic 回歸對文章進行分類。

#load data and Word2vec model
df = pd.read_csv("news_dataset.csv")
data = df[['body','headline','category']]
w2v = gensim.models.KeyedVectors.load_word2vec_format('/GoogleNews-vectors-negative300.bin', binary=True)
#Build X and Y
x = np.random.rand(len(data),300)
for i in range(len(data)):
   k = 0
   non = 0
   values = np.zeros(300)
   for j in data['headline'].iloc[i].split(' '):
       if j in w2v:
           values+= w2v[j]
           k+=1
   if k > 0:
       x[i,:]=values/k
   else: non+=1
y = LabelEncoder().fit_transform(data['category'].values)
msk = np.random.rand(len(data)) < 0.8
X_train,y_train,X_test,y_test = x[msk],y[msk],x[~msk],y[~msk]
#Train the model
lr = LogisticRegression().fit(X_train,y_train)
lr.score(X_test,y_test)

我們的基線 average Word2Vec 模型達到了 68% 的準確率。這很不錯了,那麼讓我們來看一看能不能做得更好。

average Word2Vec 方法有兩個弱點:它是詞袋模型(bag-of-words model),與單詞順序無關,所有單詞都具備相同的權重。為了進行句子表徵,我們將在下面的方法中使用 RNN 架構解決這些問題。

自編碼器

自編碼器是一種無監督深度學習模型,它試圖將自己的輸入複製到輸出。自編碼器的技巧在於中間隱藏層的維度要低於輸入數據的維度。所以這種神經網絡必須以一種聰明、緊湊的方式來表徵輸入,以完成成功的重建。在很多情況下,使用自編碼器進行特徵提取被證明是非常有效的。

我們的自編碼器是一個簡單的序列到序列結構,由一個輸入層、一個嵌入層、一個 LSTM 層,以及一個 softmax 層組成。整個結構的輸入和輸出都是標題,我們將使用 LSTM 的輸出來表徵標題。在得到自編碼器的表徵之後,我們將使用 logistics 回歸來預測類別。為了得到更多的數據,我們會使用文章中所有句子來訓練自編碼器,而不是僅僅使用文章標題。

#parse all sentences
sentenses = []
for i in data['body'].values:
   for j in nltk.sent_tokenize(i):
       sentenses.append(j)
#preprocess for keras
num_words=2000
maxlen=20
tokenizer = Tokenizer(num_words = num_words, split=' ')
tokenizer.fit_on_texts(sentenses)
seqs = tokenizer.texts_to_sequences(sentenses)
pad_seqs = []
for i in seqs:
   if len(i)>4:
       pad_seqs.append(i)
pad_seqs = pad_sequences(pad_seqs,maxlen)
#The model
embed_dim = 150
latent_dim = 128
batch_size = 64
#### Encoder Model ####
encoder_inputs = Input(shape=(maxlen,), name='Encoder-Input')
emb_layer = Embedding(num_words, embed_dim,input_length = maxlen, name='Body-Word-Embedding', mask_zero=False)
# Word embeding for encoder (ex: Issue Body)
x = emb_layer(encoder_inputs)
state_h = GRU(latent_dim, name='Encoder-Last-GRU')(x)
encoder_model = Model(inputs=encoder_inputs, outputs=state_h, name='Encoder-Model')
seq2seq_encoder_out = encoder_model(encoder_inputs)
#### Decoder Model ####
decoded = RepeatVector(maxlen)(seq2seq_encoder_out)
decoder_gru = GRU(latent_dim, return_sequences=True, name='Decoder-GRU-before')
decoder_gru_output = decoder_gru(decoded)
decoder_dense = Dense(num_words, activation='softmax', name='Final-Output-Dense-before')
decoder_outputs = decoder_dense(decoder_gru_output)
#### Seq2Seq Model ####
#seq2seq_decoder_out = decoder_model([decoder_inputs, seq2seq_encoder_out])
seq2seq_Model = Model(encoder_inputs,decoder_outputs )
seq2seq_Model.compile(optimizer=optimizers.Nadam(lr=0.001), loss='sparse_categorical_crossentropy')
history = seq2seq_Model.fit(pad_seqs, np.expand_dims(pad_seqs, -1),
         batch_size=batch_size,
         epochs=5,
         validation_split=0.12)
#Feature extraction
headlines = tokenizer.texts_to_sequences(data['headline'].values)
headlines = pad_sequences(headlines,maxlen=maxlen)x = encoder_model.predict(headlines)
#classifier
X_train,y_train,X_test,y_test = x[msk],y[msk],x[~msk],y[~msk]
lr = LogisticRegression().fit(X_train,y_train)
lr.score(X_test,y_test)

我們實現了 60% 的準確率,比基線模型要差一些。我們可能通過優化超參數、增加訓練 epoch 數量或者在更多的數據上訓練模型,來改進該分數。

語言模型

我們的第二個方法是訓練語言模型來表徵句子。語言模型描述的是某種語言中一段文本存在的概率。例如,「我喜歡吃香蕉」(I like eating bananas)這個句子會比「我喜歡吃卷積」(I like eating convolutions)這個句子具備更高的存在概率。我們通過分割 n 個單詞組成的窗口以及預測文本中的下一個單詞來訓練語言模型。你可以在這裡了解到更多基於 RNN 的語言模型的內容:http://karpathy.github.io/2015/05/21/rnn-effectiveness/。通過構建語言模型,我們理解了「新聞英語」(journalistic English)是如何建立的,並且模型應該聚焦於重要的單詞及其表徵。

我們的架構和自編碼器的架構是類似的,但是我們只預測一個單詞,而不是一個單詞序列。輸入將包含由新聞文章中的 20 個單詞組成的窗口,標籤是第 21 個單詞。在訓練完語言模型之後,我們將從 LSTM 的輸出隱藏狀態中得到標題表徵,然後運行 logistics 回歸模型來預測類別。

#Building X and Y
num_words=2000
maxlen=20
tokenizer = Tokenizer(num_words = num_words, split=' ')
tokenizer.fit_on_texts(df['body'].values)
seqs = tokenizer.texts_to_sequences(df['body'].values)
seq = []
for i in seqs:
   seq+=i

X = []
Y = []
for i in tqdm(range(len(seq)-maxlen-1)):
   X.append(seq[i:i+maxlen])
   Y.append(seq[i+maxlen+1])
X = pd.DataFrame(X)
Y = pd.DataFrame(Y)
Y[0]=Y[0].astype('category')
Y =pd.get_dummies(Y)
#Buidling the network
embed_dim = 150
lstm_out = 128
batch_size= 128
model = Sequential()
model.add(Embedding(num_words, embed_dim,input_length = maxlen))
model.add(Bidirectional(LSTM(lstm_out)))
model.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)
model.compile(loss = 'categorical_crossentropy', optimizer=adam)
model.summary()
print('fit')
model.fit(X, Y, batch_size =batch_size,validation_split=0.1, epochs = 5,  verbose = 1)
#Feature extraction
headlines = tokenizer.texts_to_sequences(data['headline'].values)
headlines = pad_sequences(headlines,maxlen=maxlen)
inp = model.input                                          
outputs = [model.layers[1].output]      
functor = K.function([inp]+ [K.learning_phase()], outputs )
x = functor([headlines, 1.])[0]
#classifier
X_train,y_train,X_test,y_test = x[msk],y[msk],x[~msk],y[~msk]
lr = LogisticRegression().fit(X_train,y_train)
lr.score(X_test,y_test)

這一次我們得到了 72% 的準確率,要比基線模型好一些,那我們能否讓它變得更好呢?

Skip-Thought 向量模型

在 2015 年關於 skip-thought 的論文《Skip-Thought Vectors》中,作者從語言模型中獲得了同樣的直覺知識。然而,在 skip-thought 中,我們並沒有預測下一個單詞,而是預測之前和之後的句子。這給模型關於句子的更多語境,所以,我們可以構建更好的句子表徵。您可以閱讀這篇博客(https://medium.com/@sanyamagarwal/my-thoughts-on-skip-thoughts-a3e773605efa),了解關於這個模型的更多信息。

skip-thought 論文中的例子(https://arxiv.org/abs/1506.06726)

我們將構造一個類似於自編碼器的序列到序列結構,但是它與自編碼器有兩個主要的區別。第一,我們有兩個 LSTM 輸出層:一個用於之前的句子,一個用於下一個句子;第二,我們會在輸出 LSTM 中使用教師強迫(teacher forcing)。這意味著我們不僅僅給輸出 LSTM 提供了之前的隱藏狀態,還提供了實際的前一個單詞(可在上圖和輸出最後一行中查看輸入)。

#Build x and y
num_words=2000
maxlen=20
tokenizer = Tokenizer(num_words = num_words, split=' ')
tokenizer.fit_on_texts(sentenses)
seqs = tokenizer.texts_to_sequences(sentenses)
pad_seqs = pad_sequences(seqs,maxlen)
x_skip = []
y_before = []
y_after = []
for i in tqdm(range(1,len(seqs)-1)):
   if len(seqs[i])>4:
       x_skip.append(pad_seqs[i].tolist())
       y_before.append(pad_seqs[i-1].tolist())
       y_after.append(pad_seqs[i+1].tolist())
x_before = np.matrix([[0]+i[:-1] for i in y_before])
x_after =np.matrix([[0]+i[:-1] for i in y_after])
x_skip = np.matrix(x_skip)
y_before = np.matrix(y_before)
y_after = np.matrix(y_after)
#Building the model

embed_dim = 150
latent_dim = 128
batch_size = 64
#### Encoder Model ####
encoder_inputs = Input(shape=(maxlen,), name='Encoder-Input')
emb_layer = Embedding(num_words, embed_dim,input_length = maxlen, name='Body-Word-Embedding', mask_zero=False)
x = emb_layer(encoder_inputs)
_, state_h = GRU(latent_dim, return_state=True, name='Encoder-Last-GRU')(x)
encoder_model = Model(inputs=encoder_inputs, outputs=state_h, name='Encoder-Model')
seq2seq_encoder_out = encoder_model(encoder_inputs)
#### Decoder Model ####
decoder_inputs_before = Input(shape=(None,), name='Decoder-Input-before')  # for teacher forcing
dec_emb_before = emb_layer(decoder_inputs_before)
decoder_gru_before = GRU(latent_dim, return_state=True, return_sequences=True, name='Decoder-GRU-before')
decoder_gru_output_before, _ = decoder_gru_before(dec_emb_before, initial_state=seq2seq_encoder_out)
decoder_dense_before = Dense(num_words, activation='softmax', name='Final-Output-Dense-before')
decoder_outputs_before = decoder_dense_before(decoder_gru_output_before)
decoder_inputs_after = Input(shape=(None,), name='Decoder-Input-after')  # for teacher forcing
dec_emb_after = emb_layer(decoder_inputs_after)
decoder_gru_after = GRU(latent_dim, return_state=True, return_sequences=True, name='Decoder-GRU-after')
decoder_gru_output_after, _ = decoder_gru_after(dec_emb_after, initial_state=seq2seq_encoder_out)
decoder_dense_after = Dense(num_words, activation='softmax', name='Final-Output-Dense-after')
decoder_outputs_after = decoder_dense_after(decoder_gru_output_after)
#### Seq2Seq Model ####
seq2seq_Model = Model([encoder_inputs, decoder_inputs_before,decoder_inputs_after], [decoder_outputs_before,decoder_outputs_after])
seq2seq_Model.compile(optimizer=optimizers.Nadam(lr=0.001), loss='sparse_categorical_crossentropy')
seq2seq_Model.summary()
history = seq2seq_Model.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)
#Feature extraction
headlines = tokenizer.texts_to_sequences(data['headline'].values)
headlines = pad_sequences(headlines,maxlen=maxlen)x = encoder_model.predict(headlines)
#classifier
X_train,y_train,X_test,y_test = x[msk],y[msk],x[~msk],y[~msk]
lr = LogisticRegression().fit(X_train,y_train)
lr.score(X_test,y_test)

這一次我們達到了 74% 的準確率。這是目前得到的最佳準確率。

總結

本文中,我們介紹了三個使用 RNN 創建句子向量表徵的無監督方法,並且在解決一個監督任務的過程中展現了它們的效率。自編碼器的結果比我們的基線模型要差一些(這可能是因為所用的數據集相對較小的緣故)。skip-thought 向量模型語言模型都利用語境來預測句子表徵,並得到了最佳結果。

能夠提升我們所展示的方法性能的可用方法有:調節超參數、訓練更多 epoch 次數、使用預訓練嵌入矩陣、改變神經網絡架構等等。理論上,這些高級的調節工作或許能夠在一定程度上改變結果。但是,我認為每一個預處理方法的基本直覺知識都能使用上述分享示例實現。

原文連結:https://blog.myyellowroad.com/unsupervised-sentence-representation-with-deep-learning-104b90079a93

投稿郵箱:liuyali@c2.org.cn

長按下方二維碼    免費訂閱!

如何加入學會


註冊學會會員:

個人會員:

關注學會微信:中國指揮與控制學會(c2_china),回復「個人會員」獲取入會申請表,按要求填寫申請表即可,如有問題,可在公眾號內進行留言。通過學會審核後方可在線進行支付寶繳納會費。

單位會員:

關注學會微信:中國指揮與控制學會(c2_china),回復「單位會員」獲取入會申請表,按要求填寫申請表即可,如有問題,可在公眾號內進行留言。通過學會審核後方可繳納會費。


長按下方學會二維碼,關注學會微信

相關焦點

  • CICC科普欄目|深度學習完全指南
    Bengio 和 Aaron Courville 合著的《深度學習》★★★你必須有基本的大學水平的數學基礎,可以在 Ian Goodfellow,Yoshua Bengio 和 Aaron Courville 合著的《深度學習》(Deep Learning)一書的前幾章中回顧這些概念:《深度學習》第2章:線性代數《深度學習》第3章:概率和信息理論
  • 【乾貨】深度學習、自然語言處理和表徵方法
    所以普適性並不能解釋為什麼神經網絡如此好用。真正的原因比這微妙得多… 為了理解它,我們需要先理解一些具體的成果。單詞嵌入(Word Embeddings)我想從深度學習研究的一個非常有意思的部分講起,它就是:單詞嵌入(word embeddings)。在我看來,單詞嵌入是目前深度學習最讓人興奮的領域之一,儘管它最早是由Bengio等人在十多年前提出的(見註解3)。
  • 73歲Hinton老爺子構思下一代神經網絡:屬於無監督對比學習
    Hinton 在此次報告中回顧了神經網絡的發展歷程,並表示下一代神經網絡將屬於無監督對比學習。人工神經網絡最重要的待解難題是:如何像大腦一樣高效執行無監督學習。第一類的典型代表是 BERT 和變分自編碼器(VAE),它們使用深度神經網絡重建輸入。但這類方法無法很好地處理圖像問題,因為網絡最深層需要編碼圖像的細節。
  • 無監督學習-自編碼器-補充|深度學習(李宏毅)(二十)
    上一篇:無監督學習-自編碼器|深度學習(李宏毅)(十九)一、最小重構代價之外的方法Using Discriminator
  • 【無監督學習最新研究】簡單的「圖像旋轉」預測,為圖像特徵學習提供強大監督信號
    我們在各種無監督的特徵學習基準中,對我們的方法進行了詳盡的評估,並在所有這些基準中展示出了最先進的性能。具體來說,我們在這些基準中的結果展現了在無監督的表徵學習中,較之先前最先進的方法,我們的方法取得了巨大改進,從而顯著縮小了與監督特徵學習之間的差距。
  • CICC科普欄目 |必備的10種機器學習算法
    1.主成分分析(PCA)/ SVDPCA是一種無監督的方法,用於對由向量組成的數據集的全局屬性進行理解。本文分析了數據點的協方差矩陣,以了解哪些維度(大部分情況)/數據點(少數情況)更為重要,即它們之間具有很多的變化,但與其他變量之間的協變性較低)。考慮一個矩陣頂級主成分(PC)的一種方式是考慮它的具有最高特徵值的特徵向量。
  • 擁有解耦表徵的無監督學習是不可能的!硬核ICML 2019最佳論文出爐
    值得關注的是,ETH Zurich、谷歌大腦等機構的論文《挑戰無監督學習中解耦表徵的一般假設》提出了一個與此前學界普遍預測相反的看法:對於任意數據,擁有相互獨立表徵(解耦表徵)的無監督學習是不可能的!在大會上,獲獎論文的部分作者也現場進行了演講。
  • 深度森林第三彈:周志華組提出可做表徵學習的多層梯度提升決策樹
    今日,南京大學的馮霽、俞揚和周志華提出了多層梯度提升決策樹模型,它通過堆疊多個回歸 GBDT 層作為構建塊,並探索了其學習層級表徵的能力。此外,與層級表徵的神經網絡不同,他們提出的方法並不要求每一層都是可微,也不需要使用反向傳播更新參數。因此,多層分布式表徵學習不僅有深度神經網絡,同時還有決策樹!近十年來,深層神經網絡的發展在機器學習領域取得了顯著進展。
  • AI 從業者都會用到的 10 個深度學習方法
    在這裡,我想分享人工智慧工程師 10 個用於解決機器學習問題的強大的深度學習方法。但是,我們首先需要定義什麼是深度學習。如何定義深度學習是很多人面臨的一個挑戰,因為它的形式在過去的十年中已經慢慢地發生了改變。下圖直觀地展示了人工智慧,機器學習和深度學習之間的關係。
  • 無監督學習的魅力
    無監督學習是機器學習算法裡非常撲朔迷離的一個類別,負責解決這些「沒有真實值 (no-ground-truth) 」的數據。本文會講到,無監督學習到底是什麼,和機器學習的其他算法有何本質區別,用的時候有哪些難點,以及推薦閱讀的傳送門。最簡單的理解方式,就是把算法想像成考試。
  • 港中文開源OpenSelfSup: Open-MMLab自監督表徵學習代碼庫
    本文作者:Xiaohang Zhanhttps://zhuanlan.zhihu.com/p/148782886本文已由原作者授權,不得擅自二次轉載前言自監督的表徵學習領域近幾個月來獲得了顯著的突破,特別是隨著Rotation Prediction, DeepCluster, MoCo, SimCLR等簡單有效的方法的誕生,大有超越有監督表徵學習的趨勢。
  • 神經網絡之父Geoffrey Hinton傑弗裡·欣頓 跨過人工智慧寒冬談深度學習
    2007年Hinton合著了一篇題為「圖像變換的無監督學習Unsupervised learning of image transformations」無監督學習論文。[26]在1992年9月和1993年10月Scientific American科學美國人雜誌Geoffrey Hinton文章中,可以找到他研究相關的可訪問介紹。
  • IT新技術篇:深度學習的57個名詞
    論文:用於在線學習和隨機優化的自適應次梯度方法(Adaptive Subgradient Methods for Online Learning andStochastic Optimization)技術博客:斯坦福 CS231n:優化算法http://cs231n.github.io/neural-networks-3/技術博客
  • 一行命令跑評測,港中文MMLab開源自監督表徵學習代碼庫OpenSelfSup
    自監督表徵學習發展迅速,但也存在諸多問題。近日,香港中文大學多媒體實驗室(MMLab)和南洋理工大學的研究者開源了一套統一的自監督學習代碼庫 OpenSelfSup。近幾個月來自監督表徵學習領域獲得了顯著突破,特別是隨著 Rotation Prediction、DeepCluster、MoCo、SimCLR 等簡單有效的方法的誕生,自監督表徵學習大有超越有監督表徵學習的趨勢。
  • CICC科普欄目|從感知機到深度神經網絡,帶你入坑深度學習
    他建議通過這種方式有效地深入理解一個學習主題。除此之外,也希望這篇博客可以幫助到那些有意入坑的朋友。言歸正傳。在我正式介紹深度學習是什麼東西之前,我想先引入一個簡單的例子,藉以幫助我們理解為什麼需要深度神經網絡。同時,本文附有使用深度神經網絡模型求解異或(XOR)問題的代碼,發布在 GitHub 上。異或問題何為異或問題?
  • 用Transformer振興CNN骨幹網絡,港大、騰訊等聯合提出視覺自監督表徵學習CARE
    自監督表徵學習近兩年十分火熱。機器學習界的三位泰鬥 Geoffroy Hinton、 Yann Lecun 、 Yoshua Bengio 一致認為自監督學習有望使 AI 產生類人的推理能力,其中 Hinton 與 Lecun 近兩年也在 ICML / NeurIPS 中發表自監督表徵學習的研究工作。
  • 【資源】深度學習Top100:近5年被引用次數最高論文(下載)
    這裡是近5年100篇被引用次數最多的深度學習論文,覆蓋了優化/訓練方法、無監督/生成模型、卷積網絡模型和圖像分割/目標檢測等十大子領域。重要的論文能夠超越其應用領域讓人獲益。新智元在每個領域都選擇了一篇論文重點介紹,這將是你縱覽深度學習研究絕好的開始。這裡是100篇被引用次數最多的深度學習論文,從海量的相關論文中脫穎而出。
  • 深度學習領域的數據增強
    數據增強一套技術,可提高訓練數據集的大小和質量,以便您可以使用它們來構建更好的深度學習模型。 在計算視覺領域,生成增強圖像相對容易。加噪(NoiseMix) (https://github.com/noisemix/noisemix):類似於圖像領域的加噪,NoiseMix提供9種單詞級別和2種句子級別的擾動來生成更多的句子,例如:這是一本很棒的書,但是他們的運送太慢了。->這是本很棒的書,但是運送太慢了。
  • 【一文讀懂】機器學習最新主戰場遷移學習,從原理、方法到應用
    假如我們不要管反對者和預測下一個 AI 冬天的人,而是選擇相信 Andrew Ng 的先見,那麼這些成功將會持續下去。然而,遷移學習已經存在了幾十年,卻幾乎從沒有在工業中得到利用,為什麼 Ng 預測遷移學習能夠爆炸式地增長呢?
  • 深度長文:NLP的巨人肩膀(上)
    語言模型 而以上這些都是相對比較傳統的方法,在介紹基於深度學習的方法之前,先來看看語言模型。做過句子匹配任務的一定知道,這個框架是一個最基本(甚至也是最簡陋)的句子匹配框架。對於底層的 Encoder 來說,論文作者分別嘗試了 7 種模型,然後分別以這些模型作為底層的 Encoder 結構在 SNLI 上進行監督訓練。