从零开始玩转TensorFlow:小明的机器学习故事 6

发布于:2025-02-26 ⋅ 阅读:(16) ⋅ 点赞:(0)

小明与企业客服升级的故事

1 场景背景:让客户满意的挑战

小明近期在一家电商企业实习,发现公司常接到顾客各种各样的问题:

  • “你们的最新产品有什么功能?”
  • “能否介绍一下优惠活动?”
  • “是否支持7天无理由退换?”
  • “我怎么查物流?”

人工客服应接不暇,于是小明提出打造一款 “自动客服机器人” 的想法,专门回答常见问题或提供产品介绍。除此之外,市场部门也希望能自动生成一段营销文案来吸引顾客。小明决定用深度学习中的RNN文本生成来为企业客服带来更多“创意回复”的可能性。


2 目标与原理:RNN帮助“写文案、答问题”

  1. 目标

    • 降低客服压力:自动回复部分重复性问题;
    • 生成简易文案:基于用户关键字自动组成一句或几句介绍文本。
  2. 为什么使用RNN来做文本生成

    • 序列数据处理:客服对话、产品描述都是自然语言文本;
    • 灵活回答:既能在已有数据基础上“学习”企业话术,又能在生成阶段适当拼接新词汇,提供多样化回复;
    • 融入对话场景:后续也可扩展为更高级的Seq2Seq或Transformer结构。

3 从数据到部署:完整代码示例

下面以两个脚本 train.pyapp.py 来演示:

  1. train.py:包含极简示例数据、数据处理、RNN 模型构建与训练,并保存为 H5 格式(Keras 3 兼容)。
  2. app.py:使用 Flask 加载已训练的 H5 模型,实现一个简易的网页界面,让用户输入开头文字,系统自动继续生成文本。

提示:以下示例仅作演示用,数据量非常少,生成效果可能“驴唇不对马嘴”。在商业场景需准备更多语料、做更强大模型或使用检索式问答等。


3.1 项目目录结构

在名为 rnn_text_generation_demo 的文件夹中放置以下文件:

rnn_text_generation_demo/
 ├── train.py         # 训练脚本
 ├── app.py           # Flask 部署脚本
 └── saved_model/     # 保存模型用,脚本运行后自动生成

3.2 训练脚本:train.py

请将下面代码复制到 train.py 文件里。它会执行以下步骤:

  1. 准备一小段原始文本数据(客服与产品描述示例)。
  2. 清洗、分词,构建词典。
  3. 组织 (input, target) 序列进行训练。
  4. 构建并训练一个简单的 LSTM 模型。
  5. 以 H5 格式 保存模型 + 词典信息(为 Keras 3 兼容重点)。
"""
train.py

示例:使用 tf.keras + RNN(LSTM) 做简单的文本生成训练,并以H5方式保存模型,兼容Keras 3。
"""

import tensorflow as tf
import re
import os

# ============= 1. 示例数据(极简) =============
raw_text_corpus = [
    "我们的新款手机屏幕是6.5英寸,拥有1080P高清分辨率。",
    "这款耳机支持降噪功能,续航时间可达24小时。",
    "满500减50的活动正在进行中,抓紧抢购哦!",
    "这款运动鞋防水、防滑,适合户外运动。",
    "物流信息可通过订单号在官网查询。",
    "我们的客服团队将竭诚为您服务。",
    "欢迎咨询产品详情或优惠活动。"
]

# ============= 2. 数据清洗与分词 =============
def simple_clean_text(text):
    # 仅作基本示例:去除特殊字符,只保留中英文、数字和常见标点
    text = re.sub(r"[^a-zA-Z0-9\u4e00-\u9fa5。,!?:,\.\!\?\:]", "", text)
    return text

def simple_tokenize(text):
    """
    极简分词示例:把中文当作逐字拆分,英文数字以字符拆分。
    真实项目请使用jieba或更成熟分词工具。
    """
    text = text.strip()
    tokens = []
    for char in text:
        if char.strip():
            tokens.append(char)
    return tokens

