当前位置:   article > 正文

最简洁的Plato-mini闲聊机器人部署教程,举一反三部署类chatGPT

plato-mini

★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>


百度PLATO-Mini闲聊模型

PLATO-MINI| 6-layers, 12-heads, 768-hidden|在十亿级别的中文对话数据上进行预训练。参数量更小,但效果更好。只支持闲聊型对话。

无需任何前端知识,学会最简单的Plato-mini闲聊机器人部署教程,举一反三,通过替换模型或者API,可以部署现有OpenAI提供的GPT API和未来的文心一言模型

学会教程,拥有一款专属于自己的chatGPT!

环境要求

# 更新paddlenlp的版本 >= 2.5.0
!pip install --upgrade paddlenlp
  • 1
  • 2

PaddleNLP2.5.0 新特新之一

HuggingFace 生态联合

PaddleNLP首次和HuggingFace生态联合,支持所有Model和Tokenizer类支持直接从Huggingface Hub下载和上传,开发者可以直接从HuggingFace体验预训练模型效果

  • 所有Model和Tokenizer类支持直接从Huggingface Hub下载和上传
  • Text Summarization, Fill Mask, Dialogue Taskflow支持直接从Huggingface Hub加载, 并且连通HuggingFace Inference API
  • 新增ConversionMixin, bert和gpt模型的from_pretrained 支持直接从Huggingface Hub加载torch权重的模型

1 开箱即用

基于PLATO-MINI,模型在十亿级别的中文对话数据上进行了预训练,闲聊场景对话效果显著。

使用Taskflow,等待模型加载完毕,可以在ai studio直接体验开箱即用的交互式闲聊对话。

# 加载Taskflow
from paddlenlp import Taskflow
dialogue = Taskflow("dialogue")
  • 1
  • 2
  • 3
# 单句对话(非交互式)
dialogue(["你好,我是桨飞飞"])
  • 1
  • 2

推荐:使用终端terminal进入python解释器进行体验

可配置参数:

  • max_turn:任务能记忆的对话轮数,当max_turn为1时,模型只能记住当前对话,无法获知之前的对话内容。

输入exit可退出交互模式

# 多轮对话(交互式)

# 取消下方代码注释,体验交互,输入`exit`可退出交互模式
# dialogue.interactive_mode(max_turn=4)
  • 1
  • 2
  • 3
  • 4

2 剖析interaction源码

从源码中看PLATO-MINI的interaction的交互是如何做工作的?
先忽略max_turn这个参数,仅看轮询交互的逻辑,地址:源码

  • 定位到源码py文件中的49~88行,可以看到如下的interaction函数
def interaction(args, model, tokenizer):
    history = []
    start_info = "Enter [EXIT] to quit the interaction, [NEXT] to start a new conversation."
    cprint(start_info, "yellow", attrs=["bold"])
    while True:
        user_utt = input(colored("[Human]: ", "red", attrs=["bold"])).strip()
        if user_utt == "[EXIT]":
            break
        elif user_utt == "[NEXT]":
            history = []
            cprint(start_info, "yellow", attrs=["bold"])
        else:
            history.append(user_utt)
            inputs = tokenizer.dialogue_encode(
                history, add_start_token_as_response=True, return_tensors=True, is_split_into_words=False
            )
            inputs["input_ids"] = inputs["input_ids"].astype("int64")
            ids, scores = model.generate(
                input_ids=inputs["input_ids"],
                token_type_ids=inputs["token_type_ids"],
                position_ids=inputs["position_ids"],
                attention_mask=inputs["attention_mask"],
                max_length=args.max_dec_len,
                min_length=args.min_dec_len,
                decode_strategy=args.decode_strategy,
                temperature=args.temperature,
                top_k=args.top_k,
                top_p=args.top_p,
                num_beams=args.num_beams,
                length_penalty=args.length_penalty,
                early_stopping=args.early_stopping,
                num_return_sequences=args.num_return_sequences,
                use_fast=True,
            )
            bot_response = select_response(
                ids, scores, tokenizer, args.max_dec_len, args.num_return_sequences, keep_space=False
            )[0]
            print(colored("[Bot]:", "blue", attrs=["bold"]), colored(bot_response, attrs=["bold"]))
            history.append(bot_response)
    return
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 在函数起始部分,源码中定义了一个名为history的列表,用于存放用户的历史问询(50行)
  • 通过user_utt接收用户的输入指令(54行)
  • 根据if-elif-else可以判断出user_utt共有三种状态:(55~61行)
    • [EXIT] :输入exit结束对话
    • [NEXT] :输入next重置机器人
    • 正常语句:输入正常对话,history会保存当前对话
  • 当用户正常输入语句时,使用tokenizer编码history中的所有对话得到inputs信息(可以猜测max_turn=n就是保留最近的n次对话,把history更改为history[-(n*2):]可以很容易自定义记忆对话轮数的功能) (62-65行)
  • 把inputs信息输入model.generate返回ids,scores,然后使用封装好的select_response(已下载带AI_Studio中)得到分数最佳的回答(66~85行)
  • 把模型的回答保存至history中(87行)
  • End

