聊天机器人实验笔记

                  目录

1. 实验介绍
    1.1 项目简介
    1.2 实验目的
    1.3 实验思路
    1.4 数据集介绍
    1.5 算法介绍
2. 对话语料处理
    2.1 实验准备
    2.2 语料处理
3.seq2seq模型构建
    3.1 实验流程
4. 模型训练
    4.1 模块引入
    4.2 数据准备
    4.3 模型准备
    4.4. 模型训练和模型保存
5. 模型测试
    5.1 实验思路
    5.2 测试结果


1. 实验介绍

项目运行环境:win10/ubuntu 16.04, python3.6, tensorflow 1.6.0

1.1 项目简介

 preprocessing.py  —— 包含大量处理数据的接口
seq2seq_model.py —— 用于构建模型对话模型
train.py   ——  模型训练
test.py  —— 模型测试

1.2 实验目的

(1)人机对话的基本原理?(了解)

(2)人机对话的基本开发流程?(掌握)

(3)seq2seq模型原理?(掌握)

1.3 实验思路

人机对话实验思路一般分两种:检索式和生成式
(1)检索式,搜集尽可能多的问答素材,利用语料库检索完成人机对话功能。
(2)生成式,结合了现今流行的算法和技术,可以更加开放型的解决对话问题,突破以往“找答案”的检索模式,更加像人类一样回答问题。主要思路: 获取对话预料 ——> 对话预料预处理 ——> 构建 seq2seq模型 ——> 模型训练 ——> 模型测试。

1.4 数据集介绍

两个日常对话的语料文档:one.txt、two.txt

      

1.5 算法介绍

Seq2Seq任务可以理解为:将sequence进行某些处理后映射到另一个sequence的任务。sequence可以理解为一个字符串。常见的Seq2Seq任务有机器翻译,词性标注,语音识别,以及本实验的人机对话。该实验当中主要用到的算法是LSTM和Encoder-Decoder框架。
(1)LSTM(Long Short-Term Memory)叫长短期记忆网络,是一种时间递归神经网络,适合于处理和预测时间序列中,间隔和延迟相对较长的重要事件。LSTM已经在科技领域有了多种应用。基于LSTM的系统可以用于机器翻译、控制机器人、语音识别,以及聊天机器人等等任务。
(2)Encoder-Decoder 是seq2seq的基础框架,包括Encoder、Decoder以及连接两者的中间状态向量;Encoder通过学习输入,将其编码成一个固定大小的状态向量S,继而将S传给Decoder,Decoder 再通过对状态向量S的学习来进行输出。

2. 对话语料处理

2.1 实验准备

以下操作通过命令行
1. 安装相关框架:
步骤1  安装jieba:  pip install jieba
步骤2  查看安装情况: pip3 list
2. 下载语料
步骤1 进入HCIA-AI文件夹,输入命令:wget https://obs-77f8.obs.cn-north-1.myhwclouds.com/chatbot.zip,下载语料
步骤2 解压zip文件输入命令:unzip chatbot.zip
步骤3 查看内容输入命令:ll(LL)

2.2 语料处理

涉及到的主要函数如下:
·句子分隔函数(可用分隔符手动分词):basic_tokenizer()
·分词函数:fenci()
·获取文件列表函数:getRawFileList()
·读取分词内容函数:get_ch_lable()
·获取文本内容函数:get_ch_path_text()
·数据集构建函数:build_dataset()
·创建词汇表函数:create_vocabulary()
·创建序列文件函数:create_seq2seqfile()
·文本分割函数:splitFileOneline()
·词汇表初始化函数:initialize_vocabulary()
·句子转ids函数:sentence_to_ids()
·文件转ids文件函数:textfile_to_idsfile()
·批量文件转ids文件函数:textdir_to_idsdir()
·lds 转文件函数:ids2texts()

#coding: utf-8 
import sys      # sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行环境;本实验中主要用于数据刷新。
import os       # os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;本市杨中主要用于对系统文件的操作,例如返回文件名列表,多路径组合等。
import matplotlib.mlab as mlab      # matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形,用少量代码就能生成各类2D图形。
import matplotlib.pyplot as plt     # matplotlib.pyplot是一个有命令风格的函数集合,它看起来和MATLAB很相似。
import numpy as np      # numpy是Python的一种开源的数值计算包;本实验中主要用于矩阵的相关处理,例如矩阵创建,结构重塑,聚合计算等。
from tensorflow.python.platform import gfile        # tensorflow.python.platform.gfile提供类似Python的file对象的API,用于对file文件的操作。
from random import shuffle      # random主要用于生成随即数据;本实验中主要用于打乱原有的数据序列。
import re       # python当中的正则表达式模块;本实验中主要用于替换和分割。 
import collections      # 是python内建的一个集合模块,提供了许多有用的集合类;本实验中主要利用collections模块中的Counter类来跟踪值出现的次数;
                        # 它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。
import jieba        # 是基于Python的中文分词工具;本实验中主要用于导入文件和分词操作
# 定义函数对句子进行分割 
def basic_tokenizer(sentence):            
    # _WORD_SPLIT = "([.,!?\"':;)(])"   # 定义英文分隔符分隔符
    _CHWORD_SPLIT = '、|。|,|‘|’'      # 定义中文分隔符
    str = ""                            # 定义空字符串
    for i in re.split(_CHWORD_SPLIT,  sentence):        # 利用_CHWORD_SPLIT当中的15种分割符对sentence语句进行分割,生成列表,并对其中每个元素进行遍历
        str = str +i                 
    return str