cleaned_sentences = []
for line in raw_text_corpus:
    line = simple_clean_text(line)
    tokens = simple_tokenize(line)
    cleaned_sentences.append(tokens)

# ============= 3. 建立词典 =============
all_tokens = []
for tokens in cleaned_sentences:
    all_tokens.extend(tokens)

unique_tokens = list(set(all_tokens))

# 保留一些特殊token
word_to_id = {"<PAD>":0, "<UNK>":1}
for idx, token in enumerate(unique_tokens, start=2):
    word_to_id[token] = idx

id_to_word = {v:k for k,v in word_to_id.items()}
vocab_size = len(word_to_id)  # 词典大小

# ============= 4. 组织 (input, target) 数据 =============
input_sequences = []
target_sequences = []

for tokens in cleaned_sentences:
    token_ids = [word_to_id.get(t, 1) for t in tokens]
    for i in range(1, len(token_ids)):
        input_part = token_ids[:i]
        target = token_ids[i]
        input_sequences.append(input_part)
        target_sequences.append(target)

max_len = 10
from tensorflow.keras.preprocessing.sequence import pad_sequences
X = pad_sequences(input_sequences, maxlen=max_len, padding='pre', value=0)
y = tf.convert_to_tensor(target_sequences)

print("样本数:", len(X))
print("词典大小:", vocab_size)

# ============= 5. 构建 LSTM 模型 =============
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(input_dim=vocab_size, 
                              output_dim=64, 
                              input_length=max_len),
    tf.keras.layers.LSTM(128),
    tf.keras.layers.Dense(vocab_size, activation='softmax')
])

model.compile(loss='sparse_categorical_crossentropy', 
              optimizer='adam', 
              metrics=['accuracy'])

model.summary()

# ============= 6. 训练 =============
model.fit(X, y, batch_size=4, epochs=20)

# ============= 7. 以 H5 格式 保存模型 =============
os.makedirs("saved_model", exist_ok=True)
save_path = "saved_model/my_rnn_model.h5"  # 使用H5后缀
model.save(save_path)
print(f"模型已保存到: {save_path}")

# ============= 8. 保存词典与参数信息 =============
import pickle
dict_info = {
    "word_to_id": word_to_id,
    "id_to_word": id_to_word,
    "max_len": max_len
}
with open("saved_model/dict_info.pkl", "wb") as f:
    pickle.dump(dict_info, f)
print("词典和参数信息已保存到: saved_model/dict_info.pkl")

如何运行

  • 进入 rnn_text_generation_demo 目录
  • 执行 python train.py
  • 若无报错,训练结束后会在 saved_model/ 目录下生成 my_rnn_model.h5dict_info.pkl

3.3 Flask部署脚本:app.py

下面是 Flask 的部署示例,放到 app.py 文件中。它将做以下几步:

  1. 加载我们在 train.py 中保存的 H5 模型 (my_rnn_model.h5);
  2. 导入词典和最大序列长度;
  3. 提供一个网页输入框,让用户输入开头的文字;
  4. 调用模型来逐词生成后续文本;
  5. 返回生成的结果到网页上显示。
"""
app.py

示例:使用Flask部署训练好的RNN模型,实现简易的“自动续写”功能。
"""
import os
import pickle
from flask import Flask, request
import tensorflow as tf
import numpy as np
import re

app = Flask(__name__)

# ============= 1. 加载模型和词典信息 (兼容Keras 3) =============
model_path = "saved_model/my_rnn_model.h5"
model = tf.keras.models.load_model(model_path)

with open("saved_model/dict_info.pkl", "rb") as f:
    dict_info = pickle.load(f)

word_to_id = dict_info["word_to_id"]
id_to_word = dict_info["id_to_word"]
max_len = dict_info["max_len"]
vocab_size = len(word_to_id)