可以发现PLATO-MINI的闲聊交互模式,逻辑是比较简单的,通过将所有历史对话数据保存并全部输入到模型的方式习得上下文信息

3 Streamlit和st-chat背景介绍

只在terminal中进行闲聊交互不满足与我们的需求
如何使用最便捷的方式构建一个交互式的前端页面用于作品分享和传播呢?
答案之一是:Streamlit

Streamlit 是一个基于 Python 的 Web 应用程序框架,致力于以更高效、更灵活的方式可视化数据,并分析结果。作为一个开源库,可以帮助数据科学家和学者在短时间内开发机器学习 (ML) 可视化仪表板。只需几行代码,我们就可以构建并部署强大的数据应用程序。

为什么选择Streamlit?

目前,应用程序需求量巨大,开发人员需要一直开发新的库和框架,帮助构建并部署快速上手的仪表板。Streamlit库可将仪表板的开发时间从几天缩短至几小时。以下是选择 Streamlit 的原因:

  1. Streamlit是一个免费的开源库,和安装其他python 包一样, Streamlit的安装非常简单。
  2. Streamlit学起来很容易,无需要任何 Web 开发经验,只需对 Python 有基本的了解,就足以构建数据应用程序。
  3. Streamlit与大部分机器学习框架兼容,包括 Tensorflow 和 Pytorch、Scikit-learn 和可视化库,如 Seaborn、Altair、Plotly 等。
  4. Streamlit作为开源库,其强大的插件生态可以帮你快速搭建很多复杂的应用。

AI Studio提供了Streamlit

通过 点击 - 文件 - 新建 - Streamlit文件 可以创建一个Streamlit.py程序用于构建即使应用

Streamlit中文使用博客推荐:无需前端技能 用Streamlit部署你的模型

st-chat一款再streamlit中快速构建聊天机器人的插件

地址:Github

首先是安装st-chat,由于AI Studio的Python环境默认为3.7版本,直接pip安装会报错,所以直接git到AI Studio本地进行加载,除了一些报错信息,目前在本项目中运行,AI Studio在本项目中运行from streamlit_chat import message不会发生错误。

在streamlit.py文件中运行一下示例代码:

import streamlit as st
from streamlit_chat import message

message("My message") 
message("Hello bot!", is_user=True)  # align's the message to the right
  • 1
  • 2
  • 3
  • 4
  • 5

如下图所示,可以看到一个经典的对话框

这里我们举一反三,仿照作者在examples给出的复杂一些/examples/chatbot.py构建基于PLATO-MINI模型的闲聊机器人

PS:若后续开放了文心一言的API,有key的小伙伴也可以尝试部署为对话机器人,其他的模型和API接口也可以举一反三部署为Chat Bot

4 在Streamlit上部署PLATO-MINI

先查看例子,看看需要修改什么?

  • 我们没有使用API获得回答,而是通过模型,需要加载模型的代码和通过模型返回答案的函数(原始query函数失效,需重写)

  • 修改一下get_text()为中文“你好!”开始

  • 没有保存历史对话功能,添加一个保存history的列表,增加历史对话保存能力

import streamlit as st
from streamlit_chat import message
import requests

st.set_page_config(
    page_title="Streamlit Chat - Demo",
    page_icon=":robot:"
)

API_URL = "https://api-inference.huggingface.co/models/facebook/blenderbot-400M-distill"
headers = {"Authorization": st.secrets['api_key']}

st.header("Streamlit Chat - Demo")
st.markdown("[Github](https://github.com/ai-yash/st-chat)")

if 'generated' not in st.session_state:
    st.session_state['generated'] = []

if 'past' not in st.session_state:
    st.session_state['past'] = []

def query(payload):
	response = requests.post(API_URL, headers=headers, json=payload)
	return response.json()

def get_text():
    input_text = st.text_input("You: ","Hello, how are you?", key="input")
    return input_text 


user_input = get_text()

if user_input:
    output = query({
        "inputs": {
            "past_user_inputs": st.session_state.past,
            "generated_responses": st.session_state.generated,
            "text": user_input,
        },"parameters": {"repetition_penalty": 1.33},
    })

    st.session_state.past.append(user_input)
    st.session_state.generated.append(output["generated_text"])

