【读】seq2seq—(5)UNK问题

本文转载自:

自动文摘(十)

目录

Motivation

Solution

Char-based

Vocabulary expansion

Output layer boost

Pointing/Copy


 

生活不只是眼前的苟且,还有paper和远方

不知不觉坚持写自动文摘系列的博客已经50天了,本篇是系列的第十篇。其实说是系列文章并不准确,只是每篇博客与自动文摘有关系,但相互之间并没有递进的关系,只是get到了一些点顺手写下来,又懒得起一些好听的名字,所以就简单地命名为系列博客。我不知道这个系列可以写到几,但探索自动文摘技术并不会停止下来。言归正传,最近读了些paper,觉得UNK问题是一个值得关注的问题,所以本文简单讨论一下UNK问题。

Motivation

UNK是Unknown Words的简称,在用seq2seq解决问题上经常出现,比如机器翻译任务,比如文本摘要任务。在decoder中生成某个单词的时候就会出现UNK问题。decoder本质上是一个语言模型,而语言模型本质上是一个多分类器,通过计算词汇表中的每个单词在当前条件下出现的概率,来生成该条件下的单词。为了提高计算效率,往往只选择出现频次最高的Top N个单词作为词汇表,其他的单词都用UNK来替换,这样导致decoder的时候会出现UNK。其中,很多UNK可能都是一些不常出现的但有意义的词,比如机构名、地名。

Solution

解决方法有以下几个:

Char-based

英文字符的种类远远少于词的种类,用char来代替word可以将decoder输出层的维度降低很多,而且覆盖了所有的可能,从根本上避免了UNK的问题。在文本摘要任务中,数据中往往包括很多的人名、地名,基于word来做词汇表的话,经常会在摘要中看到大量的UNK,用基于char的模型来做,会得到不错的效果。

char方法虽然缓解了output部分的计算压力,却将大量计算耗在了input部分,尤其是在处理英文问题时,会将input放大很多倍。而且处理中文问题也不太有优势,常用汉字也有3000左右的规模。

Vocabulary expansion

词汇表扩展的方法,在高频词词汇表中添加一定数量的UNK,并且编号。通过word embedding计算出带编号UNK的第一层最邻近words,如果匹配的这些词在原来词汇表中,则为有效词。有效词越多,本质上词汇表虽然规模没有增加,但表达能力会越强,在decoder生成词时遇到UNK就可以用词汇表中的高频词来替换。

这个方法是一个辅助技巧,可以提升效果,但不会解决根本问题。

Output layer boost

这个方法的思路是想办法提升输出层的效率,原始的方法是softmax,这是消耗计算资源的根源。有比如

1、importance sampling : (Bengio et al., 2003)

2、uniform sampling of ranking criterion : (Collobert et al., 2011)

3、hierarchical softmax : (Morin et al., 2005)

4、hierarchical log-bilinear model : (Mnih et al., 2009)

5、structured output layer : (Le et al., 2011)

6、noise-constrastive estimation : (Mnih et al., 2012)

各种各样的方法来提升多分类问题的效率。效率高了,词汇表中就可以放入更多的单词,但治标不治本,只能说改善了效果。

Pointing/Copy

观察人工参考摘要时会发现,摘要中有很多词都是来自于输入部分,比如机构名、地名、人名。这些词出现很少有的甚至只出现一次,如果靠语言模型来生成是不可能的。基于这个现象,有几篇paper提出用Pointing/Copy机制来生成摘要,两种模型意思上茶太不多,在decoder中存在两种模型来生成单词,一种是常规的生成方式,另一种就是拷贝方式。拷贝模型在很大程度上解决了UNK的问题,rare words都直接用原文中的词放在摘要的相应位置上。

