90后技术哥哥“笑了”,65岁退休怕啥,上数字替身!微调后“我”又变聪明了
文中参考文档点击阅读原文打开, 同时推荐2个学习环境:
1、懒人Docker镜像, 已打包200+插件:《最好的PostgreSQL学习镜像》
2、有web浏览器就能用的云起实验室: 《免费体验PolarDB开源数据库》
3、PolarDB开源数据库内核、最佳实践等学习图谱: https://www.aliyun.com/database/openpolardb/activity
微调后, 我的数字人变聪明了!90后,咱有数字替身,提前退休指日可待
背景
系列文章:
《微调后, 我的数字人变聪明了 》 《我的数字人:投喂中》 《英伟达暴跌1.5万亿,苹果笑了!低配MBP流畅运行LLama3:8b,简单到不需要教程! 》
以前觉得AI笨笨的, 经过近期的折腾, 特别是在找到正确的微调姿势后, 突然发现它变聪明了. 第一次感受到AI带来的威胁.
不过有危就有机, 在出生率逐渐走低的背景下, 未来的劳动力、养老金来源都是巨大的挑战, 所以要搞AI嘛, 想象一下有个数字替身给你工作(哪怕是能给你降低50%工作量)是不是很爽? 所以说掌握先进生产力工具本身就像掌握信息差一样, 放在任何时代都是非常重要的. 企业不是要率先AI化, 而是要先将员工使用先进生产力工具的能力提升起来, 才能赢得未来. 我去高校给同学们分享的观点也非常明确, 这5点非常重要! 《德说-第227期, 致大学生的入学第一课, 如何从大一开始就为就业做正确的事情?》 :
行业/赛道 思维模型 专业能力及先进生产力工具 影响力(连接) 战绩
90后也许会是第一批享受数字替身的, 怕什么65岁退休.
AI的优势:
能微调, 学习速度快 不用休息 触手可得, 现在一般的笔记本都能跑大模型. 或者调api. 总之使用门槛很低, 非常简单.
两种常用微调手段:
Prompt tuning 提示词微调(不需要训练), 本篇重点. Fine tuning (需要训练), 下一篇介绍.
一、提示词微调之前
测试问题:
请问PostgreSQL rum和gin索引的区别是什么?
先测试mistral:7b和gemma2:9b的输出如下. 都不知道rum是什么, 胡编乱造.
1 mistral:7b
rum (Rule-Based Optimizer) 和 GIN (Generalized Inverted Index) 在 PostgreSQL 中是两个相对独立的概念,但它们之间有密切的关联。
rum 是 PostgreSQL 优化器的一部分,负责根据查询并行度、表大小、统计信息等因素选择最佳执行计划(explain plan)。GIN 索引则是 PostgreSQL 提供的一种特殊索引类型,主要用于支持快速执行包含左边前缀匹配的查
询。
在 GIN 索引中,B-tree 索引结合了 GiST (Generic Search Tree) 索引的功能,其中 GiST 是用来处理多维区域查询和文本搜索的索引类型。GIN 索引主要使用 GIST 技术来实现在 B-tree 基础之上对多值属性执行快速范围
扫描。
GIN 索引最常见的应用场景是全文检索和区间查询,比如 SQL 语句中使用了 LIKE 操作符或者 BETWEEN 关键字。GIN 索引能够大大提高这类查询的性能,因为它可以在索引上快速地过滤出符合条件的记录。
总的来说,rum 是 PostgreSQL 优化器的一部分,负责选择执行计划;GIN 索引则是 PostgreSQL 提供的一种特殊索引类型,可以支持快速执行包含左边前缀匹配的查询。
2 gemma2:9b
在 PostgreSQL 中,GIN 和 RUM 都是用于处理文本搜索的特殊索引类型,但它们各有优缺点:
**GIN (Generalized INdex)**:
优点:
通用性强: 支持多种数据类型,包括字符串、数组、几何图形等。 灵活度高: 可以自定义比较函数来实现特定类型的搜索逻辑。 成熟稳定: 已经广泛使用且经过充分测试。 缺点:
性能较低: 对于大型文本数据集,GIN 的查询性能可能不如 RUM 高。 内存占用大: 为了高效地查找匹配项,GIN 需要在内存中存储大量数据。
RUM (Regexp Unique Match):
优点:
高性能: 专为正则表达式搜索优化,对大型文本数据集具有较高的查询效率。 低内存占用: RUM 使用更精简的数据结构,因此内存占用比 GIN 小。 缺点:
功能受限: 仅支持正则表达式搜索,不能用于其他类型数据的索引。 灵活度低: 无法自定义比较函数,只能使用内置的正则表达式引擎。
总结:
如果需要对多种数据类型进行搜索或自定义比较逻辑,可以选择 GIN。 如果主要进行基于正则表达式的文本搜索,且需要高性能和低内存占用,可以选择 RUM。
选择建议:
确定您的主要搜索需求是什么,是多类型数据搜索还是文本搜索? 评估数据规模的大小,如果数据量很大,RUM 的高性能优势会更加明显。 考虑内存资源的限制,RUM 的内存占用比 GIN 小。
希望以上解释能够帮助您理解 PostgreSQL rum和gin索引的区别!
二、Prompt tuning 上场
接下来用到我github这篇文章作为prompt, 看看回答有没有改观.
https://github.com/digoal/blog/tree/master/201907/20190706_01.md
提取文章标题作为quesion:
## PostgreSQL rum 索引结构 - 比gin posting list|tree 的ctid(行号)多了addition info
提取文章的完整内容作为answer.
注意: 每种模型的提示参数不一样, 请参考对应的说明
https://www.promptingguide.ai/models/mistral-7b https://apeatling.com/articles/part-2-building-your-training-data-for-fine-tuning/
mistral 提示参数
https://ollama.com/library/mistral
<s>[INST] 相关的问题1 [/INST] 答案1 </s>[INST] 请问PostgreSQL rum和gin索引的区别是什么? [/INST]
gemma 提示参数
https://ollama.com/library/gemma2
<start_of_turn>user
相关的问题1 <end_of_turn>
<start_of_turn>model
答案1 <end_of_turn>
<start_of_turn>user
请问PostgreSQL rum和gin索引的区别是什么? <end_of_turn>
<start_of_turn>model
1 mistral:7b 微调后
ollama run mistral:7b
输入prompt tunning + prompt
<s>[INST] ## PostgreSQL rum 索引结构 - 比gin posting list|tree 的ctid(行号)多了addition info [/INST] https://github.com/digoal/blog/tree/master/201907/20190706_01.md 内容贴到这里 </s>[INST] 请问PostgreSQL rum和gin索引的区别是什么? [/INST]
PostgreSQL rum(Reverse-Index with Additional Information)索引和GIN(Generalized Inverted Index)索引的主要区别在于:
结构:GIN索引以TREE数据结构存储,查询时从根节点开始遍历到叶子节点的行号。RUM索引以倒排表的形式存储,每个单词或者短语对应一个条目,其中包含行号和附加信息(例如这一行包含了多少次这个单词/短语,或者
时间戳等)。功能:GIN索引支持的操作主要为包含、相交等,对于需要排序的操作(如ranking),需要额外的计算和扫描heap tuples。RUM索引则可以提供排序的结果,例如根据时间戳或者词频进行排序。 效率:由于GIN索引需要在运行时构建树,并且对于某些查询可能需要遍历整个树,因此可能会比RUM索引慢一点。RUM索引预先构建好了倒排表,使得查询速度更快。 应用:GIN索引主要用于全文搜索和统计分析,如对文本数据进行词频统计或者关键字匹配等。RUM索引可以用于时间序列数据的查询和排序,例如根据时间戳进行排序、统计、聚合等操作。 开源:RUM是PostgreSQL社区提供的一个扩展,需要手动安装和使用。GIN则是PostgreSQL内置的索引方案。
2 gemma2:9b 微调后
PostgreSQL RUM 和 GIN 索引的区别
GIN 和 RUM 都是 PostgreSQL 中用于全文检索的倒排索引,但它们在结构和功能方面存在一些关键区别:
1. 结构:
GIN (Generalized INdex): 存储索引字段 Entry 的TREE结构。每个Entry对应一个数据范围,末端是Posting list|tree, 存储对应的ctid(行号)。额外信息不存储。 RUM (Rank-aware Unique Matching): 在 Posting list|tree 的每一个 ctid 后面添加额外的属性信息(例如目标词个数、时间戳等)。这些额外的信息允许 RUM 进行更复杂的检索和排序操作。
2. 功能:
GIN: 擅长于包含、相交等简单的搜索操作,但对于 ranking 排序、phrase search 和基于其他字段的排序效率较低。 RUM: 支持更加丰富的检索功能,例如: Ranking sort: 根据目标词个数或其他额外属性进行排名。 Phrase search: 支持根据词语顺序查找短语。 Timestamp based ordering: 支持根据时间戳排序结果。
3. 效率:
GIN: 对于简单的包含、相交查询,GIN 的效率较高。但对于 ranking 排序等操作,需要额外的 heap scan, 效率较低。 RUM: 通过在 Posting list|tree 中存储额外信息,可以避免额外的 heap scan,提高了排序和排名等操作的效率。
4. 应用场景:
GIN: 适用于简单的全文检索场景,例如查找包含特定词语的数据。 RUM: 适用于需要进行复杂检索和排序场景,例如搜索引擎、推荐系统等。
总而言之,选择合适的索引类型取决于具体的应用场景。如果只需要简单的包含、相交查询,可以使用 GIN 索引;如果需要进行排名、短语搜索或基于其他字段的排序,则建议使用 RUM 索引。
三、附
以下两个python脚本结果还不太对, 和ollama里面运行的结果有差别, 回头再看看啥原因.
mistral.py
import ollama
import sys def main():
# Get the file path from the command line argument
if len(sys.argv) < 3:
print("Usage: python script.py [prompt] [file1] [file2] ... ")
sys.exit(1)
"""Reads files, extracts first line as promptN, remaining content as answerN, and formats the output."""
prompt = sys.argv[1] # Get the user-provided prompt
file_prompts_answers = []
for i in range(2, len(sys.argv)): # Iterate over file paths starting from the second argument
try:
with open(sys.argv[i], 'r') as f:
promptN = f.readline().strip() # Read and strip the first line
answerN = f.read().strip() # Read the remaining content
file_prompts_answers.append((promptN, answerN))
except FileNotFoundError:
print(f"Error: File '{sys.argv[i]}' not found.")
output_string = f"<s>"
for i, (promptN, answerN) in enumerate(file_prompts_answers):
output_string += f"[INST] {promptN} [/INST] {answerN} "
output_string += f"</s>[INST] {prompt} [/INST]"
output = ollama.generate(
model="mistral:latest",
prompt=output_string
)
print(output['response'])
if __name__ == "__main__":
main()
gemma2.py
import ollama
import sys def main():
# Get the file path from the command line argument
if len(sys.argv) < 3:
print("Usage: python script.py [prompt] [file1] [file2] ... ")
sys.exit(1)
"""Reads files, extracts first line as promptN, remaining content as answerN, and formats the output."""
prompt = sys.argv[1] # Get the user-provided prompt
file_prompts_answers = []
for i in range(2, len(sys.argv)): # Iterate over file paths starting from the second argument
try:
with open(sys.argv[i], 'r') as f:
promptN = f.readline().strip() # Read and strip the first line
answerN = f.read().strip() # Read the remaining content
file_prompts_answers.append((promptN, answerN))
except FileNotFoundError:
print(f"Error: File '{sys.argv[i]}' not found.")
output_string = f""
for i, (promptN, answerN) in enumerate(file_prompts_answers):
output_string += f"<start_of_turn>user\n{promptN} <end_of_turn>\n<start_of_turn>model\n{answerN} <end_of_turn>\n"
output_string += f"<start_of_turn>model\n{prompt} <end_of_turn>\n"
output = ollama.generate(
model="gemma2:9b",
prompt=output_string
)
print(output['response'])
if __name__ == "__main__":
main()
参考
https://www.promptingguide.ai/models/mistral-7b
https://apeatling.com/articles/part-2-building-your-training-data-for-fine-tuning/
https://ollama.com/library/mistral
https://ollama.com/library/gemma2
本期彩蛋-配图为cuug陈老师,恭喜 CUUG获得PostgreSQL数据库认证与培训合作伙伴
文章中的参考文档请点击阅读原文获得.
欢迎关注我的github (https://github.com/digoal/blog) , 学习数据库不迷路.
近期正在写公开课材料, 未来将通过视频号推出, 欢迎关注视频号: