如何避免LLM的“幻觉”(Hallucination)

news2024/11/19 16:42:46

生成式大语言模型(LLM)可以针对各种用户的 prompt 生成高度流畅的回复。然而,大模型倾向于产生幻觉或做出非事实陈述,这可能会损害用户的信任。

大语言模型的长而详细的输出看起来很有说服力,但是这些输出很有可能是虚构的。这是否意味着我们不能信任聊天机器人,每次都必须手动检查输出的事实?有一些方法可以让聊天机器人在适当的保护措施下不太可能说假话。

一个最简单的方法就是调整temperature到一个很大的值,例如0.7,然后使用相同的提问多次对话。这样得到的输出应该只会改变句子的结构,输出之间的差异应该只是语义上的,而不是事实上的。

这个简单的想法允许引入一种新的基于样本的幻觉检测机制。如果LLM对同一提示的输出相互矛盾,它们很可能是幻觉。如果它们相互关联,就意味着信息是真实的。对于这种类型的求值,我们只需要llm的文本输出。这被称为黑盒评估。

余弦距离

余弦距离(Cosine Distance)是衡量两个向量之间相似度的一种度量方法,通常用于文本相似性、推荐系统和机器学习等领域。我们可以计算嵌入句子的对应对之间的两两余弦相似度。下面的函数将最初生成的句子output和一个包含3个示例输出的列表sampled_passages作为输入。

这里使用了all-MiniLM-L6-v2轻量模型。嵌入一个句子会把它变成它的向量表示。

 output = "Evelyn Hartwell is a Canadian dancer, actor, and choreographer." 
 output_embeddings= model.encode(output)
 
 array([ 6.09108340e-03, -8.73148292e-02, -5.30637987e-02, -4.41815751e-03,
  1.45469820e-02, 4.20340300e-02, 1.99541822e-02, -7.29453489e-02,
 …
  -4.08893749e-02, -5.41420840e-02, 2.05906332e-02, 9.94611382e-02,
  -2.24501686e-03, 2.29083393e-02, 7.80007839e-02, -9.53456461e-02],
  dtype=float32)

将LLM的每个输出生成嵌入,然后使用sentence_transformers中的pairwise_cos_sim函数计算cos相似度。将原始响应与每个新样本响应进行比较,然后求平均值。

 from sentence_transformers.util import pairwise_cos_sim
 from sentence_transformers import SentenceTransformer
 
 def get_cos_sim(output,sampled_passages):
     model = SentenceTransformer('all-MiniLM-L6-v2')
     sentence_embeddings = model.encode(output).reshape(1, -1)
     sample1_embeddings = model.encode(sampled_passages[0]).reshape(1, -1)
     sample2_embeddings = model.encode(sampled_passages[1]).reshape(1, -1)
     sample3_embeddings = model.encode(sampled_passages[2]).reshape(1, -1)
     cos_sim_with_sample1 = pairwise_cos_sim(
     sentence_embeddings, sample1_embeddings
     )
     cos_sim_with_sample2  = pairwise_cos_sim(
     sentence_embeddings, sample2_embeddings
     )
     cos_sim_with_sample3  = pairwise_cos_sim(
     sentence_embeddings, sample3_embeddings
     )
     cos_sim_mean = (cos_sim_with_sample1 + cos_sim_with_sample2 + cos_sim_with_sample3) / 3
     cos_sim_mean = cos_sim_mean.item()
     return round(cos_sim_mean,2)

从上面的图像可以看到矢量之间的角度大约是30⁰,因此它们彼此接近。余弦大约是0.87。余弦函数越接近1,这两个向量就越接近。

 cos_sim_score = get_cos_sim(output, [sample1,sample2,sample3])

嵌入的cos_sim_score的平均值为0.52。

为了理解如何解释这个数字,让我们将其与一些有效输出的余弦相似度评分进行比较

这个输出的余弦相似度为0.93。所以说第一个输出很有可能是LLM的幻觉。

BERTScore

BERTScore建立在两两余弦相似度思想的基础上。

