本期文心开发者说邀请到飞桨开发者技术专家谢杰航老师,分享如何利用AI技术构建风景园林行业的植物知识科普系统,接着还介绍了大模型应用的基本技术流程框架,多模态特征提取以及使用向量数据库的优势,使用飞桨星河社区运行向量数据库的方法,以及创建向量数据库、数据表和embedding操作的过程等。此外,老师还介绍了文心大模型的重要任务,即为不同用户群体生成个性化版本的内容输出。
点击链接 立刻体验:
基于文心大模型的儿童植物识别科普系统
大模型与植物相遇
创新植物科普路径
所有的应用都值得用大模型进行重构,但是在实际过程中,大模型落地可能会存在成本问题。如何去评估大模型,以及这个应用是否值得用大模型去做,我们要认识到大模型能够为应用带来什么样的创新点,能够带来什么样的价值。所以我们在做植物识别科普应用的时候,便对应用市场上的植物识别App做了调研。我们发现目前的同类App都有两个问题,一是只包含了很简单的识别功能,用户扫一下某种植物,App只会输出是哪个品种,没有对识别结果进一步介绍;还有另外一类App,对植物的解释是简单地生搬硬套教科书,专业术语众多,内容缺乏趣味性。
关于植物的教科书内容包含大量专业术语,例如玄参科植物,大部分非植物专业的人群是不知道这些术语的。为了增强内容的趣味性,达到科普的目的,我们使用文心大模型对输出结果进行重写,让输出的植物介绍更加口语化,适应不同群体的阅读需求,吸引大家关注植物、了解植物,让用户产生对植物知识的学习兴趣,这就是我们做这个应用的出发点。如果你是其他行业的,也可能会面临同样的问题。比如产品的说明书,现在很多产品说明书大多晦涩难懂,或者用户提问的时候,客服常常答非所问。这种情况就符合大模型的应用场景,可以根据不同的用户画像,给用户回答的时候,让这个回答更加的自然、更加的流畅、更加的口语化,让用户容易理解接受。
识别植物不简单
大模型应用的基本技术流程框架
下图是语言大模型应用的基本技术流程框架。
首先,用户拿手机拍下植物,输入一张植物的图像,我们需要对这个图像进行一个特征提取。特征提取就是把图像变成一个高维向量。我们把这个植物特征输入向量数据库里面做向量比对计算。如果数据库里面已经有相似的植物向量,就把植物名和植物知识直接给到文心大模型做文本重写最后输出文本。
如果输入植物图像是全新的图片,其特征在数据库中未有相似结果,我们把这个图像输入到公版的分类模型,或者输入到自己训练的分类模型做植物图像识别,然后将特征向量和识别结果插入数据库。下次用户上传相似图片的时候,植物特征与前面用户的图像特征具有一定相似度的,那么就可以不通过分类模型,直接通过向量比对的方法确定植物种类。这个方案不需要重复调用分类模型接口,推理整体耗时得到大幅降低。
文心大模型的主要任务是将复杂、专业或书面化的知识转化为易于理解,同时能引起用户阅读兴趣的内容。文心大模型生成植物科普内容后,我们通过向量数据库构建缓存,以便在用户下次读取类似图片时,通过特征抽取和向量对比,快速找到并输出相同的内容,而无需再次调用文心大模型。整个技术架构核心由向量数据库、知识库和文心大模型构成。因此,如果我们要开发一个大模型应用,只要做好这三个技术版块,那么应用的后端也就基本完成了。下面就对每个部分进行详细讲解。
特征提取
首先是特征提取,我们使用了PaddleNLP中内置的CLIP多模态模型提取图像特征向量,提取后的特征向量既可用于相似度比较做图像分类,也可用于如图文搜索、图像二次创作生成等其他多模态应用。如果用小模型,比如ResNet50也可以做特征提取,但是它提取的向量只能做单一的任务,不能做其他跨模态任务。所以在软硬件成本条件允许的情况下,比较推荐大家尽可能用一些多模态模型来做特征提取,这能为之后的应用开发提供数据基础。
这一步可以简单通过调用paddlenlp.transformers的CLIPProcessor类,对图片进行特征向量提取,提取后得到一组由浮点数组成的特征向量。
特征提取
from PIL import Image
import requests
from paddlenlp.transformers import CLIPProcessor, CLIPVisionModelWithProjection
model = CLIPVisionModelWithProjection.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
def extractFeatures(image: Image.Image):
inputs = processor(images=image, return_tensors="pd")
outputs = model(**inputs)
imageEmbeds = outputs.image_embeds
imageEmbedding = imageEmbeds.numpy()
return imageEmbedding
向量数据库解决方案
在本项目中,我们选择Milvus作为向量数据库。Milvus是用Go语言编写的,它天然支持分布式和高并发的特性,在这方面相比其他数据库具有一定优越性。此外,它与飞桨的融合度也很高,星河社区中已经有一些使用Milvus的案例可供我们更好地学习和上手实践。
为什么我们要使用向量数据库而不是直接使用分类模型来进行植物识别呢?
它的第一个好处是向量数据库可以存储、管理和检索特征向量。特征向量除了可以用于相似度比较之外,还能为文—图搜索、图—图搜索、图文生成,图像生成等多模态应用提供数据基础。
第二个好处在于其速度快。深度学习模型推理过程较为耗费GPU资源。在一般情况下,采用相似度计算的方法得到图片分类,计算速度会更快,并且可以全程使用CPU进行计算,而无需依赖GPU,从而节约了成本。
第三个优势在于具有较强的泛化能力。在面对识别准确率下降和罕见样本的情况时,基于深度学习模型的解决方案通常需要重新训练或微调模型,需要较高的时间和算力成本。相比之下,采用向量数据库的方案,可以通过添加若干正例图片到数据库中,从而快速有效地提高识别精度。
创建向量数据库
接着介绍Milvus向量数据库的创建操作。下面将用milvus轻量化版本做部署演示。首先引入milvus.default_server将它启动,连接到数据库后,打印数据库的版本确定启动成功后,创建一个命名为plant的数据库以及同名的集合(数据表在Milvus里面被称为集合)。plant的集合里包含了plant_id自增字段,记录数据库内的数据量。plant_name是植物名称字段,plant_info是对植物的介绍信息字段,字符串类型数据通过向量数据库存储,可以免去跨多个数据库操作的过程。embeddings向量存储字段,它的数据维度是512。最后通过CollectionSchema将fileds封装起来,通过调用Collection函数创建集合。
启动并创建数据库
from milvus import default_server
from pymilvus import connections, utility, db
启动向量数据库
default_server.start()
检查是否连接成功
connections.connect(host='127.0.0.1', port=default_server.listen_port)
print("Milvus version:", utility.get_server_version())
创建数据库
database = db.create_database("plant")
db.using_database("plant")
创建数据库(集合)
from pymilvus import Collection, CollectionSchema, FieldSchema, DataType
# 定义集合名
collection_name = "plant"
# 定义数据列
plantId = FieldSchema(
name = "plant_id",
dtype = DataType.INT64,
is_primary = True,
auto_id = True,
)
plantName = FieldSchema(
name = "plant_name",
dtype = DataType.VARCHAR,
max_length = 200,
)
plantInfo = FieldSchema(
name = "plant_info",
dtype = DataType.VARCHAR,
max_length = 10000,
)
plantEmbeddings = FieldSchema(
name="embeddings",
dtype=DataType.FLOAT_VECTOR,
dim=512
)
# 创建schema
schema = CollectionSchema(
fields=[plantId, plantName, plantInfo, plantEmbeddings],
description="plant embeddings database",
enable_dynamic_field=True
)
# 创建数据集合
collection = Collection(
name=collection_name,
schema=schema,
using='default',
shards_num=2
对图像的特征向量进行相似度计算,需要对embeddings字段做索引。我们这里用的是L2(欧氏距离计算方法),索引的类型选择IVF-FLAT类型。如果是真实业务场景,用户量、并发量、数据量较大的情况下,建议使用IVFSQ8对向量数据进行压缩,它的存储成本更低,计算速度更快,内存占用更少。“nlist”是聚合的数量,一般设置固定,数量越大,内存的消耗成本越高。创建索引后,将集合数据加载到内存中。
创建索引
index_params = {
"metric_type":"L2",
"index_type":"IVF_FLAT",
"params":{"nlist":1024}
}
collection = Collection("plant")
collection.create_index(
field_name="embeddings",
index_params=index_params
)
utility.index_building_progress("plant")
# 加载集合
collection.load()
下一步是向量检索,即相似度比对计算。假设V1为图片1的向量,V2是向量数据库内的向量,计算这两个向量的相似度,当高度相似时可以直接输出V2对应的plant_name作为V1的识别结果。具体代码操作是将V1向量输入collection.search函数,Milvus自动计算出与V1相似度最高向量结果V2,最终输出植物名、介绍和相似度结果。
向量检索(相似度比对)
import numpy as np
search_params = {
"metric_type": "L2",
"ignore_growing": False,
"params": {"nprobe": 10}
}
def searchDb(embeddings: np.ndarray):
results = collection.search(
data=embeddings,
anns_field="embeddings",
param=search_params,
limit=1,
expr=None,
output_fields=['plant_name', "plant_info"],
consistency_level="Strong"
)
return results[0][0].entity.get('plant_name'), results[0][0].entity.get('plant_info'), results[0].distances[0]
当相似度较低时要借助其他小模型,或者是百度云植物识别的API辅助判断。此外,有能力的开发者和机构可以将该模块替换为私有植物图像分类模型和植物知识库。以公版模型接口为例,用户上传向日葵的图片,然后给用户返回相对应的植物名称和简介。
图像识别
from aip import AipImageClassify
from io import BytesIO
from PIL import Image
def plantRec(image: Image.Image):
bytesIO = BytesIO()
img.save(bytesIO, format='PNG')
client = AipImageClassify(BDAPPID, BDAK, BDSK)
options = {
"baike_num": 1
}
result = client.plantDetect(bytesIO.getvalue(), options)
name = result["result"][0]["name"]
info = result["result"][0]["baike_info"]["description"]
return name, info
接下来对这个模块进行简单封装,例如用户提供04.jpg图像文件,对输入图像进行特征提取后得到一组512维的向量。通过前面封装好的searchDB函数在数据库中找相似的向量,得到一个检索结果相似度。如果相似度较高,直接返回到plant_name和plant_info。如果数据库没有相似的向量,则请求公版模型识别,同时将结果存入向量数据库中用于日后数据比对,节省下一次相似数据请求识别返回的时间。
个性化定制植物科普内容
让不同人群重新认识花草
在本项目中文心大模型的任务是根据不同的用户画像,输出不同版本的植物介绍,对植物科普内容进行定制化输出。这一步骤使用到ERNIE Bot SDK接口,飞桨星河社区为每位开发者提供了100万tokens的免费调用额度。
基本流程如下,引入ERNIE Bot的SDK,配置token,这一步有个重点概念叫prompt template,即做好的prompt模版。在模板中输入用户画像、需要介绍的植物、语言风格要求、参考材料给大模型,文心大模型可以为prompt template生成个性化定制内容,输出结果给前端用户。(视频 最终效果演示)
文心大模型生成定制化内容
import erniebot
erniebot.api_type = "aistudio"
erniebot.access_token = ERNIETOKEN
templatePrompts = """
作为一名植物科普员,你将要写一份面向{role}的植物科普内容,介绍的植物是{plant}。
为了让孩子们更好地了解{plant},请提供一份轻松明快、通俗易懂的介绍内容。
你可以从{plant}的外形、生长环境、果实特点等方面入手,让孩子们对这种植物有更深入的了解。
同时,你也可以参考一些相关的图片、视频或其他资料,丰富孩子们的知识,提高他们的学习兴趣。
请注意,你的介绍语言生动形象,让孩子们愿意听、记得住,并且能够对{plant}产生兴趣和好奇心。
为了你的内容准确无误,请参考以下材料:{info}。开头不要有标题,内容最后不要出现参考文献。
""".format(role=role, plant=plantName, info=plantInfo)
response = erniebot.ChatCompletion.create(
model="ernie-bot",
messages=[{"role": "user", "content": templatePrompts}]
)
print(response.result)
视频效果演示
飞桨开发者技术专家谢杰航老师,他为大家带来如何用文心大模型助力实现植物种类的识别,以及如何用AI技术构建风景园林行业的一个植物知识科普系统。同时他也在直播中讲解了创作过程当中的代码和步骤,帮助大家更好理解大模型应用开发的相关知识。想要了解技术详情可加入文心开发者说课程观看回放:飞桨AI Studio星河社区-人工智能学习与实训社区
其他领域开发者也可以根据不同的行业特点制作不同的prompt template,应用大模型进行个性化定制。希望大家在飞桨星河社区里面去学习更多大模型的知识,制作更多基于大模型的原生应用。
相关阅读
飞桨星河社区项目链接:飞桨AI Studio星河社区项目
文心开发者说课程:飞桨AI Studio星河社区-人工智能学习与实训社区
关注【飞桨PaddlePaddle】公众号
获取更多技术内容~