让GPT成为护理专家 - 护士的工作如此简单

news2024/11/25 6:41:28

引子   

  书接上文《GPT接入企微应用 - 让工作快乐起来》,我把GPT接入了企微应用,不少同事都开始尝试起来了。有的浅尝辄止,有的刨根问底,五花八门,无所不有。这里摘抄几份:

  “帮我写一份表白信,我们是大学同学,暗恋十年”

  ”顺产后多久可以用收腹带?生完宝宝用收腹带好还是不用好“ (背景:公司主营月子中心,护理相关的领域知识是公司对于护士培训的重点内容

  ”我的工资是多少“ (这个有点强机器人所难了,不过如果机器人有了公司的人事语料数据,应该是可以回答的)

   ......

   总的来说,除了一些尝鲜,猎奇之外,有相当一部分还是咨询公司的内部的相关信息,比如HR方面的育儿假等,再就是母婴护理方面的问题了(公司有近60%的是护理人员,日常工作就是与宝宝,宝妈一起,这就不奇怪了)。

  看到这些问题后,我就开始尝试通过Fine-tune训练公司内部的护理机器人,希望他可以为护士们的工作带来一些便利。诸多尝试失败后,索性就放了一些时间。

  恰逢五一假,回了媳妇娘家,掐指一算,已经3年6个月没有回来过了,二娃子都快3岁了,还没见过外婆。想不到娃子亲舅舅,我到清闲了,又捡起护理机器人捣鼓起来了。于是有了这篇文章。

Fine-tune可能真的不合适

  刚看到Fine-tune的介绍时就想,如果通过fine-tune构建个性化的模型,导入公司的母婴护理知识,并且在未来了问答中进化,变成企业内部专家。所以一开始就是向这样的路子摸索着。毕竟介绍里也说了通过少量样本即可完成训练,分类这样的任务可能只需要200个左右的样本即可。(其实问答模型的样本要求至少要有几千个可能会有点效果)

   

  当然,文档中也有一些关于Fine-tune的一些指南和准则。一来是全是英文文档,理解不太深入;二来就是无知无畏,不尝试下就是不死心。这是文档原文,大概的意思Fine-tune可以用来解决一些类似分类(判断对错,情绪判断(乐观,悲观),邮件分类),以及扩写总结之类的场景。 文档也有提到案例”Customer support chatbot“,这可能也是大家这样尝试的原因之一吧。 在其demo推荐使用 emebedding 来实现,也是本文的重点内容。这是后

  虽然通过Fine-tune的方式最终也没有好的效果,一来可能是样本太少,或者样本质量不好;也或者过程中有疏漏的地方。在这里也和大家一起探讨下。毕竟fine-tune的方式还是让人非常神往的。实现代码基本是参考了 openai-cookbook 中的 fine-tuned_qa Demo。大致流程如入:

  • 环境配置就不多说了(版本 python 3.10.4 整个过程基本还是流畅的。除了v-p-n自身原因折腾好久(原来用的是mono),换个客户端居然好了)
  • 收集文本数据并根据token的限制,合理分段落。(我自己则是找到内部了母婴护理培训的电子版本。)
  • 用模型text-davinci-003 为每个段落自动生成若干问题,并根据段落及问题自动生成答案。
  • 使用所有生成问题及答案组织成fine-tuen所需要的数据集。
  • 创建新模型并使用。

  1,文本分段 - 因为拿到的资料是word,并且有标题,就直接根据标题他分段了,超过2048的再分一次,代码如下(现学现用,比较粗漏)

 

import docx
import pandas as pd

def getText(fileName):
    doc = docx.Document(fileName)
    TextList = []

    data = {"title":"","content":""}
    for paragraph in doc.paragraphs:
        if paragraph.style.name == 'Heading 1':
            print("title %s " % paragraph.text)
            if (len(data['content']) > 0):
                datax = {}
                datax['title'] = data['title']
                datax['content'] = data['content']

                TextList.append(datax)
            data['title'] = paragraph.text
            data['content'] = ''
        else:
            data['content'] += paragraph.text+"\n"
    TextList.append(data)
    return TextList

## 根据doc 转 csv
if __name__ == '__main__':
    fileName = '/Users/jijunjian/openai/test2.docx'

    articList = getText(fileName)
    count = 0
    for article in articList:
        if len(article['content']) > 800:
            print("%s,%s,\n%s" % (article['title'], len(article['content']),article['content']))
        count += 1

    header = ['title', 'content']
    print("总共 %s 篇文章" % count)
    pd.DataFrame(articList, columns=header).to_csv('data_oring.csv', index=False, encoding='utf-8')


  2,生成问题与答案 - 这样生成的质量可能不是太高,可能实际使用时还是要对生成的问题和答案,让领域专家进行修正比较好。

  据官方文档介绍,建议生成的数据集中,prompt与completion都要有固定的结尾,且尽量保证其他地方不会出现这个,所以我们这里使用了”\n\n###\n\n“作为结束标志。


import pandas as pd
import openai
import sys
sys.path.append("..")
from tools.OpenaiInit import openai_config
from transformers import GPT2TokenizerFast


tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")

def count_tokens(text: str) -> int:
    """count the number of tokens in a string"""
    return len(tokenizer.encode(text))


COMPLETION_MODEL = "text-davinci-003"
FILE_TUNE_FILE = "search_data.jsonl"


# 获取训练数据
def     get_training_data():
    file_name = "data_oring.csv"
    df = pd.read_csv(file_name)
    df['context'] = df.title + "\n\n" + df.content
    print(f"{len(df)} rows in the data.")
    return df


# 根据内容,生成问题
def get_questions(context):
    print("正在生成问题")
    try:
        response = openai.Completion.create(
            engine=COMPLETION_MODEL,
            prompt=f"基于下面的文本生成问题\n\n文本: {context}\n\n问题集:\n1.",
            temperature=0,
            max_tokens=500,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0,
            stop=["\n\n"]
        )
        return response['choices'][0]['text']
    except Exception as e:
        print("创建问题错误 %s"  % e)
        return ""


# 根据问题,生成答案
def get_answers(row):
    print("正在生成答案")
    try:
        response = openai.Completion.create(
            engine=COMPLETION_MODEL,
            prompt=f"基于下面的文本生成答案\n\n文本: {row.context}\n\n问题集:\n{row.questions}\n\n答案集:\n1.",
            temperature=0,
            max_tokens=500,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )
        return response['choices'][0]['text']
    except Exception as e:
        print (e)
        return ""


# 获取训练数据 /Users/jijunjian/tuningdata.xlsx
if __name__ == '__main__':
     openai_config()
     df = get_training_data()
     df['tokens'] = df.context.apply(count_tokens)
     # questions 根据返回生成
     df['questions']= df.context.apply(get_questions)
     df['questions'] = "1." + df.questions

     df['answers']= df.apply(get_answers, axis=1)
     df['answers'] = "1." + df.answers
     df = df.dropna().reset_index().drop('index',axis=1)

     print("正在保存数据")
     df.to_csv('nursing_qa.csv', index=False)



     df['prompt'] = df.context + "\n\n###\n\n"
     df['completion'] = " yes\n\n###\n\n"

     df[['prompt', 'completion']].to_json(FILE_TUNE_FILE, orient='records', lines=True)

     search_file = openai.File.create(
        file=open(FILE_TUNE_FILE),
        purpose='fine-tune'
     )
     qa_search_fileid = search_file['id']
     print("上传文件成功,文件ID为:%s" % qa_search_fileid)

     # file_id = file-Bv5gP2******

  3,根据生成数据集,创建新的模型。

  官方的demo,还有生成验证集,测试集,生成相识的文本,同样的问题与答案来增加一些对抗性,因为最终效果不太好,再是文档中有使用search 模块,但是这已经下线了,我用prompt-completion的数据结构模拟了下,也不知道有没有效果, 因为使用openai tools 创建模型可以有一些交互动作,也方便看一些执行结果,花费数据,这里就使用这这工具作了演示,执行一段时间后,可以通过”openai.Model.list()“查看我们创建的模型。当时大概有1000来个问题与答案,花费了0.78刀。(这是4月13尝试的,因为效果不好,结果一放就是半月有余了。时间真是如白驹过隙一般)  

 1 openai api fine_tunes.create -t "discriminator_train.jsonl" -v "discriminator_test.jsonl" --batch_size 16  --compute_classification_metrics --classification_positive_class yes --model ada --suffix 'discriminator'
 2 
 3 Uploaded file from discriminator_train.jsonl: file-5OeHx3bMDqk******
 4 Uploaded file from discriminator_test.jsonl: file-AnOiDwG1Oqv3Jh******
 5 Created fine-tune: ft-cQBMLPzqVNml1ZWqkGYQKUdO
 6 Streaming events until fine-tuning is complete...
 7 
 8 (Ctrl-C will interrupt the stream, but not cancel the fine-tune)
 9 [2023-04-13 23:17:05] Created fine-tune: ft-cQBMLPz********
10 [2023-04-13 23:17:22] Fine-tune costs $0.78
11 [2023-04-13 23:17:23] Fine-tune enqueued. Queue number: 3

   最后,效果不太理想,一番尝试后,看到文档中的提示信息:

  ”Note: To answer questions based on text documents, we recommend the procedure in Question Answering using Embeddings. Some of the code below may rely on deprecated API endpoints.“  于是借着五一的空闲,开始尝试emebedding 方式 了

emebedding可能是当下最好的选择

  GPT擅长回答训练数据中存在的问题,对于一些不常见的话题,或者企业内部的语料信息,则可以通过把相关信息放在上下文中,传给GPT,根据上下问进行回答。因为不同模型对于token的限制,以及Token本身的成本因素。

  具体实现时,我们需要把文本信息Chunk(分块)并Embed(不知道如何翻译)得到一个值,收到问题时,同样进行Embed,找到最相近的Chunk,做为上下文传给GPT。官方文档如下: 

  Specifically, this notebook demonstrates the following procedure:

  1. Prepare search data (once)
    1. Collect: We'll download a few hundred Wikipedia articles about the 2022 Olympics
    2. Chunk: Documents are split into short, mostly self-contained sections to be embedded
    3. Embed: Each section is embedded with the OpenAI API
    4. Store: Embeddings are saved (for large datasets, use a vector database)
  2. Search (once per query)
    1. Given a user question, generate an embedding for the query from the OpenAI API
    2. Using the embeddings, rank the text sections by relevance to the query
  3. Ask (once per query)
    1. Insert the question and the most relevant sections into a message to GPT
    2. Return GPT's answer

  一开始本想参考这个demo Question_answering_using_embeddings.ipynb 编写代码,后来有意无意看到使用llama_index的实现,并且对于语料信息格式无要求,就摘抄过来了,感谢代码的贡献者,节省了大家好些时间。

#!/usr/bin/env python
# coding=utf-8

from langchain import OpenAI
from llama_index import SimpleDirectoryReader, LangchainEmbedding, GPTListIndex,GPTSimpleVectorIndex, PromptHelper
from llama_index import LLMPredictor, ServiceContext
import gradio as gr
import sys
import os
os.environ["OPENAI_API_KEY"] = 'sk-fHstI********************'

#MODEL_NAME = "text-davinci-003"
MODEL_NAME = "ada:ft-primecare:*************"

def construct_index(directory_path):
    max_input_size = 2048
    num_outputs = 512
    max_chunk_overlap = 20
    chunk_size_limit = 600
    prompt_helper = PromptHelper(max_input_size, num_outputs, max_chunk_overlap, chunk_size_limit=chunk_size_limit)
    llm_predictor = LLMPredictor(llm=OpenAI(temperature=0.7, model_name=MODEL_NAME, max_tokens=num_outputs))
    documents = SimpleDirectoryReader(directory_path).load_data()
    #index = GPTSimpleVectorIndex(documents, llm_predictor=llm_predictor, prompt_helper=prompt_helper)

    service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper)
    index = GPTSimpleVectorIndex.from_documents(documents, service_context=service_context)

    index.save_to_disk('index.json')
    return index