用于计算上下文嵌入的标记器是RobertaTokenizer。上下文嵌入不同于静态嵌入,因为它们会考虑单词周围的上下文。

 def get_bertscore(output, sampled_passages):
     # spacy sentence tokenization
     sentences = [sent.text.strip() for sent in nlp(output).sents] 
     selfcheck_bertscore = SelfCheckBERTScore(rescale_with_baseline=True)
     sent_scores_bertscore = selfcheck_bertscore.predict(
         sentences = sentences, # list of sentences
         sampled_passages = sampled_passages, # list of sampled passages
     )
     df = pd.DataFrame({
     'Sentence Number': range(1, len(sent_scores_bertscore) + 1),
     'Hallucination Score': sent_scores_bertscore
     })
     return df

selfcheck_bertscore没有将完整的原始输出作为参数传递,而是将其分成单独的句子。

 ['Evelyn Hartwell is an American author, speaker, and life coach.',
  'She is best known for her book, The Miracle of You: How to Live an Extraordinary Life, which was published in 2007.',
  'She is a motivational speaker and has been featured on TV, radio, and in many magazines.',
  'She has authored several books, including How to Make an Impact and The Power of Choice.']

这一步很重要,因为selfcheck_bertscore.predict函数将每个句子的BERTScore计算为与样本中每个句子匹配的原始响应。它创建一个数组,其行数等于原始输出中的句子数,列数等于样本数。

 array([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])

用于计算候选句子和参考句子之间BERTScore的模型是RoBERTa large,共17层。最初的输出有4个句子,分别是r1 r2 r3和r4。第一个样本有两个句子:c1和c2。计算原始输出中的每个句子与第一个样本中的每个句子匹配的F1 BERTScore。然后我们对基线张量b =([0.8315,0.8315,0.8312])进行缩放。基线b是使用来自Common Crawl单语数据集的100万个随机配对句子来计算的。他们计算了每一对的BERTScore,并取其平均值。这代表了一个下界,因为随机对几乎没有语义重叠。

保留原始回复中每个句子的BERTScore,并从每个抽取的样本中选择最相似的句子。其逻辑是,如果一条信息出现在由同一提示生成的多个样本中,那么该信息很有可能是真实的。如果一个语句只出现在一个示例中,而没有出现在来自同一提示的任何其他示例中,则更有可能是伪造的。

所以我们计算最大相似度:

 bertscore_array
 array([[0.43343216, 0.        , 0.        ],
        [0.12838356, 0.        , 0.        ],
        [0.2571277 , 0.        , 0.        ],
        [0.21805632, 0.        , 0.        ]])

对另外两个样本重复这个过程:

 array([[0.43343216, 0.34562832, 0.65371764],
        [0.12838356, 0.28202596, 0.2576825 ],
        [0.2571277 , 0.48610589, 0.2253703 ],
        [0.21805632, 0.34698656, 0.28309497]])

然后我们计算每行的平均值,给出原始回复中每个句子与每个后续样本之间的相似度得分。

 array([0.47759271, 0.22269734, 0.32286796, 0.28271262])

每句话的幻觉得分是通过从上面的每个值中减去1得到的。

将结果与尼古拉斯·凯奇(Nicolas Cage)的答案进行比较。

有效输出的幻觉得分较低,而虚构输出的幻觉得分较高。但是计算BERTScore的过程非常耗时,这使得它不适合用于实时幻觉检测。

NLI

自然语言推理(NLI)涉及确定一个假设在逻辑上是遵循给定前提还是与给定前提相矛盾。这种关系可分为牵连、矛盾或中立。对于NLI,我们利用在MNLI数据集上进行微调的DeBERTa-v3-large模型来执行NLI。

下面是一些前提-假设对及其标签的例子。

 def get_self_check_nli(output, sampled_passages):
     # spacy sentence tokenization
     sentences = [sent.text.strip() for sent in nlp(output).sents] 
     selfcheck_nli = SelfCheckNLI(device=mps_device) # set device to 'cuda' if GPU is available
     sent_scores_nli = selfcheck_nli.predict(
         sentences = sentences, # list of sentences
         sampled_passages = sampled_passages, # list of sampled passages
     )
     df = pd.DataFrame({
     'Sentence Number': range(1, len(sent_scores_nli) + 1),
     'Probability of Contradiction': sent_scores_nli
     })
     return df

