【大模型实战篇】关于Bert的一些实操回顾以及clip-as-service的介绍

news2024/9/22 13:49:48

        最近在整理之前的一些实践工作,一方面是为了笔记记录,另一方面也是自己做一些温故知新,或许对于理解一些现在大模型工作也有助益。

1. 基于bert模型实现中文语句的embedding编码

        首先是基于bert模型实现中文语句的embedding编码,主要是借助了bert-as-service项目,目前该项目已经更新为了clip-as-service【1】,提供低延迟、高可扩展性的服务,主要用于图像和文本的嵌入。不过本文的内容主要还是围绕之前的工作的总结。

        利用bert-as-service项目,实现利用 BERT 模型来获取中文句子的嵌入(embedding)编码。通过anaconda配置bert的运行环境。从bert和bert-as-service的readme里面,可以看到,bert依赖的python版本需要大于3.5(因此选择3.7版本), 同时tensorflow需要大于1.10版本(选择1.13.1这个版本)。

(1) 首先使用anaconda,创建一个新的环境(在Environment中create即可),命名为tf20。执行:conda install ipykernel。

        在 tf20 环境写入 notebook 的 kernel 中:python -m ipykernel install --name 环境名 --display-name "展示名",即:

        python -m ipykernel install --user --name tf20 --display-name "tf20"

(2) 安装tensorflow,执行: conda install tensorflow==1.13.1

(3) 安装成功之后,开始安装bert-as-service, 它包括两部分:server和client,是典型的CS的架构。执行:

pip install bert-serving-server 

pip install bert-serving-client

(4)配置预训练模型,下载bert的pretraining 模型,有很多版本,因为是用在中文相关的任务,因此下载这个版本chinese_L-12_H-768_A-12即可。即BERT-Base, Chinese。模型文件信息:Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters。

(5) 启动BERT服务,在anaconda prompt中执行:

bert-serving-start -model_dir /tmp/chinese_L-12_H-768_A-12/ -num_worker=2

作为示例,只启动两个work,也就是一次能够应对两个并发请求。看到 work ready and listening的提示,说明你的服务就启动成功了。

(6) 使用client来获取中文语句的embedding

from bert_serving.client import BertClient
bc = BertClient()
embs = bc.encode(['我非常荣幸来到这', '很高兴来到这里', '很高兴来这里游玩', '请好好游玩'])

可以获得以下的编码:

另外,还可以实现计算句对之间的余弦相似度。

from  math import *

def cosine_similarity(x,y): 
   numerator = sum(a*b for a,b in zip(x,y))
   denominator = square_rooted(x)*square_rooted(y)
   return round(numerator/float(denominator),3)

def square_rooted(x):
   return round(sqrt(sum([a*a for a in x])),3)

cosine_similarity(embs[0], embs[1])
cosine_similarity(embs[0], embs[2])
cosine_similarity(embs[1], embs[2])
cosine_similarity(embs[2], embs[3])
cosine_similarity(embs[1], embs[3])
cosine_similarity(embs[0], embs[3])

        虽然使用通用的bert 预训练模型获得了语句编码向量,能够进行相似度衡量。但是也能发现明显的问题,即使某些语句的语义是完全相反的,但是相似度却很高。需要针对具体的业务要求,进行fine tune来更新参数,适配你的具体应用场景。

        一些说明:bert-as-service 仅仅是对BERT的特征提取服务,因此可以使用任意的经过fine tune之后的模型文件;最后得到的embedding vector,是使用倒数第二层针对所有token的输出做平均池化得到的;如果你想使用多层的输出来计算最后的embedding结果,而不是仅仅依赖倒数第二层的输出,那么可以使用类似下面的命令启动server:

bert-serving-start -pooling_layer -4 -3 -2 -1 -model_dir chinese_L-12_H-768_A-12/

        另外为什么bert-as-service不使用[CLS]作为sentencen的embedding输出,而采用所有tokens的embedding average呢,是因为假如使用的bert model文件只是pre-trained的话,没有经过fine tune,那么使用[CLS]没有什么意义。假如使用的是fine tune之后的model文件,那么可以使用[CLS]。启动的方式如下:

bert-serving-start -pooling_strategy CLS_TOKEN  -model_dir /Users/yuanquan/bert

2. 基于bert模型实现简易对话机器人        

        原理:利用bert来进行文本语义匹配的工作。假如用户问一个问题,需要为用户从知识库中抽取出最匹配的相应问答对。

        这里以社保咨询为例:

from bert_serving.client import BertClient
import numpy as np

bc = BertClient()
questions = [
                    '医疗保险怎么缴纳', 
                    '医疗保险如何交费', 
                    '养老保险补缴流程', 
                    '养老保险断缴以后怎么办',
                    '养老保险缴费地址',
                    '养老能不能迁移',
                    '医保定点医院',
                    '定点医院报销',
                    '定点医院有哪些',
                    '社保福利',
                    '杭州社保怎么缴纳',
                    '工伤标准是啥',
                    '医保断交了怎么办'
                    ]

embs = bc.encode(questions)
topk = 3
while True:
    query = input('your question: ')
    query_vec = bc.encode([query])[0]
    score = np.sum(query_vec * embs, axis=1) / np.linalg.norm(embs, axis=1)
    topk_idx = np.argsort(score)[::-1][:topk]
    for idx in topk_idx:
        print('> %s\t%s' % (score[idx], questions[idx]))

        进一步,可以使用faiss来做正式可用的对话机器人,Faiss是用于相似性搜索和密集聚类向量的库。

3. 微调模型(fine-tuning)

        使用预训练模型的信息如下:Chinese Simplified and Traditional, 12层,768维隐藏层,12个注意力头,包含1.1亿参数。该模型可以从Google在GitHub上的开源代码中找到下载链接。下载并解压压缩文件后,会发现其中有五个文件,其中以 bert_model.ckpt 开头的文件负责加载模型变量,vocab.txt 文件则是在训练过程中使用的中文词汇表,而 bert_config.json 则提供了在训练期间可以调整的BERT模型参数。

        模型的训练与预测都需要清晰的输入格式,而在BERT的代码中,processor 类负责处理输入数据。以分类任务为例,要修改 processor 类以适应自己的数据集并进行微调。在 run_classifier.py 文件中,Google 已经为一些公共数据集编写了相应的处理器,例如 XnliProcessorMnliProcessorMrpcProcessorColaProcessor。这些现成的处理器为我们如何针对自己的数据集编写处理器提供了很好的参考。

        对于需要经历训练、交叉验证以及测试全流程的模型来说,自定义的 processor 类需要继承自 DataProcessor 类,并且要重写 get_labels 方法来获取标签列表,以及 get_train_examplesget_dev_examplesget_test_examples 方法来分别获取训练、验证和测试数据。这些方法会在主函数中依据 FLAGS.do_trainFLAGS.do_evalFLAGS.do_predict 参数被调用。

        上述三个方法的功能相似,主要区别在于它们各自读取的数据文件路径不同。以 get_train_examples 方法为例,该方法应返回一个由 InputExample 对象构成的列表。InputExample 是一个简单的类,它具有一个构造函数,要求传入的参数包括用于唯一标识每个样例的 guid,可以按 train-%d'%(i) 的方式定义。text_a 是一个字符串,代表输入文本的一部分,而 text_b 则是另一个可选的字符串。经过后续处理(这部分工作已在BERT代码中实现)之后,text_atext_b 将会被转化为 [CLS] text_a [SEP] text_b [SEP] 的格式输入到模型中。最后,标签 label 应该是一个字符串,并且要确保其值包含在 get_labels 方法返回的标签列表中。

        这里介绍两种数据的fine tune:(1)利用分类信息数据(如新闻类别);(2)判断句子相似度(两句话是否为同一语义)

        (1)以新闻类别为例

        参照ColaProcessor进行添加数据处理的类,程序如下:

class NicoProcessor(DataProcessor):

  """Processor for the Demo data set."""

  def __init__(self):
    self.labels = set()

  def get_train_examples(self, data_dir):
    """定义训练集的数据,文件名需要根据自己的实际情况修改"""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "train.tsv")), "train")

  def get_dev_examples(self, data_dir):
    """定义验证集的数据,文件名需要根据自己的实际情况修改."""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")

  def get_test_examples(self, data_dir):
    """定义测试集的数据,文件名需要根据自己的实际情况修改."""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")

  def get_labels(self):
    """这里是分类的标签,根据实际情况修改,我这里是3类"""
    return ['民生', '文化', '娱乐', '体育', '财经', '房产', '汽车', '教育', '科技', '军事','旅游', '国际', '证券', '农业', '电竞']

  def _create_examples(self, lines, set_type):
    """Creates examples for the training and dev sets.
    这个函数是用来把数据处理, 把每一个例子分成3个部分,填入到InputExample的3个参数
    text_a 是第一个句子 的文本数据
    text_b是第二个句子的文本,但是由于此任务是单句分类, 所以 这里传入为None
    guid 是一个二元组  第一个表示此数据是什么数据集类型(train dev test) 第二个表示数据标号。
    label 表示句子类别

  """

    examples = []
    for (i, line) in enumerate(lines):
      # Only the test set has a header
      if set_type == "test" and i == 0:
        continue

      guid = "%s-%s" % (set_type, i)
      if set_type == "test":
        text_a = tokenization.convert_to_unicode(line[1])
        label = "民生" 
      else:
        text_a = tokenization.convert_to_unicode(line[1])
        label = tokenization.convert_to_unicode(line[0])

      examples.append(InputExample(guid=guid, text_a=text_a, text_b=None, label=label))

    return examples

def main(_):
  tf.logging.set_verbosity(tf.logging.INFO)
  processors = {
      "cola": ColaProcessor,
      "mnli": MnliProcessor,
      "mrpc": MrpcProcessor,
      "xnli": XnliProcessor,
      "nico": NicoProcessor,

  }

        然后配置环境,运行run_classifier.py代码

export BERT_Chinese_DIR=/user/yuanquan/bert/chinese_L-12_H-768_A-12
export Nico_DIR=/user/yuanquan/data
python run_classifier.py \
  --task_name=nico \ #task_name 表示我调用的是什么处理类,这里需要修改成我们新的定义的demo
  --do_train=true \
  --do_eval=true \
  --data_dir=$Nico_DIR \
  --vocab_file=$BERT_Chinese_DIR/vocab.txt \
  --bert_config_file=$BERT_Chinese_DIR/bert_config.json \
  --init_checkpoint=$BERT_Chinese_DIR/bert_model.ckpt \
  --max_seq_length=128 \
  --train_batch_size=32 \
  --learning_rate=2e-5 \
  --num_train_epochs=3.0 \
  --output_dir=/tmp/Nico_output

train完之后,就可以得到fine tune的model文件,接下去进行测试

python run_classifier.py \
  --task_name=nico \
  --do_predict=true \
  --data_dir=$Nico_DIR \
  --vocab_file=$BERT_Chinese_DIR/vocab.txt \
  --bert_config_file=$BERT_Chinese_DIR/bert_config.json \
  --init_checkpoint=/tmp/Nico_output \
  --max_seq_length=128 \
  --output_dir=/tmp/Nico_output

(2)以自定义的数据为例

        假如我们输入的训练数据格式如下,第一列为相似度标签:

0,医保缴纳流程,养老保险缴费流程

1,医保怎么缴纳,医疗保险怎么缴费

        那么可以写一个如下的get_train_examples的函数。当然对于csv的处理,可以使用诸如csv.reader的形式进行读入。

