赞
踩
自然语言生成(Natural Language Generation, NLG)是自然语言处理领域的一个重要研究方向,指计算机通过模型或算法从各种形式的输入中生成自然语言文本输出。大多数自然语言处理任务可以描述为自然语言生成任务或文本生成任务,应用广泛,例如:文本分类、文本纠错和智能问答等。本文将介绍一些常见的文本生成任务,其中包括一些曾经不属于文本生成类任务而现在也可使用NLG技术解决的任务。
**自然语言生成任务(Natural Language Generation)**是自然语言处理领域内的一个重要研究方向,指的是计算机通过模型或算法,从文本、语音等各种形式的输入中生成自然语言文本输出的过程。
我们知道,任何知识都能被描述为文本或者说语言,从而先人的智慧才被记录在书卷上代代相传。因此,绝大多数的自然语言处理任务都可以描述为自然语言生成任务,甚至是文本生成任务,将文本作为输入并将新的文本作为输出,这也是近两年大火的**T5模型(Text-to-Text Transfer Transformer)**的初衷。举例来说,文本分类任务可以理解为输出类别名,如猫/狗、是/否;文本纠错任务可以理解为输入有错误的文本并理解,输出正确的文本描述;智能问答可以理解为根据背景知识及问句进行推理,输出相应的回答。
可以说,文本生成类任务的应用相当之广,本篇将介绍一些常见的文本生成任务,其中也包含一些曾经并不属于文本生成类任务,但如今也能使用NLG技术进行解决的任务。
# # 安装一些必要的包
# !pip install openai
# # torch install 命令 https://pytorch.org/get-started/locally/
# !pip install torch==2.0.0+cpu torchvision==0.15.1+cpu --extra-index-url https://download.pytorch.org/whl/cpu
# !pip install tokenizers==0.13.2
# !pip install transformers==4.27.4
# !pip install --no-binary=protobuf protobuf==3.20.1
# !pip install sentencepiece==0.1.97
# !pip install redlines
# !pip install tenacity==8.2.2
# 配置openai api key
import openai
OPENAI_API_KEY = "输入你的key" # TODO
openai.api_key = OPENAI_API_KEY
# 查看API支持的模型
models = openai.Model.list()
print([x.id for x in models.data])
['babbage', 'davinci', 'text-davinci-edit-001', 'babbage-code-search-code', 'text-similarity-babbage-001', 'code-davinci-edit-001', 'text-davinci-001', 'ada', 'babbage-code-search-text', 'babbage-similarity', 'code-search-babbage-text-001', 'text-curie-001', 'code-search-babbage-code-001', 'text-ada-001', 'text-embedding-ada-002', 'text-similarity-ada-001', 'curie-instruct-beta', 'ada-code-search-code', 'ada-similarity', 'code-search-ada-text-001', 'text-search-ada-query-001', 'davinci-search-document', 'ada-code-search-text', 'text-search-ada-doc-001', 'davinci-instruct-beta', 'gpt-3.5-turbo', 'text-similarity-curie-001', 'code-search-ada-code-001', 'ada-search-query', 'text-search-davinci-query-001', 'curie-search-query', 'gpt-3.5-turbo-0301', 'davinci-search-query', 'babbage-search-document', 'ada-search-document', 'text-search-curie-query-001', 'whisper-1', 'text-search-babbage-doc-001', 'curie-search-document', 'text-davinci-003', 'text-search-curie-doc-001', 'babbage-search-query', 'text-babbage-001', 'text-search-davinci-doc-001', 'text-search-babbage-query-001', 'curie-similarity', 'curie', 'text-similarity-davinci-001', 'text-davinci-002', 'davinci-similarity', 'cushman:2020-05-03', 'ada:2020-05-03', 'babbage:2020-05-03', 'curie:2020-05-03', 'davinci:2020-05-03', 'if-davinci-v2', 'if-curie-v2', 'if-davinci:3.0.0', 'davinci-if:3.0.0', 'davinci-instruct-beta:2.0.0', 'text-ada:001', 'text-davinci:001', 'text-curie:001', 'text-babbage:001', 'ada:ft-personal-2023-05-07-07-50-50', 'ada:ft-personal-2023-04-15-13-19-25', 'ada:ft-personal-2023-04-15-13-29-50']
模型列表中包含内置的60多个可用模型,以及自己fine tune的模型,fine tune模型以"ft-personal"开头。
# 如需删除自己fine tune的模型,可以使用openai.Model.delete命令。
openai.Model.delete('ada:ft-personal-2023-04-15-12-54-03')
<Model model id=ada:ft-personal-2023-04-15-12-54-03 at 0x20506421090> JSON: {
"deleted": true,
"id": "ada:ft-personal-2023-04-15-12-54-03",
"object": "model"
}
models = openai.Model.list()
print([x.id for x in models.data if x.id.find('ft-personal') != -1])
['ada:ft-personal-2023-04-15-13-19-25', 'ada:ft-personal-2023-04-15-13-29-50']
文本摘要任务指的是用精炼的文本来概括整篇文章的大意,使得用户能够通过阅读摘要来大致了解文章的主要内容。
从实现手法来说,文本摘要任务主要分为以下三种:
以下是一个基于mT5模型(T5模型的多语言版)的文本摘要样例。
**注:**下载模型较大,可前往huggingface->Hosted inference API 在线测试。https://huggingface.co/csebuetnlp/mT5_multilingual_XLSum
import re import torch from transformers import AutoTokenizer, AutoModelForSeq2SeqLM # 载入模型 tokenizer = AutoTokenizer.from_pretrained("csebuetnlp/mT5_multilingual_XLSum") model = AutoModelForSeq2SeqLM.from_pretrained("csebuetnlp/mT5_multilingual_XLSum") WHITESPACE_HANDLER = lambda k: re.sub('\s+', ' ', re.sub('\n+', ' ', k.strip())) text = """自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望""" text = WHITESPACE_HANDLER(text) input_ids = tokenizer([text], return_tensors="pt", padding="max_length", truncation=True, max_length=512)["input_ids"] # 生成结果文本 output_ids = model.generate(input_ids=input_ids, max_length=84, no_repeat_ngram_size=2, num_beams=4)[0] output_text = tokenizer.decode(output_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False) print("原始文本: ", text) print("摘要文本: ", output_text)
C:\Softwares\Programming\Python\Anaconda\envs\chatgpt\lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
C:\Softwares\Programming\Python\Anaconda\envs\chatgpt\lib\site-packages\transformers\convert_slow_tokenizer.py:446: UserWarning: The sentencepiece tokenizer that you are converting to a fast tokenizer uses the byte fallback option which is not implemented in the fast tokenizers. In practice this means that the fast version of the tokenizer can produce unknown tokens whereas the sentencepiece version would have converted these unknown tokens into a sequence of byte tokens matching the original piece of text.
warnings.warn(
原始文本: 自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望
摘要文本: 自动信任协商(AI)是互信关系建立的最新研究工作的一部分。
GPT 3.5
def summarize_text(text): response = openai.Completion.create( engine="text-davinci-003", prompt=f"请对以下文本进行总结,注意总结的凝炼性,将总结字数控制在20个字以内:\n{text}", temperature=0.3, max_tokens=500, ) summarized_text = response.choices[0].text.strip() return summarized_text text = "自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望。""" output_text = summarize_text(text) print("原始文本: ", text) print("摘要文本: ", output_text) print("摘要文本长度: ", len(output_text))
原始文本: 自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望。
摘要文本: 自动信任协商解决跨安全域信任建立问题,但面临多种安全威胁,需要分析攻击方式及防御措施。
摘要文本长度: 43
ChatGPT
def summarize_text(text): content = f"请对以下文本进行总结,注意总结的凝炼性,将总结字数控制在20个字以内:\n{text}" response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": content}], temperature=0.3 ) summarized_text = response.get("choices")[0].get("message").get("content") return summarized_text text = """自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望。""" output_text = summarize_text(text) print("原始文本: ", text) print("摘要文本: ", output_text) print("摘要文本长度: ", len(output_text)) # 注意,chatgpt并不能完美限制摘要输出的字数
原始文本: 自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望。
摘要文本: 自动信任协商解决跨域信任建立,但面临多方面安全威胁,需分类防御。研究不足,未来展望。
摘要文本长度: 42
对于垂直领域的数据或任务,有时直接使用LLM的效果不佳。
当然,由于ChatGPT强大的内在理解能力,在某些情况下使用一个比较好的Prompt,通过Zero-Shot或者Few-Shot也能得到一个不错的结果。
我们这里简单地介绍如何通过自定义语料库对模型进行fine tune。目前OpenAI仅开放了ada, babbage, curie, davinci四个小模型的fine tune接口,其中最大的davinci模型约175亿参数。
https://platform.openai.com/docs/guides/fine-tuning
# 查看所有的fine tune模型
!openai api fine_tunes.list
{ "data": [ { "created_at": 1681558899, "fine_tuned_model": null, "hyperparams": { "batch_size": null, "learning_rate_multiplier": null, "n_epochs": 4, "prompt_loss_weight": 0.01 }, "id": "ft-dsshfnyndpY14OqgnRya8ExI", "model": "davinci", "object": "fine-tune", "organization_id": "org-U35hu1wdD7w3HnkgJ5fdBW8m", "result_files": [], "status": "failed", "training_files": [ { "bytes": 380384, "created_at": 1681558899, "filename": "./dataset/csl_summarize_finetune_prepared.jsonl", "id": "file-0akQ6d59yrShNHtrCrh93U4w", "object": "file", "purpose": "fine-tune", "status": "processed", "status_details": null } ], "updated_at": 1681558911, "validation_files": [] }, { "created_at": 1681559488, "fine_tuned_model": "ada:ft-personal-2023-04-15-11-57-25", "hyperparams": { "batch_size": 1, "learning_rate_multiplier": 0.1, "n_epochs": 4, "prompt_loss_weight": 0.01 }, "id": "ft-lcIkh8dG2t1V4GAWWsFC644V", "model": "ada", "object": "fine-tune", "organization_id": "org-U35hu1wdD7w3HnkgJ5fdBW8m", "result_files": [ { "bytes": 114680, "created_at": 1681559846, "filename": "compiled_results.csv", "id": "file-CwFfIH8HHXqpk3YCg0x1Yphn", "object": "file", "purpose": "fine-tune-results", "status": "processed", "status_details": null } ], "status": "succeeded", "training_files": [ { "bytes": 380384, "created_at": 1681559487, "filename": "./dataset/csl_summarize_finetune_prepared.jsonl", "id": "file-0d35aGDx0Mn33tZ6x070HzmV", "object": "file", "purpose": "fine-tune", "status": "processed", "status_details": null } ], "updated_at": 1681559846, "validation_files": [] }, { "created_at": 1681562888, "fine_tuned_model": "ada:ft-personal-2023-04-15-12-54-03", "hyperparams": { "batch_size": 1, "learning_rate_multiplier": 0.1, "n_epochs": 4, "prompt_loss_weight": 0.01 }, "id": "ft-cSvqpGrrohBdPPmE7oxR2Xy3", "model": "ada", "object": "fine-tune", "organization_id": "org-U35hu1wdD7w3HnkgJ5fdBW8m", "result_files": [ { "bytes": 114651, "created_at": 1681563244, "filename": "compiled_results.csv", "id": "file-Zfbqegb2TiJztX9R30ikbiG1", "object": "file", "purpose": "fine-tune-results", "status": "processed", "status_details": null } ], "status": "succeeded", "training_files": [ { "bytes": 380384, "created_at": 1681562888, "filename": "./dataset/csl_summarize_finetune_prepared.jsonl", "id": "file-Cet8LADkX8SiGnUtAcktsoZ7", "object": "file", "purpose": "fine-tune", "status": "processed", "status_details": null } ], "updated_at": 1681563245, "validation_files": [] }, { "created_at": 1681564395, "fine_tuned_model": "ada:ft-personal-2023-04-15-13-19-25", "hyperparams": { "batch_size": 1, "learning_rate_multiplier": 0.1, "n_epochs": 4, "prompt_loss_weight": 0.01 }, "id": "ft-UzytubaVgNI8SAwqLuZba4T9", "model": "ada", "object": "fine-tune", "organization_id": "org-U35hu1wdD7w3HnkgJ5fdBW8m", "result_files": [ { "bytes": 114523, "created_at": 1681564766, "filename": "compiled_results.csv", "id": "file-kq3Dhk5R95SI6taHP0ERWqkc", "object": "file", "purpose": "fine-tune-results", "status": "processed", "status_details": null } ], "status": "succeeded", "training_files": [ { "bytes": 380384, "created_at": 1681564395, "filename": "./dataset/csl_summarize_finetune_prepared.jsonl", "id": "file-ajKeL2f93LaU09WRNj4kF6uV", "object": "file", "purpose": "fine-tune", "status": "processed", "status_details": null } ], "updated_at": 1681564767, "validation_files": [] }, { "created_at": 1681565036, "fine_tuned_model": "ada:ft-personal-2023-04-15-13-29-50", "hyperparams": { "batch_size": 1, "learning_rate_multiplier": 0.1, "n_epochs": 4, "prompt_loss_weight": 0.01 }, "id": "ft-LoKi6mOxlkOtfZcZTrmivKDa", "model": "ada", "object": "fine-tune", "organization_id": "org-U35hu1wdD7w3HnkgJ5fdBW8m", "result_files": [ { "bytes": 112280, "created_at": 1681565392, "filename": "compiled_results.csv", "id": "file-TTRfuuyBXuZ4BKwX9I4i2zA4", "object": "file", "purpose": "fine-tune-results", "status": "processed", "status_details": null } ], "status": "succeeded", "training_files": [ { "bytes": 380384, "created_at": 1681565036, "filename": "./dataset/csl_summarize_finetune_prepared.jsonl", "id": "file-S3SIEZoJbqPXTGT16YxPThVO", "object": "file", "purpose": "fine-tune", "status": "processed", "status_details": null } ], "updated_at": 1681565392, "validation_files": [] } ], "object": "list" }
数据集来源:CSL摘要数据集,是计算机领域的论文摘要和标题数据,包含3500条数据,
数据源地址:https://github.com/liucongg/GPT2-NewsTitle 项目中的CSL摘要数据集
import json
with open('dataset/csl_data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
data[-1]
{'title': '自动信任协商中的攻击与防范',
'content': '自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望。'}
import pandas as pd
df = pd.DataFrame(data)
df = df[['content', 'title']]
df.columns = ["prompt", "completion"]
df_train = df.iloc[:500]
df_train.head(5)
prompt | completion | |
---|---|---|
0 | 提出了一种新的保细节的变形算法,可以使网格模型进行尽量刚性的变形,以减少变形中几何细节的扭曲... | 保细节的网格刚性变形算法 |
1 | 实时服装动画生成技术能够为三维虚拟角色实时地生成逼真的服装动态效果,在游戏娱乐、虚拟服装设计... | 一种基于混合模型的实时虚拟人服装动画方法 |
2 | 提出一种基于模糊主分量分析技术(FPCA)的人脸遮挡检测与去除方法.首先,有遮挡人脸被投影到... | 人脸遮挡区域检测与重建 |
3 | 图像匹配技术在计算机视觉、遥感和医学图像分析等领域有着广泛的应用背景.针对传统的相关匹配算法... | 一种基于奇异值分解的图像匹配算法 |
4 | 提出了一种基于片相似性的各项异性扩散图像去噪方法.传统的各项异性图像去噪方法都是基于单个像素... | 片相似性各项异性扩散图像去噪 |
df_train.to_json("dataset/csl_summarize_finetune.jsonl", orient='records', lines=True, force_ascii=False)
!openai tools fine_tunes.prepare_data -f dataset/csl_summarize_finetune.jsonl -q
Analyzing... - Your file contains 500 prompt-completion pairs - More than a third of your `prompt` column/key is uppercase. Uppercase prompts tends to perform worse than a mixture of case encountered in normal language. We recommend to lower case the data if that makes sense in your domain. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more details - More than a third of your `completion` column/key is uppercase. Uppercase completions tends to perform worse than a mixture of case encountered in normal language. We recommend to lower case the data if that makes sense in your domain. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more details - Your data does not contain a common separator at the end of your prompts. Having a separator string appended to the end of the prompt makes it clearer to the fine-tuned model where the completion should begin. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more detail and examples. If you intend to do open-ended generation, then you should leave the prompts empty - Your data does not contain a common ending at the end of your completions. Having a common ending string appended to the end of the completion makes it clearer to the fine-tuned model where the completion should end. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more detail and examples. - The completion should start with a whitespace character (` `). This tends to produce better results due to the tokenization we use. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more details Based on the analysis we will perform the following actions: - [Recommended] Lowercase all your data in column/key `prompt` [Y/n]: Y - [Recommended] Lowercase all your data in column/key `completion` [Y/n]: Y - [Recommended] Add a suffix separator ` ->` to all prompts [Y/n]: Y - [Recommended] Add a suffix ending `\n` to all completions [Y/n]: Y - [Recommended] Add a whitespace character to the beginning of the completion [Y/n]: Y Your data will be written to a new JSONL file. Proceed [Y/n]: Y Wrote modified file to `dataset/csl_summarize_finetune_prepared (1).jsonl` Feel free to take a look! Now use that file when fine-tuning: > openai api fine_tunes.create -t "dataset/csl_summarize_finetune_prepared (1).jsonl" After you’ve fine-tuned a model, remember that your prompt has to end with the indicator string ` ->` for the model to start generating completions, rather than continuing with the prompt. Make sure to include `stop=["\n"]` so that the generated texts ends at the expected place. Once your model starts training, it'll approximately take 9.31 minutes to train a `curie` model, and less for `ada` and `babbage`. Queue will approximately take half an hour per job ahead of you.
import os
os.environ.setdefault("OPENAI_API_KEY", OPENAI_API_KEY)
!openai api fine_tunes.create \
-t "./dataset/csl_summarize_finetune_prepared.jsonl" \
-m ada\
--no_check_if_files_exist
Uploaded file from ./dataset/csl_summarize_finetune_prepared.jsonl: file-gPzuOBUizUDCGO7t0oDYoWQB Upload progress: 0%| | 0.00/380k [00:00<?, ?it/s] Upload progress: 100%|██████████| 380k/380k [00:00<00:00, 239Mit/s] Created fine-tune: ft-px9hve11l6YjizCQ8I6MyLCK Streaming events until fine-tuning is complete... (Ctrl-C will interrupt the stream, but not cancel the fine-tune) [2023-05-07 20:27:26] Created fine-tune: ft-px9hve11l6YjizCQ8I6MyLCK [2023-05-07 20:27:45] Fine-tune costs $0.43 [2023-05-07 20:27:45] Fine-tune enqueued. Queue number: 0 [2023-05-07 20:27:46] Fine-tune started Stream interrupted (client disconnected). To resume the stream, run: openai api fine_tunes.follow -i ft-px9hve11l6YjizCQ8I6MyLCK
# 根据上一步的输出,得到fine tune运行的key ft-LoKi6mOxlkOtfZcZTrmivKDa,
# 我们可以通过get来获取当前执行进度,
# 如发现与openai的连接断开,可通过follow重新排队连接
# !openai api fine_tunes.follow -i ft-LoKi6mOxlkOtfZcZTrmivKDa
!openai api fine_tunes.get -i ft-LoKi6mOxlkOtfZcZTrmivKDa
{ "created_at": 1681565036, "events": [ { "created_at": 1681565036, "level": "info", "message": "Created fine-tune: ft-LoKi6mOxlkOtfZcZTrmivKDa", "object": "fine-tune-event" }, { "created_at": 1681565045, "level": "info", "message": "Fine-tune costs $0.43", "object": "fine-tune-event" }, { "created_at": 1681565045, "level": "info", "message": "Fine-tune enqueued. Queue number: 0", "object": "fine-tune-event" }, { "created_at": 1681565046, "level": "info", "message": "Fine-tune started", "object": "fine-tune-event" }, { "created_at": 1681565139, "level": "info", "message": "Completed epoch 1/4", "object": "fine-tune-event" }, { "created_at": 1681565216, "level": "info", "message": "Completed epoch 2/4", "object": "fine-tune-event" }, { "created_at": 1681565293, "level": "info", "message": "Completed epoch 3/4", "object": "fine-tune-event" }, { "created_at": 1681565369, "level": "info", "message": "Completed epoch 4/4", "object": "fine-tune-event" }, { "created_at": 1681565391, "level": "info", "message": "Uploaded model: ada:ft-personal-2023-04-15-13-29-50", "object": "fine-tune-event" }, { "created_at": 1681565392, "level": "info", "message": "Uploaded result file: file-TTRfuuyBXuZ4BKwX9I4i2zA4", "object": "fine-tune-event" }, { "created_at": 1681565392, "level": "info", "message": "Fine-tune succeeded", "object": "fine-tune-event" } ], "fine_tuned_model": "ada:ft-personal-2023-04-15-13-29-50", "hyperparams": { "batch_size": 1, "learning_rate_multiplier": 0.1, "n_epochs": 4, "prompt_loss_weight": 0.01 }, "id": "ft-LoKi6mOxlkOtfZcZTrmivKDa", "model": "ada", "object": "fine-tune", "organization_id": "org-U35hu1wdD7w3HnkgJ5fdBW8m", "result_files": [ { "bytes": 112280, "created_at": 1681565392, "filename": "compiled_results.csv", "id": "file-TTRfuuyBXuZ4BKwX9I4i2zA4", "object": "file", "purpose": "fine-tune-results", "status": "processed", "status_details": null } ], "status": "succeeded", "training_files": [ { "bytes": 380384, "created_at": 1681565036, "filename": "./dataset/csl_summarize_finetune_prepared.jsonl", "id": "file-S3SIEZoJbqPXTGT16YxPThVO", "object": "file", "purpose": "fine-tune", "status": "processed", "status_details": null } ], "updated_at": 1681565392, "validation_files": [] }
# 保存openai fine tune过程的记录
!openai api fine_tunes.results -i ft-cSvqpGrrohBdPPmE7oxR2Xy3 > dataset/metric.csv
def summarize_text(text, model_name):
response = openai.Completion.create(
engine=model_name,
prompt=f"请对以下文本进行总结,注意总结的凝炼性,将总结字数控制在20个字以内:\n{text}",
temperature=0.7,
max_tokens=100,
)
summarized_text = response.choices[0].text.strip()
return summarized_text
text = "自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望。"""
print("原始文本: ", text)
print("ada摘要文本: ", summarize_text(text, model_name='ada'))
print("ada fine-tune摘要文本: ", summarize_text(text, model_name='ada:ft-personal-2023-04-15-13-29-50'))
原始文本: 自动信任协商主要解决跨安全域的信任建立问题,使陌生实体通过反复的、双向的访问控制策略和数字证书的相互披露而逐步建立信任关系。由于信任建立的方式独特和应用环境复杂,自动信任协商面临多方面的安全威胁,针对协商的攻击大多超出常规防范措施所保护的范围,因此有必要对自动信任协商中的攻击手段进行专门分析。按攻击特点对自动信任协商中存在的各种攻击方式进行分类,并介绍了相应的防御措施,总结了当前研究工作的不足,对未来的研究进行了展望。
ada摘要文本: 因此,为了在未来进行研究,本次研究也许能给学术界其他学者带来建议,更多读者本次研究期间的能查
ada fine-tune摘要文本: -> 分布式防御措施的自动信任协商
面向自动信任协商的防御措施研究
自动信任协商的攻击面临
由于资费与效率原因,本次实验基于Ada模型进行fine tune。可以看到,原始的Ada模型几乎完全没有get到文本摘要任务,只是在文本背景上生成了一段新的文本。在经过简单的fine tune后,虽然生成的文本仍然远不及ChatGPT或者其他在该任务上做过精细微调的大模型,但是已经能在一定程度上生成一个还算不错的摘要了。
如果有需要在一个微调模型上继续微调,直接将fine_tunes.create的-m参数改为微调后的模型名称即可。例如对于以上案例,可使用:
!openai api fine_tunes.create \
-t "./dataset/csl_summarize_finetune_prepared.jsonl" \
-m ada:ft-personal-2023-04-15-13-29-50\
--no_check_if_files_exist
Uploaded file from ./dataset/csl_summarize_finetune_prepared.jsonl: file-adsjU97Wo9bPNmdAa1LTMkQC Created fine-tune: ft-d6qvvl7cr6WYvkSOBu7YVO2p Streaming events until fine-tuning is complete... (Ctrl-C will interrupt the stream, but not cancel the fine-tune) [2023-05-07 15:44:48] Created fine-tune: ft-d6qvvl7cr6WYvkSOBu7YVO2p [2023-05-07 15:45:03] Fine-tune costs $0.43 [2023-05-07 15:45:03] Fine-tune enqueued. Queue number: 0 [2023-05-07 15:45:05] Fine-tune started Stream interrupted (client disconnected). To resume the stream, run: openai api fine_tunes.follow -i ft-d6qvvl7cr6WYvkSOBu7YVO2p Upload progress: 0%| | 0.00/380k [00:00<?, ?it/s] Upload progress: 100%|██████████| 380k/380k [00:00<?, ?it/s]
在日常生活中,不管是微信聊天、微博推文甚至是出版书籍中,我们都或多或少地会发现文本中的错别字现象。
这些错别字可能源于语音输入时的口音偏差,如“飞机”被识别成了“灰机”;也可能是拼音输入时误触了临近键位或者选错了结果,如“飞机”被识别成了“得急”、“肥鸡”;亦或是手写输入时写成了形近字,如“战栗”被识别为了“战粟”……
常见的错误类型包括:
总之,文本错误可能是千奇百怪的。对于人类而言,凭借着常识与上下文,实现语义理解尚不是什么难事,有时只是些许影响阅读体验;而对于一些特定的文本下游任务,如命名实体识别或意图识别,一条不加处理的错误输入文本可能会导致南辕北辙的识别结果。|
文本纠错任务指的是通过自然语言处理技术对文本中出现的错误进行检测和纠正的过程。目前已经成为自然语言处理领域中的一个重要分支,被广泛地应用于搜索引擎、机器翻译、智能客服等各种领域。纵然由于文本错误的多样性,我们往往难以将所有错误通通识别并纠正成功,但是如果能尽可能多且正确地识别文本中的错误,能够大大降低人工审核的成本,也不失为一桩美事~
常见的文本纠错技术主要有以下几种:
这种文本纠错技术是通过实现定义的规则来检查文本中的拼写、语法、标点符号等常见错误,假如“金字塔”常被误写为“金子塔”,则在数据库中加入两者的映射关系。由于这种传统方法需要大量的人工工作以及专家对于语言的深刻理解,因此难以处理海量文本或较为复杂的语言错误。
基于语言模型的文本纠错技术包括错误检测和错误纠正,这种方法同样比较简单粗暴,方法速度快,扩展性强,效果一般。常见的模型有Kenlm。
错误检测:使用jieba
中文分词器对句子进行切词,然后结合字粒度和词粒度两方面的疑似错误结果,形成疑似错误位置候选集。
错误纠正:遍历所有的候选集并使用音似、形似词典替换错误位置的词,然后通过语言模型计算句子困惑度,最后比较并排序所有候选集结果,得到最优纠正词。
我们知道,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掉,并预测出真实词汇。
上述提到的Mask方法只能用于输入与输出等长的情况,但是实际应用中往往会出现两者不等长的情况,如错字或多字。一种可能的解决办法是,在原有的BERT模型后嵌入一层Transformer Decoder,即将“文本纠错”任务等价于“将错误的文本翻译成正确的文本”,此时我们没法保证输出文本与原始文本中正确的部分一定能保持完全一致,可能在语义不变的情况下,会生成了一种新的表达方式。
pycorrector是一个文本纠错工具集,内置了KenLM、MacBERT、Transformer等多种文本纠错模型。
pycorrector不仅可以通过“import pycorrector”调用,也提供了Huggingface的预训练模型调用方式,以下是一个基于Huggingface的MacBERT4CSC调用样例。
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)]
def correct_text(text):
content = f"请对以下文本进行文本纠错:\n{text}"
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": content}]
)
corrected_text = response.get("choices")[0].get("message").get("content")
return corrected_text
text = "大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课乘吧!"
output_text = correct_text(text)
print("原始文本: ", text)
print("纠错文本: ", output_text)
原始文本: 大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课乘吧!
纠错文本: 大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课程吧!
from redlines import Redlines
from IPython.display import display, Markdown
diff = Redlines(' '.join(list(text)),' '.join(list(output_text)))
display(Markdown(diff.output_markdown))
大 家 好 , , 一 起 来 参 加 D a t a W h a l e 的 《 C h a t G P T 使 用 指 南 》 组 队 学 习 课 乘 程 吧 !
机器翻译,又称为自动翻译,是利用计算机将一种自然语言(源语言)转换为另一种自然语言(目标语言)的过程。据不完全统计,世界上约有7000种语言,两两配对约有 700 0 2 7000^2 70002 种组合,这些语言中又不乏一词多义、垂类知识等现象,因此能够使用更少的标注数据,或者无监督地让计算机真正地理解输入语言的含义,并“信”、“达”、“雅”地转化为输出语言,是历来学者们的研究重心。
众所周知,机器翻译一直是自然语言处理领域备受关注的研究方向,也是自然语言处理技术最早展露头角的任务之一。如今市面上的机器翻译工具层出不穷,如大家常用的百度翻译、谷歌翻译,乃至小时候科幻片里才有的AI同声传译,如讯飞听见同传。简单来说可以将其划分为通用领域(多语种)、垂直领域、术语定制化、领域自适应、人工适应、语音翻译等。
从机器翻译的发展历程来看,主要经历了如下几个阶段:
基于规则的方法需要建立各类知识库,描述源语言和目标语言的词法、句法以及语义知识,有时知识无关的世界知识。
基于统计的方法认为对于一条源语言 R R R,任何一条目标语言 T T T 都可能是它的译文,只是可能性有高有低。对于源语言中的每个词 r i r_i ri 及目标语言中的每个词 t j t_j tj,判断词对齐的概率,再通过期望最大算法(如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.
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)
原始文本: 大家好,一起来参加DataWhale的《ChatGPT使用指南》组队学习课程吧!
输出文本: Hello everyone, let's join the team learning course of "ChatGPT User Guide" organized by DataWhale together!
可以看到,ChatGPT明显比Helsinki-NLP在中翻英上的效果更好,将《ChatGPT使用指南》翻译得更加具体。
导入书籍
数据来源:https://github.com/LouisScorpio/datamining/tree/master/tensorflow-program/nlp/word2vec/dataset
with open("dataset/哈利波特1-7英文原版.txt", "r") as f:
text = f.read()
print('全书字符数: ', len(text))
# 整本书的字符数约有635万,但我们知道,chatgpt的api调用是根据token数量来的,
# tokenizer本身的作用是将句子切分成单词,再将单词转化为数值型的输入,我们可以简单地使用tokenizer来统计token数量
全书字符数: 6350735
from transformers import GPT2Tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2") # GPT-2的tokenizer和GPT-3是一样的
token_counts = len(tokenizer.encode(text))
print('全书token数: ', token_counts)
# chatgpt的api调用价格是 1000 token 0.01美元,因此可以大致计算翻译一本书的价格
translate_cost = 0.01 / 1000 * token_counts
print(f'翻译全书约需{translate_cost}美元')
Token indices sequence length is longer than the specified maximum sequence length for this model (1673251 > 1024). Running this sequence through the model will result in indexing errors
全书token数: 1673251
翻译全书约需16.73251美元
# 翻译全书约需115.14 rmb成本,有点贵了,我们试着只翻译第一本
end_idx = text.find('2.Harry Potter and The Chamber Of Secrets.txt')
text = text[:end_idx]
print('第一册字符数: ', len(text))
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
token_counts = len(tokenizer.encode(text))
print('第一册token数: ', token_counts)
translate_cost = 0.01 / 1000 * token_counts
print(f'翻译第一册约需{translate_cost}美元')
第一册字符数: 442815
Token indices sequence length is longer than the specified maximum sequence length for this model (119873 > 1024). Running this sequence through the model will result in indexing errors
第一册token数: 119873
翻译第一册约需1.19873美元
GPT-3的token限制大约在4096左右(据说GPT-4最多输入3.2万token),因此无法直接将12万token的文本输进去。
我们可以将使用一个简单的方法,将文本分成若干份,每一份使用chatgpt翻译,最终再拼接起来。
首先,我们最好能保证每份文本本身的语义连贯性,如果从一个句子中间将上下文拆成两块,则翻译时容易存在歧义。
一个比较直观的想法是,将每个段落当成一个文本块,每次翻译一段。
但是本书的段落非常多,一段一段翻译显然会降低翻译的效率。同时,由于每段的上下文较少,导致翻译错误的可能性上升。
paragraphs = text.split('\n')
print('段落数: ', len(paragraphs))
ntokens = []
for paragraph in paragraphs:
ntokens.append(len(tokenizer.encode(paragraph)))
print('最长段落的token数: ', max(ntokens))
段落数: 3038
最长段落的token数: 275
因此,我们选定一个阈值,如500,每次加入一个文本段落,如果总数超过500,则开启一个文本块。
def group_paragraphs(paragraphs, ntokens, max_len=1000): """ 合并短段落为文本块,用于丰富上下文语境,提升文本连贯性,并提升运算效率。 :param paragraphs: 段落集合 :param ntokens: token数集合 :param max_len: 最大文本块token数 :return: 组合好的文本块 """ batches = [] cur_batch = "" cur_tokens = 0 # 对于每个文本段落做处理 for paragraph, ntoken in zip(paragraphs, ntokens): if ntoken + cur_tokens + 1 > max_len: # '1' 指的是'\n' # 如果加入这段文本,总token数超过阈值,则开启新的文本块 batches.append(cur_batch) cur_batch = paragraph cur_tokens = ntoken else: # 否则将段落插入文本块中 cur_batch += "\n" + paragraph cur_tokens += (1 + ntoken) batches.append(cur_batch) # 记录最后一个文本块 return batches batchs = group_paragraphs(paragraphs, ntokens, max_len=500) print('文本块数: ', len(batchs)) new_tokens = [] for batch in batchs: new_tokens.append(len(tokenizer.encode(batch))) print('最长文本块的token数: ', max(new_tokens))
文本块数: 256
最长文本块的token数: 500
# 展示第一段文本
print(batchs[0])
1.Harry Potter and the Sorcerer's Stone.txt
Harry Potter and the Sorcerer's Stone
CHAPTER ONE
THE BOY WHO LIVED
Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you'd expect to be involved in anything strange or mysterious, because they just didn't hold with such nonsense.
Mr. Dursley was the director of a firm called Grunnings, which made drills. He was a big, beefy man with hardly any neck, although he did have a very large mustache. Mrs. Dursley was thin and blonde and had nearly twice the usual amount of neck, which came in very useful as she spent so much of her time craning over garden fences, spying on the neighbors. The Dursleys had a small son called Dudley and in their opinion there was no finer boy anywhere.
The Dursleys had everything they wanted, but they also had a secret, and their greatest fear was that somebody would discover it. They didn't think they could bear it if anyone found out about the Potters. Mrs. Potter was Mrs. Dursley's sister, but they hadn't met for several years; in fact, Mrs. Dursley pretended she didn't have a sister, because her sister and her good-for-nothing husband were as unDursleyish as it was possible to be. The Dursleys shuddered to think what the neighbors would say if the Potters arrived in the street. The Dursleys knew that the Potters had a small son, too, but they had never even seen him. This boy was another good reason for keeping the Potters away; they didn't want Dudley mixing with a child like that.
When Mr. and Mrs. Dursley woke up on the dull, gray Tuesday our story starts, there was nothing about the cloudy sky outside to suggest that strange and mysterious things would soon be happening all over the country. Mr. Dursley hummed as he picked out his most boring tie for work, and Mrs. Dursley gossiped away happily as she wrestled a screaming Dudley into his high chair.
# 实操中发现,使用chatgpt翻译长文本很慢,这里改用Davinci实现,感兴趣的同学可以尝试优化 # 速率限制见:https://platform.openai.com/docs/guides/rate-limits/overview # 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 def translate_text(text): response = openai.Completion.create( engine="text-davinci-003", prompt=f"请将以下英文翻译成中文:\n{text}", max_tokens=2048 ) translate_text = response.choices[0].text.strip() return translate_text print(translate_text(batchs[0]))
欣欣夫妇对4号普里维特路的房子非常自豪,他们乐呵呵地表示,自己完全是一家正常家庭,也就不沾任何奇怪或神秘的事情。要是提到像这样的废话,他们实在是有点不屑一顾。欣欣先生当时正在格林宁公司任出品部主任,他长得又胖又壮,脖子很粗,只有一撮大胡子。欣欣太太瘦得非常,并且,出乎意料的是,她的脖子竟然站地比正常人都长,这样就非常省事,因为欣欣太太经常会在花园栅栏上俯瞰,窥探邻居的一举一动。欣欣夫妇有一个小儿子,叫达力,他们认为,没有比这孩子更好的了。
欣欣夫妇有很多东西,但其实他们也拥有一个秘密,最怕的是被有人发现。他们实在不敢想象,如果波特家来他们街上,会有什么样的下场……波特太太就是欣欣太太的妹妹,但是他们已经好几年没有见过面了。实际上,欣欣太太压根就假装没有妹妹,因为妹妹和他那没用的丈夫,实在是与欣欣家的一切都格格不入。同时,欣欣夫妇还知道波特家有一个小儿子,但是他们从来都没有见过。这孩子可就是欣欣夫妇珍爱达力的另一个绝好理由,不要让达力和他有接触。
当本故事发生的比较乏味的周二早晨,欣欣夫妇醒来,天空阴沉沉的,毫不暗示即将发生的奇异神秘的事情。欣欣先生嗯嗯哼哼地挑出今天上班穿的最没气质的领带,欣欣太太讨论着什么有趣的闲事,忙着把尖叫的达力抱进高脚高位椅里。
接下来,我们对每个文本块做翻译,并将结果合并起来。
from tqdm import tqdm
translated_batchs = []
# 有的时候由于VPN等问题,可能会出现断联,也即443 timeout,可以在断点batch处重连
translated_batchs_bak = translated_batchs.copy()
cur_len = len(translated_batchs)
for i in tqdm(range(cur_len, len(batchs))):
translated_batchs.append(translate_text(batchs[i]))
100%|████████████████████████████████████████████████████████████████████████████████████| 8/8 [07:50<00:00, 58.79s/it]
# 另一种方法是,参考openai的util函数,加入retry机制,如果失败则尝试重连
from tenacity import retry, stop_after_attempt, wait_random_exponential
@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
def translate_text(text):
response = openai.Completion.create(
engine="text-davinci-003",
prompt=f"请将以下英文翻译成中文:\n{text}",
temperature=0.3,
max_tokens=2048
)
translate_text = response.choices[0].text.strip()
return translate_text
for i in tqdm(range(len(batchs))):
translated_batchs.append(translate_text(batchs[i]))
100%|██████████████████████████████████████████████████████████████████████████████████| 20/20 [25:31<00:00, 76.55s/it]
# 保存结果至txt文件
result = '\n'.join(translated_batchs)
with open('dataset/哈利波特1中文版翻译.txt','w', encoding='utf-8') as f:
f.write(result)
如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。