【ChatGPT原理与应用开发】第三章:句词分类

【ChatGPT原理与应用开发】第三章:句词分类

原文链接:HuggingLLM(ChatGPT原理与应用开发)-课程详情 | Datawhale

此处仅为学习记录和总结

3:句词分类------句子Token都是类别

3.1:句词分类基础

NLU(自然语言理解)

natural language understanding

Query解析:用户输入查询(Query),需要系统给出响应的场景

🤔Query解析(例如:智能对话)的处理过程

  • 情感分析

    • 细粒度情感分析:对不同实体或属性的情感倾向
      例如:商品评论 => 价格 & 快递 & 客服服务...
  • 意图识别

    • 多标签分类:给定输入文本,输出多个标签

      例如:地址、时间、价格

    • 层级标签分类:给定输入文本,输出从根节点到最终细粒度类别的路径

      例如:地址/家庭地址、地址/公司地址

  • 实体和关系抽取

    • 实体:具有特定意义的实词
      例如:人名、地名
    • 关系抽取:实体和实体之间的关系判断,常用三元组表示
      例如:曹雪芹(人名)、红楼梦(作品),编写(二者之间的关系),三元组表示为(曹雪芹,编写,红楼梦)

句词分类

句子级别的分类:给一个句子,给出一个或多个标签

  • 情感分析
  • 意图识别
  • 关系抽取

token级别的分类:给一段文本和一个问题,在文本中找出问题的答案(即:给一个句子,给出对应实体或答案的索引位置)

  • 实体抽取
  • 阅读理解

🤔token级别分类的例子

句子:中国四大名著之首红楼梦由清代作家曹雪芹编写

标注:token以字进行分割

中
国
四
大
名
著
之
首
红	begin-work
楼	inter-work
梦	inter-work
由
清
代
作
家
曹	begin-person
雪	inter-person
芹	inter-person
编
写

其他字的标注为	others
begin标签表示开始
inter标签表示内部
others标签表示其他非实体
work标签表示作品
person标签表示人名

句子分类,sequence classification