在selfcheck_nli.predict函数,原始响应中的每个句子都与三个样本中的每个配对。

 logits = model(**inputs).logits # neutral is already removed
 probs = torch.softmax(logits, dim=-1)
 prob_ = probs[0][1].item() # prob(contradiction)

现在我们对这四个句子中的每一个重复这个过程。

可以看到,模型输出的矛盾概率非常高。现在我们将其与实际输出进行比较。

这个模特做得很好!但是NLI检查时间有点太长了。

Prompt

较新的方法已经开始使用llm本身来评估生成的文本。而不是使用公式来计算分数,我们将输出与三个样本一起发送到gpt-3.5 turbo。该模型将决定原始输出相对于生成的其他三个样本的一致性。

 def llm_evaluate(sentences,sampled_passages):
     prompt = f"""You will be provided with a text passage \
                 and your task is to rate the consistency of that text to \
                 that of the provided context. Your answer must be only \
                 a number between 0.0 and 1.0 rounded to the nearest two \
                 decimal places where 0.0 represents no consistency and \
                 1.0 represents perfect consistency and similarity. \n\n \
                 Text passage: {sentences}. \n\n \
                 Context: {sampled_passages[0]} \n\n \
                 {sampled_passages[1]} \n\n \
                 {sampled_passages[2]}."""
 
     completion = client.chat.completions.create(
     model="gpt-3.5-turbo",
     messages=[
         {"role": "system", "content": ""},
         {"role": "user", "content": prompt}
     ]
     )
 
     return completion.choices[0].message.content

Evelyn Hartwell的自相似性得分为0。Nicolas Cage相关的输出得分为0.95。获得分数所需的时间也很低。

这似乎是案例的目前最佳解决方案,Prompt的性能明显优于所有其他方法,NLI是性能第二好的方法。

评估数据集是通过使用WikiBio数据集和GPT-3生成合成维基百科文章来创建的。为了避免模糊的概念,238篇文章的主题是从最长文章的前20%中随机抽取的。GPT-3被提示以维基百科风格为每个概念生成第一段。

,这些生成的段落在句子层面上被手工标注为事实。每个句子被标记为主要不准确,次要不准确,或准确。总共有1908个句子被注释,大约40%的句子主要不准确,33%的句子次要不准确,27%的句子准确。

为了评估注释者的一致性,201个句子有双重注释。如果注释者同意,则使用该标签;否则选择最坏情况的标签。Cohen’s kappa测量的注释者间一致性在准确、次要不准确和主要不准确之间进行选择时为0.595,在次要/主要不准确合并到一个标签时为0.748。

评价指标AUC-PR是指准确率-召回率曲线下的面积,是用来评价分类模型的指标。

实时幻觉检测

我们可以构建一个实时幻觉检测的Streamlit应用。如前所述,最好的度量是LLM自相似性得分。我们将使用0.5的阈值来决定是显示生成的输出还是显示免责声明。

 import streamlit as st
 import utils
 import pandas as pd
 
 # Streamlit app layout
 st.title('Anti-Hallucination Chatbot')
 
 # Text input
 user_input = st.text_input("Enter your text:")
 
 if user_input:
 
     prompt = user_input
 
     output, sampled_passages = utils.get_output_and_samples(prompt)
 
     # LLM score
     self_similarity_score = utils.llm_evaluate(output,sampled_passages)
 
     # Display the output
     st.write("**LLM output:**")
     if float(self_similarity_score) > 0.5:
         st.write(output)
     else:
         st.write("I'm sorry, but I don't have the specific information required to answer your question accurately. ")

我们看看结果。

总结

聊天机器人的幻觉检测一直是人们讨论已久的质量问题。

我们只是概述的了目前的研究成果:通过生成对同一提示的多个响应并比较它们的一致性来完成。

还有更多的工作要做,但与其依赖于人工评估或手工制定的规则,让模型自己捕捉不一致似乎是一个很好的方向。

本文引用:

https://avoid.overfit.cn/post/f32f440c1b99458e86d3e48c70ddcf94

作者:Iulia Brezeanu

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

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

相关文章

Modbus 通信协议 二

