进阶课6——基于Seq2Seq的开放域生成型聊天机器人的设计和开发流程

news2024/11/21 1:43:56

情感聊天机器人通常属于开放领域,用户可以与机器人进行各种话题的互动。例如,微软小冰和早期的AnswerBus就是这种类型的聊天机器人。基于检索的开放领域聊天机器人需要大量的语料数据,其开发流程与基于任务型的聊天机器人相似,而基于深度学习的生成类型聊天机器人则具有处理开发领域的先天优势。其中,以Seq2Seq模型为基础的闲聊机器人已经在机器翻译领域取得了成功的应用。

Seq2Seq模型是NLP中的一个经典模型,最初由Google开发,并用于机器翻译。它基于RNN网络模型构建,能够支持且不限于的应用包括:语言翻译、人机对话、内容生成等。Seq2Seq,就如字面意思,输入一个序列,输出另一个序列。这种结构最重要的地方在于输入序列和输出序列的长度是可变的。Seq2Seq属于Encoder-Decoder的大范畴,主要是一个由编码器(encoder)和一个解码器(decoder)组成的网络。编码器将输入项转换为包含其特征的相应隐藏向量,解码器反转该过程,将向量转换为输出项,解码器每次都会使用前一个输出作为其输入。不断重复此过程,直到遇到结束字符。

1.基于Seq2Seq的聊天机器人开发流程

我们将基于TensorFlow深度学习框架,介绍以Seq2Seq为基础的聊天机器人的开发流程。

1.语料准备

首先是语料准备,先准备基于开放域聊天语料进行模型训练。在我们的聊天语料中,奇数行是问题,偶数行对应的回答。

1 聊点么好呢?

2 那我们随便聊聊吧

3 你是什么人?

4 我是智能客服

5 有人在吗

6 小宝一直会在这里诚心为您服务

基于生成方式的开放领域聊天机器人需要充足的聊天语料,聊天语料需要覆盖大部分的话题,才能保证回答的多样性和语句的通顺。然后我们通过对所有的聊天语料进行预处理,进行字典统计。

python
def create_vocabulary(vocabulary_path, data_path, max_vocabulary_size, tokenizer=None, normalize_digits=True):  
    if not gfile.Exists(vocabulary_path):  
        print("Creating vocabulary %s from data %s" % (vocabulary_path, data_path))  
    vocab = {}  
    with gfile.GFile(data_path, mode="rb") as f:  
        counter = 0  
        for line in f:  
            counter += 1  
            if counter % 100000 == 0:  
                print("processing line %d" % counter)  
            line = tf.compat.as_bytes(line)  
            tokens = tokenizer(line) if tokenizer else basic_tokenizer(line)  
            for win tokens:  
                word = _DIGIT_RE.sub(b"0", w) if normalize_digits else w  
                if word in vocab:  
                    vocab[word] += 1  
                else:  
                    vocab[word] = 1  
    vocab_list = _START_VOCAB + sorted(vocab, key=vocab.get, reverse=True)  
    if len(vocab_list) > max_vocabulary_size:  
        vocab_list = vocab_list[:max_vocabulary_size]  
    with gfile.GFile(vocabulary_path, mode="wb") as vocab_file:  
        for win vocab_list:  
            vocab_file.write(w + b"\n")

根据统计的词频和字典,我们为聊天语料建立Token Id,比如“聊点什么好呢”这句话,根据每个词在词组中的位置[“聊”:0,“点”:1,“什么”:2,“好”:3,“呢”:4]可以表征为[0,1,2,3,4]。

python
def data_to_token_ids(data_path, target_path, vocabulary_path, tokenizer=None, normalize_digits=True):  
    """将数据文件进行分词并转换为token-ids,使用给定的词汇文件。此函数逐行加载来自data_path的数据文件,调用上述sentence_to_token_ids,并将结果保存在target_path中。有关token-ids格式的详细信息,请参阅sentence_to_token_ids的注释。  
    Args:  
        data_path (str): 数据文件的路径,格式为每行一句。  
        target_path (str): 将创建的文件token-ids的路径。  
        vocabulary_path (str): 词汇文件的路径。  
        tokenizer: 用于对每个句子进行分词的函数;如果为None,将使用basic_tokenizer。  
        normalize_digits (bool): 如果为True,则将所有数字替换为O。  
    """  
    if not gfile.Exists(target_path):  
        print("正在对位于 {} 的数据进行分词".format(data_path))  
    vocab = initialize_vocabulary(vocabulary_path)  
    with gfile.GFile(data_path, mode="rb") as data_file:  
        with gfile.GFile(target_path, mode="w") as tokens_file:  
            counter = 0  
            for line in data_file:  
                try:  
                    line = line.decode('utf8', 'ignore')  
                except Exception as e:  
                    print(e, line)  
                    continue  
                counter += 1  
                if counter % 100000 == 0:  
                    print("正在对第 {} 行进行分词".format(counter))  
                token_ids = sentence_to_token_ids(tf.compat.as_bytes(line), vocab, tokenizer, normalize_digits)  
                tokens_file.write(" ".join([str(tok) for tok in token_ids]) + "\n")