def chatbot(input_text):
    index = GPTSimpleVectorIndex.load_from_disk('data/index.json')
    response = index.query(input_text, response_mode="compact")
    return response.response

if __name__ == '__main__':

    iface = gr.Interface(fn=chatbot,inputs=gr.inputs.Textbox(lines=7, label="输入你的问题"),outputs="text",title="护理智能机器人")
    ## 用于生成数据, 放在docs文件夹下
    ##index = construct_index("docs")
    iface.launch(share=True, server_name='0.0.0.0', server_port=8012)

  使用了gradio 作为演示,效果如下,基本可以根据我们的内部培训资料中回复,美中不足的就是通过要10几秒才可以完成回复,至少比之前fine-tune有了很大的进步了。至此,总算可以安抚下这半月的苦恼了。(下图中的output 如果变成自定义的文本,尝试多次一起没有成功,也是有点遗憾)

曲折的部署之路

  孟子有云:独乐乐不如众乐乐。如何让同事们一起体验,又是一个艰巨任务开始了。再则也需要让护理专家们看看回复的质量,以及如何优化文本内容。原本以为部署是一件简答的事儿,但是对于python菜-鸡的我,每一步都是坎坷。

  一开始以为直接用pyinstaller 打包就可以直接放在服务器上执行,结果 pyinstaller -F, -D 尝试很久都无法打包依赖,  --hidden-import 也用了, .spec也用了,都不好使。索性放弃了。

  到了晚上12点半时,毫无进展,索性直接放原在码放上去。结果又提示无法安装指定版本的langchain。然后开始捣腾pip版本升级到最新,python版本升级到3.10.4(和本地一样)。

  python升级后,又是提示ModuleNotFoundError: No module named '_bz2',总算是错误信息变了。这个错误大概就是原来自带中的版本中有_bz2模块,重安装的3.10中没有,解决版本都是复制这个文件到新的版本中。