def get_train_examples(self, data_dir):
    file_path = os.path.join(data_dir, 'train.csv')
    with open(file_path, 'r') as f:
        reader = f.readlines()

    examples = []
    for index, line in enumerate(reader):
        guid = 'train-%d'%index
        split_line = line.strip().split(',')
        text_a = tokenization.convert_to_unicode(split_line[1])
        text_b = tokenization.convert_to_unicode(split_line[2])
        label = split_line[0]
        examples.append(InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))

    return examples

同时对应判断句子相似度这个二分类任务,get_labels函数可以写成如下的形式:

def get_labels(self):
    reutrn ['0','1']

        在对get_dev_examples和get_test_examples函数做类似get_train_examples的操作后,便完成了对processor的修改。其中get_test_examples可以传入一个随意的label数值,因为在模型的预测(prediction)中label将不会参与计算。

        修改完成processor后,需要在在原本main函数的processor字典里,加入修改后的processor类,即可在运行参数里指定调用该processor。

processors = {
      "cola": ColaProcessor,
      "mnli": MnliProcessor,
      "mrpc": MrpcProcessor,
      "xnli": XnliProcessor, 
      "selfsim": SelfProcessor #添加自己的processor
  }

        之后就可以直接运行run_classsifier.py进行模型的训练。在运行时需要制定一些参数,一个较为完整的运行参数如下所示:

export BERT_BASE_DIR=/user/yuanquan/bert/chinese_L-12_H-768_A-12 #全局变量 下载的预训练bert地址
export MY_DATASET=/user/yuanquan/xnli #全局变量 数据集所在地址
python run_classifier.py \
  --task_name=selfsim \ #自己添加processor在processors字典里的key名
  --do_train=true \
  --do_eval=true \
  --dopredict=true \
  --data_dir=$MY_DATASET \
  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
  --max_seq_length=128 \ #模型参数
  --train_batch_size=32 \
  --learning_rate=5e-5 \
  --num_train_epochs=2.0 \
  --output_dir=/tmp/selfsim_output/ #模型输出路径

4. text-to-image 图像编码及文本找图或者图生文本    

        开头我们提到bert-as-service已经更新成了clip-as-service【1】,而clip模型(Contrastive Language-Image Pre-training)是由oai在2021年发布的一种多模态预训练神经网络模型,用于匹配图像和文本。‌ 该模型通过对比学习的方式进行预训练,将图像和文本映射到统一的向量空间中,使得模型能够直接在向量空间中计算图像和文本之间的相似性,无需额外的中间表示。CLIP模型的核心原理包括使用大量图像和文本的配对数据进行预训练,以学习图像和文本之间的对齐关系。它具有多模态学习的能力,能够同时理解图像和文本两种不同模态的信息,并在它们之间建立联系。‌

        所以我们完全可以使用clip-as-service建立一套通过文本查询图像的搜素引擎。接下来展示一下如何实现:

         使用 Totally Looks Like 数据集(也可以使用你自己的图像数据集)和 DocArray 包。DocArray 已作为上游依赖包含在 clip-client 中,所以无需单独安装。DocArray 是用于多模态数据的表示、传输、存储和检索。

        下载数据(也可以手动下载后解压加载):

from docarray import DocumentArray

da = DocumentArray.pull('ttl-original', show_progress=True, local_cache=True)

da.plot_image_sprites()

        编码图像,使用 python -m clip_server 启动服务器。假设服务器地址为 0.0.0.0:51000 并且使用 gRPC 协议。

from clip_client import Client

c = Client(server='grpc://0.0.0.0:51000')
da = c.encode(da, show_progress=True)

如果执行过慢的话,也可以使用已经编码好的版本:

from docarray import DocumentArray

da = DocumentArray.pull('ttl-embedding', show_progress=True, local_cache=True)

接下来就可以通过句子进行搜索,创建一个简单的提示,允许用户输入句子:”

while True:
    vec = c.encode([input('sentence> ')])
    r = da.find(query=vec, limit=9)
    r[0].plot_image_sprites()

