蝴蝶书-task2: 文本推理、摘要、纠错 transformers实现翻译 OpenAI翻译 PyDeepLX翻译 DeepLpro翻译
ChatGPT使用指南——文本推理
推理的类型
相关资料:Logical Reasoning (fibonicci.com)
常见的推理类型主要包含3种,即亚里士多德在公元前的《前分析篇》中列举了推理的三种类型,为演绎、归纳以及溯回。
演绎推理
一般来说,演绎推理是指使用一组给定的事实或数据,通过逻辑推理来推导出其他事实。演绎推理,也称为三段论,通常的理解包括两个前提,一个大的和一个小的,然后一个逻辑结论,可以用来证明这些新的事实是真实的。
例如,经典的例子:
大前提:人类都是凡人
小前提:苏格拉底是人
结论:苏格拉底是凡人
在 "苏格拉底是人"(小前提)的具体情况下,对 "所有的人都是凡人"(大前提)的一般规则应用演绎法,可以得出结论:"苏格拉底是凡人"。
归纳推理
归纳推理是寻找一种模式或趋势,然后对其进行概括。当你对信息进行归纳和推断时,你并不确定这一趋势是否会继续下去,但你假设它会继续下去。因此,你并不确定基于归纳推理的结论会是100%的真实。
一个著名的假说是: "天鹅都是白的"
这个结论是在没有观察到任何黑天鹅的情况下从大量的观察中得出的,因此在逻辑上假设黑天鹅不存在。所以,归纳推理是一种有风险的逻辑推理形式,因为从天鹅的例子来看,如果发现了一只黑天鹅,那么结论就很容易不正确了。
溯因推理
溯因推理与归纳推理有些类似。它最早是由“猜测”一词引入的,因为这里得出的结论是基于概率的。在归纳推理中,人们假定最合理的结论也是正确的。
例如:
大前提:罐子里装满了黄色的弹珠
小前提:鲍勃手里有一颗黄色的弹珠
结论:鲍勃手中的黄色弹珠是从罐子里拿出来的。
通过溯因推理,鲍勃从罐子里拿走黄色弹珠的可能性是合理的,然而这纯粹是基于推测。黄色弹珠可能是任何人送给鲍勃的,也可能是鲍勃在商店里买的黄色弹珠。因此,从“装满黄色大理石的罐子”的观察中推断出鲍勃拿走了黄色大理石,可能会导致一个错误的结论。
prompt技巧总结
# 两个原则
1.明确且具体的指令
具体的指令不等于短指令,长指令往往能提供更高的清晰度
1.使用分隔符划分不同的文本内容
2.请求模型输出HTML或者JSON格式
3.使用类似于异常捕获的理念,教会模型处理文本中遇到的不同情况
4.给模型提供少量示例,相当于让模型模仿着示例来进行任务。
2.给模型时间去思考
让更多的计算资源分配到我们想让模型做的事情上。
1.对一个复杂任务,将其拆分为多个步骤,这一目的是给模型提供更高的清晰度。对于每个步骤还可以再次细化,直到模型给出理想的结果。
2.不要让模型短时间的去下一个结论,而是请求模型在提供最终答案之前进行一系列相关的推理,然后再给出结论。
# 幻觉
模型在训练过程中接触了大量的知识,它并没有完全记住所见的信息,因此它并不很清楚自己知识的边界。这意味着它可能会尝试回答有关晦涩主题的问题,并编造听起来合理但实际上并不正确的答案。我们称这些编造的想法为幻觉。
也就是说对于模型不清楚的知识,模型更倾向于一本正经的胡说八道。
# prompt技巧:
结构化输入:角色 + 场景 + 思维链 + 回复示例
# 少样本提示
few-shot是普通的禁止指令的上位替代。与其告诉模型不能做什么,不如提供示例,告诉模型怎么做。如果一个例子的效果不好,可以尝试用多个。
# 思维链:
相当于把问题的解法给llm
Let's think step by step.
# ReAct
让模型去推理,推理的过程中自己决定调用哪个工具。再把工具结果告诉模型,模型再次推理下一步。
# Self Consistency
不仅仅生成一个思维链,而是生成多个思维链,然后取多数答案作为最终答案。
你现在是 MultiverseGPT:你与 ChatGPT 一样,但对于每一个问题, 你会思考10种不同的思路,然后将它们结合起来,输出最佳的措辞、最全面和最准确的答案。
可以针对单个场景,提供多种思考方式,最后总结多种思考方式的答案。
# ReAct类比程序员的开发过程
需求 写代码 运行代码看结果 改代码 运行代码看结果
think react think react
ChatGPT使用指南——文本生成
文本摘要任务
定义:文本摘要任务指的是用精炼的文本来概括整篇文章的大意,使得用户能够通过阅读摘要来大致了解文章的主要内容。
从实现手法来说,文本摘要任务主要分为以下三种:
- 抽取式摘要:从原文档中提取现成的句子作为摘要句。
- 压缩式摘要:对原文档的冗余信息进行过滤,压缩文本作为摘要。
- 生成式摘要:基于NLG技术,根据源文档内容,由算法模型自己生成自然语言描述。(使用大模型总结)
通常使用llm进行总结即可获得不错效果,如果是专业领域则需要使用专业数据集进行微调。
文本纠错任务
在日常生活中,不管是微信聊天、微博推文甚至是出版书籍中,我们都或多或少地会发现文本中的错别字现象。
这些错别字可能源于语音输入时的口音偏差,如“飞机”被识别成了“灰机”;也可能是拼音输入时误触了临近键位或者选错了结果,如“飞机”被识别成了“得急”、“肥鸡”;亦或是手写输入时写成了形近字,如“战栗”被识别为了“战粟”……
常见的错误类型
- 拼写错误:中文课程->中文磕碜;明天会议->明天会易
- 语法错误:他昨天去参加会议了->他昨天将要去参加会议
- 标点符号错误:您好,请多指教!->您好,请多指教???
- 知识性错误:上海黄浦区->上海黄埔区
- 重复性错误:您好,请问您今天有空吗?->您好,请问您今天有空吗吗吗吗吗吗
- 遗漏性错误:他昨天去参加会议了->他昨天去参加了
- 语序性错误:他昨天去参加会议了->他昨天去会议参加了
- 多语言错误:他昨天去参加会议了->他昨天去参加huiyi了
- ……
常见的文本纠错技术
常见的文本纠错技术主要有以下几种:
- 基于规则的文本纠错技术
- 基于语言模型的文本纠错技术
- 基于MLM的文本纠错技术
- 基于NLG的文本纠错技术
基于规则的文本纠错技术
这种文本纠错技术是通过实现定义的规则来检查文本中的拼写、语法、标点符号等常见错误,假如“金字塔”常被误写为“金子塔”,则在数据库中加入两者的映射关系。由于这种传统方法需要大量的人工工作以及专家对于语言的深刻理解,因此难以处理海量文本或较为复杂的语言错误。
基于语言模型的文本纠错技术
基于语言模型的文本纠错技术包括错误检测和错误纠正,这种方法同样比较简单粗暴,方法速度快,扩展性强,效果一般。常见的模型有Kenlm。
- 错误检测:使用
jieba
中文分词器对句子进行切词,然后结合字粒度和词粒度两方面的疑似错误结果,形成疑似错误位置候选集。 - 错误纠正:遍历所有的候选集并使用音似、形似词典替换错误位置的词,然后通过语言模型计算句子困惑度,最后比较并排序所有候选集结果,得到最优纠正词。
基于MLM的文本纠错技术
我们知道,BERT在预训练阶段使用了Masked Language Model掩码语言模型(MLM)及Next Sentence Prediction下一句预测(NSP)两个任务,其中MLM任务中有15%*10%的Token会被替换为随机的其他词汇,迫使模型更多地依赖于上下文信息去预测Mask词汇,在一定程度上赋予了模型纠错能力。
因此,我们将BERT的MLM任务做一下简单的修改,将输入设计为错误的词汇,输出为正确的词汇,做一下简单的fine tune,即可轻松实现文本纠错功能。
例如,ACL2020的Soft-Masked BERT模型(论文笔记),设计了一个二重网络来进行文本纠错,其中“错误检测网络”通过Bi-GRU识别每个字符错误的概率,“错误纠正网络”倾向将错误概率更高的词Mask掉,并预测出真实词汇。
基于NLG的文本纠错技术
上述提到的Mask方法只能用于输入与输出等长的情况,但是实际应用中往往会出现两者不等长的情况,如错字或多字。一种可能的解决办法是,在原有的BERT模型后嵌入一层Transformer Decoder,即将“文本纠错”任务等价于“将错误的文本翻译成正确的文本”,此时我们没法保证输出文本与原始文本中正确的部分一定能保持完全一致,可能在语义不变的情况下,会生成了一种新的表达方式。
一个文本纠错工具集:pycorrector
pycorrector是一个文本纠错工具集,内置了KenLM、MacBERT、Transformer等多种文本纠错模型。
from transformers import BertTokenizer, BertForMaskedLM
# 载入模型
tokenizer = BertTokenizer.from_pretrained("shibing624/macbert4csc-base-chinese")
model = BertForMaskedLM.from_pretrained("shibing624/macbert4csc-base-chinese")
text = "大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课乘吧!"
input_ids = tokenizer([text], padding=True, return_tensors='pt')
# 生成结果文本
with torch.no_grad():
outputs = model(**input_ids)
output_ids = torch.argmax(outputs.logits, dim=-1)
output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True).replace(' ', '')
print("原始文本: ", text)
print("纠错文本: ", output_text)
原始文本: 大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课乘吧!
纠错文本: 大家好,一起来参加datawhale的《chatgpt使用指南》组队学习课程吧!
# 查看修改点
import operator
def get_errors(corrected_text, origin_text):
sub_details = []
for i, ori_char in enumerate(origin_text):
if ori_char in [' ', '“', '”', '‘', '’', '琊', '\n', '…', '—', '擤']:
# add unk word
corrected_text = corrected_text[:i] + ori_char + corrected_text[i:]
continue
if i >= len(corrected_text):
continue
if ori_char != corrected_text[i]:
if ori_char.lower() == corrected_text[i]:
# pass english upper char
corrected_text = corrected_text[:i] + ori_char + corrected_text[i + 1:]
continue
sub_details.append((ori_char, corrected_text[i], i, i + 1))
sub_details = sorted(sub_details, key=operator.itemgetter(2))
return corrected_text, sub_details
correct_text, details = get_errors(output_text[:len(text)], text)
print(details)
[('乘', '程', 37, 38)]
还可以直接使用chatgpt进行文本纠错。
机器翻译任务
从机器翻译的发展历程来看,主要经历了如下几个阶段:
- 基于规则的方法
- 基于统计的方法
- 基于神经网络的方法
基于规则的方法需要建立各类知识库,描述源语言和目标语言的词法、句法以及语义知识,有时知识无关的世界知识。
基于统计的方法认为对于一条源语言 𝑅,任何一条目标语言 𝑇 都可能是它的译文,只是可能性有高有低。对于源语言中的每个词 𝑟𝑖 及目标语言中的每个词 𝑡𝑗,判断词对齐的概率,再通过期望最大算法(如EM算法)得到最大词对齐概率的对齐方式。这便是基于词的翻译模型。显然,将翻译的最小单位设计成词是不符合语法的,因此后来又延申出了基于短语的翻译方法,将最小翻译单位设计成连续的词串。
2013年,一种用于机器翻译的新型端到端编码器-解码器架构问世,将CNN用于隐含表征挖掘,将RNN用于将隐含向量转化为目标语言,标志了神经机器翻译开端。后来,Attention、Transformer、BERT等技术被相继提出,大大提升了翻译的质量。
基于transformers实现机器翻译
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
tokenizer = AutoTokenizer.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
model = AutoModelForSeq2SeqLM.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
text = "大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课程吧!"
inputs = tokenizer(text, return_tensors="pt", )
outputs = model.generate(inputs["input_ids"], max_length=40, num_beams=4, early_stopping=True)
translated_sentence = tokenizer.decode(outputs[0], skip_special_tokens=True)
print('原始文本: ', text)
print('翻译文本: ', translated_sentence)
原始文本: 大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课程吧!
翻译文本: Hey, guys, let's join the ChatGPT team at DataWhale.
基于OpenAI接口的机器翻译
def translate_text(text):
content = f"请将以下中文文本翻译成英文:\n{text}"
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": content}]
)
translated_text = response.get("choices")[0].get("message").get("content")
return translated_text
text_to_translate = "大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课程吧!"
translated_text = translate_text(text_to_translate)
print("原始文本: ", text_to_translate)
print("输出文本: ", translated_text)
使用PyDeepLX免费翻译、deepl pro账号翻译
PyDeepLX可以免费使用deepl,安装即可:pip install PyDeepLX
,请求不能太快会失败。
deepl pro账号会得到一个auth_key,它没有速度限制。并且可以使用词汇表,来增强我们的翻译效果
如下封装了PyDeepLX、deepl、以及deepl词汇表:
import json
import deepl
import requests
from PyDeepLX import PyDeepLX
auth_key = "Replace with your key"
def deepl_free(text: str, proxies: dict = None, form: str = 'EN', to: str = 'ZH', ):
return PyDeepLX.translate(text=text, sourceLang=form, targetLang=to, numberAlternative=0,
printResult=True, proxies=proxies)
def deepl_pro(text, source_lang: str = 'EN', target_lang: str = 'ZH', context: str = '',
split_sentences: str = '1', formality: str = 'prefer_less', glossary: str = ''):
translator = deepl.Translator(auth_key)
result = translator.translate_text(
text=text,
source_lang=source_lang,
target_lang=target_lang,
context=context,
split_sentences=split_sentences,
formality=formality,
glossary=glossary,
)
return result.text
class BaseManager:
def __init__(self, auth_key, api_type='free'):
self.auth_key = auth_key
self.api_type = api_type
self.headers = {
"Authorization": f"DeepL-Auth-Key {self.auth_key}",
'Accept': 'text/tab-separated-values',
}
def choice_url(self):
if self.api_type == 'free':
return 'https://api-free.deepl.com'
elif self.api_type == 'pro':
return 'https://api.deepl.com'
else:
raise Exception('api type error')
class GlossaryManager(BaseManager):
def glossary_language_pairs(self):
url = self.choice_url() + '/v2/glossary-language-pairs'
return requests.get(url, headers=self.headers).json()
def glossary_list(self):
url = self.choice_url() + '/v2/glossaries'
return requests.get(url, headers=self.headers).json()
def glossary_create(self, name, source_lang, target_lang, entries, entries_format):
data = {
'name': name,
'source_lang': source_lang,
'target_lang': target_lang,
'entries': entries,
'entries_format': entries_format
}
url = self.choice_url() + '/v2/glossaries'
return requests.post(url, headers=self.headers, data=data).json()
def glossary_delete(self, glossary_id):
url = self.choice_url() + f'/v2/glossaries/{glossary_id}'
respose = requests.delete(url, headers=self.headers).text
if respose:
return json.loads(respose)
else:
return {}
def glossary_retrieve(self, glossary_id):
url = self.choice_url() + f'/v2/glossaries/{glossary_id}'
return requests.get(url, headers=self.headers).text
def entry_list(self, glossary_id):
url = self.choice_url() + f'/v2/glossaries/{glossary_id}/entries'
return {'entries': requests.get(url, headers=self.headers).text}
'''
词汇表参数说明:
split_sentences
0- 完全没有拆分,整个输入被视为一个句子
1(默认值 when not 设置为 ) - 标点符号和换行符的拆分tag_handlinghtml
nonewlines(默认时) - 仅在标点符号上拆分,忽略换行符tag_handling=html
对于每个文本参数发送一个句子的应用程序,我们建议设置为 ,以防止引擎无意中拆分句子。split_sentences0
preserve_formatting
是否应遵循原始格式,即使它通常会更正某些方面。
受此设置影响的格式设置方面包括:
句子开头和结尾的标点符号
句子开头的大写/小写
formality
设置翻译文本应倾向于正式语言还是非正式语言。
此功能目前仅适用于目标语言(德语)、(法语)、(意大利语)、(西班牙语)、(荷兰语)、(波兰语)和(葡萄牙语)、(日语)、 和(俄语)。
在此处了解有关日语的简单/礼貌功能的更多信息。使用不支持形式化的目标语言设置此参数将失败。
default(默认)
more- 更正式的语言
less- 使用更非正式的语言
prefer_more- 对于更正式的语言(如果可用),否则回退到默认形式
prefer_less- 使用更非正式的语言(如果有),否则回退到默认形式
'''
if __name__ == '__main__':
print(deepl_pro('Hello, world!'))
deepl_free('Hello, world!') # 源码内部有一次print