🤔句子分类的步骤

  • 将给定句子或文本,变成embedding表示
  • 将embedding表示传入神经网络,计算不同标签的概率分布
  • 比较标签概率分布与真实标签,将误差回传,修改神经网络参数(训练神经网络)
  • 得到训练好的神经网络(模型

🤔单个标签的句子分类的示例

embedding数组:生成一个均值为0、标准差为1的1 * 32的高斯分布

维度1 => 词表里面只有1个token(即这1个句子就是1个token)

import numpy as np
np.random.seed(0)

# 0:均值,1:标准差,1*32:维度
emd = np.random.normal(0, 1, (1, 32))

句子实行三分类 ,模型参数 W 的维度为32 * 3

W = np.random.random((32, 3))
z = emd @ W

# z的结果
# z == array([[6.93930177, 5.96232449, 3.96168115]])
# z.shape == (1, 3)

标签概率分布 => 归一化z

def norm(z):
    exp = np.exp(z)
    return exp / np.sum(exp)

y = norm(z)

# y的结果,各个标签的概率求和后为1
# y == array([[0.70059356, 0.26373654, 0.0356699 ]])
# np.sum(y) == 0.9999999999999999

预测标签为0的概率最大,为70.06%

假设真实标签为1,为100%,而该标签对应在模型中的概率为26.37%,则下一次训练时会回传loss,调整参数 W

注意: W 可以是多个数组组成,只要最后矩阵乘法的结果是1 * 3即可

例如:W由3个子矩阵组成,分别是w1、w2和w3

w1 = np.random.random((32, 100))
w2 = np.random.random((100, 32))
w3 = np.random.random((32, 3))

y = norm(norm(norm(emd @ w1) @ w2) @ w3)

# y的结果
y == array([[0.32940147, 0.34281657, 0.32778196]])

🤔多个标签的句子分类的示例

假设有10个标签,需要表示10个标签的概率分布。例如:

def norm(z):
	# 指定维度求和
    axis = -1
    exp = np.exp(z)
    return exp / np.expand_dims(np.sum(exp, axis=axis), axis)

np.random.seed(42)

# embedding数组为1 * 32
emd = np.random.normal(0, 1, (1, 32))
# W数组为10 * 32 * 2
W = np.random.random((10, 32, 2))


y = norm(emd @ W)
# y数组为10 * 1 * 2
# 即10个标签最后均输出为1 * 2的矩阵
# y.shape == (10, 1, 2)

y == array([
    [[0.66293305, 0.33706695]],
    [[0.76852603, 0.23147397]],
    [[0.59404023, 0.40595977]],
    [[0.04682992, 0.95317008]],
    [[0.84782999, 0.15217001]],
    [[0.01194495, 0.98805505]],
    [[0.96779413, 0.03220587]],
    [[0.04782398, 0.95217602]],
    [[0.41894957, 0.58105043]],
    [[0.43668264, 0.56331736]]
])

输出每一行有两个值,分别表示"不是该标签"和"是该标签"的概率

token分类

🤔embedding数组的对比

假设给定文本的长度是10,维度是32,则:

  • 句子分类为 (1, 32)
  • token分类为 (1, 10, 32)

即:文本的每个token是一个32维的向量

假设标签有5个,则:

# 生成一个均值为0,标准差为1的1*10*32维度的embedding向量
emd = np.random.normal(0, 1, (1, 10, 32))

# 参数矩阵的维度是32*5
W = np.random.random((32, 5))

z = emd @ W
y = norm(z)

# y的维度,1*10*5
# y.shape == (1, 10, 5)

"""
y == array([[
    [0.23850186, 0.04651826, 0.12495322, 0.28764271, 0.30238396],
    [0.06401011, 0.3422055 , 0.54911626, 0.01179874, 0.03286939],
    [0.18309536, 0.62132479, 0.09037235, 0.06016401, 0.04504349],
    [0.01570559, 0.0271437 , 0.20159052, 0.12386611, 0.63169408],
    [0.1308541 , 0.06810165, 0.61293236, 0.00692553, 0.18118637],
    [0.08011671, 0.04648297, 0.00200392, 0.02913598, 0.84226041],
    [0.05143706, 0.09635837, 0.00115594, 0.83118412, 0.01986451],
    [0.03721064, 0.14529403, 0.03049475, 0.76177941, 0.02522117],
    [0.24154874, 0.28648044, 0.11024747, 0.35380566, 0.0079177 ],
    [0.10965428, 0.00432547, 0.08823724, 0.00407713, 0.79370588]
]])
"""

第一个token是0标签的概率是23.85%,是1标签的概率是4.65%,是2标签的概率是12.50%,是3标签的概率是28.76%,是4标签的概率是30.24%,因此标签概率最高的是4标签

而后根据第一个token的真实标签,进行损失回传,调整 W 矩阵的参数

3.2:ChatGPT接口使用

OpenAI的Completion接口

利用大模型的In-Context能力进行零样本或少样本的推理

  • in-context:模型根据输入的文本,可以自动给出对应的结果

  • 零样本:直接给模型文本,获得标签或输出

  • 少样本:给模型一些类似的样例(输入+输出),再拼上一个新的没有输出的输入,让模型给出输出

    import openai

    OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
    openai.api_key = OPENAI_API_KEY

    def complete(prompt: str) -> str:
    response = openai.Completion.create(
    model="text-davinci-003",
    prompt=prompt,
    temperature=0,
    max_tokens=64,
    top_p=1.0,
    frequency_penalty=0.0,
    presence_penalty=0.0
    )
    ans = response.choices[0].text
    return ans

🤔completion的参数说明

  • model:指定的openai模型
  • prompt:提示词,默认为<|endoftext|>
  • temperature:采样温度,默认为1
    • 取值范围:[0, 2]
    • 值越小,输出更确定
    • 值越大,输出更随机(多样化)
  • max-tokens:生成的最大token数,默认为16
    • 提示词 + 生成的文本,所有的token长度不能超过模型的上下文长度
  • top-p:下一个token在累计概率为top_p的token中采样,默认为1
    • 0.8:只选择前80%概率的token进行下一次采样
  • frequency_penalty:频次惩罚,默认为0
    • 取值范围:[-2, 2]
    • 正值:根据新token到目前为止在文本中的现有频率来惩罚新token
    • 降低模型重复生成相同内容的可能性
  • presence_penalty:存在惩罚,默认为0
    • 取值范围:[-2, 2]
    • 正值:根据新token到目前为止是否出现在文本中来惩罚
    • 增加模型讨论新主题的可能性

🤔零样本示例

prompt只有问题和输出格式

prompt="""The following is a list of companies and the categories they fall into:

Apple, Facebook, Fedex

Apple
Category:
"""

ans = complete(prompt)

ans输出结果

模型返回每个公司所属的类别

ans == """
Technology 

Facebook
Category:
Social Media 

Fedex
Category:
Logistics and Delivery
"""

🤔少样本示例

prompt给出2个案例,以及需要回答的问题

prompt = """今天真开心。-->正向
心情不太好。-->负向
我们是快乐的年轻人。-->
"""

ans = complete(prompt)

ans输出结果

模型返回第三个句子的情感分类

ans == """
正向
"""

OpenAI的ChatCompletions接口

🤔ChatCompletions的参数说明

  • model:指定模型
  • messages:会话消息,支持多轮 (即,多条消息)
    • 每条消息是1个字典,包含rolecontent字段
    • 例如:[{"role": "user", "content": "Hello!"}]
  • temperature:采样温度
  • top-p:采样范围的概率门槛
  • stop
  • max-tokens
  • presence-penalty
  • frequency-penalty

通用方法导入

import openai

OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
openai.api_key = OPENAI_API_KEY

def ask(content: str) -> str:
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo", 
        messages=[{"role": "user", "content": content}]
    )

    ans = response.get("choices")[0].get("message").get("content")
    return ans

