学术论文GPT源码解读:从chatpaper、chatwithpaper到gpt_academic

前言

之前7月中旬,我曾在微博上说准备做“20个LLM大型项目的源码解读”

针对这个事,目前的最新情况是

  • 已经做了的:LLaMA、Alpaca、ChatGLM-6B、deepspeedchat、transformer、langchain、langchain-chatglm知识库
  • 准备做的:chatpaper、deepspeed、Megatron-LM
  • 再往后则:BERT、GPT、pytorch、chatdoctor、baichuan、BLOOM/BELLE、Chinese LLaMA、PEFT BLIP2 llama.cpp

总之,够未来半年忙了。为加快这个事情的进度,本文解读两个关于学术论文的GPT(由于我司每周都有好几个或为申博、或为评职称、或为毕业而报名论文1V1发表辅导的,比如中文期刊、EI会议、ei期刊/SCI等等,所以对这个方向一直都是高度关注,我司也在做类似的LLM产品,敬请期待)

  • 一个是chatpaper:https://github.com/kaixindelele/ChatPaper
  • 一个是gpt_academic:https://github.com/binary-husky/gpt_academic

我把这两个项目的结构做了拆解/解析,且基本把原有代码的每一行都补上了注释,如果大家对任何一行代码有疑问,可以随时在本文评论区留言,我会及时做补充说明


第一部分 ChatPaper:论文对话、总结、翻译

ChatPaper的自身定位是全流程加速科研:论文总结+专业级翻译+润色+审稿+审稿回复,因为论文更多是PDF的格式,故针对PDF的对话、总结、翻译,便不可避免的涉及到PDF的解析

1.1 ChatPaper/ChatReviewerAndResponse

1.1.1 对PDF的解析:ChatReviewerAndResponse/get_paper.py

// 待更

1.1.2 论文审查:ChatReviewerAndResponse/chat_reviewer.py