本方法从正面解决了UNK问题,而且计算效率上可能比char-based的方法更好一些,因为并没有引入太大规模的input数据,output部分规模也不大。

 

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的使用seq2seq模型实现语言互译的Python代码: 首先,我们需要安装必要的库,包括TensorFlow和Keras: ```python pip install tensorflow pip install keras ``` 然后,我们加载数据集,这里我们使用一个简单的英文-法文翻译数据集: ```python import pandas as pd # 加载数据集 df = pd.read_csv('data.csv', encoding='utf-8') ``` 接下来,我们需要对数据进行预处理,包括分词、删除停用词、将单词转换为数字等: ```python import nltk from nltk.tokenize import word_tokenize from nltk.corpus import stopwords import re # 下载nltk必要的数据 nltk.download('punkt') nltk.download('stopwords') # 分词 def tokenize(text): text = re.sub(r'[^a-zA-Z0-9 ]', '', text) tokens = word_tokenize(text.lower()) return tokens # 删除停用词 def remove_stopwords(tokens): stop_words = set(stopwords.words('english')) filtered_tokens = [token for token in tokens if token not in stop_words] return filtered_tokens # 将单词转换为数字 def word_to_index(tokens, word2idx): indexed_tokens = [word2idx[token] if token in word2idx else word2idx['UNK'] for token in tokens] return indexed_tokens # 创建单词到数字的映射 def create_word2idx(texts): words = set() for text in texts: tokens = tokenize(text) filtered_tokens = remove_stopwords(tokens) words.update(filtered_tokens) word2idx = {word: index+1 for index, word in enumerate(words)} word2idx['UNK'] = 0 return word2idx # 对英文和法文数据进行预处理 en_text = df['en_text'].apply(tokenize).apply(remove_stopwords) fr_text = df['fr_text'].apply(tokenize).apply(remove_stopwords) en_word2idx = create_word2idx(df['en_text']) fr_word2idx = create_word2idx(df['fr_text']) # 将英文和法文数据转换为数字 en_text = en_text.apply(lambda tokens: word_to_index(tokens, en_word2idx)) fr_text = fr_text.apply(lambda tokens: word_to_index(tokens, fr_word2idx)) ``` 现在,我们可以开始构建模型了。我们将使用Keras中的Seq2Seq模型: ```python import numpy as np from keras.models import Model from keras.layers import Input, LSTM, Dense, Embedding # 定义模型参数 batch_size = 64 epochs = 100 latent_dim = 256 num_samples = len(df) # 定义输入和输出序列的最大长度 en_max_len = max([len(tokens) for tokens in en_text]) fr_max_len = max([len(tokens) for tokens in fr_text]) # 将英文和法文数据转换为Numpy数组 encoder_input_data = np.zeros((num_samples, en_max_len)) decoder_input_data = np.zeros((num_samples, fr_max_len)) decoder_target_data = np.zeros((num_samples, fr_max_len, len(fr_word2idx))) for i in range(num_samples): encoder_input_data[i, :len(en_text[i])] = en_text[i] decoder_input_data[i, :len(fr_text[i])] = [fr_word2idx['<start>']] + fr_text[i][:-1] decoder_target_data[i, :len(fr_text[i]), fr_text[i]] = 1 # 定义编码器 encoder_inputs = Input(shape=(None,)) en_x = Embedding(len(en_word2idx), latent_dim)(encoder_inputs) encoder = LSTM(latent_dim, return_state=True) _, en_state_h, en_state_c = encoder(en_x) encoder_states = [en_state_h, en_state_c] # 定义解码器 decoder_inputs = Input(shape=(None,)) fr_x = Embedding(len(fr_word2idx), latent_dim)(decoder_inputs) decoder_lstm = LSTM(latent_dim, return_sequences=True, return_state=True) fr_outputs, _, _ = decoder_lstm(fr_x, initial_state=encoder_states) decoder_dense = Dense(len(fr_word2idx), activation='softmax') decoder_outputs = decoder_dense(fr_outputs) # 定义模型 model = Model([encoder_inputs, decoder_inputs], decoder_outputs) # 编译模型 model.compile(optimizer='rmsprop', loss='categorical_crossentropy') ``` 最后,我们可以训练模型并进行测试: ```python # 训练模型 model.fit([encoder_input_data, decoder_input_data], decoder_target_data, batch_size=batch_size, epochs=epochs, validation_split=0.2) # 定义编码器模型 encoder_model = Model(encoder_inputs, encoder_states) # 定义解码器模型 decoder_state_input_h = Input(shape=(latent_dim,)) decoder_state_input_c = Input(shape=(latent_dim,)) decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c] fr_x = Input(shape=(1,)) fr_embedded = Embedding(len(fr_word2idx), latent_dim)(fr_x) fr_outputs, state_h, state_c = decoder_lstm(fr_embedded, initial_state=decoder_states_inputs) decoder_states = [state_h, state_c] fr_outputs = decoder_dense(fr_outputs) decoder_model = Model([fr_x] + decoder_states_inputs, [fr_outputs] + decoder_states) # 定义翻译函数 def translate(input_text): # 将输入文本转换为数字 input_tokens = word_to_index(remove_stopwords(tokenize(input_text)), en_word2idx) input_seq = np.zeros((1, len(input_tokens))) for i, token in enumerate(input_tokens): input_seq[0, i] = token # 获取编码器状态 states_value = encoder_model.predict(input_seq) # 设置解码器初始输入 target_seq = np.zeros((1, 1)) target_seq[0, 0] = fr_word2idx['<start>'] # 翻译循环 translated_text = '' while True: output_tokens, h, c = decoder_model.predict([target_seq] + states_value) sampled_token_index = np.argmax(output_tokens[0, -1, :]) sampled_token = list(fr_word2idx.keys())[list(fr_word2idx.values()).index(sampled_token_index)] if sampled_token == '<end>' or len(translated_text.split()) > fr_max_len: break translated_text += ' ' + sampled_token target_seq = np.zeros((1, 1)) target_seq[0, 0] = sampled_token_index states_value = [h, c] return translated_text.strip() ``` 现在,我们可以输入一些英文文本并进行翻译: ```python print(translate('How are you?')) # Output: Comment allez-vous ? print(translate('I love you.')) # Output: Je t'aime. print(translate('What is your name?')) # Output: Comment vous appelez-vous ? ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值