Modbus 常用缩写 通用Modbus帧结构 -应用数据单元(ADU) Modbus数据模型 Modbus ADU 和 PDU 的长度 Modbus PDU结构 串行链路上的 Modbus 帧结构 Modbus 地址规则 ASCLL 模式 和 RTU 模式的比较 RTU 模式 RTU 模式位序列 帧格式 帧的标识与鉴别 CRC 循环冗…

linux系统下sql脚本的执行与导出

terminal中执行 执行 mysql -u [username] -p -D [databasename] < [XXX.sql] 导出 mysql -u [username] -p [datbasename] > [XXX.sql] 导出的数据库名自定义。 mysql -u [username] -p [databasename] [tablename] > [xxx.sql] 导出表名自定义 mysql shell 执行 …

众和策略:沪指震荡跌0.21%,煤炭、电力等板块拉升,核电概念活跃

2日早盘&#xff0c;三大股指盘中震荡走低&#xff0c;创业板指跌逾1%&#xff0c;北证50指数逆市拉升&#xff1b;北向资金大幅流出。 到午间收盘&#xff0c;沪指跌0.21%报2968.7点&#xff0c;深成指跌0.91%&#xff0c;创业板指跌1.38%&#xff0c;北证50指数涨1.33%&…

Java学习路线第六篇:互联网生态(1)

这篇则分享Java学习路线第六part&#xff1a;互联网生态 恭喜你已经成功追到第六章节啦&#xff0c;要被自己的努力感动到了吧&#xff0c;而这节将承担起学完互联网生态的使命&#xff0c;本使命为单向契约&#xff0c;你可选择YES或者选择YES。 Linux Linux从入门到精通视…

基于电商场景的高并发RocketMQ实战-促销活动推送至用户完整流程、Spring结合RocketMQ的生产者消费者使用

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff09;&#xff0c;发送【资料】可领取 深入理解 Redis 系列文章结合电商场景讲解 Redis 使用场景、中间件系列…

【Apache-2.0】springboot-openai-chatgpt超级AI大脑产品架构图

springboot-openai-chatgpt: 一个基于SpringCloud的Chatgpt机器人&#xff0c;已对接GPT-3.5、GPT-4.0、百度文心一言、stable diffusion AI绘图、Midjourney绘图。用户可以在界面上与聊天机器人进行对话&#xff0c;聊天机器人会根据用户的输入自动生成回复。同时也支持画图&a…

【微服务架构】Spring Cloud入门概念讲解

目录 一、单体架构VS微服务架构 1.1 单体应用 单体架构的优点 单体应用的缺点 1.2 微服务“定义” 微服务的特性 微服务的缺点 微服务的适用场景 二、微服务常见概念与核心模块 三、Spring Cloud 工作流程 一、单体架构VS微服务架构 1.1 单体应用 一个归档包&#x…

数据损毁!250 亿美金的 Pinterest,在数据库选型上的翻车经历

原文链接 Pinterest 是一个以图片为主的社交网络&#xff0c;用户可以将图片保存或 "钉 / pin" 在自己的图板上。Pinterest 在 2019 年上市&#xff0c;目前市值 250 亿美金。本文内容主要根据 2012 年 Scaling Pinterest 的分享。 2012 年 1 月&#xff0c;Pinteres…

ARM NEON 指令

NEON指令 按照操作数类型可以分为正常指令、宽指令、窄指令、饱和指令、长指令。 正常指令&#xff1a;生成大小相同且类型通常与操作数向量相同到结果向量。长指令&#xff1a;对双字向量操作数执行运算&#xff0c;生产四字向量到结果。所生成的元素一般是操作数元素宽度到…

从0搭建github.io网页

点击跳转到&#x1f517;我的博客文章目录 从0搭建github.io网页 文章目录 从0搭建github.io网页1.成果展示1.1 网址和源码1.2 页面展示 2.new对象2.1 创建仓库 3.github.io仓库的初始化3.1 千里之行&#xff0c;始于足下3.2 _config.yml3.3 一点杂活 4.PerCheung.github.io.p…

Qt(三):udp组播的发送与接收