使用OpenAI的GPT模型进行论文审查的脚本。它首先定义了一个Reviewer类来处理审查工作,然后在if __name__ == '__main__':语句下使用argparse处理命令行参数,并调用chat_reviewer_main函数来开始审查过程

  • 导入模块:与第一段代码相似,但新增了一些库,如jieba、tenacity等
  • 命名元组定义:用于保存与论文审稿相关的参数
    ReviewerParams = namedtuple(
        "ReviewerParams",
        [
            "paper_path",
            "file_format",
            "research_fields",
            "language"
        ],
    )
  • 判断文本中是否包含中文:
    def contains_chinese(text):
        for ch in text:
            if u'\u4e00' <= ch <= u'\u9fff':
                return True
        return False
  • 插入句子到文本
    主要功能是在给定文本的每隔一定数量的单词或中文字符后插入一个指定的句子。如果文本行包含中文字符,则使用jieba分词工具来切分中文,否则使用空格来切分:
    def insert_sentence(text, sentence, interval):
        # 将输入文本按换行符分割成行
        lines = text.split('\n')
        # 初始化一个新的行列表
        new_lines = []
    
        # 遍历每一行
        for line in lines:
            # 检查行中是否包含中文字符
            if contains_chinese(line):
                # 如果是中文,使用jieba分词工具进行分词
                words = list(jieba.cut(line))
                # 定义分隔符为空字符(对于中文分词)
                separator = ''
            else:
                # 如果不包含中文,按空格分割行
                words = line.split()
                # 定义分隔符为空格(对于英文或其他非中文语言)
                separator = ' '
    
            # 初始化一个新的单词列表
            new_words = []
            # 初始化一个计数器
            count = 0
    
            # 遍历当前行的每一个单词
            for word in words:
                # 将当前单词添加到新的单词列表
                new_words.append(word)
                # 计数器增加
                count += 1
    
                # 检查是否达到了插入句子的间隔
                if count % interval == 0:
                    # 在达到指定间隔时,将要插入的句子添加到新的单词列表
                    new_words.append(sentence)
    
            # 将新的单词列表连接起来,并添加到新的行列表
            new_lines.append(separator.join(new_words))
    
        # 将新的行列表连接起来,返回结果
        return '\n'.join(new_lines)
  • 论文审稿类:定义了一个Reviewer类,包含以下功能:
    \rightarrow  第一阶段审稿:先是基于论文标题和摘要,选择要审稿的部分
    # 定义Reviewer类
    class Reviewer:
        # 初始化方法,设置属性
        def __init__(self, args=None):
            if args.language == 'en':
                self.language = 'English'
            elif args.language == 'zh':
                self.language = 'Chinese'
            else:
                self.language = 'Chinese'        
            # 创建一个ConfigParser对象
            self.config = configparser.ConfigParser()
            # 读取配置文件
            self.config.read('apikey.ini')
            # 获取某个键对应的值        
            self.chat_api_list = self.config.get('OpenAI', 'OPENAI_API_KEYS')[1:-1].replace('\'', '').split(',')
            self.chat_api_list = [api.strip() for api in self.chat_api_list if len(api) > 5]
            self.cur_api = 0
            self.file_format = args.file_format        
            self.max_token_num = 4096
            self.encoding = tiktoken.get_encoding("gpt2")
        
        def validateTitle(self, title):
            # 修正论文的路径格式
            rstr = r"[\/\\\:\*\?\"\<\>\|]" # '/ \ : * ? " < > |'
            new_title = re.sub(rstr, "_", title) # 替换为下划线
            return new_title
    然后分别实现两个函数
    一个stage_1主要功能是为了与GPT-3模型进行对话,获取模型对于文章的两个最关键部分的选择意见
    def stage_1(self, paper):
        # 初始化一个空列表,用于存储生成的HTML内容
        htmls = []
        
        # 初始化一个空字符串,用于存储文章的标题和摘要
        text = ''
        # 添加文章的标题
        text += 'Title: ' + paper.title + '. '
        # 添加文章的摘要
        text += 'Abstract: ' + paper.section_texts['Abstract']
        
        # 计算文本的token数量
        text_token = len(self.encoding.encode(text))
        # 判断token数量是否超过最大token限制的一半减去800
        if text_token > self.max_token_num/2 - 800:
            input_text_index = int(len(text)*((self.max_token_num/2)-800)/text_token)
            # 如果超出,则截取文本以满足长度要求
            text = text[:input_text_index]
        
        # 设置OpenAI API的密钥
        openai.api_key = self.chat_api_list[self.cur_api]
        # 更新当前使用的API索引
        self.cur_api += 1
        # 如果当前API索引超过API列表的长度,则重置为0
        self.cur_api = 0 if self.cur_api >= len(self.chat_api_list)-1 else self.cur_api
        
        # 创建与GPT-3的对话消息
        messages = [
            {"role": "system",
             "content": f"You are a professional reviewer in the field of {args.research_fields}. "
                        f"I will give you a paper. You need to review this paper and discuss the novelty and originality of ideas, correctness, clarity, the significance of results, potential impact and quality of the presentation. "
                        f"Due to the length limitations, I am only allowed to provide you the abstract, introduction, conclusion and at most two sections of this paper."
                        f"Now I will give you the title and abstract and the headings of potential sections. "
                        f"You need to reply at most two headings. Then I will further provide you the full information, includes aforementioned sections and at most two sections you called for.\n\n"
                        f"Title: {paper.title}\n\n"
                        f"Abstract: {paper.section_texts['Abstract']}\n\n"
                        f"Potential Sections: {paper.section_names[2:-1]}\n\n"
                        f"Follow the following format to output your choice of sections:"
                        f"{{chosen section 1}}, {{chosen section 2}}\n\n"},
            {"role": "user", "content": text},
        ]
        
        # 调用OpenAI API与GPT-3进行对话
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=messages,
        )
        
        # 初始化一个空字符串,用于存储模型的回复
        result = ''
        # 遍历模型的回复,将其添加到结果字符串中
        for choice in response.choices:
            result += choice.message.content
        # 打印模型的回复
        print(result)
        
        # 返回模型的回复,将其分割为多个部分
        return result.split(',')
    一个chat_review,主要功能是调用GPT-3模型进行论文审稿,对输入的文章文本进行审查,并按照预定格式生成审稿意见
    def chat_review(self, text):
        # 设置OpenAI API的密钥
        openai.api_key = self.chat_api_list[self.cur_api]
        
        # 更新当前使用的API密钥索引
        self.cur_api += 1
        # 如果当前API密钥索引超过API密钥列表的长度,则将其重置为0
        self.cur_api = 0 if self.cur_api >= len(self.chat_api_list)-1 else self.cur_api
    
        # 定义用于审稿提示的token数量
        review_prompt_token = 1000
        
        # 计算输入文本的token数量
        text_token = len(self.encoding.encode(text))
        # 计算输入文本的截取位置
        input_text_index = int(len(text)*(self.max_token_num-review_prompt_token)/text_token)
        # 截取文本并添加前缀
        input_text = "This is the paper for your review:" + text[:input_text_index]
        
        # 从'ReviewFormat.txt'文件中读取审稿格式
        with open('ReviewFormat.txt', 'r') as file:
            review_format = file.read()
        
        # 创建与GPT-3的对话消息
        messages=[
            {"role": "system", 
             "content": "You are a professional reviewer in the field of "+args.research_fields+". Now I will give you a paper. You need to give a complete review opinion according to the following requirements and format:"+ review_format +" Please answer in {}.".format(self.language)},
            {"role": "user", "content": input_text},
        ]
        
        # 调用OpenAI API与GPT-3进行对话
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=messages,
        )
        
        # 初始化一个空字符串,用于存储模型的回复
        result = ''
        # 遍历模型的回复,将其添加到结果字符串中
        for choice in response.choices:
            result += choice.message.content
    
        # 在结果中插入特定的句子,警告不允许复制
        result = insert_sentence(result, '**Generated by ChatGPT, no copying allowed!**', 15)
        # 追加伦理声明
        result += "\n\n⚠伦理声明/Ethics statement:\n--禁止直接复制生成的评论用于任何论文审稿工作!\n--Direct copying of generated comments for any paper review work is prohibited!"
        
        # 打印分隔符和结果
        print("********"*10)
        print(result)
        print("********"*10)
        # 打印相关的token使用信息和响应时间
        print("prompt_token_used:", response.usage.prompt_tokens)
        print("completion_token_used:", response.usage.completion_tokens)
        print("total_token_used:", response.usage.total_tokens)
        print("response_time:", response.response_ms/1000.0, 's')
        
        # 返回模型生成的审稿意见
        return result  
    \rightarrow  使用ChatGPT进行审稿,且有tenacity重试机制和更多的功能,其中review_by_chatgpt 调用了上面所示的两个函数,一个stage_1,一个chat_review
    def review_by_chatgpt(self, paper_list):
        # 创建一个空列表用于存储每篇文章审稿后的HTML格式内容
        htmls = []
        
        # 遍历paper_list中的每一篇文章
        for paper_index, paper in enumerate(paper_list):
            # 使用第一阶段审稿方法选择文章的关键部分
            sections_of_interest = self.stage_1(paper)
            
            # 初始化一个空字符串用于提取文章的主要部分
            text = ''
            # 添加文章的标题
            text += 'Title:' + paper.title + '. '
            # 添加文章的摘要
            text += 'Abstract: ' + paper.section_texts['Abstract']
            
            # 查找并添加“Introduction”部分
            intro_title = next((item for item in paper.section_names if 'ntroduction' in item.lower()), None)
            if intro_title is not None:
                text += 'Introduction: ' + paper.section_texts[intro_title]
            
            # 同样地,查找并添加“Conclusion”部分
            conclusion_title = next((item for item in paper.section_names if 'onclusion' in item), None)
            if conclusion_title is not None:
                text += 'Conclusion: ' + paper.section_texts[conclusion_title]
            
            # 遍历sections_of_interest,添加其他感兴趣的部分
            for heading in sections_of_interest:
                if heading in paper.section_names:
                    text += heading + ': ' + paper.section_texts[heading]
            
            # 使用ChatGPT进行审稿,并得到审稿内容
            chat_review_text = self.chat_review(text=text)
            
            # 将审稿的文章编号和内容添加到htmls列表中
            htmls.append('## Paper:' + str(paper_index+1))
            htmls.append('\n\n\n')
            htmls.append(chat_review_text)
            
            # 获取当前日期和时间,并转换为字符串格式
            date_str = str(datetime.datetime.now())[:13].replace(' ', '-')
            try:
                # 创建输出文件夹
                export_path = os.path.join('./', 'output_file')
                os.makedirs(export_path)
            except:
                # 如果文件夹已存在,则不执行任何操作
                pass
            
            # 如果是第一篇文章,则写模式为'w',否则为'a'
            mode = 'w' if paper_index == 0 else 'a'
            
            # 根据文章标题和日期生成文件名
            file_name = os.path.join(export_path, date_str+'-'+self.validateTitle(paper.title)+"."+self.file_format)
            
            # 将审稿内容导出为Markdown格式并保存
            self.export_to_markdown("\n".join(htmls), file_name=file_name, mode=mode)
            
            # 清空htmls列表,为下一篇文章做准备
            htmls = []
  • 主程序部分:
    定义了一个chat_reviewer_main 函数,该函数创建了一个Reviewer对象,并对指定路径中的PDF文件进行审稿
    def chat_reviewer_main(args):            
    
        reviewer1 = Reviewer(args=args)
        # 开始判断是路径还是文件:   
        paper_list = []     
        if args.paper_path.endswith(".pdf"):
            paper_list.append(Paper(path=args.paper_path))            
        else:
            for root, dirs, files in os.walk(args.paper_path):
                print("root:", root, "dirs:", dirs, 'files:', files) #当前目录路径
                for filename in files:
                    # 如果找到PDF文件,则将其复制到目标文件夹中
                    if filename.endswith(".pdf"):
                        paper_list.append(Paper(path=os.path.join(root, filename)))        
        print("------------------paper_num: {}------------------".format(len(paper_list)))        
        [print(paper_index, paper_name.path.split('\\')[-1]) for paper_index, paper_name in enumerate(paper_list)]
        reviewer1.review_by_chatgpt(paper_list=paper_list)
    主程序中定义了命令行参数解析,并调用了chat_reviewer_main 函数
    在主程序中增加了审稿时间的计算功能
    if __name__ == '__main__':    
        parser = argparse.ArgumentParser()
        parser.add_argument("--paper_path", type=str, default='', help="path of papers")
        parser.add_argument("--file_format", type=str, default='txt', help="output file format")
        parser.add_argument("--research_fields", type=str, default='computer science, artificial intelligence and reinforcement learning', help="the research fields of paper")
        parser.add_argument("--language", type=str, default='en', help="output lauguage, en or zh")
        
        reviewer_args = ReviewerParams(**vars(parser.parse_args()))
        start_time = time.time()
        chat_reviewer_main(args=reviewer_args)
        print("review time:", time.time() - start_time)

