MoreRSS

site icondata4fun | 小数据不简单修改

在这里,我们聊聊数据,聊聊AI,聊聊个人成长,有趣的,简单的,快乐的
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

data4fun | 小数据不简单的 RSS 预览

AI 新手村:CLIP

2025-06-19 10:12:10

2021 年 OpenAI 在推出 1750 亿参数的 GPT-3 模型的时候,也推出了 120 亿参数的 DALL·E模型和几亿参数的 CLIP 模型,这两个模型都是多模态模型(不仅可以处理文本还可以处理图片)。

然而,这两者的类型和应用场景有所不同。DALL·E模型是生成式模型,它学习数据的分布并能生成新的数据样本,与 GPT 系列异曲同工。而 CLIP 模型则属于判别式模型,它旨在学习数据之间的区分边界,主要用于分类和判断,但不能生成新样本。具体来说,DALL·E模型的核心功能是根据文本生成图像,常见于封面设计等场景;CLIP 模型则主要用于计算文本与图像的相似度,广泛应用于图像搜索和文案推荐。

CLIP

CLIP 是一种多模态模型,它通过对比学习来对齐文本和图像,也就是把文本和图像映射到同一个空间中,比如提到“狗”这个文本的时候,通过 embedding 对应高维空间的一个点,而提到一个包含有狗的图像的时候,通过 embedding 也会对应同一个空间的点,CLIP 的目标是让这两个对应的点尽可能接近。

CLIP的训练

CLIP 模型由图像编码器(通常是 ViT 或 ResNet)和文本编码器(Transformer)组成,在训练这个模型的时候,图像编码器负责把一张图片映射到空间中的某一点,文本编码器负责把一段文字映射到空间中的某一点。每次训练拿出 n 张图片和对应的文字,n 张图片丢给图像编码器产出 In,n 段文字丢给文本编码器产出 Tn,我们定义损失函数为对应的(In,Tn)要越像越好,也就是内积相乘越大越好,对应的就是图中蓝色部分。而其余部分则希望它们的相似度尽可能低,通过内积值越接近 0 来表示(图中灰色部分)。

CLIP 模型训练

CLIP的推理

在使用 CLIP 模型的时候,我们给出几段文字和一张图片,CLIP 模型会计算图像嵌入与每一段文本嵌入在共享空间中的相似度(内积值),并输出与图像最接近的文本(即内积值最大的文本)。

同理,我们也可以给出多张图片和一段文字描述,从而得到与该文字描述最接近的图片。例如,知名的图片网站 Unsplash 就是利用 CLIP 模型实现了其全站图片检索功能。

CLIP 推理

CLIP的优缺点

CLIP 模型以其快速的计算速度和对不同类型图片内容出色的泛化识别能力而著称。然而,它的主要缺点在于对图像中细节的识别能力相对较弱。例如,在以下以图搜图的场景中,将一张正在缫丝的图片传递给不同模型时,CLIP 模型可能仅能捕捉到这是一种 “手工艺活动”,而无法识别出具体的精细缫丝过程,这与一些更专业的模型DINO-v2 和 BLIP2有所不同。

CLIP和其他模型的对比

CLIP 实战演示

我们将选择一个本地图片文件夹,遍历目录下所有图片并通过 CLIP 建立 Embedding。然后,通过一段文本或一张图片进行检索查询,找出最相似的前 5 张图片。

from sentence_transformers import SentenceTransformer
import random
import glob,os
from PIL import Image
import matplotlib.pyplot as plt
#图片目录
image_folder = 'xxx/xx'
# 使用CLIP模型构建特征
def generate_clip_embeddings(images_path, model):

 image_paths = glob.glob(os.path.join(images_path, '**/*.jpg'), recursive=True)

 embeddings = []
 for img_path in image_paths:
 image = Image.open(img_path)
 embedding = model.encode(image)
 embeddings.append(embedding)

 return embeddings, image_paths

model = SentenceTransformer('clip-ViT-B-32')
embeddings, image_paths = generate_clip_embeddings(image_folder, model)

import faiss
import numpy as np


# FAISS 构建索引
features = np.array(embeddings).astype(np.float32)
faiss.normalize_L2(features)
vector_dim = features.shape[1]

index = faiss.IndexFlatIP(vector_dim)
index.add(features)

# 图片查询:选一张图(或上传图)再计算 embedding 作为查询向量
# query_image = Image.open('xxxx/feiji.jpeg')
# query_vector = model.encode(query_image)
# query_vector = np.array(query_vector).reshape(1, -1).astype(np.float32)
# faiss.normalize_L2(query_vector)