if st.session_state['generated']:

    for i in range(len(st.session_state['generated'])-1, -1, -1):
        message(st.session_state["generated"][i], key=str(i))
        message(st.session_state['past'][i], is_user=True, key=str(i) + '_user')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

4.1 增加 - 模型加载

# 加载模型
from paddlenlp.transformers import UnifiedTransformerTokenizer
from paddlenlp.transformers import UnifiedTransformerLMHeadModel

model_name = 'plato-mini'
model = UnifiedTransformerLMHeadModel.from_pretrained(model_name)
tokenizer = UnifiedTransformerTokenizer.from_pretrained(model_name)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4.2 修改query - 获取回答

from utils import select_response
# 修改query,参数使用源码中的默认值
def query(history):
    inputs = tokenizer.dialogue_encode(
        history, add_start_token_as_response=True, return_tensors=True, is_split_into_words=False
    )
    inputs["input_ids"] = inputs["input_ids"].astype("int64")
    ids, scores = model.generate(
        input_ids=inputs["input_ids"],
        token_type_ids=inputs["token_type_ids"],
        position_ids=inputs["position_ids"],
        attention_mask=inputs["attention_mask"],
        max_length=64,
        min_length=1,
        decode_strategy="sampling",
        temperature=1.0,
        top_k=5,
        top_p=1.0,
        num_beams=0,
        length_penalty=1.0,
        early_stopping=False,
        num_return_sequences=20,
    )
    max_dec_len = 64
    num_return_sequences = 20
    bot_response = select_response(
        ids, scores, tokenizer, max_dec_len, num_return_sequences, keep_space=False
    )[0]
    return bot_response
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

4.3 修改get_text - 切换中文

# 修改后
def get_text():
    input_text = st.text_input("用户: ","你好!", key="input")
    return input_text 
  • 1
  • 2
  • 3
  • 4

4.4 增加history - 保留上下文

history = []
user_input = get_text()
history.append(user_input)
if user_input:
    output = query(history)
    st.session_state.past.append(user_input)
    st.session_state.generated.append(output)
    history.append(output)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4.5 修改后的完整代码

import streamlit as st
from streamlit_chat import message
from utils import select_response
# 加载模型
from paddlenlp.transformers import UnifiedTransformerTokenizer
from paddlenlp.transformers import UnifiedTransformerLMHeadModel

model_name = 'PLATO-MINI'
model = UnifiedTransformerLMHeadModel.from_pretrained(model_name)
tokenizer = UnifiedTransformerTokenizer.from_pretrained(model_name)

st.set_page_config(
    page_title="PLATO-MINI Chat - Demo",
    page_icon=":robot:"
)

st.header("PLATO-MINI Chat - Demo")
st.markdown("[Github](https://github.com/ai-yash/st-chat)")

if 'generated' not in st.session_state:
    st.session_state['generated'] = []

if 'past' not in st.session_state:
    st.session_state['past'] = []

def query(history):
    inputs = tokenizer.dialogue_encode(
        history, add_start_token_as_response=True, return_tensors=True, is_split_into_words=False
    )
    inputs["input_ids"] = inputs["input_ids"].astype("int64")
    ids, scores = model.generate(
        input_ids=inputs["input_ids"],
        token_type_ids=inputs["token_type_ids"],
        position_ids=inputs["position_ids"],
        attention_mask=inputs["attention_mask"],
        max_length=64,
        min_length=1,
        decode_strategy="sampling",
        temperature=1.0,
        top_k=5,
        top_p=1.0,
        num_beams=0,
        length_penalty=1.0,
        early_stopping=False,
        num_return_sequences=20,
    )
    max_dec_len = 64
    num_return_sequences = 20
    bot_response = select_response(
        ids, scores, tokenizer, max_dec_len, num_return_sequences, keep_space=False
    )[0]
    return bot_response

def get_text():
    input_text = st.text_input("用户: ","你好!", key="input")
    return input_text  

history = []
user_input = get_text()
history.append(user_input)
if user_input:
    output = query(history)
    st.session_state.past.append(user_input)
    st.session_state.generated.append(output)
    history.append(output)

if st.session_state['generated']:

    for i in range(len(st.session_state['generated'])-1, -1, -1):
        message(st.session_state["generated"][i], key=str(i))
        message(st.session_state['past'][i], is_user=True, key=str(i) + '_user')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

5 更新Streamlit.py看效果

结束语

相信大家已经掌握了Taskflow和Streamlit部署PLATO-MINI的正确打开方式,快快动手体验吧!

本项目基于PaddleNLP 一键预测功能。

如果对您有帮助,欢迎star收藏一下,不易走丢哦~链接指路:https://github.com/PaddlePaddle/PaddleNLP

现在,开启你的NLP之旅吧!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/337093
推荐阅读
相关标签