jieba.load_userdict("myjiebadict.txt")  # 利用jieba框架中的load_userdict函数读取数据

# 定义分词函数,对训练数据training_data进行分词 
def fenci(training_data):               
    seg_list = jieba.cut(training_data) # 对training_data进行分词,默认是精确模式(总共有三种模式),赋值给seg_list,分词结果返回的是一个生成器
    training_ci = " ".join(seg_list)    # 对分词后的每个元素利用空格进行组合   
    training_ci = training_ci.split()   # 对每个元素进行分割
    return training_ci                  # 返回分词+分割的结果

#获取文件列表
def getRawFileList(path):       # 创建函数getRawFileList用于获取文件列表,返回文件路径和文件名称。
    files = []                  # 创建空文件列表,用于存放文件
    names = []                  # 创建空名称列表,用于存放文件名称
    for f in os.listdir(path):      # 遍历path路径中存放的文件,利用os.listdir读取其中文件名称
        files.append(os.path.join(path, f))     # 将文件路径和文件名称join到一起,并将其添加到files列表当中
        names.append(f)     # 将文件名称添加到names列表当中
    return files,names      # 函数最终返回文件路径+名称的列表files和文件名称列表names

#读取分词后的中文词
def get_ch_lable(txt_file):    # 定义函数get_ch_lable,读取分词之后的中文词
    labels= list()                                              # 定义标签labels的列表,此处list() 方法用于将元组转换为列表
    labelssz = []                                               # 定义标签索引labelssz的列表
    with open(txt_file, 'rb') as f:                             # 打开txt_file文件,且以二进制读模式打开,文件定义为f
        for label in f:                                         # 变量f文件中的
            linstr1 = label.decode('gb2312')                    # 对f文件中每行元素进行decode解码,即将gb2312格式转化为unicode
            # print("haha:",linstr1)                            # 查看f文件中每一行的元素
            notoken = basic_tokenizer(linstr1 )                 # 对每行元素进行分割处理
            notoken = fenci(notoken)                            # 没分割处理过后的元素进行分词
            labels.extend(notoken)                              # 利用list.extend()函数在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
            labelssz.append(len(labels))                        # 计算每一行元素的的长度,并将其添加到labelssz列表当中
    return  labels,labelssz                                     # 返回文件中每行元素与其对应长度
 
#获取文件文本
def get_ch_path_text(raw_data_dir):                             # 创建函数get_ch_path_text用于获取文本文件的内容
    text_files,_ = getRawFileList(raw_data_dir)                 # 调用getRawFileList函数,获取文件路径及名称,并将文件的详细路径与名称赋值给text_files
    labels = []                                                 # 定义空的列表,用于存放经过处理的文件内容
    training_dataszs = list([0])                                # 定义只有一个0元素的列表

    print(len(text_files),"files,one is",text_files[0])         
    print(len(text_files),"files,two is",text_files[1])         # 分别查看两个训练数据的路径和名称,在文件量比较大的情况下需要对文件顺序先进行shuffle
    
    for text_file in text_files:                                # 遍历文件夹中每一个文件
        training_data,training_datasz =get_ch_lable(text_file)  # 调用get_ch_lable函数,获取每个文件中的具体内容和内容长度,并赋值training_data为内容,training_datasz为内容长度
        training_ci = np.array(training_data)                   # 将文件中内容转换成数组training_ci
        # training_ci = np.reshape(training_ci, [-1, ])           # 将数组training_ci转化成
        labels.append(training_ci)                              # 将处理后的文件内容training_ci添加到labels列表中
        
        training_datasz =np.array( training_datasz)+training_dataszs[-1]        # 这一组内容的长度就是上一组内容的长度加上这一组长度(初始内容长度为0)
        training_dataszs.extend(list(training_datasz))          # 利用list.extend()函数在列表末尾一次性追加另一个序列中的多个值。
        print("here",training_dataszs)                          # 输出每一个text_file文件中每行内容的迭代长度
    return labels,training_dataszs                              # 输出所有文件中的内容与内容长度

#系统字符,创建字典时需要加入:用于辅助标记
_PAD = "_PAD"       # 在桶机制中为了对其填充和占位
_GO = "_GO"         # 解码输入时候的开头标记位置
_EOS = "_EOS"       # 用于标记输出结果的结尾 
_UNK = "_UNK"       # 用来代替处理样本时出现字典中没有的字符 
_NUM = "_NUM"       # 数字字符替换,不属于系统字符 

PAD_ID = 0
GO_ID = 1
EOS_ID = 2
UNK_ID = 3

#数据集构建函数
def build_dataset(words, n_words):
    count = [[_PAD, -1],[_GO, -1],[_EOS, -1],[_UNK, -1]]        # 定义初始count 
    count.extend(collections.Counter(words).most_common(n_words - 1))       # 利用Counter统计输入内容words各个词汇的频数,同时利用most_common排序去除最常用的前n个词,并将其一次性添加到count中
    
    dictionary = dict()     # 定义空字典,用于存储内容与频数 
    for word, _ in count:   # 遍历每一组count,提取每一组count的内容 
        dictionary[word] = len(dictionary)      # 将其转化成字典格式
    
    data = list()           # 定义空列表,用于保存每一组内容的顺序
    unk_count = 0           # 预定义未知的count内容其顺序为0 
    fo
  • 11
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值