# 文本查询
query_text = "一辆自行车"
query_vector = model.encode(query_text) # 使用同一个模型对文本编码
query_vector = np.array(query_vector).reshape(1, -1).astype(np.float32)
faiss.normalize_L2(query_vector)

# 搜索最相似的图片
top_k = 5
distances, ann = index.search(query_vector, k=top_k)

# 显示搜索结果
for i, idx in enumerate(ann[0]):
 print(f"Top {i+1} match: {image_paths[idx]} (Score: {distances[0][i]:.4f})")

AI新手村:LLM

2025-06-13 09:57:45

近两年当人们谈起 LLM 的时候,似乎已经和 AI 画上了等号,但是 LLM 其实只是 AI 领域的一个重要组成部分。

LLM的历史

自然语言处理(NLP)是人工智能领域一个重要分支,它主要研究内容和方向有:分词(Tokenization)、文本分类(Text Classification)、情感分析(Sentiment Analysis)、实体命名(Named Entity Recognition)、文本摘要(Topic Modeling)。上面所有这些研究方向底层的技术基础都是从 RNN 神经网络发展而来,在此基础上又产生了基于encoder-decoder 结构的Seq2seq 模型。

然而,RNN 在处理长文本时存在固有的缺陷:它会逐步计算每个词元(token)之间的依赖关系,这不仅会导致长文本信息丢失或遗忘,而且每一步计算都必须顺序进行,无法实现并行运算。

2017 年 Google 发布了 Transformer 架构,Transformer 是一种基于自注意力机制的神经网络架构,它的目标是处理序列资料,特别擅长处理长距离的元素依赖相关性,而且可以并行运算。Transformer 由两部分组成:编码器(encoder)和解码器(decoder),其结构无疑借鉴了 Seq2seq 模型,并成功克服了 RNN 的内在缺点。 以 Transformer 架构为基础,各家公司开始开发自家的模型。2018年当时最火的还是Google 的 BERT模型,BERT模型其实是一个理解式的模型,而 OpenAI 的 GPT是一个生成式的模型,使用的是 decode-only 的结构。其他的语言模型大多数采用的是编码器加解码器这种方式,编码器负责理解,解码器负责输出。 2022 年OpenAI 推出的 GPT3模型,其中的参数量达到了千亿级别,而且实际的测试效果碾压当时市面上的所有模型,真正实现了“大力出奇迹”,大语言模型(LLM) 的时代来临了。 随后,Meta 推出了 LLaMA 系列,Google 发布了 Gemini 系列,国内的深度求索推出了 DeepSeek 系列,阿里巴巴也推出了 Qwen 系列。一时间,各类大型语言模型百花齐放,共同推动着 AI 领域的飞速发展。

LLM的使用

在 LLM 的基础上,许多产品得以封装并广泛应用。其中,ChatGPT 是最广为人知的产品之一,国内也有豆包、通义千问、文心一言等同类产品。除了通过产品界面直接使用 LLM,我们还可以通过代码的方式灵活调用 LLM。

以下是使用 GPT-3.5-turbo 模型和 DeepSeek-R1 模型的代码示例:

from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage

llm = ChatOpenAI(
 api_key=env_settings.OPENAI_API_KEY,
 model_name="gpt-3.5-turbo",
 base_url='https://burn.hair/v1'
)

ai_message = llm.invoke([
 SystemMessage(content="please speak in chinese"),
 HumanMessage(content="hello"),
])

print(ai_message.content)
#输出:你好!有什么可以帮助你的吗?
from langchain_core.messages import SystemMessage, HumanMessage
from langchain_deepseek import ChatDeepSeek

llm = ChatDeepSeek(
 api_key=env_settings.DS_API_KEY,
 model="deepseek-ai/DeepSeek-R1",
 temperature=0,
 max_tokens=None,
 timeout=None,
 max_retries=2,
 api_base='https://api.siliconflow.cn'
)
ai_message = llm.invoke([
 SystemMessage(content="please speak in chinese"),
 HumanMessage(content="hello"),
])

print(ai_message.content)
# 你好!😊 有什么可以帮您的吗?

从一张表格谈起

2025-05-19 18:10:22

今年年初,我基于一份记录去年消费情况的 CSV 格式表格,使用 Cursor 代码生成工具,根据我的需求生成了 Python 代码,成功分析了去年的年度消费情况,过程清晰且高效。如今,半年过去了,更多的基于大模型的产品层出不穷,近期 MCP(Model Context Protocol)备受关注,各厂商也积极适配自身工具,提供相应的 MCP Server 服务。