零样本

prompt="""The following is a list of companies and the categories they fall into:

Apple, Facebook, Fedex

Apple
Category:
"""

ans = ask(prompt)
ans == """
Technology/Electronics

Facebook 
Category:
Technology/Social Media

Fedex
Category:
Logistics/Shipping
"""

修改输出格式

prompt="""please output the category of the following companies:
Apple, Facebook, Fedex

The output format should be:
<company>
Category:
<category>
"""

ans = ask(prompt)
ans == """
Apple
Category:
Technology

Facebook
Category:
Technology/Social Media

Fedex
Category:
Delivery/Logistics
"""

prompt

🤔提示词工程的写法建议

  • 清晰
  • 描述具体
  • 问题聚焦
  • 间接
  • 主题相关

3.3:相关任务与应用

文档问答

文档问答:用QA的方法召回一个相关的文档,让模型在这个文档中找出问题的答案

🤔流程

  • 召回相关文档(给定问题与一批文档,计算相似度,从中选出相似度最高的那个文档)
  • 做阅读理解任务(预测答案在原始文档中的位置索引,即开始和结束的位置)
    • 大模型环境下,任务变为:将召回来的文档和问题以提示词的方式提交给大语言模型接口,直接让大模型帮忙得出答案

🤔提示词限制(保证输出结果的准确性)

  • 要求根据给定的文本尽量真实地回答问题
  • 如果答案未包含在给定文本中,就回复"我不知道"

模型微调

🤔出现分歧输出的调整手段

  • 少样本:每次随机从训练数据集里抽几条样本(包括句子和标签),作为提示词的一部分
  • 微调:把数据集按指定格式准备好,提交给微调接口,让接口微调一个在给定数据集上学习过的模型

🤔接口微调的步骤

  • 准备数据
    • 按照接口要求的格式修改数据集,至少包含一段文本和应该类别
    • 在openai的接口中,需要有prompt、completion 这2列,例如:
      {"prompt":"哈尔滨 东北抗日联军博物馆 ->","completion":" culture"}
  • 微调
    • 使用微调接口传递数据集
    • 服务器自动完成微调,得到新模型ID
  • 使用新模型推理
    • 把接口的model参数 换成新模型ID

智能对话

智能对话:和用户通过聊天方式进行交互

🤔传统对话机器人的模块

  • 自然语言理解模块NLU:对用户输入进行理解
  • 对话管理模块DM:对话方向的控制
  • 回复生成模块NLG:生成最终要回复的输出文本

🤔智能对话的关键设计

  • 对用户输入进行敏感性检查,确认没问题后开始对话
  • 存储用户消息,并在每轮对话时将用户历史消息传递给接口
相关推荐
Shaidou_Data14 分钟前
数据治理如何激活企业沉睡数据价值?
信息可视化·数据挖掘·数据分析·数据治理
骑单车的王小二32 分钟前
【文本分类】bert二分类
分类·bert
想胖的壮壮1 小时前
WorldQuant参数详解
数据挖掘
石臻臻的杂货铺10 小时前
OpenAI CEO 奥特曼发长文《反思》
人工智能·chatgpt
QQ_77813297412 小时前
ChatGPT在数据分析与处理中的使用详解
机器学习·chatgpt
AI小欧同学12 小时前
【AIGC-ChatGPT进阶提示词指令】AI美食助手的设计与实现:Lisp风格系统提示词分析
人工智能·chatgpt·aigc
爱学习的uu15 小时前
KAGGLE竞赛实战2-捷信金融违约预测竞赛-part1-数据探索及baseline建立
人工智能·python·决策树·机器学习·金融·数据挖掘·逻辑回归
杨超越luckly15 小时前
Python应用指南:高德交通态势数据
python·arcgis·数据挖掘·数据分析·交通态势
AnRan080816 小时前
ChatGPT如何赋能办公
人工智能·chatgpt
IT古董16 小时前
【机器学习】机器学习的基本分类-自监督学习(Self-supervised Learning)
人工智能·学习·机器学习·分类