1.2定义Encoder和Decoder


根据Seq2Seq的结构,需要首先定义Cell,选择GRU或者LSTM的Cell,并确定Size。然后利用Tensorflow中tf_Seq2Seq.embedding_attention_Seq2Seq这个函数来构架Encoder和Decoder模型,在训练模式下,Decoder的输入是真实的Target序列。

def single_cel1():  
    return tf.contrib.rnn.GRUCell(size) if use_lstm else tf.contrib.rnn.BasicLSTMCell(size)  
  
def single_cell():  
    return tf.contrib.rnn.BasicLSTMCell(size)  
  
cell = single_cel1() if num_layers > 1 else single_cell()  
cell = tf.contrib.rnn.MultiRNNCell([single_cell() for _ in range(num_layers)])  
  
# The seq2seg function: we use embedding for the input and attention.  
def seq2seq_f(encoder_inputs, decoder_inputs, feed_previous):  
    return tf_seq2seq.embedding_attention_seq2seq(  
        encoder_inputs, decoder_inputs, cell,  
        num_encoder_symbols=source_vocab_size, num_decoder_symbols=target_vocab_size,  
        embedding_size=size, output_projection=output_projection,  
        feed_previous=feed_previous, dtype=dtype)
# Training outputs and losses, if forward_only:  
self.outputs, self.losses, self.encoder_state = tf_seq2seq.model_with_buckets(  
    self.encoder_inputs,  
    self.decoder_inputs,  
    targets,  
    self.target_weights,  
    buckets,  
    lambda x, y: seq2seq_f(x, y, True),  
    softmax_loss_function=softmax_loss_function  
)  
  
# If we use output projection, we need to project outputs for decoding.   
if output_projection is not None:  
    for b in xrange(len(buckets)):  
        self.outputs[b] = [  
            tf.matmul(output, output_projection[0]) + output_projection[1] for output in self.outputs[b]  
        ]  
else:  
    self.outputs, self.losses, self.encoder_state = tf_seq2seq.model_with_buckets(  
        self.encoder_inputs,  
        self.decoder_inputs,  
        targets,  
        self.target_weights,  
        buckets,  
        lambda x, y: seq2seq_f(x, y, False),  
        softmax_loss_function=softmax_loss_function  
    )

1.3模型训练和评估模块


对于训练阶段,首先定义Encoder和Decoder的网络结构(12.3.2节),然后对输入进行预处理(12.3.1节),最后通过Get_Batch将数据分成多个Batch,并利用Session进行训练。此外每次Epoch都要通过对模型生成语句的困惑度进行计算,来评估生成回答语句是否通顺。