def simple_clean_text(text):
    text = re.sub(r"[^a-zA-Z0-9\u4e00-\u9fa5。,!?:,\.\!\?\:]", "", text)
    return text.strip()

def simple_tokenize(text):
    tokens = []
    for char in text:
        if char.strip():
            tokens.append(char)
    return tokens

# ============= 2. 构建文本生成函数 =============
def generate_text_rnn(model, start_string, num_generate=10):
    start_string = simple_clean_text(start_string)
    tokens = simple_tokenize(start_string)
    token_ids = [word_to_id.get(t, 1) for t in tokens]

    # 保证输入长度不超过max_len
    if len(token_ids) > max_len:
        token_ids = token_ids[-max_len:]

    input_eval = np.zeros((1, max_len), dtype=np.int32)
    input_eval[0, -len(token_ids):] = token_ids

    result = tokens[:]

    for _ in range(num_generate):
        predictions = model.predict(input_eval, verbose=0)
        predicted_id = np.argmax(predictions[0])
        predicted_word = id_to_word.get(predicted_id, "<UNK>")
        result.append(predicted_word)

        seq_list = list(input_eval[0])
        seq_list.append(predicted_id)
        seq_list = seq_list[-max_len:]
        input_eval[0] = seq_list

    return "".join(result)

# ============= 3. Flask 路由 =============
@app.route("/", methods=["GET", "POST"])
def index():
    html_form = """
    <html>
    <head>
      <title>RNN Text Generation Demo</title>
    </head>
    <body>
      <h1>简易RNN文本生成演示</h1>
      <form method="post">
          <label>请输入开头文本:</label><br>
          <input type="text" name="user_input" style="width:400px;" /><br><br>
          <button type="submit">生成</button>
      </form>
      <hr>
      {}
    </body>
    </html>
    """

    if request.method == "POST":
        user_input = request.form.get("user_input", "")
        if user_input.strip():
            generated_text = generate_text_rnn(model, user_input, num_generate=20)
            return html_form.format(f"<p><strong>生成结果:</strong> {generated_text}</p>")
        else:
            return html_form.format("<p>请输入有效文本。</p>")
    else:
        return html_form.format("")

if __name__ == "__main__":
    app.run(debug=True, port=5000)

如何运行

  • 确保 train.py 已成功执行并生成 my_rnn_model.h5dict_info.pkl
  • 执行 python app.py
  • 打开浏览器访问 http://127.0.0.1:5000/
  • 在输入框里键入一些文字(如“我们的新款手机”),点击“生成”,即可得到后续词生成的演示结果。

在这里插入图片描述

5 结果验证与改进方向

  1. 生成结果:由于示例数据非常有限,你可能得到语句片段像“我们的新款耳机支持客服活动满500减”。这说明模型只是在小样本上拼接 learned tokens,缺乏长语境训练。
  2. 数据规模:商业场景通常需要数千甚至数十万条客服/产品记录,以提升模型的生成质量;
  3. 模型结构:可以尝试多层RNN、双向RNN、Seq2Seq、Transformer等,更适合问答或复杂上下文;
  4. 部署:若要上线,需要考虑并发量、响应速度、GPU加速或容器化(Docker/K8s)等。

6 小结:企业客服升级的第一步

  • 你已看到一个从数据训练保存Flask加载的端到端流程;
  • 通过 H5 文件 来存储模型,以便在 Keras 3 环境下顺利使用;
  • 尽管示例极其简化,却为你在“对话与文案生成”的商业项目中打下基础。如果想让客服机器人真正可用,还需结合“知识库检索”“问答匹配”与“强化生成式”方法,使回复既有创意又能正确地回答顾客问题。

祝你在企业客服升级之路上一切顺利,为公司和客户提供更优质、更高效的服务体验!


网站公告

今日签到

点亮在社区的每一天
去签到