正文之前的BB时间
因为个人实验需要,要对Cornell Movie Dialogs Corpus进行一些预处理,记录一下处理过程,以后其他类似的数据处理可以借鉴。
我的实验是实现一个主题驱动的自动聊天机器人,Cornell Movie Dialogs Corpus是一个从电影数据中生成的电影对白语料库,包含大概600部电影对白,并且语料中含有电影名、角色、IMDB评分等许多信息。但我的实验中只需要里面的纯对话信息,将每个对话处理成前面几句是对话上下文context、最后一句是对话回复response,并需要替换其中的低频词,将其保存为tfrecord。
语料库中原始文件包含:
- movie_titles_metadata.txt 包含每部电影标题信息
- movie_characters_metadata.txt 包含每部电影角色信息
- movie_lines.txt 每个表达(utterance)的实际文本
- movie_conversations.txt 对话的结构,用语句ID表示
- raw_script_urls.txt 原始来源的url
*具体介绍可见文章http://blog.csdn.net/zdcs/article/details/53465855
我已经用numpy和pandas在jupyter中将上面的文件处理成 convLine.csv 和 lineIndex.csv 两个文件,两个文件格式如下:
convLine.csv 对话文件,每个对话语句line用ID表示:
L1,L2,L3 || L4,L5,L6,L7,L8 || L9,L10,L11 ...
lineIndex.csv 语句文件,每个语句lineID对应的真正的句子:
L1,hello! || L2, how are you? || L3, fine,thank you. ...
(||表示换行)
下面对这两个文件进行处理,正文开始~~
这里是正文
处理数据集的过程有两轮遍历。
第一轮遍历完成文件对齐、分割seq2seq数据集、获得数据集大小和词汇表;
第二轮遍历得到忽略词、获得topic训练数据集以及写入tfrecord。
第一轮遍历
利用lineIndex.csv 文件建立字典。
meta_lineIndex_path = os.path.join(config.data_root, 'lineIndex.csv')
convline_dict = {}
with open(meta_lineIndex_path, newline='')as f:
lineIndex_reader = csv.reader(f)
for row in lineIndex_reader:
convline_dict[row[0]] = row[1]
由于数据集中有的的对话比较长、轮数较多,因此进行了采样,将轮次长的对话拆分成几个轮次短的对话,分割次数视长度而定。这里需要注意同一个对话拆分开后,分割数据集时应该分到一起。
采样过程示意:
对话数据
L1, L2, L3, L4, L5, L6, L7, L8
[---对话1---]
[--------对话2-------]
[--------------对话3---------------]
new_max_turn = min(len(row)-1,max_turn)
assert min_turn <= new_max_turn, "context最小轮数大于最大轮数"
sampling_count_range = list(map(int, sampling_range.split(',')))
sample_count_tag = bisect.bisect_left(sampling_count_range, new_max_turn)//获得采样次数
context_list = list()
response = list()
while sample_count_tag != 0:
context = list()
context_truns=new_max_turn
if sample_count_tag > 1:
while True:
alternative_context_truns=random.randint(
min_turn,
new_max_turn
)
if alternative_context_truns!=context_truns://防止重复采样
context_truns=alternative_context_truns
break
# 处理context
for turn in row[:context_truns]:
word_list = word_tokenize(convline_dict[turn])
context.extend(list(word_list) + [end_of_turn_symbol])
context_list.append(context)
# 处理response
word_list = word_tokenize(convline_dict[row[context_truns]])
response.append(list(word_list) + [end_of_turn_symbol])
#注意多次采样的context和response分开
sample_count_tag = sample_count_tag-1
采样后得到了对话的context和response数据,将其分割成训练集、测试集和验证集,更新词汇表。
第二轮遍历
将数据集中的词表word_list转换为idx_list,并添加忽略词symbol。
seq2seq_context = token_manager.translate_word_list_to_idx_list(context_word_list, False)
seq2seq_response = token_manager.translate_word_list_to_idx_list([go_symbol] + response_word_list, False)
topic_context = token_manager.translate_word_list_to_idx_list(context_word_list, True)
topic_response = token_manager.translate_word_list_to_idx_list(response_word_list, True)
写入topic训练数据集以及生成tfrecord文件。
完成!
正文之后再BB两句
整个数据集处理过程还是比较简单的,用到的技巧也不多,以后再有其他实验也算有经验了。
就是一开始采样完分割数据集时,没有注意对同一个对话多次采样获得多个对话应该分割到同一个数据集中,差点造成实验造假。(¦3」∠)。。。还好小H童靴帮我发现了~以后还是要多多注意!