// 待更

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

时序预测 | MATLAB实现EEMD-LSTM、LSTM集合经验模态分解结合长短期记忆神经网络时间序列预测对比

时序预测 | MATLAB实现EEMD-LSTM、LSTM集合经验模态分解结合长短期记忆神经网络时间序列预测对比 目录 时序预测 | MATLAB实现EEMD-LSTM、LSTM集合经验模态分解结合长短期记忆神经网络时间序列预测对比效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 时序预测 | …

爬虫与搜索引擎优化:通过Python爬虫提升网站搜索排名

作为一名专业的爬虫程序员&#xff0c;我深知网站的搜索排名对于业务的重要性。在如今竞争激烈的网络世界中&#xff0c;如何让自己的网站在搜索引擎结果中脱颖而出&#xff0c;成为关键。今天&#xff0c;和大家分享一些关于如何通过Python爬虫来提升网站的搜索排名的技巧和实…

动态优先权算法

1.设计目的与要求 1.1设计目的 通过动态优先权算法的模拟加深对进程概念和进程调度过程的理解。 1.2设计要求 本实验要求学生独立地用C或C语言编写一个简单的进程管理程序&#xff0c;其主要部分是进程调度。调度算法可由学生自行选择&#xff0c;如基于动态优先级的调度算法…

