蝴蝶書-task2: 文字推理、摘要、糾錯 transformers實現翻譯 OpenAI翻譯 PyDeepLX翻譯 DeepLpro翻譯

passion2021發表於2024-04-29

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了
  • ……

常見的文字糾錯技術

常見的文字糾錯技術主要有以下幾種:

  1. 基於規則的文字糾錯技術
  2. 基於語言模型的文字糾錯技術
  3. 基於MLM的文字糾錯技術
  4. 基於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

相關文章