mv _bz2.cpython-36m-x86_64-linux-gnu.so /usr/local/python/lib/python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so

  再次运行终于启动了,太不容易了。配置好防火墙,腾讯云的安全组, 输入外网ip:8012,潇洒的一回车 - 还是无法访问。 借用毛爷爷的一句话描述下当下的心情:它是站在海岸遥望海中已经看得见桅杆尖头了的一只航船,它是立于高山之巅远看东方已见光芒四射喷薄欲出的一轮朝日,它是躁动于母腹中的快要成熟了的一个婴儿。加之夜确实太深了,才踏实的睡下了。

1 /usr/local/python/lib/python3.10/site-packages/gradio/inputs.py:27: UserWarning: Usage of gradio.inputs is deprecated, and will not be supported in the future, please import your component from gradio.components
2   warnings.warn(
3 /usr/local/python/lib/python3.10/site-packages/gradio/deprecation.py:40: UserWarning: `optional` parameter is deprecated, and it has no effect
4   warnings.warn(value)
5 /usr/local/python/lib/python3.10/site-packages/gradio/deprecation.py:40: UserWarning: `numeric` parameter is deprecated, and it has no effect
6   warnings.warn(value)
7 Running on local URL:  http://127.0.0.1:8012
8 Running on public URL: https://11d5*****.gradio.live

  第二天,找到gradio 中Interface.launch 的参数有个 server_name 设置成 通过设置server_name=‘0.0.0.0’ 即可通过IP访问。 通过ss -tnlp | grep ":8012" 也可以看到端口的监听从   ”127.0.0.1:8012“ 就成了 ”0.0.0.0:8012 “。

LISTEN 0      128          0.0.0.0:8012      0.0.0.0:*    users:(("python",pid=2801254,fd=7))

 展望一下

  从目前测试的情况来,每问一个问题成本在10美分左右(成本还是比较高),优化的方向可能Chunk的大小,太小无法包含住够的上下问,太大成本又比较高。再回头看Fine-tune的方式,应该是前期训练话费的成本会比较高,后期回答的成本会比较少,只是目前训练效果不太好,看其他文章也是同样的问题。从目前的情况来可能 emebedding的是一个较为合适的落地方式。

      接下看看使用的情况,如果效果不错,考虑增加语音转文字,用GPT回复答案,甚至可以再文字转语音播报出来,这样护士们的工作可能会更加便利与快乐了。

   成为一名优秀的程序员!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Prompt】7 个向 chatGPT 高效提问的方法

欢迎关注【youcans的 AIGC 学习笔记】原创作品 【Prompt】7 个向 chatGPT 高效提问的方法 0. 向 chatGPT 高效提问的方法1. 提问方法:明确问题2. 提问方法:简洁清晰3. 提问方法:避免歧义4. 提问方法:提供上下文5. 提问方法&#x…

很不错的一篇文章,值得点赞收藏,带你全面了解MySQL性能调优、错误代码总结和全局参数配置(持续更新中ing)

前言 本文主要介绍当前MySQL性能优化原理实战,包括以下方面: 已更新文章目录MySQL遇到的的错误及解决方法全局参数文件配置详解。 后续希望大家提出宝贵的建议。喜欢的话点赞收藏关注走一波。如有错误的地方,请指出!!&…

C51 - 自写操作系统

最简OS 1> 版本1:任务建立与切换2> 版本2:定时器切换2.1> main.c2.2> task.c2.3> sleep.c 3> 版本3:加时间片轮转 在51单片机上,实现操作系统最简模型, 学习理解操作系统的基本概念; &am…

〖Python网络爬虫实战㉑〗- 数据存储之JSON操作

订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列(零基础小白搬砖逆袭) 说明:本专栏持续更新中,目前专栏免费订阅,在转为付费专栏前订阅本专栏的,可以免费订阅付…

912. 排序数组

1.题目: 2.我的代码: C语言: /*** Note: The returned array must be malloced, assume caller calls free().*/ int* sortArray(int* nums, int numsSize, int* returnSize) {//希尔排序int gap numsSize;//多次预排while (gap > 1) {/…

【Linux】初识Linux

目录 🍎一.Linux历史🍎 1.UNIX发展的历史 2.Linux发展历史 🍏二.开源🍏 🍑三.官网🍑 🍊四.企业应用现状🍊 1.Linux在服务器领域的发展 2.Linux在桌面领域的发展 3.Linux在移…

自实现朴素贝叶斯分类器with案例:基于SMS Spam Collection数据集的广告邮件分类

目录 贝叶斯分类器何为朴素案例:基于SMS Spam Collection数据集的广告邮件分类SMS数据集词向量表示Laplacian平滑训练过程分类过程 完整代码 贝叶斯分类器 首先要理解贝叶斯决策的理论依据,引用西瓜书上的原话:对于分类任务,在所…

【小呆的力学笔记】非线性有限元的初步认识【二】

文章目录 1.2 有限元分析的数学原理1.2.1 基于最小势能原理的变分法提法1.2.1.a 弹性力学方程简化记法1.2.1.b 应变能密度和应变余能密度1.2.1.c 最小势能原理变分基础 1.2 有限元分析的数学原理 书接上回,我们已经回顾了线性有限元分析的理论基础——线弹性力学的…

TryHackMe-Lunizz CTF(boot2root)

Lunizz CTF 端口扫描 循例nmap Web枚举 进80,apache默认页面 gobuster扫一下目录 /hidden一个文件上传点, 图片上传后无权访问/hidden/uploads/ /whatever一个假的命令执行点 /instructions.txt 由 CTF_SCRIPTS_CAVE 制作(不是真实的)感谢…

如何看待人工智能技术的变革与未来?

人工智能是当今科技领域中最具前景的技术之一。从最初的逻辑推理到现在的深度学习,人工智能技术的发展已经经历了多个阶段。在本文中,我们将从技术的角度,探讨人工智能的发展历程和未来发展趋势。 一、起源和逻辑推理阶段 人工智能的起源可…

【五一创作】Java 反射

在了解反射前,我们先要知道一些相关知识 Class类 Class类的实例表示java应用运行时的类或接口,每个java类运行时都在JVM里表现为一个class对象,可通过类名.class、类型.getClass()、Class.forName("类名")等方法获取class对象。 …

关于 IO、存储、硬盘和文件系统

关于IO、存储、硬盘和文件系统 0.引入1.了解IO1.1.存储器IO1.2.设备IO 2.存储介质和存储类型2.1.内存2.2.硬盘2.3.固态硬盘(SSD)2.4.U盘 3.硬盘的工作原理3.1.磁头3.2.盘片3.3.电动机3.4.硬盘的读写操作 4.文件系统概述4.1.文件系统的类型4.2.文件系统的…

vagrant virtualbox 复制

菜鸟学习,记录一下 vagrant virtualbox 虚拟机复制。 目录 第一步,使用 virtualbox 复制虚拟机 第二步,复制 vagrant 文件 第三步,重命名相关文件夹及文件并修改配置: 第四步,注册运行复制后的虚拟机 第…

ImageJ实践——测量大小/长短(以细胞为例)

ImageJ是一款功能强大的图像处理软件。毫无疑问它在测量方面提供了十分便利的功能。下面我将以测量细胞的长短、大小(面积)为例,详细介绍ImageJ的测量操作流程。 1. ImageJ打开图像文件 在弹出的文件选择对话框中选择目标文件,即…

Spring Data Elasticsearch--ElasticsearchRestTemplate--使用/教程/实例

原文网址:Spring Data Elasticsearch--ElasticsearchRestTemplate--使用/教程/实例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文用实例来介绍如何使用Spring Data Elasticsearch的ElasticsearchRestTemplate来操作ES。包括:索引的增删等、文档的增删改查…

【拓扑排序】课程表系列

文章目录 课程表(环检测算法)1. DFS2. BFS 课程表 II(拓扑序列)1. DFS2. BFS 课程表 IV(记忆化搜索)1. DFS2. BFS 课程表(环检测算法) 1. DFS 先修课程之间的关系可以用有向图表示&…

AI题目整理

1、网络配置时batchsize的大小怎样设置?过小和过大分别有什么特点? Batch size是指一次迭代过程中,输入到神经网络的样本数量。 batchsize太小的缺点: ①耗时长,训练效率低。 ②训练数据就会非常难收敛,从而导致欠拟合。 batch…

MySQL后台线程详解

前言 MySQL的服务实现通过后台多个线程、内存池、文件交互来实现对外服务的,不同线程实现不同的资源操作,各个线程相互协助,共同来完成数据库的服务。本章简单总结MySQL的一些后台线程以及主要作用。 本章收录在MySQL性能优化原理实战专栏&am…

js常见混淆加密技术

下面,我将通过一个案例来演示如何使用JavaScript混淆加密技术来保护你的网站。 假设你有一个网站,其中包含一个登录页面,该页面的JavaScript代码如下所示: function login(username, password) {if (username "admin"…

Doris(21):Doris的函数—日期函数

1 CONVERT_TZ(DATETIME dt, VARCHAR from_tz, VARCHAR to_tz) 转换datetime值dt,从 from_tz 由给定转到 to_tz 时区给出的时区,并返回的结果值。 如果参数无效该函数返回NULL。 select convert_tz(2019-08-01 13:21:03, Asia/Shanghai, America/Los_Angeles); select co…