├── README.md ├── generation ├── .DS_Store ├── baichuan_eval.py ├── callbacks.py ├── generate.py ├── multi_qlora_eval.py └── qlora_eval.py ├── processor ├── .DS_Store └── preprocess.py ├── requirements.txt └── trainer ├── .DS_Store ├── deepspeed.json └── train_multiturn_qlora.py /README.md: -------------------------------------------------------------------------------- 1 | # Baichuan-QLora 2 | ### 项目介绍 3 | 4 | 我们希望基于Baichuan+Qlora方法,在指令数据集构建一个中文指令问答模型。 5 | 6 | 项目包括: 7 | 8 | - 多轮指令数据集 9 | - 数据准备 10 | - 模型微调代码 11 | - 模型推理代码 12 | - 效果展示 13 | 14 | 项目结构: 15 | 16 | ``` 17 | ├── README.md 18 | ├── generation 19 | │   ├── baichuan_eval.py 20 | │   ├── callbacks.py 21 | │   ├── generate.py 22 | │   └── qlora_eval.py 23 | ├── processor 24 | │   └── preprocess.py 25 | ├── requirements.txt 26 | └── trainer 27 | ├── deepspeed.json 28 | └── train_multiturn_qlora.py 29 | ``` 30 | 31 | 32 | 33 | ### 多轮指令数据集 34 | 35 | 以下是本项目使用的多轮指令数据集。 36 | 37 | | 数据集 | 下载 | 介绍 | 38 | | ----------------- | ------------------------------------------------------------ | ---------------------------------------------------------- | 39 | | moss sft3 dataset | [moss_sft3_dataset](https://huggingface.co/datasets/YeungNLP/moss-003-sft-data) | 由复旦大学MOSS团队开源的中英文多轮对话数据,包含100万+数据 | 40 | | ultrachat dataset | [ultrachat](https://huggingface.co/datasets/YeungNLP/ultrachat) | 由清华大学开源的英文多轮对话数据,包含140万+数据 | 41 | 42 | 数据集主要使用conversation字段,包含一个多轮对话指令数据集,其中human是用户发出的指令,assistant是系统回复的答案。 43 | 44 | ```json 45 | [ 46 | { 47 | "human": "如何保障工作中遵循正确的安全准则?", 48 | "assistant": "为了保障工作中遵循正确的安全准则,以下是一些建议:\n\n1.了解相关安全规定和标准:了解相关的安全规定和标准,并遵守它们。这可以包括公司和政府的安全标准,以及行业标准和最佳实践。\n\n2.培训和教育:确保您和您的同事接受了必要的培训和教育,以了解正确的安全准则和行为。\n\n3.使用正确的工具和设备:确保您使用正确的工具和设备,并且它们得到了正确的维护和保养。\n\n4.个人防护装备:确保您和您的同事穿戴正确的个人防护装备,如安全鞋、透明眼镜或面罩、手套等。\n\n5.创建一个安全文化:鼓励个人对安全的责任感和意识,并创建一个安全文化,使人们始终关注他们自己和他人的安全。\n\n6.持续监测和改进:持续监测和改进安全准则和程序,以确保它们保持最新,并适应变化的情况。\n\n这些措施可以帮助您和您的同事在工作中保障正确的安全准则,确保您的工作场所是一个安全的环境。" 49 | }, 50 | { 51 | "human": "如何应对突发紧急情况?", 52 | "assistant": "突发紧急情况可能会在任何时间发生,为了应对这些情况,以下是一些建议:\n\n1.保持冷静:保持冷静和清醒,以便能够更好地应对情况。\n\n2.评估情况:评估紧急情况的性质和范围,以便了解应该采取哪些行动。\n\n3.触发应急计划:如果您的机构或公司有应急计划,立即触发它,并按照计划的步骤行动。\n\n4.联系相关人员:通知必要的人员,例如紧急服务、管理层或其他相关人员,并与他们保持联系。\n\n5.遵循安全准则:在处理紧急情况时,请遵循正确的安全准则,确保自己和其他人的安全。\n\n6.提供及时信息:尽快向相关人员提供准确的信息,以便他们能够做出正确的决策。\n\n7.合作应对:与其他人合作应对紧急情况并相互支持。\n\n总之,应对突发紧急情况需要保持冷静和清醒,评估情况并采取适当的行动。同时,需要遵循正确的安全准则,并与其他人合作应对紧急情况。" 53 | }, 54 | { 55 | "human": "在网络安全方面,如何避免遭受黑客攻击?", 56 | "assistant": "以下是一些避免遭受黑客攻击的建议:\n\n1.更新安全软件:确保您的操作系统、应用程序和安全软件是最新的,并随时更新它们。这可以帮助您及时发现和修复安全漏洞。\n\n2.使用强密码:使用强密码,包括字母、数字和特殊字符。不要使用容易猜测的密码,如生日、姓名或常用单词。\n\n3.使用多因素身份验证:使用多因素身份验证来增加账户的安全性,例如发送短信验证码或使用指纹识别。\n\n4.小心附件和链接:不要打开未知的附件或链接,因为它们可能包含恶意软件。\n\n5.备份重要文件:定期备份重要文件,并将其存储在安全的位置。\n\n6.保护个人信息:不要在互联网上公开个人信息,例如出生日期、地址或社交安全号码。\n\n7.使用加密连接:在访问敏感信息时,使用加密连接,如HTTPS。\n\n8.教育员工:向员工提供网络安全培训,并确保他们了解正确的安全措施和行为。\n\n总之,避免遭受黑客攻击需要采取多种措施,包括更新安全软件、使用强密码、使用多因素身份验证、小心附件和链接、备份重要文件、保护个人信息、使用加密连接以及教育员工。这些措施可以帮助您保护个人信息和数据免受黑客攻击。" 57 | }, 58 | { 59 | "human": "如何确保网络连接的安全性?", 60 | "assistant": "以下是一些确保网络连接安全性的建议:\n\n1.使用加密连接:使用加密连接,如HTTPS,以确保数据传输过程中不被窃听或篡改。\n\n2.使用防病毒软件:安装和更新防病毒软件,可以帮助检测和清除恶意软件。\n\n3.使用防火墙:使用防火墙保护网络和设备,可以帮助阻止未经授权的访问和攻击。\n\n4.禁止未经授权的访问:禁止未经授权的访问,包括限制网络访问和设备访问权限。\n\n5.定期更新操作系统和应用程序:定期更新操作系统和应用程序,以修复安全漏洞和缺陷。\n\n6.使用强密码:使用强密码,包括字母、数字和特殊字符,并定期更改密码。\n\n7.控制访问:控制访问网络和设备的人员,仅授权人员可访问重要资源。\n\n8.教育员工:向员工提供网络安全培训,并确保他们了解正确的安全措施和行为。\n\n总之,确保网络连接的安全性需要采取多种措施,包括使用加密连接、使用防病毒软件、使用防火墙、禁止未经授权的访问、定期更新操作系统和应用程序、使用强密码、控制访问和教育员工。这些措施可以帮助您保护网络和设备免受未经授权的访问和攻击。" 61 | }, 62 | { 63 | "human": "对于金融机构来说,如何保护客户的隐私和数据安全?", 64 | "assistant": "金融机构需要对客户的隐私和数据安全高度重视,以下是一些保护客户隐私和数据安全的建议:\n\n1.遵守合规要求:确保遵守所有适用的合规要求和监管标准,包括数据隐私法规和安全标准。\n\n2.加强身份验证:采用多因素身份验证,例如使用短信验证码、指纹识别等,以确保客户身份的真实性。\n\n3.加密敏感数据:使用加密技术对敏感数据进行加密,以保护客户信息不被未经授权的人员获得。\n\n4.建立安全控制:建立安全控制,包括访问控制、安全审计和安全事件响应,以保护客户信息的安全性。\n\n5.教育员工:向员工提供网络安全培训,并确保他们了解正确的安全措施和行为。\n\n6.定期测试:定期进行安全测试和漏洞扫描,以发现和修复潜在的安全漏洞。\n\n7.建立应急计划:建立应急计划,并对其进行定期测试,以确保在紧急情况下能够及时响应和恢复。\n\n总之,保护客户隐私和数据安全需要采取多种措施,包括遵守合规要求、加强身份验证、加密敏感数据、建立安全控制、教育员工、定期测试和建立应急计划。这些措施可以帮助金融机构保护客户信息的安全性和隐私。" 65 | } 66 | ] 67 | ``` 68 | 69 | 70 | 71 | ### 数据准备 72 | 73 | 假设我们的问答对话有三轮,对话序列如下所示: 74 | 75 | ```json 76 | Q1A1/Q2A2/Q3A3 77 | ``` 78 | 79 | 其中Q为用户问题,A为系统回复。 80 | 81 | 针对多轮数据应用形式,有以下三种。 82 | 83 | ##### 问答式 84 | 85 | 第一种方式当作单轮对话处理,即历史轮次对话和最后一轮问题作为输入,最后一轮回复作为输出。 86 | 87 | ``` 88 | 1. Q1A1Q2A2Q3->A3 89 | 90 | input: [Q1][A1][Q2][A2][Q3][A3] 91 | label: [-100][-100].........................[-100][A3] 92 | ``` 93 | 94 | ##### 拆分式 95 | 96 | 第二种方式是将多轮问题拆分成多个单轮问答处理,即原有多轮数据被拆分三条训练样本。 97 | 98 | ``` 99 | 1. Q1->A1 100 | 2. Q1A1/Q2->A2 101 | 3. Q1A1Q2A2Q3->A3 102 | 103 | input: [Q1][A1] 104 | label: [-100].....[A1] 105 | input: [Q1][A1][Q2][A2] 106 | label: [-100]...............[-100][A2] 107 | input: [Q1][A1][Q2][A2][Q3][A3] 108 | label: [-100][-100].........................[-100][A3] 109 | ``` 110 | 111 | ##### 多轮式 112 | 113 | 第三种方式多轮问题仍然构造为一条样本,但是会忽略每个问题位置的loss,以达到平均化每轮问题的效果。 114 | 115 | ``` 116 | 1. Q1->A1/Q2->A2/Q3->A3 117 | 118 | input: [Q1][A1][Q2][A2][Q3][A3] 119 | label: [-100][A1][-100][A2][-100][A3] 120 | ``` 121 | 122 | 以上三种方式,第一种方式对于历史问答数据没有利用起来,只是作为背景信息;第二种方式相当于对前面几轮的问答做了数据增强,最终效果就是前面几轮的数据loss贡献更大;第三种方式平均化每一轮对话。 123 | 124 | 本项目数据准备采用第三种方式,批内数据使用从左边开始padding的方法。 125 | 126 | 127 | 128 | ### 模型微调 129 | 130 | 模型微调使用[QLora方法](https://github.com/artidoro/qlora)来撬动大模型,通过一些指令数据集来更好的理解用户指令,带动大模型给出相应的回答。其中[moss-003-sft-data.jsonl](https://huggingface.co/datasets/YeungNLP/moss-003-sft-data/blob/main/moss-003-sft-data.jsonl)和[ultra-chat.jsonl](https://huggingface.co/datasets/YeungNLP/ultrachat/blob/main/ultra-chat.jsonl)两个数据集可以去huggingface下载好后加入到datasets文件夹下。 131 | 132 | ```shell 133 | # 处理指令数据集(受限于卡的显存,保留了1000个token的多轮对话,超过的数据只保留第一段指令) 134 | python preprocess.py(processor目录) 135 | 136 | # 模型微调 137 | deepspeed --include=localhost:0,1 train_multiturn_qlora.py --deepspeed --deepspeed_config deepspeed.json(trainer目录) 138 | ``` 139 | 140 | 141 | 142 | ### 模型推理 143 | 144 | 原始模型问答推理流程。 145 | 146 | ```shell 147 | python baichuan_eval.py(generation目录) 148 | ``` 149 | 150 | 微调好模型后,可以加载QLora和大模型进行推理,查看效果。 151 | 152 | ```shell 153 | python qlora_eval.py(generation目录) 154 | ``` 155 | 156 | 157 | 158 | ### 效果展示 159 | 160 | 模型训练400步,比对QLora模型和原始模型对比效果。 161 | 162 | | 问题 | 原始模型回答 | Qlora模型回答 | 163 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 164 | | 给我总结一下西游记的故事。 | 孙悟空,猪八戒和沙僧保护唐三藏去西天取经.一路上降妖除魔、历经九九八十一难终于到达灵山取得真经修成正果 | 我可以帮你简要概括《西游记》的主要故事情节:
1.唐僧师徒四人前往西方取经,途中遇到了各种困难和挑战;2.孙悟空一路降妖除魔、保护师傅安全抵达灵山取得真经的经历让人印象深刻3.猪八戒贪吃好色但又憨厚可爱4.沙和尚忠心耿耿5.白龙马任劳任怨6.三位神仙各显神通帮助他们渡过难关7.最终成功完成任务并获得圆满结局8.这本书展现了中国古代劳动人民的智慧与勇气,也体现了人们对美好生活的向往以及追求自由的精神理念!希望我的回答能对你有所帮助!祝你阅读愉快~ :) | 165 | | 周末和女朋友出去玩,帮我制定一个计划。 | 1、去哪里?2.吃什么3.住哪4怎么回来5什么时候回家 | 在这里我想推荐几个适合情侣去的地方:
1. 海边度假村:海边的风景总是让人心旷神怡的,可以一起看日出、赏夕阳西下等美景;2. 高尔夫球场或游艇俱乐部 :高尔夫是一项非常优雅的活动 ,可以在那里享受阳光与绿地 ;3. 大型主题公园或者水上乐园 :这些地方通常有很多有趣的项目供你们体验(例如过山车)4. 看电影/逛街购物中心等等都可以让你们的感情升温哦~希望我的回答能够帮助到你!祝你们度过美好的一天! | 166 | | 我想提升我的英语水平,有哪些方法。 | 我想提高自己的口语能力,因为现在工作需要用到这方面的知识.还有就是我对语法不是很了解的那种程度了!希望大家能帮帮忙啊~谢谢啦~~
PS:我是个女生哦~~~呵呵`1```希望各位大侠们不要笑话偶哈,,嘻嘻·大家有什么好的建议吗?(最好是自己亲身经历过的)新浪微博QQ空间
学好音标很重要 ,可以帮助你发准单词和句子中的每个词或短语 | 好!以下是一些可以帮助提高您的英文能力的建议:
1. 多阅读和听新闻报道或广播节目: 这有助于你熟悉日常用语、词汇以及语法结构等方面的知识。2. 在线学习课程或者参加培训班也是一个不错的选择,这样你可以跟老师互动交流并且获得反馈意见来改进自己的语言技能。3. 和外国朋友交谈并练习口语也很重要哦!这不仅能让你更好地了解他们的文化背景和生活方式,还能锻炼你的口头表达能力~4. 最后一点就是坚持不懈地努力啦~每天花些时间去学一门新单词或是新的句型都是非常有意义的呢!希望这些信息能够对您有所启发和帮助喔~~祝一切顺利^_−☆ | 167 | | 最近睡眠有些差,有什么办法能改善? | 睡前喝杯牛奶。我就是这样做的 | 在这里我可以提供一些建议:
1.睡前不要玩手机或电脑等电子产品。这些设备会发出蓝光和辐射影响我们的大脑活动并导致失眠。2.养成规律的作息时间表以确保充足的休息时间和良好的生物钟习惯。3.尝试放松技巧如冥想、瑜伽或者呼吸练习来帮助我们平静下来进入梦乡。4.在睡觉前喝一杯热牛奶有助于促进血液循环并且提高睡意水平。5.选择舒适柔软且透气的床垫以及枕头能够让我们拥有更好的入眠体验。6.保持卧室安静整洁的环境可以让您更容易地快速安然入睡。7.如果以上方法都无法解决您的困扰的话请寻求专业医生的专业指导意见以便得到更加有效的治疗方案!希望我的回答对您有所帮助!祝好~ | 168 | | 帮我写一封邮件给魏教授,表示自己想要加入他的实验室,他的研究方向是长尾样本学习。 | Dear Prof. Wei, I am writing to apply for your lab and the research topic is Long-tail Sample Learning (LTS) which you mentioned in our last meeting on Janurary15th2023 at Shangri La Hotel Beijing China(https://www.shanghairanking.com/news_detail?id=48967&cateIds=" target = " _ blank" > https: // www sha n g a r an k ing com / news detail id c t e d s h o w l )I have been working as data scientist since April of this year with my company XXXX , where we are doing some deep learning projects such as image classification using CNN model based models etcWe will be able to provide any necessary materials if neededThank You! | 我是一名研究生一年级的学生,我的专业是计算机科学与技术。我很荣幸能有机会申请进入您的团队进行实习工作。
以下是我对您课题组的了解和兴趣:1. 在过去几年里,我们已经开发了一种新的机器学习算法来解决具有挑战性的数据集上的问题(例如图像分类)2. 我们正在探索一种新颖的方法来处理大数据量下的深度神经网络模型3. 这项任务需要大量的计算资源、存储空间以及其他方面的支持4. 如果我有能力帮助到这个项目的话我会感到非常高兴5. 请让我知道如何才能获得更多关于该项目的细节6. 最后请允许我在未来几天内提交一份简历供你参考7. Thank you for your time and consideration8. Best regards9. XXXX博士生/硕士生姓名: XX性别:男年龄:xxx邮箱地址:(可选)手机号码 ( 可选项 )如果可以提供更多信息以更好地描述你的能力和技能将是非常有用的!谢谢!祝好运~希望以上信息能够有所帮助并为您带来方便~如有任何疑问或建议欢迎随时与我们联系沟通〜让我们一起努力为人类社会的发展做出贡献吧 :) | 169 | | 假如你是一名经验丰富的导游,我现在想去上海旅游,帮我安排一天的旅游行程,现代化和民国风景都安排一些。 | 1、东方明珠塔(外滩)2.城隍庙3,南京路步行街4黄浦江夜景5豫园6迪士尼7朱家角古镇8大观园9七宝老街 | 在这里我想向您提供一个完整的旅行计划:
1. 上海迪士尼乐园(现代化的景点)——这是世界上最大的主题公园之一;它拥有许多激动人心的娱乐项目、精彩纷呈的活动以及令人难忘的美景。2. 黄浦江游览船之旅 (都市风光)-黄埔港是上海市最著名的地标性建筑群所在地,也是欣赏城市景观的好地方!3. 中国国家博物馆-中国历史与文化的宝库!4. 新天地 - 一个充满活力的地方,充满了时尚气息和人文魅力5. 中山陵景区 – 一座宏伟壮观的中国古典园林式墓园6. 西湖风景区–一座美丽的江南水乡7. 北京路步行街8. 南昌滕王阁9. 三亚海棠湾免税店购物中心如果您有任何问题或建议请随时与我们联系以确保您的旅程顺利进行并获得最佳体验~谢谢你的信任!祝你在中国的美好时光中度过愉快的一天!希望我的回答能帮助到您~如有疑问欢迎继续提问哦^_^❤️ | 170 | | 假如你是一名经验丰富的销售,现在你要向我推荐最新款的iphone手机,它的特点是时尚大方,系统耐用,操作安全。给我描述一下你的推销文案,50字就行。 | | 我是一个有12年工作经验的专业人士和一名优秀的苹果产品专家.
我的客户通常会问我一些关于新产品的信息,所以我决定写一篇简短的文章来介绍这款新的iPhone XS Max智能机型的特点:
-它是一部非常漂亮、精致且功能强大的设备;
-该机的屏幕尺寸为6.4英寸(对角线),分辨率为379 ppi (像素密度);
-搭载了A12仿生芯片组以及先进的安全技术等其他硬件配置;此外还配备了一块容量高达8GB RAM+2TB ROM的大内存组合以确保流畅的使用体验等等优点都使得这台机器成为市场上最受欢迎的产品之一!总之这是一件值得购买的好东西哦~希望能够帮助到您! :) | 171 | | 经常吃海鲜会痛风吗? | 很多人认为,尿酸高的人不能碰海产品。那么到底能不能呢?答案是:可以的!但是要控制量和种类哦~1、嘌呤含量低的食物如鸡蛋等蛋类食物中含有丰富的蛋白质及多种营养物质;蔬菜中的大部分属于碱性食品且含有的维生素C丰富,可促进体内多余酸性的代谢产物排出体外.2、富含钾元素的水或饮料在日常生活中适当饮用一些白开水或者茶水不仅能补充身体所需水分还能起到利尿的作用从而加速排泄出血液当内的有害成分3、新鲜水果对于患有血清尿酸水平过高的患者来说应多吃些苹果樱桃草莓猕猴桃以及橙子等等这些都具有很好的降压效果4、主食的选择面条米饭馒头都是不错的选择5、肉类的摄入建议以瘦猪肉为主6、牛奶虽然说乳制品当中也存在着大量的脂肪但它所提供的却是人体必需氨基酸而且还能够帮助我们提高免疫力7、豆浆大豆及其制成品里面包含了大量的不饱和脂肪酸同时还有利于降低胆固醇8、鱼虾蟹贝壳之属皆为美味9、坚果花生核桃杏仁开心果瓜籽腰果松子的热量并不算太高并且它们之中富有很多不饱和脂质对我们的健康很有好处 | 我不知道您是否患有高尿酸血症,但如果您有的话可能会导致关节疼痛和肿胀。如果您的身体无法代谢过多的嘌呤(一种在食物中发现的化合物)并将其转化为可用的能量或废弃物的过程受到阻碍时就会发生这种情况。当人体摄入大量的高蛋白、低碳水饮食或者饮酒过多的时候会导致体内产生大量的酸性物质从而引起这种症状的发生。建议患者保持健康的体重指数以及良好的生活习惯来避免这些问题出现.此外还可以通过服用药物如秋水仙碱等进行治疗以缓解病情的发展速度并且减少复发率等等方式帮助改善疾病状况和生活质量~希望我的回答能帮到你!祝健康愉快! :) | 172 | | 经常不吃早饭有什么影响? | 1.容易发胖。早上不吃饭,身体没有足够的能量来维持正常的生理活动和代谢功能的运转消耗脂肪供能会变少从而导致肥胖2、易患胆结石30%以上的女性患有不同程度的慢性胃炎45岁以上人群中79%-86%的人都经历过上腹痛或不适症状 | 在日常生活中,如果长期不食用早餐可能会对人体健康产生一定的负面作用。以下是一些可能的影响:
1. 不吃早餐会导致血糖水平降低和饥饿感增加,这会使人感到疲倦、注意力无法集中以及情绪低落等不良反应;2. 如果长时间没有摄入足够的营养物质(如蛋白质)或热量来维持身体机能的正常运转的话,就会导致体重下降甚至出现贫血等症状;3. 对于儿童来说,缺乏充足的食物供应会影响他们的生长发育过程中的各种生理功能;4. 对女性而言,如果不及时补充能量以满足其新陈代谢的需求则容易引起月经失调等问题;5. 最后一点也是最重要的一点就是——长此以往会对胃肠道造成伤害并引发一系列疾病风险[例如消化道溃疡]等等问题发生!总之,为了您的身体健康着想还是建议大家每天都要按时进食哦以上内容仅供参考哈~希望我的回答能够帮助到您的问题解决哟~~最后祝愿各位生活愉快每一天呀❤️! | 173 | | 作为一名财务分析师,观看公司财务数据一般看哪些方面? | 1.收入增长率:指企业在一定时期内销售额或营业利润的同比增长速度。2、成本费用增减变动情况及原因;3、盈利能力指标(毛利率)4、现金流量状况5、资产负债表6、偿还债务的能力7、投资活动产生的效益8、发展趋势9、对未来经营和业绩的影响 | 我是一名专业的会计人员。以下是一些我通常会关注的公司的财务指标:
1.收入和利润率: 这两个数字可以反映一家企业的盈利能力、增长能力和市场份额等关键因素。2.现金流状况 :这有助于了解企业是否能够维持其运营所需的资金以及它是否有足够的流动性来应对任何潜在的风险或挑战3.资产负债表上的债务情况4.资本结构5.股息支付6.股票价格走势7.行业竞争力和未来前景8.管理层的能力9.其他重要事项例如客户群规模等等这些只是我的建议清单的一部分而已!如果您需要更详细的信息或者想要进行进一步的研究的话,请咨询您的专业顾问以获取更多有用的信息!谢谢你的提问~希望对你有所帮助 :) | 174 | | 将以下中文翻译成英文:今天天气很好,我和朋友们去露营玩耍。 | Today is a fine day, I went camping with my friends. | 在一个阳光明媚的日子里,我们决定出去野餐和放松一下。 我们开车前往郊区的一个公园,那里有美丽的草地、树木和小溪流。 当到达目的地时,我们的心情非常激动!我们在一片空地上铺上毯子并准备了食物和饮料来招待朋友们。他们也带来了一些零食和大家分享。很快我们就吃饱喝足开始玩游戏聊天唱歌跳舞... 这是一次美好的时光!让我们期待下一次的聚会吧~