maven Jar包反向install到本地仓库

maven Jar包反向install到本地仓库 需求实现 需求 项目打包时报错&#xff0c;缺少一个jar包。 但是在maven仓库都找不到此jar包&#xff0c;其他人提供了这个jar包。 需要把这个jar包install到本地仓库&#xff0c;使项目能正常打包运行。 实现 使用git bash命令执行以下脚…

iTOP-STM32MP157开发板Linux Misc驱动编写实验程序(运行测试)

启动 STM32MP157 开发板&#xff0c;我们通过 nfs 挂载共享文件目录&#xff0c;我们进入到共享目录&#xff0c;加载驱动模块如 图所示&#xff1a; insmod misc.ko 驱动加载成功后&#xff0c;输入以下命令&#xff0c;查看注册的设备节点是否存在&#xff0c;如下图所示&a…

【C++类和对象】类有哪些默认成员函数呢?(上)

目录 1. 类的6个默认成员函数 2. 构造函数(*^▽^*) 2.1 概念 2.2 特性 3. 析构函数(*^▽^*) 3.1 概念 3.2 特性 4. 拷贝构造函数(*^▽^*) 4.1 概念 4.2 特性 5. 赋值运算符重载(*^▽^*) 5.1 运算符重载 5.2 赋值运算符重载 ヾ(๑╹◡╹)&#xff89;"人总要为…

django使用多个数据库实现

一、说明&#xff1a; 在开发 Django 项目的时候&#xff0c;很多时候都是使用一个数据库&#xff0c;即 settings 中只有 default 数据库&#xff0c;但是有一些项目确实也需要使用多个数据库&#xff0c;这样的项目&#xff0c;在数据库配置和使用的时候&#xff0c;就比较麻…

体渲染原理及WebGL实现【Volume Rendering】

体渲染&#xff08;Volume Rendering&#xff09;是NeRF神经场辐射AI模型的基础&#xff0c;与传统渲染使用三角形来显示 3D 图形不同&#xff0c;体渲染使用其他方法&#xff0c;例如体积光线投射 (Volume Ray Casting)。本文介绍体渲染的原理并提供Three.js实现代码&#xff…

中睿天下Coremail | 2023年第二季度企业邮箱安全态势观察

今日&#xff0c;中睿天下联合Coremail邮件安全发布《2023第二季度企业邮箱安全性研究报告》&#xff0c;对2023第二季度和2023上半年的企业邮箱的安全风险进行了分析。 一 垃圾邮件同比下降16.38% 根据监测&#xff0c;2023年Q2垃圾邮件数量达到6.47亿封&#xff0c;环比下降…

HTML5 游戏开发实战 | 五子棋

01、五子棋游戏设计的思路 在下棋过程中&#xff0c;为了保存下过的棋子的信息&#xff0c;使用数组 chessData。chessData&#xff3b;x&#xff3d;&#xff3b;y&#xff3d;存储棋盘(x&#xff0c;y)处棋子信息&#xff0c;1 代表黑子&#xff0c;2 代表白子&#xff0c;0…

C# PDF加盖电子章

winform界面 1.选择加签pdf按钮代码实现 private void button1_Click(object sender, EventArgs e){OpenFileDialog op new OpenFileDialog();op.Filter "PDF文件(*.pdf)|*.pdf";bool flag op.ShowDialog() DialogResult.OK;if (flag){string pdfPath Path.Get…

R语言 列表中嵌套列名一致的多个数据框如何整合为一个数据框

在批量建模后容易得到list&#xff0c;list中的每个元素都是单个的tibble 或者 dataframe&#xff0c;如何将这些数据整合为一张表呢&#xff1f; 载入R包 library(broom) library(tidyverse) 模拟数据 models <- txhousing %>% group_by(city) %>% do(modlm(lo…

将.doc文档的默认打开方式从WPS修改为word office打开方式的具体方法(以win 10 操作系统为例)

将.doc文档的默认打开方式从WPS修改为word office打开方式的具体方法&#xff08;以win 10 操作系统为例&#xff09; 随着近几年WPS软件的不断完善和丰富&#xff0c;在某些方面取得了具有特色的优势。在平时编辑.doc文档时候也常常用到wps软件&#xff0c;不过WPS文献也存在…

Android Jetpack Compose 中的分页与缓存展示

Android Jetpack Compose 中的分页与缓存展示 在几乎任何类型的移动项目中&#xff0c;移动开发人员在某个时候都会处理分页数据。如果数据列表太大&#xff0c;无法一次从服务器检索完毕&#xff0c;这就是必需的。因此&#xff0c;我们的后端同事为我们提供了一个端点&#…

动手学深度学习(三)线性神经网络—softmax回归

推荐课程&#xff1a;Softmax 回归_哔哩哔哩_bilibili 目录 一、softmax回归 1.1 网络架构 1.2 softmax运算 1.3 交叉熵损失函数 二、图像分类数据集 2.1 导包 2.2 创建数据集 2.3 可视化数据集函数 2.4 读取小批量 2.5 整合所有组件 三、softmax回归的从零开始实现…

【C/C++】用return返回一个函数

2023年8月13日&#xff0c;周日早上 我的第一篇使用了动态图的博客 #include<iostream> #include<windows.h>int loop(){int i0;while(1){Sleep(1000);std::cout<<i<<std::endl;}return 1; }int main(){std::cout<<"程序开始"<<…

解密Flink的状态管理:探索流处理框架的数据保留之道,释放流处理的无限潜能!

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 文章目录 一、什么是状态二、应用场景三、Flink中状态的分类四、算子状态1. 列表状态&#xff08;List State&#xff09;2. 广播状态&#xff08;Broadcast State&#xff09; 五、键控状态1. Val…

平替 Docker - 玩转容器新利器 Podman Desktop (视频)

《OpenShift 4.x HOL教程汇总》 在 podman-desktop 1.2.1 podman 4.4 环境中验证。 文章目录 什么是 podman 和 podman-desktop安装 podman 和 podman-desktop 基本环境Image、Container 和 Pod 的基本操作拉取 Image运行 Container 将 Pod 部署到 Kubernetes安装 Kind 扩展插…

在 IntelliJ IDEA 中使用 Docker 开发指南

目录 一、IDEA安装Docker插件 二、IDEA连接Docker 1、Docker for Windows 连接 2、SSH 连接 3、Connection successful 连接成功 三、查看Docker面板 四、使用插件生成镜像 一、IDEA安装Docker插件 打开 IntelliJ IDEA&#xff0c;点击菜单栏中的 "File" -&g…

面试热题(最大子数组和)

给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#xff1a;6 解释&#xff1a;连续…