一些文字找图片示例:

        也可以将上述程序的输入和输出进行交换,以实现图像到文本的搜索。具体来说,给定一个查询图像,找到最能描述该图像的句子。

        首先下载文本描述数据:

from docarray import Document, DocumentArray

d = Document(uri='https://www.gutenberg.org/files/1342/1342-0.txt').load_uri_to_text()
da = DocumentArray(
    Document(text=s.strip()) for s in d.text.replace('\r\n', '').split('.') if s.strip()
)

然后对文本进行clip模型编码:

from clip_client import Client

c = Client('grpc://0.0.0.0:51000')
r = c.encode(da, show_progress=True)

执行文本编码与图片编码的最相似计算,输出得分最高的文本内容

from docarray import DocumentArray

img_da = DocumentArray.load_binary('ttl-image')
for d in img_da.sample(10):
    print(da.find(d.embedding, limit=1)[0].text)

        从示例来看,受限于文本内容过少,得到的结果有些不靠谱,数据越丰富应该可以获得更可靠的结果输出。在这里主要就是了解下这种场景的原理,document array支持ANN vector search。

5. 参考材料

【1】clip-as-service

【2】bert fine-tune 实践

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

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

相关文章

使用库函数点亮一个LED灯

软件设计 STM32Gpio的介绍 如果想让LED0点亮,那么R12就要是高电平,LED0就要是低电平,也就是PF9就是低电平 F407系统主频要工作在168MHZ F103的话是工作在72mhz F429的话就180MHZ 接着我们就要使能Gpio的时钟,使能之后对GPIO相关…

ES7 -- ES13

