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

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

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.mfbz.cn/a/881786.html

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

相关文章

鸿蒙【项目打包】- .hap 和 .app;(测试如何安装发的hap包)(应用上架流程)

#打包成.hap需要用到真机 原因是:只有用上了真机才能在项目中配置 自动签名 #步骤: ##第一步:选择真机->选择项目结构->点Sigining Configs(签名配置) ##第二步:勾选Automatically generate signature(自动签名)->点击ok ##第三步:点击构建->点击 …

接口幂等性和并发安全的区别?

目录标题 幂等性并发安全总结 接口幂等性和并发安全是两个不同的概念,虽然它们在设计API时都很重要,但侧重点不同。 幂等性 定义:幂等性指的是无论对接口进行多少次相同的操作,结果都是一致的。例如,HTTP的PUT和DELE…

QT快速安装使用指南

在Ubuntu 16.04上安装Qt可以通过多种方式进行。以下是使用Qt在线安装程序和apt包管理器的两种常见方法: 方法一:使用Qt在线安装程序 下载Qt在线安装程序 访问Qt官方网站:Try Qt | Develop Applications and Embedded Systems | Qt找到并下载…

Hadoop的安装

文章目录 一. 到Hadoop官网下载安装文件hadoop-3.4.0.tar.gz。二. 环境变量三. 配置 一. 到Hadoop官网下载安装文件hadoop-3.4.0.tar.gz。 随后点击下载即可 由于Hadoop不直接支持Windows系统,因此,需要修改一些配置才能运行 二. 环境变量 三. 配置 进…

arcgisPro地理配准

1、添加图像 2、在【影像】选项卡中,点击【地理配准】 3、 点击添加控制点 4、选择影像左上角格点,然后右击填入目标点的投影坐标 5、依次输入四个格角点的坐标 6、点击【变换】按钮,选择【一阶多项式(仿射)】变换 7…

VisualPromptGFSS

COCO-20 i ^i i太大,不建议复现

大学生必看!60万人在用的GPT4o大学数学智能体有多牛

❤️作者主页:小虚竹 ❤️作者简介:大家好,我是小虚竹。2022年度博客之星🏆,Java领域优质创作者🏆,CSDN博客专家🏆,华为云享专家🏆,掘金年度人气作者&#x1…

14年数据结构

第一题 解析: 求时间复杂度就是看程序执行了多少次。 假设最外层执行了k次,我们看终止条件是kn,则: 有, 内层是一个j1到jn的循环,显然执行了n次。 总的时间复杂度是内层外层 答案选C。 第二题 解析: 一步一…

基于协同过滤+python+django+vue的音乐推荐系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤pythondjangovue…

【前端】ES6:Class语法和Class继承

文章目录 1 Class语法1.1 类的写法1.2 getter与setter1.3 静态属性和静态方法 2 Class继承 1 Class语法 1.1 类的写法 class Person {constructor(name,age){this.name name;this.age age;}say(){console.log(this.name,this.age)} } let obj new Person("kerwin&quo…

双击热备 Electron网页客户端

安装流程: 1.下载node.js安装包进行安装 2.点击Next; 3.勾选,点击Next; 4.选择安装目录 5.选择Online 模式 6.下一步执行安装 。 7.运行cmd,执行命令 path 和 node --version,查看配置路径和版本 8.Goland安装插件node.js 9.配置运行…

【C#】内存的使用和释放

在 C# 中,内存管理主要是由 .NET 的垃圾回收器(Garbage Collector, GC)自动处理的。然而,了解如何正确地使用和释放内存对于编写高效且可靠的代码非常重要。以下是一些关键点和最佳实践: 1. 内存分配 托管资源&#x…

【我的 PWN 学习手札】House Of Karui —— tcache key 绕过手法

目录 前言 一、House of Karui 二、测试与模板 前言 早期版本的 tcachebin 由于毫无保护,导致攻击利用非常容易,成为重灾区。tcache dup,也即 tcachebin 中的 double free 利用手法,是攻击者常常选用的攻击方式。然而&#xf…

计算机网络(八) —— Udp协议

目录 一,再谈端口号 1.1 端口号 1.2 netsta命令 二,UDP协议 2.1 关于UDP 2.2 Udp协议格式 2.3 Udp协议特点 2.4 Udp的缓冲区 一,再谈端口号 http协议本质是“请求 - 响应”形式的协议,但是应用层需要先将数据交给传输层&…

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

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

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking/手势跟踪)

前言 最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能,但是遇到了如下问题: 在Unity里面没法串流调试眼动追踪功能,根本获取不到Device,只能将整个场景build成APK,安装到头盔里,才能在…

【机器学习(七)】分类和回归任务-K-近邻 (KNN)算法-Sentosa_DSML社区版

文章目录 一、算法概念二、算法原理(一)K值选择(二)距离度量1、欧式距离2、曼哈顿距离3、闵可夫斯基距离 (三)决策规则1、分类决策规则2、回归决策规则 三、算法优缺点优点缺点 四、KNN分类任务实现对比&am…

数据结构--链表

文章目录 链表1.链表的特点2.链表的基础操作2.1增2.2删 3.自定义链表3.1 自定义单向链表3.2 自定义双向链表 链表 链表是一种常见的数据结构,由一系列节点构成,每个节点包含当前节点的数据和一个指针(单向链表)或者两个指针(双向链表),链表是…

渗透测试入门学习——php表单form与POST、GET请求练习

最终效果&#xff1a; 必填项为空报错提示&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>php表单练习</title> </head> <body> <?php//php中的…

Aegisub字幕自动化及函数篇(图文教程附有gif动图展示)(一)

目录 自动化介绍 bord 边框宽度 随机函数 fsvp 随机颜色 move 自动化介绍 自动化介绍:简单来说自动化能让所有字幕行快速拥有你指定的同一种特效 对时间不同的行应用相同的效果 只要设计好一个模板&#xff0c;然后让所有行都执行这个模板上的特效就好了 首先制作模板行…