python
def det_train(args):  
    print("Preparing dialog data in to", args.model_name, args.data_dir)  
    setup_workpath(workspace*args.workspace)  
  
    train_data, dev_data, _ = data_utils.prepare_dialog_data(args.data_dir, args.vocab_size)  
  
    if args.reinforce_learn:  
        args.batch_size = # is decode one sentence at a time  
        gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction*args.gpu_usage)  
        with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:  
            # Create model,  
            print("Creating id layers of hd units.")  
            model = seq2seq_model_utils.create_model(sess, args.forward_only-False)  
            # Read data into buckets and compute their sizes,  
            print("Reading development and training data (limit: %d)," % args.max_train_data_size)  
            dev_set = data_utils.read_data(dev_data, args.buckets*args.rev_model)  
            train_set = data_utils.read_data(train_data, args.buckets, args.max_train_data_size, args.rev_model)  
            #Tev mode  
            train_bucket_sizes = [len(train_set[b]) for b in range(len(args.buckets))]  
            train_total_size = float(sum(train_bucket_sizes))  
            train_buckets_scale = [sum(train_bucket_sizes[:i + 1]) / train_total_size for i in range(len(train_bucket_sizes))]  
            # This is the training loop  
            step_time, loss = 0.0, 0.0  # current step and loss so far  
            previous_losses = []  # to keep track of the losses in every epoch  
            # Load vocabularies  
            vocab_path = os.path.join(args.data_dir, "rocabid.%d" % args.vocab_size)  
            vocab, rev_vocab = data_utils.initialize_vocabulary(vocab_path)  
            while True:  
                random_number = np.random.random()  # random number between 0 and 1  
                bucket_id = min([i for i in range(len(train_buckets_scale)) if train_buckets_scale[i] > random_number])  # find the bucket id based on the random number  
                # Get a batch and make a step  
                start_time = time.time()  # record the start time of this batch  
                encoder_inputs, decoder_inputs, target_weights = model.get_batch(train_set, bucket_id)  # get a batch from the selected bucket id  
                if args.reinforce_learn:  
                    step_loss = model.step_rf(args, sess, encoder_inputs, decoder_inputs, target_weights, bucket_id, rev_vocab)  # make a step using the reinforcement learning loss function  
                else:  
                    step_loss = model.step(sess, encoder_inputs, decoder_inputs, target_weights, bucket_id=bucket_id, forward_only=False)  # make a step using the default loss function  
                # update the loss and current step after each batch/step finishs (in the end of this loop)  
                loss += step_loss / (time.time() - start

1.4模型预测和Beam Search模块


在预测模块,对应生成对话,我们需要利用Beam Search来寻找最优解。通过对Beam Size的控制可以保证输出语句的多样性。此外我们也可以加入强化学习,对于不同的机器人回答进行及时的人工反馈,通过Reinforcement Learning不断优化模型。

python
Get output logits for the sentence  
beams, now_beams, results = [(1.0, 0.0, i'eos': 0.0, 'dec inp': decoder_inputs, 'prob': 1.0, 'prob_ts': 1.0, 'prob_t': 4.0))]. []. [  
  
    Adjusted probability  
    all_prob_ts = model_step(encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id) if args.antilm else None  
    all_prob_t = model_step(dummy_encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id)  
  
    Normal seg2seg  
    if debug:  
        print(' '.join([dict_lookup(rev_vocab, w) for w in cand['dec_inp']]))  
    if cand[eos']:  
        results += [(prob, 0, cand)]  
        continue  
  Adjusted probability  
    all_prob_ts = model_step(encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id) if args.antilm else None  
    all_prob_t = model_step(dummy_encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id)  
  
  Adjusted probability  
    all_prob_ts = model_step(encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id) if args.antilm else None  
    all_prob_t = model_step(dummy_encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id)  
  
  Adjusted probability  
    all_prob_ts = model_step(encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id) if args.antilm else None  
    all_prob_t = model_step(dummy_encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id)  
]
all_prob_ts = model_step(encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id) if args.antilm else None  
all_prob_t = model_step(dummy_encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id)  
all_prob_ts = model_step(encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id) if args.antilm else None  
all_prob_t = model_step(dummy_encoder_inputs, cand['dec_inp'], dptr, target_weights, bucket_id)  
  
all_prob = all_prob_ts - args.antilm * all_prob_t #+ args.n_bonus * dptr + random() * 1e-50  
all_prob = all_prob_ts - args.antilm * all_prob_t  
if args.n_bonus != 0:  
    all_prob += args.n_bonus * dptr  
  
Suppress copy-cat (respond the same as input)  
if dptr < len(input_token_ids):  
    all_prob[input_token_ids[dptr]] = all_prob[input_token_ids[dptr]] * 0.01  
  
if return_raw:  
    return all_prob, all_prob_ts, all_prob_t  # beam search  
  
for c in np.argsort(all_prob)[::-1][:args.beam_size]:  
new_cand "  
gos	dec_inp"	(c - data_utils.EOS_ID),	[(np.array([c]) if i -- (dptr+1) else k) 
for i, k in enumerate(cand['dec_inp'])]	  
prob_ts	cand['prob_ts	*all_prob_ts[c]	  
prob prob cand['prob _ cand['prob ] * all_prob t[c]	  
new_cand = (new_cand['prob'], random(). new_cand) # stuff a randon to prevent comparing new_cand  
if len (new_beams) < args.beam_size:  
heapq. heappush(new_beams, new cand)   
elif (new cando[0] > new _beams[0][0]):   
heapq. heapreplace(new _beams, new _cand)   
except Exception as e:   
print("[Error]', e)  
print(" ----[new _beams]-- ")  
print("-ines _cand]\n", new _cand) -\n". new _beams)  
results += new _cands # flush last cands post-process results res _cands  
for prob, _ in sorted(results, reverse=True):  
cand['dec _inp']l- res _cands. append(cand) join([dict _lookup(rev _vocab. w) for w in cand['dec _inp']l]) retugn res _cands[:args. beam _size]

往期精彩文章:

基础课22——云服务(SaaS、Pass、laas、AIaas)-CSDN博客文章浏览阅读47次。云服务是一种基于互联网的计算模式,通过云计算技术将计算、存储、网络等资源以服务的形式提供给用户,用户可以通过网络按需使用这些资源,无需购买、安装和维护硬件设备。云服务具有灵活扩展、按需使用、随时随地访问等优势,可以降低用户成本,提高资源利用效率。随着云计算技术的不断发展,云服务的应用范围也将越来越广泛。https://blog.csdn.net/2202_75469062/article/details/134212001?spm=1001.2014.3001.5501

基础课20——智能客服系统的使用维护-CSDN博客文章浏览阅读72次。智能客服系统在上线后,仍然需要定期的维护和更新。这是因为智能客服系统是一个复杂的软件系统,涉及到多个组件和功能,需要不断优化和改进以满足用户需求和保持市场竞争力。https://blog.csdn.net/2202_75469062/article/details/134211359?spm=1001.2014.3001.5501

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1195546.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4面百度软件测试工程师的面试经验总结

没有绝对的天才&#xff0c;只有持续不断的付出。对于我们每一个平凡人来说&#xff0c;改变命运只能依靠努力幸运&#xff0c;但如果你不够幸运&#xff0c;那就只能拉高努力的占比。 2023年7月&#xff0c;我有幸成为了百度的一名测试工程师&#xff0c;从外包辞职了历经100…

解决Scrapy爬虫多线程导致抓取错乱的问题

目录 一、概述 二、问题分析 三、解决方案 四、案例分析 五、总结 一、概述 Scrapy是一个流行的Python爬虫框架&#xff0c;可以轻松地抓取网页数据并对其进行解析。然而&#xff0c;在抓取过程中&#xff0c;如果使用多线程进行并发处理&#xff0c;可能会遇到数据抓取错…

TCP触发海康扫码相机S52CN-IC-JQR-NNN25

PC环境设置 为保证客户端正常运行以及数据传输的稳定性&#xff0c;在使用客户端软件前&#xff0c;需要对 PC 环境 进行设置 关闭防火墙 操作步骤如下&#xff1a; 1. 打开系统防火墙。 2. 在自定义设置界面中&#xff0c;选择关闭防火墙的对应选项&#xff0c;并单击…

Linux学习教程(第一章 简介)1

Linux 系统已经渗透到 IT 领域的各个角落&#xff0c;作为一名 IT 从业人员&#xff0c;不管你是专注于编程&#xff0c;还是专注于运维&#xff0c;都应该对 Linux 有所了解&#xff0c;甚至还要深入学习&#xff0c;掌握核心原理。 Linux 学习建议&#xff1a;一定要安装 Li…

JSON可视化管理工具JSON Hero

本文软件由网友 zxc 推荐&#xff1b; 什么是 JSON Hero &#xff1f; JSON Hero 是一个简单实用的 JSON 工具&#xff0c;通过简介美观的 UI 及增强的额外功能&#xff0c;使得阅读和理解 JSON 文档变得更容易、直观。 主要功能 支持多种视图以便查看 JSON&#xff1a;列视图…

【斗罗二】霍雨浩拿下满分碾压戴华斌,动用家族力量,海神阁会议

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 深度爆料《绝世唐门》第23话最新预告分析&#xff0c;魂兽升学考试中一场白虎魂师戴华斌与千年级别的风虎的决斗即将上演。风虎&#xff0c;作为虎类魂兽的王者&#xff0c;其强大的实力和独特的技能让这场战…

现在学编程还能够月薪过万吗?

当我们谈到职业选择时&#xff0c;一项常受人关注的问题是&#xff0c;现在学编程还能月薪过万吗&#xff1f;这似乎是一个不断挂在年轻人嘴边的问题&#xff0c;尤其是在数字化时代&#xff0c;编程的需求越来越大。 所以今天让我们一起探讨这个问题&#xff0c;看看现实生活…

漫谈广告机制设计 | 万剑归宗:聊聊广告机制设计与收入提升的秘密(1)

小时候看武侠电视剧《风云》的时候&#xff0c;其中无名有一招叫“万剑归宗”&#xff0c;乃是剑术最高境界。修炼的口诀是“万气自生&#xff0c;剑冲废穴&#xff1b;归元武学&#xff0c;宗远功长”&#xff0c;也就是说欲练此功&#xff0c;先自废武功&#xff0c;然后回归…

HIT_OS_LAB3 操作系统的引导

操作系统实验三 3.1. 实验目的 熟悉实验环境&#xff1b;建立对操作系统引导过程的深入认识&#xff1b;掌握操作系统的基本开发过程&#xff1b;能对操作系统代码进行简单的控制&#xff0c;揭开操作系统的神秘面纱。 3.2. 实验内容 3.2.1. 改写 bootsect.s 主要完成如下功…

如何下载Linux源码,看这篇就够了!

文章目录 前言一、linux官网二、查找发布版本三、下载方式 前言 在工作中&#xff0c;我们难免会遇到需要去找某个版本的linux源码的情况&#xff0c;今天这篇文章就手把手教大家如何找到自己想要的linux源码版本 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例…

医学影像系统源码(MRI、CT三维重建)

一、MRI概述 核磁共振成像&#xff08;英语&#xff1a;Nuclear Magnetic Resonance Imaging&#xff0c;简称NMRI&#xff09;&#xff0c;又称自旋成像&#xff08;英语&#xff1a;spin imaging&#xff09;&#xff0c;也称磁共振成像&#xff08;Magnetic Resonance Imag…

大数据Doris(二十):数据导入(Broker Load)介绍

文章目录 数据导入(Broker Load)介绍 一、​​​​​​​适用场景

docker通过nginx代理tomcat-域名重定向

通过昨天的调试&#xff0c;今天做这个域名就简单了&#xff0c; 正常我们访问网站一般都是通过域名比如&#xff0c;www.baidu.com对吧&#xff0c;有人也通过ip&#xff0c;那么这个怎么做呢&#xff1f;物理机windows可以通过域名访问虚拟机linux的nginx代理转向tomcat服务…

6.5对称二叉树(LC101-E)

算法&#xff1a; 其实就是比较左右子树是否可以翻转 比较的时候&#xff1a; 比较外面的节点是否相等&#xff0c;如示例1中的节点3 比较里面的节点是否相等&#xff0c;如示例1中的节点4 基本思路是这样的&#xff0c;那怎么遍历呢&#xff1f; 二叉树的题一定要掌握到…

开放式耳机井喷阶段,南卡品牌何以成为“头号玩家”?

对于耳机行业而言,过去两年的聚光灯属于开放式耳机这一才闯入赛道的品类。 在消费电子寒冬持续蔓延的时间节点,夺下属于自己的高光时刻实属不易,毕竟无论是过去数年间高歌猛进的智能可穿戴设备行业,还是更垂直的耳机赛道,现阶段均面临承压的局面。 一面是“前辈”们昔日的“爆…

HTB——常见端口及协议总结

文章目录 一、 常见端口二、HTTP协议三、FTP四、SMB 一、 常见端口 http协议&#xff1a;80、8000https协议&#xff1a;443、8443ftp协议&#xff1a;20&#xff08;数据传输&#xff09;、21&#xff08;发送命令&#xff09;smb协议&#xff1a;445 二、HTTP协议 https的…

【电源专题】POE 802.3af/at与802.3bt在握手阶段有什么差异

在文章:【电源专题】PSE如何与PD握手协商功率等级?中我们以PSE与PD设备在802.3af/at协议握手为例,讲到了PSE与PD协商时通过三个阶段:检测阶段、握手阶段、电压提升阶段。而对于802.3bt的握手存在明显的不同,所以本文就详细解释一下802.3bt协议为什么握手阶段与802.3af/at存…

《RN移动开发实战》3出版了,文末抽奖

前言 众所周知&#xff0c;传統的原生Android、iOS开发技术虽然比较成熟&#xff0c;但是多端重复开发的成本和开发效率的低下也是很多企业不愿意看到的&#xff0c;而不断崛起的跨平台技术让企业看到了曙光&#xff0c;“一次编写&#xff0c;处处运行”也不再是难以企及的目…

Mac上好用的翻译软件推荐 兼容m

Mac翻译软件可以用在学习&#xff0c;工作&#xff0c;生活当中&#xff0c;一款好用的翻译软件&#xff0c;具有翻译准确&#xff0c;翻译快速等基本特点&#xff0c;能够帮您提高工作效率。Mac上有什么好用的翻译软件呢&#xff1f;今天小编为大家整理了6款好用的Mac翻译软件…

YOLOv7改进:RefConv | 即插即用重参数化重聚焦卷积替代常规卷积,无额外推理成本下涨点明显

1.该文章属于YOLOV5/YOLOV7/YOLOV8改进专栏,包含大量的改进方式,主要以2023年的最新文章和2022年的文章提出改进方式。 2.提供更加详细的改进方法,如将注意力机制添加到网络的不同位置,便于做实验,也可以当做论文的创新点 3.涨点效果:RefConv,实现有效涨点! 论文地址 …