1. ES7 – 2016 1. 数组的includes方法 数组中是否包含某个元素,返回值为boolean let arr [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; arr.includes(5); // true2. ** 幂次方 let res 2 ** 3; // 82. ES8 --2017 1. 字符串补全 基本使用 let str 123;str.padStart…

Django 请求配置

http请求配置 请求流程 urls.py配置 from first_app import viewsurlpatterns [path(admin/, admin.site.urls),path(test/,views.first_test), ] views.py配置 from django.shortcuts import render,HttpResponse# Create your views here. def first_test(request):prin…

Kubernetes 安装网络插件flannel报错Init:ImagePullBackOff,flannel下载镜像报错问题解决

Kubernetes1.28安装网络插件flannel,报错Init:ImagePullBackOff ,flannel安装下载镜像失败 问题 1.安装flannel kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml 2.flannel报错信息 执行查看安装…

Flutter 约束布局

配置插件依赖 设置组件大小 通过属性 childConstraints 实现 分别设置 约束布局一 和 约束布局二 大大小为:160 和 200 点击查看代码文件 class SummaryPageState extends State<SummaryPage1> {ConstraintId constraintId_1 = ConstraintId(ConstraintId_1);Constrain…

【GUI设计】基于Matlab的图像处理GUI系统(1),用matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于Matlab的图像处理GUI系统&#xff0c;用matlab实现。 本次内容主要分为两部分&a…

专题七_分治_快排_归并_算法专题详细总结

目录 分治 一、分治思想的概念 二、分治思想的步骤 1. 颜⾊分类&#xff08;medium&#xff09; 解析&#xff1a; 2. 快速排序&#xff08;medium&#xff09; 解析&#xff1a; 总结&#xff1a; 3. 快速选择算法&#xff08;medium&#xff09; 解析&#xff1a; …

【BurpSuite】Cross-site scripting (XSS 学徒部分:1-9)

&#x1f3d8;️个人主页&#xff1a; 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞&#x1f44d;收藏&#x1f497;支持一下哦 【BurpSuite】Cross-site scripting (XSS 学徒部分:1-9&#xff09; 实验一 Lab: Reflected XSS into HTML context with nothing…

maven手动导入本地仓库

maven手动导入本地仓库 1.在maven仓库下载对应的依赖 一定要把jar包下载到maven仓库的bin下 2.找到自己仓库的maven仓库下的bin目录cmd进去 在cmd窗口中输入以下命令&#xff1a;&#xff08;这里根据你的groupId、artifactId、version修改即可&#xff09; <!-- https:…

乱弹篇(53)丹桂未飘香

今天是2024年“秋分”节气&#xff0c;也是第7个中国“农民丰收节”&#xff0c;本“人民体验官”推广人民日报官方微博文化产品《文化中国行看丰收之美》。 截图&#xff1a;来源“人民体验官”推广平台 人民微博说&#xff1a;“春华秋实&#xff0c;岁物丰成。”又说&#…

dhtmlxGantt 甘特图 一行展示多条任务类型

效果如图: 后台拿到数据 处理之后如图: 含义: 如上图所示, 如果一行需要展示多个 需要给父数据的那条添加render:split属性, 子数据的parent为父数据的Id即可 切记 父数据的id 别为0 为0 时 会出现错乱 因为有些小伙伴提出分段展示的数据结构还是有点问题,下面展示一个完整…

机器人时代的“触觉革命”:一块小传感器如何颠覆你的认知?

你是否曾经想过,机器人也能像人类一样有“触觉”?不再是简单的机械操作,而是具备真正的感知能力,能够学会精细的任务。今天我想和你聊聊一种让机器人“长出触觉”的技术:一种小巧的触觉传感器,它的名字叫“AnySkin”。别看它小,它的潜力可一点都不小,或许能彻底改变我们…

Windows下如何定时执行自定义任务

目录 一.前言二.设置定时自动执行自定义任务 一.前言 本文环境是Windows11系统。 有时候我们希望能够在Windows下定时自动执行自定义任务&#xff0c;比如检测数据库服务的状态。那在Windows下怎么定时自动执行自定义任务&#xff0c;这篇文章介绍一种方法。 二.设置定时自动…

NLP 主流应用方向

主流应用 文本分类文本匹配序列标注生成式任务 应用细分 文本纠错话者分离 本质为文本分类任务数字归一化 实现数字映射&#xff0c;提高内容可读性 如将一九九九转1999

AI基础 L26 Introduction to Automated Planning - II

ADL Action Description Language (ADL) is a richer language than STRIPS. It allows for • Positive and negative literals in states • The open world assumption • Quantified variables in goals as well as conjunctions and disjunctions • Conditional effects …

Web_php_include 攻防世界

<?php show_source(__FILE__); echo $_GET[hello]; $page$_GET[page]; while (strstr($page, "php://")) { 以是否检测到php://为判断执行循环$pagestr_replace("php://", "", $page);//传入空值&#xff0c;替换 } include($page); ?&g…

226. 翻转二叉树之多种解法(递归法、深度优先(迭代法)、广度优先【层序遍历】)

文章目录 226. 翻转二叉树题外话思路递归法迭代法:深度优先遍历层序遍历&#xff1a;广度优先遍历拓展总结 226. 翻转二叉树 226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;r…

【JAVA开源】基于Vue和SpringBoot的在线文档管理系统

本文项目编号 T 038 &#xff0c;文末自助获取源码 \color{red}{T038&#xff0c;文末自助获取源码} T038&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

单片机原理及应用详解

目录 1. 什么是单片机&#xff1f; 2. 单片机的基本组成 3. 单片机的工作原理 4. 常见的单片机分类 5. 单片机的应用领域 6. 单片机开发流程 7. 单片机开发中的常见问题及解决方案 8. 单片机的未来发展趋势 9. 总结 1. 什么是单片机&#xff1f; 单片机&#xff08;Mi…

美食共享圈:Spring Boot校园周边美食平台

第二章 系统分析 2.1 可行性分析 可行性分析的目的是确定一个系统是否有必要开发、确定系统是否能以最小的代价实现。其工作主要有三个方面&#xff0c;分别是技术、经济和社会三方面的可行性。我会从这三个方面对网上校园周边美食探索及分享平台进行详细的分析。 2.1.1技术可行…