最近,我尝试使用了两款基于大型模型的 AI 产品,并选取一份新的表格数据(采用 2025 年的记账记录)来探究它们在使用上的特色。原始的表格样式如下所示。

2025 年记账表(部分)

Vanna

Vanna 是一个 MIT 协议的开源 RAG(检索增强生成)框架,用于 SQL 生成和相关数据分析展示。Vanna 的工作流程可分为两个主要阶段:首先,利用您的数据训练生成一个基于 RAG 的模型;然后,针对您的每次提问,Vanna 会自动生成并执行相应的 SQL 语句,同时生成可视化图表。如果产生的 SQL 语句有问题,Vanna 允许人工介入更改,并且把更改后的 SQL 语句作为新的训练资料注入到 RAG 的向量数据库中。

Vanna 的工作流程

Vanna 的使用流程

Vanna实战

首先,需要准备用于分析的数据。Vanna 支持 SQLite、PostgreSQL (PG)、MySQL、BigQuery 等多种数据库。为简化演示,本文使用 SQLite 数据库。先根据表头建立一张表 t_cost,然后把 csv 的数据导入,最后验证一下导入内容。

sqlite3 example.db
drop table t_cost;
CREATE TABLE t_cost (
 datetime TEXT, -- 例如 "2025/1/1 18:08"
 category TEXT,
 item TEXT,
 note TEXT,
 price REAL,
 exchangerate REAL,
 account TEXT,
 targetaccount TEXT,
 targetamount TEXT
);

# 注意设定csv分隔符
.separator ","

.import --skip 1 /xxx/converted_english_headers_corrected.csv t_cost

select datetime from t_cost limit 1;

然后,根据 SQLite 数据库的连结信息,训练 Vanna模型。

client = OpenAI(
 # This is the default and can be omitted
 # api_key=os.environ.get("OPENAI_API_KEY"),
 api_key= api_key,
 base_url = "https://burn.hair/v1" # 换成代理
)
config_g = {}
# 可换成其他大模型
config_g['model']= "gpt-3.5-turbo"

class MyVanna(ChromaDB_VectorStore, OpenAI_Chat):
 def __init__(self, config=None):
 # 这里向量数据库使用ChromaDB
 ChromaDB_VectorStore.__init__(self, config=config)
 OpenAI_Chat.__init__(self, client=client,config=config_g)

vn = MyVanna()
# vn.connect_to_sqlite('Chinook.sqlite')
vn.connect_to_sqlite('/xx/example.sqlite')

df_ddl = vn.run_sql("SELECT type, sql FROM sqlite_master WHERE sql is not null")

for ddl in df_ddl['sql'].to_list():
 vn.train(ddl=ddl)

training_data = vn.get_training_data()
training_data

最后,启动 Vanna 前端页面,开始根据我们提供的数据库,向 Vanna 提问。

from vanna.flask import VannaFlaskApp
app = VannaFlaskApp(vn,allow_llm_to_see_data=True)
app.run()

我先问了一个问题:“2025 年午餐的总消费次数和金额”,从截图可以看到,Vanna 的回答并不正确,原因在于它没有区分出大类别(category)和小项目(item)的区别,而且对于中文的识别也并不是很好,不过我们可以在 Vanna 提供的 SQL 基础上稍微修改一下,再次提交,可以看到,这次的回答就正确了。

Vanna 的提问页面

我们进一步追问:“晚餐的总消费次数和金额”,可以看到,经过前一次的人工修正,Vanna 已经能够直接给出正确答案。

Vanna 的提问页面2

Duckdb MCP

另一个要说的工具是,使用 Claude 3.5 Sonnet 作为 LLM,配合Duckdb MCP,其中Duckdb MCP如下所示。

"mcp-server-motherduck": {
 "command": "uvx",
 "args": [
 "mcp-server-motherduck",
 "--db-path",
 ":memory:"
 ]
 }

我们使用如下的提示词询问大模型:“加载下面文件到 DuckDB “~/Downloads/2025_05_18 13.24.18.csv”,

在 DuckDB 中新建表 xiaofei,然后统计 2025 年总的消费次数 ”。可以看到大模型可以准确的回答对应的问题。

Trae 的截图

思考

上面试验的例子都是根据一张数据表做一些简单的分析,从使用过程来看,或许有些大材小用,然而,在处理涉及复杂数据表关联的场景时,这两款工具都应具备广阔的应用前景,因为它们都能满足用户通过自然语言探索和分析数据表的需求。

这两款工具,分别基于 “LLM + RAG” 和 “LLM + MCP” 的技术实现路径,尽管技术细节不同,但其本质都是为了准确刻画上下文信息,从而协助 LLM 精确理解并执行用户的请求。