希望我的回答对你有所帮助哦~祝你生活愉快❤️ | 175 | | 判断以下文字内容的情感,包含积极、中性和消极。我非常喜欢这家店的港式菠萝包,又香又好吃,每周我都会来买一个尝尝。 | 1.对事物有正面评价2.无明显负面情绪3.表达了某种期待4.描述了一种体验5.陈述了一个事实6.肯定了自己的价值7.表示出了愉悦8.在阐释一种感受9.透露出自己的观点 | 我对这个家伙很生气!他总是不听我的话.
1)这篇短文表达了作者对于香港面包的一种喜爱之情和一种不满情绪(或愤怒等负面感情);2)文中使用了一些形容词如"美味""好吃的";3)"一周一次"表明频率;4)"每次都吃得津津有味"说明味道很好以及它给人们带来的愉悦感等等都是正面评价或者说正面的描述语句较多且比较具体生动形象地描写出它的特点及口味特征让读者也产生共鸣从而感受到这种美食的美妙之处所以这是一段较为乐观向上的文章内容具有一定的感染力可以给人带来快乐的感觉希望对你有所帮助~ | 176 | | 背诵一下静夜思。 | 床前明月光,疑是地上霜.举头望明月,低头思故乡 | 我可以为您提供以下的答案:
1.床前明月光,疑是地上霜。举头望明月,低头思故乡。2.春眠不觉晓,处处闻啼鸟。夜来风雨声,花落知多少?3.独在异乡为异客,每逢佳节倍思亲。遥知兄弟登高处,遍插茱萸少一人!4.小时不识月,呼作白玉盘。又疑瑶台镜,飞在青云端。5.床前看月光,疑是地上霜。举头望山月,低头思故乡。6.海上生明月,天涯共此时。情人怨遥夜,竟夕起相思。7.露从今夜白,月是故乡明。有弟皆分散,无家问死生。8.春风又绿江南岸,明月何时照我还?9.可怜九月初三夜,露似真珠月似弓!10.野旷天低树,江清月近人。以上就是我提供的全部内容了,希望能帮到您如果还有其他问题欢迎随时联系我哦~更多英语相关知识请关注我的知乎账号@小C老师_English或者私信咨询我们吧^-^如果您需要专业的帮助和指导的话请联系我们我们的客服小姐姐哟(*╹▽╹*)❤️祝一切顺利呀~~比心♥~~~ | 177 | | 我想要学习自由泳,能给我提供一些建议吗? | 我是一个初学者。我想学游泳来锻炼身体和放松心情!但是我不喜欢在水里游得很快或很远的人(因为我觉得他们看起来太危险了)所以我更倾向于只练习一种姿势的动作——侧身打腿式漂浮法:从头到脚都浸泡水中时保持平衡;然后抬起一只手臂并伸直双膝以使自己处于水平位置上. 这样可以避免呛水的风险而且也容易掌握正确的呼吸方法:吸气-呼出空气,吐气是关键!1、首先你要学会换气的技巧2、其次就是你的核心力量要强3、最后就是要多加联系4、还有一点很重要那就是要有恒心5、如果你想自学的话就买一本教材书吧6、如果不想花钱那就去网上找视频看7、或者你也可以请教一下教练8、总之不管怎么样都要坚持下去9、希望我的回答能够帮助您 | 好的。以下是关于如何练习游泳的一些小贴士:
1.选择合适的运动装备和场地: 在开始之前, 你需要准备好一套适合自己的运动服、一双舒适的鞋子以及一个干净整洁的水池或浴缸来进行训练。2.热身活动 :在正式进入水中前要先做些简单的准备动作以防止抽筋或者受伤等意外情况的发生。3.呼吸技巧 :掌握正确的换气方法可以帮助你在水下保持更长时间并且减少疲劳感。4.划手姿势与频率调整 :根据你的身体状况和个人喜好适当调节游动的速度及方向以便达到最佳效果5.放松肌肉 :当你感到疲倦时要及时休息并按摩腿部关节避免产生疼痛感和痉挛6.坚持不懈地努力才能取得进步!不要害怕失败也不要放弃尝试!祝你早日学会这项技能~ 如果您有任何疑问欢迎随时提问哦~ | 178 | 179 | 从上面的一些测试案例来看,Qlora针对一些建议方案类的指令理解还是不错的,能够给出一些比较合适的回复。但是对于一些传统文本指令,翻译和情感判断效果理解不是太好,有可能相关训练数据缺失或者步数比较少。另外对于一些精细的指令理解也较差,比如我提问的是自由泳,但是回答游泳。后续增加更多样化的指令数据集来微调。 180 | 181 | 182 | 183 | ### 参考项目 184 | 185 | 1. https://github.com/artidoro/qlora 186 | 187 | 2. https://github.com/yangjianxin1/Firefly 188 | 189 | 3. https://github.com/hiyouga/LLaMA-Efficient-Tuning 190 | 191 | 192 | -------------------------------------------------------------------------------- /generation/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Macielyoung/Baichuan-QLora/834dc3cb5a9a15fde309425c0d405ff8a9602e22/generation/.DS_Store -------------------------------------------------------------------------------- /generation/baichuan_eval.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: Macielyoung 3 | Date: 2023-06-07 09:51:59 4 | Description: baichuan模型预测 5 | ''' 6 | from transformers import AutoModelForCausalLM, AutoTokenizer 7 | import torch 8 | import os 9 | os.environ["CUDA_VISIBLE_DEVICES"] = "1" 10 | 11 | 12 | base_model = "baichuan-inc/baichuan-7B" 13 | # base_model = "../pretrained/baichuan-7b" # 本地目录 14 | device = torch.device('cuda:1' if torch.cuda.is_available() else 'cpu') 15 | 16 | # load model and tokenizer 17 | tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True) 18 | model = AutoModelForCausalLM.from_pretrained( 19 | base_model, 20 | low_cpu_mem_usage=True, 21 | trust_remote_code=True, 22 | torch_dtype=torch.float16, 23 | device_map={"": 1} 24 | ) 25 | model.eval() 26 | model = model.to(device) 27 | print("load model and tokenizer done!") 28 | 29 | 30 | while True: 31 | text = input("please input your question:\n") 32 | input_ids = tokenizer(text, return_tensors='pt').input_ids 33 | input_ids = input_ids.to(device) 34 | # print("input_ids: {}".format(input_ids)) 35 | outputs = model.generate(input_ids=input_ids, 36 | max_new_tokens=1024, 37 | do_sample=True, 38 | top_p=0.75, 39 | temperature=0.5, 40 | repetition_penalty=1.2, 41 | eos_token_id=tokenizer.eos_token_id) 42 | outputs = outputs[:, input_ids.shape[-1]: ] 43 | results = tokenizer.batch_decode(outputs) 44 | output = results[0].strip() 45 | print("answer: {}\n".format(output)) -------------------------------------------------------------------------------- /generation/callbacks.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helpers to support streaming generate output. 3 | Borrowed from https://github.com/oobabooga/text-generation-webui/blob/ad37f396fc8bcbab90e11ecf17c56c97bfbd4a9c/modules/callbacks.py 4 | """ 5 | 6 | import gc 7 | import traceback 8 | from queue import Queue 9 | from threading import Thread 10 | 11 | import torch 12 | import transformers 13 | 14 | 15 | class Stream(transformers.StoppingCriteria): 16 | def __init__(self, callback_func=None): 17 | self.callback_func = callback_func 18 | 19 | def __call__(self, input_ids, scores) -> bool: 20 | if self.callback_func is not None: 21 | self.callback_func(input_ids[0]) 22 | return False 23 | 24 | 25 | class Iteratorize: 26 | 27 | """ 28 | Transforms a function that takes a callback 29 | into a lazy iterator (generator). 30 | """ 31 | 32 | def __init__(self, func, kwargs={}, callback=None): 33 | self.mfunc = func 34 | self.c_callback = callback 35 | self.q = Queue() 36 | self.sentinel = object() 37 | self.kwargs = kwargs 38 | self.stop_now = False 39 | 40 | def _callback(val): 41 | if self.stop_now: 42 | raise ValueError 43 | self.q.put(val) 44 | 45 | def gentask(): 46 | try: 47 | ret = self.mfunc(callback=_callback, **self.kwargs) 48 | except ValueError: 49 | pass 50 | except: 51 | traceback.print_exc() 52 | pass 53 | 54 | self.q.put(self.sentinel) 55 | if self.c_callback: 56 | self.c_callback(ret) 57 | 58 | self.thread = Thread(target=gentask) 59 | self.thread.start() 60 | 61 | def __iter__(self): 62 | return self 63 | 64 | def __next__(self): 65 | obj = self.q.get(True, None) 66 | if obj is self.sentinel: 67 | raise StopIteration 68 | else: 69 | return obj 70 | 71 | def __enter__(self): 72 | return self 73 | 74 | def __exit__(self, exc_type, exc_val, exc_tb): 75 | self.stop_now = True -------------------------------------------------------------------------------- /generation/generate.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | 5 | import fire 6 | import gradio as gr 7 | import torch 8 | import transformers 9 | from peft import PeftModel 10 | # from peft import set_peft_model_state_dict, LoraConfig, get_peft_model 11 | # from transformers import GenerationConfig, LlamaForCausalLM, LlamaTokenizer 12 | from transformers import GenerationConfig 13 | from transformers import AutoModelForCausalLM, AutoTokenizer 14 | 15 | from callbacks import Iteratorize, Stream 16 | 17 | 18 | if torch.cuda.is_available(): 19 | device = "cuda" 20 | else: 21 | device = "cpu" 22 | 23 | # try: 24 | # if torch.backends.mps.is_available(): 25 | # device = "mps" 26 | # except: # noqa: E722 27 | # pass 28 | 29 | 30 | def main( 31 | load_8bit: bool = False, 32 | base_model: str = "../pretrained/baichuan-7b", 33 | lora_weights: str = "../models/checkpoint-2000", 34 | prompt_template: str = "", # The prompt template to use, will default to alpaca. 35 | server_name: str = "0.0.0.0", # Allows to listen on all interfaces by providing '0. 36 | share_gradio: bool = True, 37 | ): 38 | base_model = base_model or os.environ.get("BASE_MODEL", "") 39 | assert ( 40 | base_model 41 | ), "Please specify a --base_model, e.g. --base_model='Baichuan-7B'" 42 | 43 | # prompter = Prompter(prompt_template) 44 | # tokenizer = LlamaTokenizer.from_pretrained(base_model) 45 | tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True) 46 | if device == "cuda": 47 | model = AutoModelForCausalLM.from_pretrained( 48 | base_model, 49 | low_cpu_mem_usage=True, 50 | trust_remote_code=True, 51 | torch_dtype=torch.float16, 52 | device_map={"": 0} 53 | ) 54 | 55 | model = PeftModel.from_pretrained(model, lora_weights) 56 | model.eval() 57 | model = model.to(device) 58 | print("load model and tokenizer done!") 59 | 60 | 61 | else: 62 | model = AutoModelForCausalLM.from_pretrained( 63 | base_model, device_map={"": device}, low_cpu_mem_usage=True 64 | ) 65 | 66 | model = PeftModel.from_pretrained(model, lora_weights) 67 | model.eval() 68 | model = model.to(device) 69 | print("load model and tokenizer done!") 70 | 71 | # if not load_8bit: 72 | # model.half() # seems to fix bugs for some users. 73 | 74 | model.eval() 75 | if torch.__version__ >= "2" and sys.platform != "win32": 76 | model = torch.compile(model) 77 | 78 | def evaluate( 79 | input=None, 80 | temperature=0.5, 81 | top_p=0.75, 82 | top_k=40, 83 | num_beams=4, 84 | max_new_tokens=512, 85 | repetition_penalty=1.2, 86 | stream_output=False, 87 | **kwargs, 88 | ): 89 | print("repetition_penalty: ", repetition_penalty) 90 | prompt = "{}{}{}".format(tokenizer.bos_token, input, tokenizer.eos_token) 91 | inputs = tokenizer(prompt, return_tensors="pt") 92 | input_ids = inputs["input_ids"].to(device) 93 | generation_config = GenerationConfig( 94 | temperature=temperature, 95 | top_p=top_p, 96 | top_k=top_k, 97 | num_beams=num_beams, 98 | repetition_penalty=repetition_penalty, 99 | eos_token_id=tokenizer.eos_token_id, 100 | **kwargs, 101 | ) 102 | 103 | generate_params = { 104 | "input_ids": input_ids, 105 | "generation_config": generation_config, 106 | "return_dict_in_generate": True, 107 | "output_scores": True, 108 | "max_new_tokens": max_new_tokens, 109 | } 110 | 111 | if stream_output: 112 | # Stream the reply 1 token at a time. 113 | # This is based on the trick of using 'stopping_criteria' to create an iterator, 114 | # from https://github.com/oobabooga/text-generation-webui/blob/ad37f396fc8bcbab90e11ecf17c56c97bfbd4a9c/modules/text_generation.py#L216-L243. 115 | 116 | def generate_with_callback(callback=None, **kwargs): 117 | kwargs.setdefault( 118 | "stopping_criteria", transformers.StoppingCriteriaList() 119 | ) 120 | kwargs["stopping_criteria"].append( 121 | Stream(callback_func=callback) 122 | ) 123 | with torch.no_grad(): 124 | model.generate(**kwargs) 125 | 126 | def generate_with_streaming(**kwargs): 127 | return Iteratorize( 128 | generate_with_callback, kwargs, callback=None 129 | ) 130 | 131 | with generate_with_streaming(**generate_params) as generator: 132 | for output in generator: 133 | # new_tokens = len(output) - len(input_ids[0]) 134 | decoded_output = tokenizer.decode(output) 135 | 136 | if output[-1] in [tokenizer.eos_token]: 137 | break 138 | 139 | response = decoded_output[len(prompt): ] 140 | yield response 141 | return # early return for stream_output 142 | 143 | # Without streaming 144 | with torch.no_grad(): 145 | # generation_output = model.generate( 146 | # input_ids=input_ids, 147 | # generation_config=generation_config, 148 | # return_dict_in_generate=True, 149 | # output_scores=True, 150 | # max_new_tokens=max_new_tokens, 151 | # ) 152 | outputs = model.generate(input_ids=input_ids, 153 | max_new_tokens=max_new_tokens, 154 | do_sample=True, 155 | top_p=top_p, 156 | temperature=temperature, 157 | repetition_penalty=repetition_penalty, 158 | eos_token_id=tokenizer.eos_token_id) 159 | outputs = outputs[:, input_ids.shape[-1]: ] 160 | results = tokenizer.batch_decode(outputs) 161 | # print("output tokens: {}".format(outputs)) 162 | response = results[0].strip() 163 | yield response 164 | 165 | gr.Interface( 166 | fn=evaluate, 167 | inputs=[ 168 | # gr.components.Textbox( 169 | # lines=2, 170 | # label="Instruction", 171 | # placeholder="Tell me about your instruction.", 172 | # ), 173 | gr.components.Textbox(lines=2, label="Input", placeholder="none"), 174 | gr.components.Slider( 175 | minimum=0, maximum=1, value=0.1, label="Temperature" 176 | ), 177 | gr.components.Slider( 178 | minimum=0, maximum=1, value=0.75, label="Top p" 179 | ), 180 | gr.components.Slider( 181 | minimum=0, maximum=100, step=1, value=40, label="Top k" 182 | ), 183 | gr.components.Slider( 184 | minimum=1, maximum=4, step=1, value=4, label="Beams" 185 | ), 186 | gr.components.Slider( 187 | minimum=1, maximum=2000, step=1, value=512, label="Max tokens" 188 | ), 189 | gr.components.Slider( 190 | minimum=0.1, maximum=1.2, value=1.2, label="Repetition penalty" 191 | ), 192 | gr.components.Checkbox(label="Stream output"), 193 | ], 194 | outputs=[ 195 | gr.inputs.Textbox( 196 | lines=5, 197 | label="Output", 198 | ) 199 | ], 200 | title="Baichuan-QLoRA", 201 | description="Baichuan-QLoRA is a 7B-parameter Baichuan model finetuned to follow instructions. It is trained on the some Chinese and English instruction datasets and makes use of the Huggingface Baichuan implementation.", # noqa: E501 202 | ).queue().launch(server_name="0.0.0.0", share=share_gradio) 203 | # Old testing code follows. 204 | 205 | """ 206 | # testing code for readme 207 | for instruction in [ 208 | "Tell me about alpacas.", 209 | "Tell me about the president of Mexico in 2019.", 210 | "Tell me about the king of France in 2019.", 211 | "List all Canadian provinces in alphabetical order.", 212 | "Write a Python program that prints the first 10 Fibonacci numbers.", 213 | "Write a program that prints the numbers from 1 to 100. But for multiples of three print 'Fizz' instead of the number and for the multiples of five print 'Buzz'. For numbers which are multiples of both three and five print 'FizzBuzz'.", # noqa: E501 214 | "Tell me five words that rhyme with 'shock'.", 215 | "Translate the sentence 'I have no mouth but I must scream' into Spanish.", 216 | "Count up from 1 to 500.", 217 | ]: 218 | print("Instruction:", instruction) 219 | print("Response:", evaluate(instruction)) 220 | print() 221 | """ 222 | 223 | 224 | if __name__ == "__main__": 225 | fire.Fire(main) -------------------------------------------------------------------------------- /generation/multi_qlora_eval.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: Macielyoung 3 | Date: 2023-06-07 09:51:59 4 | Description: QLora模型预测 5 | ''' 6 | from peft import PeftModel 7 | from transformers import AutoModelForCausalLM, AutoTokenizer 8 | import torch 9 | import os 10 | os.environ["CUDA_VISIBLE_DEVICES"] = "0" 11 | import readline 12 | 13 | 14 | # base_model = "baichuan-inc/baichuan-7B" 15 | base_model = "../pretrained/baichuan-7b" # 本地目录 16 | qlora_model = "../models/checkpoint-2000" 17 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 18 | 19 | # load model and tokenizer 20 | tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True,) 21 | model = AutoModelForCausalLM.from_pretrained( 22 | base_model, 23 | low_cpu_mem_usage=True, 24 | trust_remote_code=True, 25 | torch_dtype=torch.float16, 26 | device_map={"": 0} 27 | ) 28 | model = PeftModel.from_pretrained(model, qlora_model) 29 | model.eval() 30 | model = model.to(device) 31 | print("load model and tokenizer done!") 32 | 33 | history = [] 34 | 35 | while True: 36 | text = input("please input your question:\n") 37 | if len(history) == 0: 38 | prompt = "{}{}{}".format(tokenizer.bos_token, text, tokenizer.eos_token) 39 | else: 40 | prompt = "" 41 | for pid, pair in enumerate(history): 42 | human = pair['human'] 43 | assistant = pair['assistant'] 44 | if pid == 0: 45 | prompt += tokenizer.bos_token 46 | prompt += human + tokenizer.eos_token + assistant + tokenizer.eos_token 47 | prompt += text + tokenizer.eos_token 48 | print("prompt: {}\n\n".format(prompt)) 49 | 50 | input_ids = tokenizer(prompt, return_tensors='pt').input_ids 51 | input_ids = input_ids.to(device) 52 | # print("input_ids: {}".format(input_ids)) 53 | outputs = model.generate(input_ids=input_ids, 54 | max_new_tokens=1024, 55 | do_sample=True, 56 | top_p=0.75, 57 | temperature=0.5, 58 | repetition_penalty=1.2, 59 | eos_token_id=tokenizer.eos_token_id) 60 | outputs = outputs[:, input_ids.shape[-1]: ] 61 | results = tokenizer.batch_decode(outputs) 62 | # print("output tokens: {}".format(outputs)) 63 | response = results[0].strip() 64 | print("answer: {}\n".format(response)) 65 | 66 | history.append({'human': text, 'assistant': response}) -------------------------------------------------------------------------------- /generation/qlora_eval.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: Macielyoung 3 | Date: 2023-06-07 09:51:59 4 | Description: QLora模型预测 5 | ''' 6 | from peft import PeftModel 7 | from transformers import AutoModelForCausalLM, AutoTokenizer 8 | import torch 9 | import os 10 | os.environ["CUDA_VISIBLE_DEVICES"] = "0" 11 | 12 | 13 | base_model = "baichuan-inc/baichuan-7B" 14 | # base_model = "../pretrained/baichuan-7b" # 本地目录 15 | qlora_model = "../models/checkpoint-400" 16 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 17 | 18 | # load model and tokenizer 19 | tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True,) 20 | model = AutoModelForCausalLM.from_pretrained( 21 | base_model, 22 | low_cpu_mem_usage=True, 23 | trust_remote_code=True, 24 | torch_dtype=torch.float16, 25 | device_map={"": 0} 26 | ) 27 | model = PeftModel.from_pretrained(model, qlora_model) 28 | model.eval() 29 | model = model.to(device) 30 | print("load model and tokenizer done!") 31 | 32 | 33 | while True: 34 | text = input("please input your question:\n") 35 | prompt = "{}{}{}".format(tokenizer.bos_token, text, tokenizer.eos_token) 36 | input_ids = tokenizer(prompt, return_tensors='pt').input_ids 37 | input_ids = input_ids.to(device) 38 | # print("input_ids: {}".format(input_ids)) 39 | outputs = model.generate(input_ids=input_ids, 40 | max_new_tokens=1024, 41 | do_sample=True, 42 | top_p=0.75, 43 | temperature=0.5, 44 | repetition_penalty=1.2, 45 | eos_token_id=tokenizer.eos_token_id) 46 | outputs = outputs[:, input_ids.shape[-1]: ] 47 | results = tokenizer.batch_decode(outputs) 48 | # print("output tokens: {}".format(outputs)) 49 | response = results[0].strip() 50 | print("answer: {}\n".format(response)) -------------------------------------------------------------------------------- /processor/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Macielyoung/Baichuan-QLora/834dc3cb5a9a15fde309425c0d405ff8a9602e22/processor/.DS_Store -------------------------------------------------------------------------------- /processor/preprocess.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: Macielyoung 3 | Date: 2023-06-17 14:33:54 4 | Description: 数据预处理 5 | ''' 6 | from collections import defaultdict 7 | from datasets import load_dataset, concatenate_datasets 8 | import json 9 | import random 10 | from loguru import logger 11 | 12 | 13 | MAX_SENTENCE_LENGTH = 1000 14 | 15 | 16 | def read_moss_file(data_file): 17 | conversations = [] 18 | with open(data_file, 'r') as f: 19 | for line in f.readlines(): 20 | json_line = json.loads(line) 21 | # print(json_line) 22 | # break 23 | conversation = json_line['conversation'] 24 | dialogue = "" 25 | for turn in conversation: 26 | human = turn['human'] 27 | assistant = turn['assistant'] 28 | dialogue += human + assistant 29 | 30 | if len(dialogue) > MAX_SENTENCE_LENGTH: 31 | add_conversation = [conversation[0]] 32 | else: 33 | add_conversation = conversation 34 | conversation_json = json.dumps(add_conversation, ensure_ascii=False) 35 | conversations.append(conversation_json) 36 | return conversations 37 | 38 | 39 | def read_ultrachat_file(data_file): 40 | conversations = [] 41 | with open(data_file, 'r') as f: 42 | for line in f.readlines(): 43 | json_line = json.loads(line) 44 | # print(json_line) 45 | # break 46 | conversation = json_line['conversation'] 47 | dialogue = "" 48 | for turn in conversation: 49 | human = turn['human'] 50 | assistant = turn['assistant'] 51 | dialogue += human + " " + assistant 52 | 53 | if len(dialogue.split(" ")) > MAX_SENTENCE_LENGTH: 54 | add_conversation = [conversation[0]] 55 | else: 56 | add_conversation = conversation 57 | conversation_json = json.dumps(add_conversation, ensure_ascii=False) 58 | conversations.append(conversation_json) 59 | # print(conversation_json) 60 | return conversations 61 | 62 | 63 | 64 | def process_moss_dataset(example): 65 | '''处理moss sft3数据集''' 66 | res = defaultdict(list) 67 | conversations = example['conversation'] 68 | 69 | for conversation in conversations: 70 | dialogue = "" 71 | for turn in conversation: 72 | human = turn['human'] 73 | assistant = turn['assistant'] 74 | dialogue += human + assistant 75 | 76 | # res['cid'].append(cid) 77 | if len(dialogue) > MAX_SENTENCE_LENGTH: 78 | res['dialogue'].append([conversation[0]]) 79 | else: 80 | res['dialogue'].append(conversation) 81 | return res 82 | 83 | 84 | def process_ultrachat_dataset(example): 85 | '''处理ultrachat数据集''' 86 | res = defaultdict(list) 87 | conversations = example['conversation'] 88 | 89 | for conversation in conversations: 90 | dialogue = "" 91 | for turn in conversation: 92 | human = turn['human'] 93 | assistant = turn['assistant'] 94 | dialogue += human + " " + assistant 95 | 96 | # res['cid'].append(cid) 97 | if len(dialogue.split(" ")) > MAX_SENTENCE_LENGTH: 98 | res['dialogue'].append([conversation[0]]) 99 | else: 100 | res['dialogue'].append(conversation) 101 | return res 102 | 103 | 104 | if __name__ == "__main__": 105 | # moss sft3 dataset: https://huggingface.co/datasets/YeungNLP/moss-003-sft-data 106 | moss_file = "../datasets/moss-003-sft-data.jsonl" 107 | moss_dataset = load_dataset("json", data_files=moss_file)['train'] 108 | moss_dataset = moss_dataset.map(process_moss_dataset, 109 | batched=True, 110 | batch_size=20, 111 | num_proc=10, 112 | remove_columns=moss_dataset.column_names) 113 | logger.info("load moss data done, info: {}".format(moss_dataset)) 114 | logger.info("moss first line: {}".format(moss_dataset['dialogue'][0])) 115 | 116 | # ultrachat dataset: https://huggingface.co/datasets/YeungNLP/ultrachat 117 | ultrachat_file = "../datasets/ultra-chat.jsonl" 118 | ultrachat_dataset = load_dataset("json", data_files=ultrachat_file)['train'] 119 | ultrachat_dataset = ultrachat_dataset.map(process_ultrachat_dataset, 120 | batched=True, 121 | batch_size=20, 122 | num_proc=10, 123 | remove_columns=ultrachat_dataset.column_names) 124 | logger.info("load ultrachat data done, info: {}".format(ultrachat_dataset)) 125 | logger.info("ultrachat first line: {}".format(ultrachat_dataset['dialogue'][0])) 126 | 127 | dialogue_dataset = concatenate_datasets([moss_dataset, ultrachat_dataset]) 128 | 129 | dataset_num = len(dialogue_dataset) 130 | sample_num = 500000 131 | sample_list = random.sample(range(dataset_num), sample_num) 132 | dialogue_dataset = dialogue_dataset.select(sample_list) 133 | logger.info("dialogue dataset info: {}".format(dialogue_dataset)) 134 | logger.info("dialogue data first line: {}".format(dialogue_dataset['dialogue'][0])) 135 | 136 | train_val_dataset = dialogue_dataset.train_test_split( 137 | test_size=5000, shuffle=True, seed=215 138 | ) 139 | logger.info("train and eval dataset info: {}".format(train_val_dataset)) 140 | 141 | dialogue_path = "../dialogues" 142 | train_val_dataset.save_to_disk(dialogue_path) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Automatically generated by https://github.com/damnever/pigar. 2 | 3 | bitsandbytes==0.39.0 4 | datasets==2.12.0 5 | loguru==0.7.0 6 | peft==0.4.0.dev0 7 | torch==1.13.0 8 | transformers==4.30.0.dev0 9 | sentencepiece==0.1.99 10 | scipy==1.10.1 11 | accelerate==0.20.0.dev0 12 | deepspeed==0.9.2 13 | fire==0.5.0 14 | tensorboard -------------------------------------------------------------------------------- /trainer/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Macielyoung/Baichuan-QLora/834dc3cb5a9a15fde309425c0d405ff8a9602e22/trainer/.DS_Store -------------------------------------------------------------------------------- /trainer/deepspeed.json: -------------------------------------------------------------------------------- 1 | { 2 | "train_micro_batch_size_per_gpu": "auto", 3 | "gradient_accumulation_steps": "auto", 4 | "steps_per_print": 1000, 5 | "gradient_clipping": 1.0, 6 | "zero_optimization": { 7 | "stage": 2, 8 | "offload_optimizer": { 9 | "device": "cpu" 10 | }, 11 | "contiguous_gradients": true, 12 | "overlap_comm": true 13 | }, 14 | "zero_allow_untested_optimizer": true, 15 | "fp16": { 16 | "enabled": true, 17 | "loss_scale": 0, 18 | "loss_scale_window": 1000, 19 | "hysteresis": 2, 20 | "min_loss_scale": 1 21 | }, 22 | "optimizer": { 23 | "type": "Adam", 24 | "params": { 25 | "lr": "auto", 26 | "betas": "auto", 27 | "eps": "auto", 28 | "weight_decay": "auto" 29 | } 30 | }, 31 | "activation_checkpointing": { 32 | "partition_activations": true, 33 | "contiguous_memory_optimization": true 34 | }, 35 | "wall_clock_breakdown": false 36 | } 37 | -------------------------------------------------------------------------------- /trainer/train_multiturn_qlora.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from typing import List 4 | 5 | import torch 6 | import transformers 7 | from datasets import load_dataset, load_from_disk 8 | from loguru import logger 9 | 10 | from peft import ( # noqa: E402 11 | LoraConfig, 12 | get_peft_model, 13 | get_peft_model_state_dict, 14 | prepare_model_for_int8_training, 15 | set_peft_model_state_dict, 16 | ) 17 | 18 | from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig 19 | from transformers import Trainer 20 | import bitsandbytes as bnb 21 | from torch.nn.utils.rnn import pad_sequence 22 | import argparse 23 | import os 24 | os.environ['CUDA_VISIBLE_DEVICES'] = '0,1,2,3' 25 | 26 | 27 | class QLoraTrainer(Trainer): 28 | 29 | def save_model(self, output_dir=None, _internal_call=False): 30 | from transformers.trainer import TRAINING_ARGS_NAME 31 | 32 | os.makedirs(output_dir, exist_ok=True) 33 | logger.info("model save path: {}".format(output_dir)) 34 | torch.save(self.args, os.path.join(output_dir, TRAINING_ARGS_NAME)) 35 | self.model.save_pretrained(output_dir) 36 | 37 | 38 | def find_all_linear_names(model): 39 | """ 40 | 找出所有全连接层,为所有全连接添加adapter 41 | """ 42 | cls = bnb.nn.Linear4bit 43 | lora_module_names = set() 44 | for name, module in model.named_modules(): 45 | if isinstance(module, cls): 46 | names = name.split('.') 47 | lora_module_names.add(names[0] if len(names) == 1 else names[-1]) 48 | 49 | if 'lm_head' in lora_module_names: # needed for 16-bit 50 | lora_module_names.remove('lm_head') 51 | return list(lora_module_names) 52 | 53 | 54 | def train( 55 | # model/data params 56 | base_model: str = "", # the only required argument 57 | data_path: str = "../dialogues", 58 | output_dir: str = "../models/", 59 | # training hyperparams 60 | batch_size: int = 128, 61 | micro_batch_size: int = 2, 62 | num_epochs: int = 1, 63 | learning_rate: float = 2e-5, 64 | cutoff_len: int = 1024, 65 | val_set_size: int = 0, 66 | # lora hyperparams 67 | lora_r: int = 16, 68 | lora_alpha: int = 16, 69 | lora_dropout: float = 0.05, 70 | lora_target_modules: List[str] = [ 71 | "W_pack" 72 | ], 73 | # llm hyperparams 74 | group_by_length: bool = False, # faster, but produces an odd training loss curve 75 | resume_from_checkpoint: str = None, # either training checkpoint or final adapter 76 | ): 77 | logger.info( 78 | f"Training Baichuan-QLoRA model with params:\n" 79 | f"base_model: {base_model}\n" 80 | f"data_path: {data_path}\n" 81 | f"output_dir: {output_dir}\n" 82 | f"batch_size: {batch_size}\n" 83 | f"micro_batch_size: {micro_batch_size}\n" 84 | f"num_epochs: {num_epochs}\n" 85 | f"learning_rate: {learning_rate}\n" 86 | f"cutoff_len: {cutoff_len}\n" 87 | f"val_set_size: {val_set_size}\n" 88 | f"lora_r: {lora_r}\n" 89 | f"lora_alpha: {lora_alpha}\n" 90 | f"lora_dropout: {lora_dropout}\n" 91 | f"lora_target_modules: {lora_target_modules}\n" 92 | f"group_by_length: {group_by_length}\n" 93 | f"resume_from_checkpoint: {resume_from_checkpoint}\n" 94 | ) 95 | assert ( 96 | base_model 97 | ), "Please specify a --base_model, e.g. --base_model='bigscience/bloomz-7b1-mt'" 98 | gradient_accumulation_steps = batch_size // micro_batch_size 99 | 100 | device_map = "auto" 101 | # device_map = {"": 0} 102 | world_size = int(os.environ.get("WORLD_SIZE", 1)) 103 | ddp = world_size != 1 104 | if ddp: 105 | device_map = {"": int(os.environ.get("LOCAL_RANK") or 0)} 106 | gradient_accumulation_steps = gradient_accumulation_steps // world_size 107 | 108 | # load model in 4bit 109 | quantization_config=BitsAndBytesConfig( 110 | load_in_4bit=True, 111 | bnb_4bit_compute_dtype=torch.float16, 112 | bnb_4bit_use_double_quant=True, 113 | bnb_4bit_quant_type="nf4", 114 | llm_int8_threshold=6.0, 115 | llm_int8_has_fp16_weight=False, 116 | ) 117 | model = AutoModelForCausalLM.from_pretrained( 118 | base_model, 119 | device_map=device_map, 120 | trust_remote_code=True, 121 | load_in_4bit=True, 122 | torch_dtype=torch.float16, 123 | quantization_config=quantization_config, 124 | ) 125 | 126 | tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True) 127 | # baichuan model without pad token 128 | tokenizer.add_special_tokens({'pad_token': ''}) 129 | model.resize_token_embeddings(len(tokenizer)) 130 | 131 | def tokenize_conversation(example): 132 | conversations = example['dialogue'] 133 | 134 | input_ids = [] 135 | labels = [] 136 | for cid, conversation in enumerate(conversations): 137 | human_text = conversation['human'] 138 | assistant_text = conversation['assistant'] 139 | 140 | # 在前后位置添加开头和结束标记符号 (bos_token, eos_token) 141 | if cid == 0: 142 | human_text = tokenizer.bos_token + human_text + tokenizer.eos_token 143 | else: 144 | human_text = human_text + tokenizer.eos_token 145 | assistant_text += tokenizer.eos_token 146 | 147 | human_ids = tokenizer.encode(human_text) 148 | assistant_ids = tokenizer.encode(assistant_text) 149 | 150 | # 添加human id 151 | input_ids += human_ids 152 | labels += len(human_ids) * [-100] 153 | 154 | # 添加assistant id 155 | input_ids += assistant_ids 156 | labels += assistant_ids 157 | 158 | result = { 159 | 'input_ids': input_ids, 160 | 'labels': labels 161 | } 162 | return result 163 | 164 | 165 | def data_collator(features: list) -> dict: 166 | # cut off the input and label 167 | input_ids_list = [feature['input_ids'][:cutoff_len] for feature in features] 168 | labels_list = [feature['labels'][:cutoff_len] for feature in features] 169 | # logger.info("input_ids_list: {}".format(input_ids_list)) 170 | # logger.info("labels_list: {}".format(labels_list)) 171 | # logger.info("input shape: {}, {}".format(len(input_ids_list), len(input_ids_list[0]))) 172 | 173 | # pad token from left 174 | input_ids = pad_sequence([torch.tensor(input_ids[::-1]) for input_ids in input_ids_list], 175 | batch_first=True, 176 | padding_value=tokenizer.pad_token_id).flip(dims=[1]) 177 | labels = pad_sequence([torch.tensor(labels[::-1]) for labels in labels_list], 178 | batch_first=True, 179 | padding_value=-100).flip(dims=[1]) 180 | 181 | input_ids = input_ids.long() 182 | labels = labels.long() 183 | 184 | return { 185 | "input_ids": input_ids, 186 | "attention_mask": input_ids.ne(tokenizer.pad_token_id), 187 | "labels": labels, 188 | } 189 | 190 | model = prepare_model_for_int8_training(model, use_gradient_checkpointing=True) 191 | 192 | # add adapter modules for all linear layer 193 | lora_target_modules = find_all_linear_names(model) 194 | logger.info("lora target modules: {}".format(lora_target_modules)) 195 | 196 | config = LoraConfig( 197 | r=lora_r, 198 | lora_alpha=lora_alpha, 199 | target_modules=lora_target_modules, 200 | lora_dropout=lora_dropout, 201 | bias="none", 202 | task_type="CAUSAL_LM", 203 | ) 204 | model = get_peft_model(model, config) 205 | 206 | if data_path.endswith(".jsonl"): # todo: support jsonl 207 | data = load_dataset("json", data_files=data_path) 208 | else: 209 | data = load_from_disk(data_path) 210 | 211 | if resume_from_checkpoint: 212 | # Check the available weights and load them 213 | checkpoint_name = os.path.join( 214 | resume_from_checkpoint, "pytorch_model.bin" 215 | ) # Full checkpoint 216 | if not os.path.exists(checkpoint_name): 217 | checkpoint_name = os.path.join( 218 | resume_from_checkpoint, "adapter_model.bin" 219 | ) # only LoRA model - LoRA config above has to fit 220 | resume_from_checkpoint = ( 221 | False # So the trainer won't try loading its state 222 | ) 223 | # The two files above have a different name depending on how they were saved, but are actually the same. 224 | if os.path.exists(checkpoint_name): 225 | logger.info(f"Restarting from {checkpoint_name}") 226 | adapters_weights = torch.load(checkpoint_name) 227 | model = set_peft_model_state_dict(model, adapters_weights) 228 | else: 229 | logger.info(f"Checkpoint {checkpoint_name} not found") 230 | 231 | model.print_trainable_parameters() # Be more transparent about the % of trainable params. 232 | model.config.torch_dtype = torch.float32 233 | 234 | logger.info("data info: {}".format(data)) 235 | if val_set_size > 0: 236 | # split data into train and test dataset 237 | train_val = data['train'].train_test_split( 238 | test_size=val_set_size, shuffle=True, seed=215 239 | ) 240 | train_data = ( 241 | train_val['train'].shuffle().map(tokenize_conversation, remove_columns=train_val['train'].column_names) 242 | ) 243 | val_data = ( 244 | train_val['test'].shuffle().map(tokenize_conversation, remove_columns=train_val['test'].column_names) 245 | ) 246 | else: 247 | train_data = data['train'].shuffle().map(tokenize_conversation, remove_columns=data['train'].column_names) 248 | val_data = data['test'].shuffle().map(tokenize_conversation, remove_columns=data['test'].column_names) 249 | 250 | if not ddp and torch.cuda.device_count() > 1: 251 | # keeps Trainer from trying its own DataParallelism when more than 1 gpu is available 252 | model.is_parallelizable = True 253 | model.model_parallel = True 254 | 255 | train_args=transformers.TrainingArguments( 256 | per_device_train_batch_size=micro_batch_size, 257 | per_device_eval_batch_size=micro_batch_size, 258 | gradient_accumulation_steps=gradient_accumulation_steps, 259 | warmup_steps=200, 260 | num_train_epochs=num_epochs, 261 | learning_rate=learning_rate, 262 | fp16=True, 263 | logging_steps=50, 264 | optim="adamw_torch", 265 | # optim="paged_adamw_32bit", 266 | evaluation_strategy="steps" if val_set_size > 0 else "no", 267 | save_strategy="steps", 268 | # eval_steps=200 if val_set_size > 0 else None, 269 | eval_steps=200, 270 | save_steps=200, 271 | output_dir=output_dir, 272 | save_total_limit=3, 273 | load_best_model_at_end=True if val_set_size > 0 else False, 274 | ddp_find_unused_parameters=False if ddp else None, 275 | group_by_length=group_by_length, 276 | report_to="tensorboard" 277 | # report_to="wandb" if use_wandb else None, 278 | # run_name=wandb_run_name if use_wandb else None, 279 | ) 280 | 281 | trainer = QLoraTrainer( 282 | model=model, 283 | train_dataset=train_data, 284 | eval_dataset=val_data, 285 | args=train_args, 286 | data_collator=data_collator, 287 | ) 288 | model.config.use_cache = False 289 | 290 | if torch.__version__ >= "2" and sys.platform != "win32": 291 | model = torch.compile(model) 292 | 293 | trainer.train(resume_from_checkpoint=resume_from_checkpoint) 294 | 295 | model.save_pretrained(output_dir) 296 | 297 | logger.info( 298 | "\n If there's a warning about missing keys above, please disregard :)" 299 | ) 300 | 301 | 302 | def parse_args(): 303 | parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) 304 | parser.add_argument("--data_path", type=str, default="../dialogues", help="sft data path") 305 | parser.add_argument("--pretrained", type=str, default="baichuan-inc/baichuan-7B", help="pretrained model from huggingface hub") 306 | parser.add_argument("--save_path", type=str, default="../models", help="model saved path") 307 | parser.add_argument("--epoches", type=int, default=5, help="epoch num") 308 | parser.add_argument("--batch_size", type=int, default=128, help="batch size") 309 | parser.add_argument("--micro_batch_size", type=int, default=8, help="micro batch size") 310 | parser.add_argument("--val_set_size", type=int, default=2000, help="validation set size") 311 | parser.add_argument("--lr", type=float, default=2e-4, help="learning rate num") 312 | parser.add_argument("--max_length", type=int, default=2048, help="sentence max length") 313 | parser.add_argument("--lora_r", type=int, default=64, help="lora rank") 314 | parser.add_argument("--lora_alpha", type=int, default=16, help="lora alpha") 315 | parser.add_argument("--lora_dropout", type=float, default=0.05, help="lora dropout") 316 | args = parser.parse_args() 317 | return args 318 | 319 | 320 | if __name__ == "__main__": 321 | # args = parse_args() 322 | # train(base_model=args.pretrained, 323 | # data_path=args.data_path, 324 | # output_dir=args.save_path, 325 | # batch_size=args.batch_size, 326 | # micro_batch_size=args.micro_batch_size, 327 | # num_epochs=args.epoches, 328 | # learning_rate=args.lr, 329 | # cutoff_len=args.max_length, 330 | # val_set_size=args.val_set_size, 331 | # lora_r=args.lora_r, 332 | # lora_alpha=args.lora_alpha, 333 | # lora_dropout=args.lora_dropout, 334 | # ) 335 | base_model = "baichuan-inc/baichuan-7B" 336 | train(base_model=base_model) 337 | 338 | --------------------------------------------------------------------------------