1. 创建UDP套接字 使用QUdpSocket类创建一个UDP套接字。 udpSendnew QUdpSocket(this);udpRecenew QUdpSocket(this); 2. 绑定套接字 绑定套接字到一个本地地址和端口。可以使用bind()函数来完成。 如果要在组播中发送数据&#xff0c;可以将套接字绑定到一个通配符地址&#…

【CASS精品教程】CASS11计算城镇建筑密度

CASS中可以很方便计算建筑密度。 文章目录 一、建筑密度介绍二、CASS计算建筑密度1. 绘制宗地范围2. 绘制建筑物3. 计算建筑密度三、注意事项一、建筑密度介绍 建筑密度(building density;building coverage ratio),指在一定范围内,建筑物的基底面积总和与占用地面积的比…

计算机网络-以太网交换基础

一、网络设备的演变 最初的网络在两台设备间使用传输介质如网线等进行连接就可以进行通信。但是随着数据的传输需求&#xff0c;多个设备需要进行数据通信时就需要另外的设备进行网络互联&#xff0c;并且随着网络传输的需求不断更新升级。从一开始的两台设备互联到企业部门内部…

【OpenCV】在MacOS上源码编译OpenCV

在MacOS上源码编译OpenCV 1. 下载项目源码2. 创建CMake编译文件3. 编译安装4. 案例测试5. 总结 前言 在做视觉任务时&#xff0c;我们经常会用到开源视觉库OpenCV&#xff0c;OpenCV是一个基于Apache2.0许可&#xff08;开源&#xff09;发行的跨平台计算机视觉和机器学习软件…

Spring技术内幕笔记之IOC的实现

IOC容器的实现 依赖反转&#xff1a; 依赖对象的获得被反转了&#xff0c;于是依赖反转更名为&#xff1a;依赖注入。许多应用都是由两个或者多个类通过彼此的合作来实现业务逻辑的&#xff0c;这使得每个对象都需要与其合作的对象的引用&#xff0c;如果这个获取过程需要自身…

Java学习苦旅(十六)——List

本篇博客将详细讲解Java中的List。 文章目录 预备知识——初识泛型泛型的引入泛型小结 预备知识——包装类基本数据类型和包装类直接对应关系装包与拆包 ArrayList简介ArrayList使用ArrayList的构造ArrayList常见操作ArrayList遍历 结尾 预备知识——初识泛型 泛型的引入 我…

WebStorm 创建一个Vue项目(1)

一、下载并安装WebStorm 步骤一 步骤二 选择激活方式 激活码&#xff1a; I2A0QUY8VU-eyJsaWNlbnNlSWQiOiJJMkEwUVVZOFZVIiwibGljZW5zZWVOYW1lIjoiVU5JVkVSU0lEQURFIEVTVEFEVUFMIERFIENBTVBJTkFTIiwiYXNzaWduZWVOYW1lIjoiVGFvYmFv77yaSkVU5YWo5a625qG25rAIOa0uW3peS9nOWup…

json解析本地数据,使用JSONObject和JsonUtility两种方法。

json解析丨网址、数据、其他信息 文章目录 json解析丨网址、数据、其他信息介绍一、文中使用了两种方法作为配置二、第一种准备2.代码块 二、第二种总结 介绍 本文可直接解析本地json信息的功能示例&#xff0c;使用JSONObject和JsonUtility两种方法。 一、文中使用了两种方法…

R语言——R函数、选项参数、数学统计函数(六)

目录 一、R函数 二、选项参数 三、数学统计函数 四、参考 一、R函数 1.lm() lm()是R语言中经常用到的函数&#xff0c;用来拟合回归模型。它是拟合线性模型最基本的函数 lm()格式如下&#xff1a; fit<-lm(formula,data) 其中&#xff0c;formula指要拟合的模型形式…

【QT 自研上位机 与 ESP32下位机联调>>>串口控制GPIO-基础样例-联合文章】

【QT 自研上位机 与 ESP32下位机联调&#xff1e;&#xff1e;&#xff1e;串口控制GPIO-基础样例-联合文章】 1、概述2、实验环境3、 自我总结4、 实验过程1、验证上位机QT程序1、下载样例代码2、修改qt程序3、运行测试验证 2、验证下位机ESP32程序1、下载样例代码2、更改ESP3…