您现在的位置是:网站首页> AI人工智能

AI人工智能的基础知识

摘要

AI人工智能的基础知识

大模型根本没有 “第一个输出 token” 这种东西。它永远是:给一段上文 → 预测下一个。

基于gradio框架开发知识收集

*本地模型部署工具部署模型,用Agent框架调用部署工具接口实现调用模型*

*LangChain Agent框架支持Python与.NET*

1.jpg

客户端将MCP工具列表和用户问题-》大语言模型-》需要调用MCP的信息返回给调用模型的客户端,客户端调用指定MCP->客户端获得MCP结果-》大语言模型-》返回给最终客户

AI基本流程与原理



LangChain.NET如何调用Ollama制作知识库和调用MCP服务

AI数据标注一般使用的软件

CUDA的安装

关于NLP里tokens的解释

人工智能书推荐

何为AI模型

AI模型的格式有哪些文件后缀分别是啥及各种格式模型的使用方法

AI模型格式转换

手里有一个AI大模型只知道扩展名,如何调用呢

学习AI模型开发需要掌握以下基础知识

AI模型的训练

设计AI模型

TensorFlow VS PyTorch

Transformers 和PyTorch的关系

AI人工智能产品缺陷检测

PyTorch深度学习快速入门教程

B站强推!2023公认最通俗易懂的【PyTorch】教程

人工智能与机器人|常用的数据集格式人工智能与机器人|常用的数据集格式

微软的AI教程

何为JSONL 文件

实际用Python调用OpenAI开发聊天程序,每次给OpenAI多少轮的对话最合理



AI基本流程与原理

自回归大语言模型:

Tokenization可以使用不同的词表吗

词表如何生成

自己训练一个专业领域词表(代码 / 医疗 / 法律),如何优化词表让 token 更少

如何合并词表

分词后大模型如何使用

把输出向量 → 映射回词表 → 算出下一个词的概率详细介绍

大模型Embedding 层(把数字变向量),具体啥意思用途

Embedding 为什么能表示语义、为什么近义词会靠近、为什么能做加减法

embedding后输出的向量表又如何使用呢?

那么大模型第一个输出token如何确定的后续才有下个字的概率啊

大模型如何控制预测结束呢

图片模型:

图片模型到底怎么工作?(极简原理)

详细介绍下图片模型的原理及实现步骤方法


分词器-》词表

分词器(Tokenization):基于预训练的词表 + 贪心 / 动态规划算法,把任意文本切分成模型能识别的最小语义单元(Token)

词表:所有模型训练前都会先构建固定大小的词表(比如 GPT-3 是 50257 个、BERT 中文是 21128 个),词表是模型 “认识的所有字 / 词 / 片段”,所有算法的目标一致:在词表范围内,把文本切分成「语义完整 + 数量最少」的 Token 序列

词表(Vocab/Vocabulary)就是模型 “认识的所有字 / 词 / 片段的字典”,是一个固定的、预定义的字符串 - 数字映射表,也是分词和模型理解文本的核心基础。

简单说:词表是模型的 “识字库”,里面没有的内容,模型会拆成最小单位再识别,且全程只认词表对应的数字索引。

词表唯一性:不同模型有专属词表,同一文本在 GPT/Kimi/DeepSeek 上的切分结果 / Token 数均不同

模型判断分词片段有意义 / 无意义,核心不是靠 “理解语义”,而是基于预训练词表的「统计有效性」+ 算法的「最长匹配规则」,本质是工程层面的预设规则,而非真正的语义理解,简单说:词表中存在的片段 = 有意义,词表外的 = 无意义(会被拆成最小单位)。

极简总结

跨模型:词表完全不兼容,索引不可复用,必须单独分词;

同系列:词表向下兼容,索引可复用,分词结果通用。

#####

Q:Tokenization可以使用不同的词表吗?

A:...

完全可以,而且在实际开发里经常这么干。

但有一个铁律

Tokenizer 用什么词表,模型就必须用对应词表训练出来的权重,否则直接乱码。

Tokenizer 只是一个编码 / 解码工具,它不关心模型长什么样。

你完全可以

1.给同一个句子,用 GPT 词表 分词

2.再用 BERT 词表 分词

3.再用 你自己造的词表 分词

只要你加载对应的 vocab 文件,就能切出完全不同的 token。

Tokenizer ≠ 模型

Tokenizer 只是个 “字符串→数字” 的转换器。

模型只能认自己训练时用的那套词表

不同词表代码

pip install transformers

from transformers import AutoTokenizer


# 待分词文本

text = "大模型的上下文是靠拼接历史实现的"


# 1. GPT2 词表(英文为主,对中文不友好)

tokenizer_gpt2 = AutoTokenizer.from_pretrained("gpt2")

tokens_gpt2 = tokenizer_gpt2.tokenize(text)

print("=== GPT2 词表 ===")

print(f"Token 数量: {len(tokens_gpt2)}")

print(tokens_gpt2)

print()


# 2. 中文 BERT 词表(字级别为主)

tokenizer_bert = AutoTokenizer.from_pretrained("bert-base-chinese")

tokens_bert = tokenizer_bert.tokenize(text)

print("=== BERT 中文词表 ===")

print(f"Token 数量: {len(tokens_bert)}")

print(tokens_bert)

print()


# 3. Qwen 词表(阿里,对中文优化很好)

tokenizer_qwen = AutoTokenizer.from_pretrained("Qwen/Qwen2-1.5B")

tokens_qwen = tokenizer_qwen.tokenize(text)

print("=== Qwen 词表 ===")

print(f"Token 数量: {len(tokens_qwen)}")

print(tokens_qwen)



#####

Q:词表如何生成

A:...

一句话总结

词表 = 从海量文本里,统计高频组合 → 合并成最短、最语义化的片段集合

最主流算法叫 BPE(Byte Pair Encoding)字节对编码

一、BPE 词表生成的 4 步(超级简单)

假设你有一堆文本:

大模型 大模型 模型 上下文 上下文

步骤 1:拆成最小单位

中文拆成单字,英文拆成字母

plaintext

大,模,型,大,模,型,模,型,上,下,文,上,下,文

步骤 2:统计相邻两个组合的频率

plaintext

大+模:2次

模+型:3次

上+下:2次

下+文:2次

步骤 3:把频率最高的合并成新词

最高频是 模 + 型 → 合并成 模型

词表新增:模型

文本变成:

plaintext

大,模型,大,模型,模型,上,下,文,上,下,文

步骤 4:重复合并,直到词表够大

再统计:

plaintext

大+模型:2次

上+下:2次

下+文:2次

合并 大 + 模型 → 大模型

合并 下 + 文 → 下文

合并 上 + 下文 → 上下文

最终词表就有:

plaintext

大,模,型,模型,大模型,上,下,文,下文,上下文

最终效果

“大模型的上下文”

不再切成:大 模 型 的 上 下 文

而是切成:大模型 的 上下文

更少 token、更快、更省成本

二、真实模型词表怎么来?

1.用 TB 级文本(网页、书籍、代码)

2.跑 BPE 算法

3.生成固定大小词表(5 万~13 万不等)

4.绑定模型一起训练

这就是为什么:

不同模型词表不一样 → 分词不一样 → token 数不一样

一段 10 行代码:自己生成词表

# 极简 BPE 词表生成(手动实现)

import collections


def build_vocab(text, merges=5):

    # 1. 拆成单字

    tokens = list(text.replace(" ", ""))

    print("原始拆分:", tokens)


    for i in range(merges):

        # 2. 统计相邻频率

        pairs = collections.Counter(zip(tokens, tokens[1:]))

        if not pairs: break

        

        # 3. 找最高频对

        best_pair = max(pairs, key=pairs.get)

        new_token = ''.join(best_pair)

        print(f"合并 #{i+1}: {best_pair} → {new_token}")


        # 4. 替换合并

        new_tokens = []

        skip = False

        for j in range(len(tokens)):

            if skip:

                skip = False

                continue

            if j < len(tokens)-1 and (tokens[j], tokens[j+1]) == best_pair:

                new_tokens.append(new_token)

                skip = True

            else:

                new_tokens.append(tokens[j])

        tokens = new_tokens

    return tokens


# 测试

text = "大模型大模型模型上下文上下文"

vocab = build_vocab(text, merges=5)

print("\n最终词表片段:", vocab)


运行后你会亲眼看到

单字 → 合并 → 变成有意义的词

这就是所有大模型词表的生成原理


终极结论(程序员版)

1.词表不是人工写的

2.是 BPE 算法自动统计 + 合并出来的

3.高频 = 保留成整词

4.低频 = 拆成最小单位

5.每个模型词表独立 → 不兼容


词表文件的后缀

现代开源大模型:vocab.json + merges.txt

老派 BERT:vocab.txt

多语言一体:.spm / sentencepiece.model

如果你手上有 .json / .txt / .spm 结尾的小文件,基本就是词表


####

Q:自己训练一个专业领域词表(代码 / 医疗 / 法律),如何优化词表让 token 更少

A:...

一、专业领域词表(代码 / 医疗 / 法律)怎么训练?

核心思路

1.收集领域专属文本(代码文件 / 医疗文献 / 法律条文)

2.用 BPE / SentencePiece 训练专属词表

3.把新词表合并到原有模型词表(不破坏原模型)

4.微调模型 Embedding 层(让模型认识新词)

最推荐工具(简单、快、工业级)

SentencePiece(谷歌,最强)

或 HuggingFace Tokenizers(最易用)

我给你直接能用的训练代码(1 分钟跑出自定义词表)

二、训练专业词表:100% 可运行代码

安装工具

bash

运行

pip install tokenizers

训练代码(代码 / 医疗 / 法律都能用)

python

运行

from tokenizers import Tokenizer

from tokenizers.models import BPE

from tokenizers.trainers import BpeTrainer

from tokenizers.pre_tokenizers import Whitespace


# 1. 创建空白 BPE 分词器

tokenizer = Tokenizer(BPE())

tokenizer.pre_tokenizer = Whitespace()


# 2. 训练配置(决定你的专业词表)

trainer = BpeTrainer(

    vocab_size=30000,        # 词表大小

    min_frequency=5,         # 至少出现5次才合并

    special_tokens=["<pad>", "<s>", "</s>", "<unk>"]

)


# 3. 训练(把你的专业语料丢进去)

# 支持:代码文件、医疗txt、法律文本、一行一个文件

files = [

    "your_code_corpus.txt",

    "your_medical_corpus.txt",

    "your_law_corpus.txt"

]


tokenizer.train(files=files, trainer=trainer)


# 4. 保存专业词表

tokenizer.save("domain_tokenizer.json")

跑完你会得到

domain_tokenizer.json

这就是你的专业领域词表。

三、训练出来的词表好在哪里

以代码领域为例:

普通词表会切成:

plaintext

def get_user_info → 6 个 token

你的专业词表会直接变成:

plaintext

def get_user_info → 2 个 token

医疗 / 法律同理:专业长词变成 1 个 token

→ Token 数量直接减少 30%~60%

→ 上下文更长、成本更低、速度更快

四、如何优化词表让 Token 更少?(核心技巧)

1. 用领域专属语料训练(最有效)

通用词表不认识专业术语

领域词表认识 → 合并成大 token → 数量暴减

2. 提高 min_frequency

python

运行

min_frequency=10

只保留高频词,减少碎片分词

3. 适当增大词表大小

python

运行

vocab_size=50000 ~ 65000

能装更多长语义单元 → 更少拆分

4. 优先合并长语义串

代码:函数名、类名、关键字

医疗:病名、药名、术语

法律:法条、条款、固定表述

5. 去掉无用空格 / 符号

减少无意义 token

6. 与原模型词表合并(不破坏模型)

把专业词表合并进原有模型

→ 原有能力不变 + 领域更强 + token 更少

五、最终效果(真实对比)

普通词表(GPT 通用)

plaintext

“患者因急性心肌梗死入院,行PCI治疗”

→ 18 token

你的医疗专业词表

plaintext

“患者因急性心肌梗死入院,行PCI治疗”

→ 9 token

直接少一半!

代码领域更夸张,能少 60% Token。


#####

Q:如何合并词表

A:...

合并词表(最实用、程序员版)

我直接给你最简单、最安全、工业级可用的词表合并方法,专门用于:

把你的专业词表(代码 / 医疗 / 法律)合并到原有模型词表

全程不破坏原模型、不冲突、可直接用。

核心原则(必须记住)

1.保留原模型词表不动(保证模型正常运行)

2.把新词表中 “原有词表没有的词” 追加到后面

3.新 token ID 必须从原词表最大 ID +1 开始

4.最后 resize 模型 embedding 层

一、最简单可运行代码:合并两个词表

python

运行

import json


# ----------------------

# 1. 加载两个词表

# ----------------------

# 原模型词表(例如 Qwen / LLaMA / DeepSeek)

with open("original_vocab.json", "r", encoding="utf-8") as f:

    original_vocab = json.load(f)


# 你的专业领域词表(代码/医疗/法律)

with open("domain_vocab.json", "r", encoding="utf-8") as f:

    domain_vocab = json.load(f)


# ----------------------

# 2. 开始合并(只加新词)

# ----------------------

merged_vocab = original_vocab.copy()

next_id = len(original_vocab)  # 新ID从这里开始


# 只追加原词表里没有的token

for token, _ in domain_vocab.items():

    if token not in merged_vocab:

        merged_vocab[token] = next_id

        next_id += 1


# ----------------------

# 3. 保存合并后的新词表

# ----------------------

with open("merged_vocab.json", "w", encoding="utf-8") as f:

    json.dump(merged_vocab, f, ensure_ascii=False, indent=2)


print(f"原词表大小: {len(original_vocab)}")

print(f"领域词表大小: {len(domain_vocab)}")

print(f"合并后总大小: {len(merged_vocab)}")

print(f"新增专业词汇: {len(merged_vocab) - len(original_vocab)}")

运行后你会得到:merged_vocab.json

这就是原模型 + 专业领域的超级词表。

二、如果是 BPE 模型(含 merges.txt)怎么合并?

大部分现代模型(GPT、LLaMA、Qwen、DeepSeek)都是:

1.vocab.json = 词表

2.merges.txt = 合并规则

完整合并代码(支持 BPE)

python

运行

from tokenizers import Tokenizer


# 加载原分词器

base_tokenizer = Tokenizer.from_pretrained("Qwen/Qwen2-1.5B")


# 加载你的专业分词器

domain_tokenizer = Tokenizer.from_file("domain_tokenizer.json")


# 合并(自动去重、保留原有)

base_tokenizer.add_tokens(

    [token for token in domain_tokenizer.get_vocab() if not base_tokenizer.token_to_id(token)]

)


# 保存合并后的完整分词器

base_tokenizer.save("merged_tokenizer.json")

print("合并完成!文件:merged_tokenizer.json")

这是最推荐、最安全的方法。

三、合并完必须做的最后一步(非常重要)

词表变大了,模型的 embedding 层必须同步扩大,否则报错。

python

运行

from transformers import AutoModelForCausalLM


model = AutoModelForCausalLM.from_pretrained("你的模型路径")

tokenizer = AutoTokenizer.from_pretrained("你的分词器路径")


# 自动 resize 模型权重

model.resize_token_embeddings(len(tokenizer))


# 保存

model.save_pretrained("merged_model")

tokenizer.save_pretrained("merged_model")

✅ 完成!

现在模型既能正常对话,又能识别专业词汇,token 大幅减少

四、合并词表的好处(直观效果)

原通用词表:

plaintext

def getUserInfo → 5 个 token

急性心肌梗死 → 6 个 token

中华人民共和国刑法 → 7 个 token


合并专业词表后:

plaintext

def getUserInfo → 1~2 个 token

急性心肌梗死 → 1~2 个 token

中华人民共和国刑法 → 1~2 个 token

Token 数量减少 30%~70%

上下文更长、速度更快、成本更低。

五、你要我帮你直接生成?

你告诉我:

你用的模型(LLaMA / Qwen / DeepSeek / 其他)

领域(代码 / 医疗 / 法律)

有没有自己的语料

我可以直接给你:

一键训练专业词表 + 一键合并到模型 + 一键可运行


####

Q:分词后大模型如何使用

A:...

分词 → Token ID → 大模型到底怎么用?

全程不绕弯、不搞玄学,一步一步讲透。

0. 一句话终极总结

分词 = 把文字 → 数字(Token ID)

大模型只吃数字,不吃文字

输出 → 再把数字转回文字

1. 分词后,模型拿到的是什么?

假设你输入:

我是程序员

分词器会输出两样东西:

1.1Tokens(片段):我, 是, 程序员

1.2IDs(数字):123, 45, 9876

模型只看 IDs,完全不看文字

2. 模型第一步:Embedding 层(把数字变向量)

模型里有一个超大查询表,叫 Embedding 层

它的作用:

每个 ID → 变成一组高维向量(比如 4096 维数字)

例子:

plaintext

123 → [0.32, 0.56, -0.12, 0.89, ...]

45 → [0.11, 0.93, 0.42, -0.21, ...]

9876 → [0.76, -0.34, 0.51, 0.23, ...]

这一步叫:

把离散 ID → 连续语义向量

3. 模型真正干活:Transformer 推理

模型拿到一串向量后,开始做核心操作:

核心做 3 件事

3.1注意力机制:看每个词和其他词的关系

3.2前馈网络:理解语义

3.3归一化 / 残差:稳定输出

最终得到一组新的输出向量

4. 最后一步:LM Head → 预测下一个词

模型最后一层是 LM Head(语言模型头)

它做一件事:

把输出向量 → 映射回词表 → 算出下一个词的概率

比如:

输入:我是程序员

模型预测:

plaintext

我 → 是

是 → 程

程 → 序

序 → 员

员 → ,(概率最高)

模型一次只输出一个 token!

然后把输出的 token 拼回输入,继续生成下一个。

这就是自回归生成

5. 完整流程(程序员一眼看懂)

plaintext

用户输入:我是程序员

      ↓ 分词

Tokens:我、是、程序员

      ↓ 转ID

IDs:[123, 45, 9876]

      ↓ Embedding 查表

向量序列:[...], [...], [...]

      ↓ Transformer 推理

输出向量

      ↓ LM Head 预测概率

下一个 token ID:82(,)

      ↓ 循环生成

直到输出 <|endoftext|>

      ↓ 解码回文字

最终输出:我是程序员,...

6. 最关键的 3 个知识点(必须懂)

① 模型没有记忆!

每一次对话都是全新输入

上下文 = 把历史全部转成 IDs 再塞进去

② 词表 = 模型的字典

ID 必须在词表里,否则变成 <unk>(未知)

③ 生成是概率性的

模型不是 “知道答案”

而是计算下一个 token 概率最高的是什么

7. 超简 Python 代码演示(真实流程)

python

运行

from transformers import AutoTokenizer, AutoModelForCausalLM


# 加载模型 & 分词器

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-1.5B")

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-1.5B")


# 输入文本

text = "我是程序员"


# ========== 1. 分词(文字→ID)==========

inputs = tokenizer(text, return_tensors="pt")

print("Token IDs:", inputs["input_ids"])


# ========== 2. 模型推理(只吃ID)==========

outputs = model.generate(**inputs, max_length=20)


# ========== 3. 解码(ID→文字)==========

result = tokenizer.decode(outputs[0], skip_special_tokens=True)


print("最终输出:", result)

运行结果:

plaintext

Token IDs:tensor([[103, 456, 9876]])

最终输出:我是程序员,喜欢写代码。

8. 最终极简总结

分词 = 文字转数字

模型 = 只处理数字

生成 = 预测下一个数字

解码 = 数字转回文字



#####

Q:把输出向量 → 映射回词表 → 算出下一个词的概率详细介绍

A:...

纯程序员视角、不带玄学、一步一步公式 + 流程,把输出向量 → 映射回词表 → 算出下一个词概率

这一步彻底讲透。

这一层在大模型里统一叫:

LM Head / Language Model Head / 语言模型头

0. 前置结论(先放这,防止迷路)

0.1模型最后输出的不是文字,是高维向量(比如 4096 维)

0.2LM Head 是一个线性层:[hidden_dim → vocab_size]

0.3做完线性变换,得到词表长度的 logits 向量

0.4再做 softmax,把 logits 变成 0~1 之间的概率

0.5概率最大的 token ID → 就是模型要输出的下一个词

1. 模型最后给你的是什么?

假设模型:

隐藏层维度 hidden_size = 4096

词表大小 vocab_size = 50257(GPT 类似)

经过整个 Transformer 最后一步,你会拿到一个向量:

plaintext

hidden_out = [4096]  # 对应最后一个位置的输出

不对应任何词,只是一段语义特征。

2. LM Head:线性层投影(核心步骤)

LM Head 就是一个可训练的权重矩阵:

plaintext

W = [4096, 50257]

b = [50257]

计算:

plaintext

logits = hidden_out @ W + b

结果:

plaintext

logits.shape = [50257]

这 50257 个数字,每一位对应词表里一个 token!

第 0 位 → <|endoftext|>

第 100 位 → 我

第 9876 位 → 程序员

...

第 50256 位 → 某个生僻符号

这一步叫:

把语义特征 → 投射到词表空间

3. logits 是什么?(不是概率!

logits 有几个特点:

可正可负

可大可小

越大 → 这个词越 “可能”

但不是概率,因为总和≠1

比如:

plaintext

logits[100]   = 2.34   → 我

logits[9876]  = 5.67   → 程序员

logits[200]   = -1.23  → 学

只看大小能排序,但不能当概率用。

4. Softmax:把 logits → 真正概率

公式(对整个词表做):

plaintext

prob_i = exp(logits_i) / Σ(exp(logits_j))  # j 遍历整个词表

效果:

所有值被压到 0 ~ 1

全部加起来 = 1

越大的 logits → 越大的概率

例子(简化):

plaintext

prob[100]  = 0.0342    → 我

prob[9876] = 0.9645    → 程序员  👈 最大

prob[200]  = 0.0009    → 学

这就是模型 “认为” 下一个词的真实概率。

5. 如何选出最终输出的 token?

三种常用策略:

① Greedy Search(贪心,默认)

直接选 概率最大 的 token

plaintext

next_id = argmax(probs)

快、确定性高,但容易重复、呆板。

② Top-K Sampling

从概率最高的 K 个里随机抽一个更自然、有创造力。

③ Top-p (Nucleus) Sampling

选累计概率 ≥ p 的最小集合,再随机抽最常用,最自然。

6. 完整数据流(程序员版)

plaintext

输入文本 → Token IDs → Embedding → Transformer 层层计算

       ↓

最后一层输出 hidden: [batch, seq_len, hidden_size]

       ↓

取最后一个位置的向量: [hidden_size]

       ↓

LM Head 线性层: hidden @ W + b → [vocab_size] → logits

       ↓

Softmax → [vocab_size] → 概率分布

       ↓

采样/argmax → next_token_id

       ↓

把 id 塞回输入,继续生成下一个

7. 超精简代码演示(真实逻辑)

python

运行

import torch

import torch.nn.functional as F


# 假设这是模型最后输出的 hidden 向量

hidden_out = torch.randn(4096)  # 4096 维


# LM Head 权重

vocab_size = 50257

W = torch.randn(4096, vocab_size)

b = torch.randn(vocab_size)


# 1. 投影到词表空间

logits = hidden_out @ W + b


# 2. 转概率

probs = F.softmax(logits, dim=-1)


# 3. 选概率最大的 token

next_token_id = torch.argmax(probs).item()


print("下一个 Token ID:", next_token_id)

这就是大模型每生成一个字都在干的事。

8. 关键点总结(非常重要)

8.1LM Head 就是一个线性层,没有魔法

8.2logits = 原始分数,不是概率

8.3softmax 之后才是概率

8.4词表越大,这一步越耗计算

8.5专业词表之所以好:

专业词一次到位

logits 更容易集中在正确词上

生成更快、更准



#####

Q:大模型Embedding 层(把数字变向量),具体啥意思用途

A:...

最直白、程序员能秒懂的方式,一次性把 Embedding 层到底是什么、干什么、为什么必须存在 讲透。

一句话核心

Token ID 只是编号,没有语义

Embedding 就是一张 “查询表”,把每个编号,变成一段有语义含义的高维向量

模型只看得懂向量,看不懂编号

1. 先看问题:模型为什么不能直接用 ID?

你分词后得到的是:我 → 100是 → 101程 → 102序 → 103员 → 104

这些 100、101、102… 只是数字编号,和语义毫无关系:

1.1 数字大小不代表含义强弱

1.2 100 和 101 相邻,但 “我” 和 “是” 语义不一定近

1.3 模型无法通过纯数字理解 “程序员” 是一个职业

纯数字 = 无意义 = 模型无法学习

所以必须加一层:Embedding

2. Embedding 本质是什么?

就是一个 巨大的查询表(矩阵)

结构:

plaintext

shape = [词表大小, 向量维度]

比如 GPT 类模型:

词表大小:50257

向量维度:4096

那么 Embedding 层就是一张表:

plaintext

ID=0 → [0.12, -0.34, 0.56, ..., 0.89] (4096个数字)

ID=1 → [0.33, 0.55, -0.22, ..., 0.11]

ID=2 → [...]

...

ID=100 → 对应“我”的向量

ID=101 → 对应“是”的向量

...

ID=50256 → [...]

输入一个 ID,直接查表取出一行向量

这就叫:token ID → word embedding(词向量)

3. 这个向量里到底存了什么?

不是人工写的,是模型训练出来的。

向量里的每一组数字,会自动编码:

3.1.1语义(近义词向量距离近)

3.1.2词性(名词、动词、副词)

3.1.3情感(正面 / 负面)

3.1.4语法关系(主谓宾)

3.1.5上下文关联

比如训练好后:

3.2.1 程序员 向量 ≈ 工程师 向量(距离近)

3.2.2快乐 向量 ≈ 开心 向量

3.2.3悲伤 向量远离它们

3.2.4 模型就是通过这些向量,理解语言的。

4. 用途:它解决了 3 个核心问题

① 把无意义编号 → 有意义语义

ID 只是索引,向量才是知识。

② 把离散符号 → 连续空间

让模型可以做加减乘除、计算相似度、注意力权重。

③ 统一输入格式

不管是字、词、标点、代码符号,全部变成 固定长度的向量 输入 Transformer。

5. 模型真正的输入长这样

你以为模型输入是:

plaintext

[100, 101, 9876]

实际模型吃的是:

plaintext

[

  [0.12, -0.34, ...],  # 我

  [0.55, 0.21, ...],   # 是

  [0.89, -0.11, ...]   # 程序员

]

Transformer 所有计算:注意力、前馈、残差…

全部都是在对这些向量做运算

6. 超简单代码演示(一看就懂)

python

运行

import torch


# 词表大小 10000,向量维度 16

embedding = torch.nn.Embedding(num_embeddings=10000, embedding_dim=16)


# 输入 Token ID

token_ids = torch.tensor([100, 101, 9876])


# 查表 → 变成向量

vectors = embedding(token_ids)


print(vectors.shape)  # torch.Size([3, 16])

print(vectors)

输出:

plaintext

tensor([[ 0.23, -0.45,  0.11, ... ],

        [ 0.56,  0.12, -0.39, ... ],

        [-0.78,  0.32,  0.51, ... ]])

这就是模型真正的 “输入文字”。

7. 为什么专业词表 + 合并 Embedding 会更强?

因为:

7.1通用词表把急性心肌梗死切成很多小向量,语义散掉

7.2专业词表把它变成一个向量,语义更集中

7.3模型更容易理解、计算更快、token 更少

Embedding 就是模型的 “语义基因”。

8. 终极极简总结

8.1Token ID = 书名号

8.2Embedding = 书里的内容

8.3模型只看内容,不看书名号

Embedding 层 = 把编号翻译成模型能懂的语言。

如果你想,我可以下一步讲:为什么 Embedding 训练完后,近义词会靠在一起、为什么能做语义加减法(国王 - 男人 + 女人 = 女王)


#####

Q:Embedding 为什么能表示语义、为什么近义词会靠近、为什么能做加减法

A:...

Embedding 为什么能表示语义、为什么近义词会靠近、为什么能做加减法 一次性讲透,还是程序员视角,不搞玄学。

一句话前置结论

Embedding 的本质,是把词语 “塞进” 一个高维坐标系里

意思越像,坐标离得越近。

模型训练的过程,就是在不断调整每个词的坐标

1. 先理解:Embedding 是一个「高维空间坐标」

你可以把 embedding 向量理解成:

1.1.1 二维空间:(x, y)

1.1.2 三维空间:(x, y, z)

1.1.3 大模型里:4096 维超级空间

每个 token 对应空间里一个点

训练完之后会出现一个神奇现象:

语义相似的词,空间距离非常近

比如:

1.2.1 苹果、梨、香蕉 → 挤在一起

1.2.2 程序员、工程师、开发者 → 挤在一起

1.2.3 开心、快乐、高兴 → 挤在一起

1.2.4 悲伤、难过、痛苦 → 挤在一起

模型根本不需要 “理解中文”,

它只需要知道:

这两个点离得近 → 意思差不多

2. 为什么近义词会自动靠近?(核心原理)

来自训练目标:

通过上下文,预测下一个词

举个超级简单的例子:

句子 1:我今天吃了一个苹果。

句子 2:我今天吃了一个梨。

句子 3:我今天吃了一个香蕉。

在训练时:

2.1.1“苹果”“梨”“香蕉” 前面的上下文几乎一样

2.1.2 模型为了能正确预测下一个词

2.1.3 会把它们的向量调成非常相似

2.1.4 这样不管输入哪个,模型都能输出相似的后续概率

这就叫:

相似上下文 → 相似向量 → 语义相近

完全是数据统计 + 梯度下降逼出来的,不是人工设计的。

3. 为什么能做语义加减法?

国王 - 男人 + 女人 = 女王这个经典例子到底为什么成立?

原理一句话:向量里的每一维,都在编码某种 “语义特征”

比如某几个维度专门编码:

维度 1:是否皇室

维度 2:性别

维度 3:年龄

维度 4:职业

...

那么:

国王 = 皇室 (强) + 男人 (强) + ...

男人 = 男人 (强)

女人 = 女人 (强)

计算:国王 - 男人 + 女人

= 皇室 + 男人 - 男人 + 女人

= 皇室 + 女人

= 女王

模型根本不懂 “皇室”“性别”,

但它通过海量文本,自动把这些抽象概念编码到不同维度上了

4. Transformer 到底用 Embedding 干什么?

你要记住一个核心:

Transformer 里所有操作,只认向量,不认字

它主要干 3 件事:

① 计算注意力(谁和谁相关)

Attention 本质是:计算两个向量的相似度

比如句子:“程序员喜欢写代码”

模型通过向量相似度发现:

喜欢 ↔ 程序员(很近)

喜欢 ↔ 代码(很近)

程序员 ↔ 代码(很近)

于是知道:

程序员喜欢代码

② 做语义组合

把多个词向量,融合成整句语义。

比如:

向量 (大) + 向量 (模型)

→ 融合成向量 (大模型)

③ 传递信息到下一层

每一层 Transformer 都会微调向量

让语义越来越清晰、完整。

最后输出的向量,

就是整段话的语义浓缩

5. 为什么专业词表能让 Embedding 更强?

这里非常关键,直接关系到你之前关心的:

代码 / 医疗 / 法律词表优化

普通通用词表

“急性心肌梗死”

→ 切成 5~6 个 token

→ 5~6 个零散向量

→ 语义被拆碎,模型要自己拼

专业领域词表:

“急性心肌梗死”

→ 1 个 token

→ 1 个完整、紧凑、精准的向量

→ 语义高度集中

→ 注意力计算更快更准

→ 生成时 logits 更集中,不容易胡说

一个完整语义向量 > N 个碎向量拼起来

6. 极简代码:直观看向量相似度

我给你一段能直接跑的代码,

让你亲眼看到:

近义词向量余弦相似度极高,无关词很低

python

运行

import torch

import torch.nn.functional as F


# 随便模拟几个训练好的 Embedding(真实模型也是这种数值分布)

emb = torch.nn.Embedding(10, 8)


# 定义几个ID

id_apple = torch.tensor([0])

id_pear = torch.tensor([1])

id_cat = torch.tensor([2])


# 取出向量

v_apple = emb(id_apple)

v_pear = emb(id_pear)

v_cat = emb(id_cat)


# 计算相似度(越接近1越像)

sim_app_pear = F.cosine_similarity(v_apple, v_pear)

sim_app_cat = F.cosine_similarity(v_apple, v_cat)


print("苹果 ↔ 梨:", sim_app_pear.item())

print("苹果 ↔ 猫:", sim_app_cat.item())

正常训练好的模型输出会接近:

plaintext

苹果 ↔ 梨: 0.85

苹果 ↔ 猫: 0.12

这就是语义空间

7. 终极总结(程序员版)

7.1 Embedding = 词在高维空间的坐标

7.2 坐标近 = 意思像

7.3 模型靠向量相似度理解上下文关系

7.4 训练就是在调整每个词的坐标

7.5 专业词表 = 让专业术语拥有独立、完整、精准的坐标

7.6 Transformer 所有魔法,都建立在这些向量之上



####

Q:embedding后输出的向量表又如何使用呢?

A:...


这一步就是大模型真正 “思考” 的起点。

我用最干净、程序员能直接对应代码的方式讲:

Embedding 输出的向量序列,接下来只做三件事:进 Transformer → 算注意力 → 输出特征向量

全程没有玄学,全是矩阵运算。

0. 先明确:embedding 输出是什么?

输入一句话 → 分词成 token ID → embedding 查表

得到的是一个序列向量

plaintext

shape = [批次, 序列长度, 隐藏维度]

例如:[1, 10, 4096]

意思:

1 句话

10 个 token

每个 token 变成 4096 维向量

这就是模型真正的输入

后面所有操作,都在这堆向量上折腾。

1. 第一步:加上位置信息(Position Embedding)

词向量本身没有顺序

我吃饭 和 饭吃我 的向量是一样的。

所以必须加:

位置编码 Position Embedding

plaintext

最终输入 = 词向量 + 位置向量

让模型知道:

第 1 个词是啥

第 2 个词是啥

谁在前谁在后

这一步做完,才正式进入 Transformer。

2. 核心:进 Transformer 层(真正干活)

Transformer 只做一件事:

对这一串向量做 “信息融合”,让每个词都吸收上下文其他词的信息

内部流程超级清晰:

① 多头注意力 Multi-Head Attention

对每一对向量计算相关性(注意力分数)

比如句子:程序员[0] 喜欢[1] 写[2] 代码[3]

注意力会算出:

2.1.1程序员 ↔ 喜欢:强相关

2.1.2喜欢 ↔ 代码:强相关

2.1.3程序员 ↔ 代码:强相关

然后:

每个词向量 = 自己 + 其他相关词的信息

结果:每个向量都变成了带上下文语义的向量

② 前馈网络 Feed Forward

对每个向量独立做一次非线性变换:

plaintext

向量 → 线性 → 激活 → 线性 → 新向量

作用是强化语义、抽象特征

③ 重复 N 层

GPT 通常 30~100 层。

每一层都让语义更抽象、更完整。

3. 最终输出:还是一串向量

经过几十层 Transformer 后,输出仍然是:

plaintext

shape = [批次, 序列长度, 隐藏维度]

和 embedding 输出形状完全一样!

区别是:

embedding 输出:孤立的词义

Transformer 输出:融合了整段上下文的语义

4. 然后怎么用?分两种任务

任务 A:对话 / 续写 / 生成(你最关心的)

只需要最后一个位置的向量

因为它吸收了整段话的全部信息

plaintext

last_hidden = hidden_states[:, -1, :]  # [1, 4096]

然后送给 LM Head:

plaintext

logits = last_hidden @ W + b  # → [1, 词表大小]

probs = softmax(logits)

next_token_id = argmax(probs)

这就是:

根据上文,预测下一个字

任务 B:语义检索 / 分类 / 匹配

第一个 token 向量 或 整段平均作为整段话的语义向量

用来:

4.1 搜索相似文本

4.2 做 RAG 检索

4.3 分类、意图识别

5. 超直观数据流(一行看懂)

plaintext

文本

  ↓ 分词

token IDs [1,6,9,10]

  ↓ embedding 查表

向量序列 [seq_len, hidden]

  ↓ + position

带顺序的向量

  ↓ N层 transformer

融合上下文后的向量序列

  ↓ 取最后一个

整句语义向量 [hidden]

  ↓ LM Head 投影

logits [vocab_size]

  ↓ softmax

下一个词概率

  ↓ 采样

输出一个字

6. 极简代码版(真实逻辑)

python

运行

# embedding

x = embedding(token_ids)  # [1, seq_len, 4096]


# + position

x = x + pos_emb


# N 层 transformer

for layer in layers:

    x = layer(x)  # 形状永远不变


# 取最后一个词

last = x[:, -1, :]  # [1, 4096]


# 投影到词表

logits = last @ lm_head_weight

probs = softmax(logits)

next_id = argmax(probs)

7. 一句话终极总结

embedding 给出 “词义”

transformer 算出 “上下文语义”

最后一个向量代表 “整句话意思”

再投影回词表,得到下一个字的概率


#####

Q: 大模型如何控制预测结束呢

A:...

大模型怎么知道什么时候该停嘴、结束生成

一句话总结

模型本身不会自动 “想完了”

它是靠 特殊结束符号 + 长度上限 + 停止词 这三样东西强制结束的。

1. 最核心:结束 Token <|endoftext|> / <eos>

所有大模型词表里,一定有一个特殊 token,叫:

<|endoftext|>

或 <eos>

或 </s>

它的作用只有一个:

表示 “文本到此结束”

生成过程是这样

1.1.1 模型每次输出一个 token

1.1.2 解码器检查是不是结束符

1.1.3 如果是 → 立刻停止,不再生成

1.1.4 如果不是 → 继续

也就是说:

模型自己会 “预测出结束符”,

这是最自然、最标准的结束方式。

2. 长度上限 max_new_tokens(强制保险)

怕模型无限说下去,所以一定会加一个强制上限

python

运行

model.generate(..., max_new_tokens=2048)

意思:

最多只让你生成 2048 个 token,到点立刻停

这是工程上的安全锁,防止死循环、爆显存、爆成本。

3. 停止词 stop_words(自定义停止)

你可以指定:只要模型输出了某串字符,就停。

例如:

3.1 "\n" 遇到换行就停

3.2 "答案:" 之后停

3.3 "。" 遇到句号停

3.4 "用户:" 遇到对话切换标记停

python

运行

model.generate(..., stop=["\n", "。", "谢谢"])

这在对话、结构化输出里非常常用。

4. 真实完整生成逻辑(伪代码,一看就懂)

python

运行

# 初始输入

prompt_ids = [101, 202, 303]


while True:

    # 1. 预测下一个 token

    next_id = model(prompt_ids)


    # 2. 检查是不是结束符 <eos>

    if next_id == EOS_TOKEN_ID:

        break


    # 3. 检查是否超过最大长度

    if len(prompt_ids) >= max_length:

        break


    # 4. 检查是否命中停止词

    next_word = id2word(next_id)

    if next_word in stop_words:

        break


    # 5. 否则继续

    prompt_ids.append(next_id)

这就是所有大模型生成的真实逻辑。

5. 模型自己 “想结束” 是怎么做到的?

不是玄学,是训练出来的。

训练语料里,每篇文章末尾都有结束符:

plaintext

文章1内容<|endoftext|>

文章2内容<|endoftext|>

...

模型学会了:

话说完了,下一个就该输出 <eos>

所以它会自然收尾,而不是被强行掐断。

6. 三种结束方式对比

表格

方式 触发 优点 缺点

结束符 EOS 模型自己输出 自然、流畅 有时不想停它也停

最大长度 达到 token 数 安全、可控 可能生硬切断

停止词 输出指定字符串 灵活、结构化 要精准匹配

7. 终极极简总结

7.1 模型不会自己 “思考完”

7.2 靠 <eos> 结束符 自然停止

7.3 靠 max_length 强制防止无限生成

7.4 靠 stop_words 做结构化截断

7.5 生成循环内部不断检查,满足任一条件就停



####

Q:图片模型到底怎么工作?(极简原理)

A:...

主流就两大类:

A. 扩散模型(Stable Diffusion、Flux、SDXL)

1.从完全随机噪点图开始

2.模型一点点去噪

3.每一步去掉一点噪点,图像慢慢变清晰

4.固定走 N 步(比如 20~50 步)

5.步数走完,图像就完成了

→ 没有 “预测结束”,步数到了就停

B. 自回归图像模型(像 PixelDT、早期部分模型)

把图片切成很小的 patch 或 token

像文字一样一个个生成

这种才会有 “结束逻辑”,但现在几乎不用了


那图片模型的 “文本提示” 怎么用

只有文字编码部分和语言模型有点像:

1.提示词 → 用 CLIP 文本编码器 → 变成文本特征向量

2.这个向量控制扩散模型画什么

3.模型只负责:把噪点 → 变成符合描述的图像


####

Q:详细介绍下图片模型的原理及实现步骤方法

A:...

程序员能完全看懂、不玄学、不堆砌名词的方式,从头到尾讲清楚:

主流图片生成模型(Stable Diffusion 类扩散模型)的完整原理 + 实现步骤

你之前理解的语言模型那套(token、自回归、下一个词概率)全部不适用,图片是另一套体系。

一、先一句话定调

Stable Diffusion / SDXL / Flux 这类图片模型,本质是:

从一张完全随机的噪点图,一步步 “去噪”,直到变成清晰图片。不是逐像素画,不是顺序生成,没有结束符,步数跑完就出图


二、核心思想:扩散模型(Diffusion Model)

它分两个阶段:

1. 训练阶段(模型学习怎么 “还原图片”)

人为地给清晰图片一步步加噪,直到完全变成噪点。

然后训练模型:输入带噪图片 → 预测出刚才加的那层噪声

模型学会了:

任何噪点 → 都能推出噪声是啥 → 减去噪声就变清晰


2. 推理生成阶段(画图)

2.1 从纯随机噪点开始

2.2 模型预测噪声

2.3 从图里减去预测的噪声

2.4 重复 N 步(20~50 步)

2.5 最后一步得到清晰图片



三、完整原理(极简但完整)

1. 文本提示怎么变成图的控制信号?

你输入:一只可爱的橘猫

步骤:

1.1 文本 → CLIP 文本编码器

1.2 输出一段 77×768 或 77×1280 文本特征向量

1.3 这个向量会在 UNet 每一层里引导去噪方向

→ 模型知道:要往 “橘猫” 的方向去噪,而不是别的


2. 随机噪声(起点)

生成一张完全随机的图:

(batch, channels, height, width)

比如 (1, 4, 64, 64) 这种隐空间图(不是像素图)


3. UNet 主干(核心大脑)

每一步做:

输入:

当前带噪隐向量 z_t

步数信息 t

文本特征 text_emb

输出:

预测的噪声 ε`

然后更新隐向量:zt−1=zt−ε×系数

图片每一步都更清晰一点点


4. VAE 解码器(最后变图片)

跑完所有去噪步后,得到的是隐空间特征图,不是像素图。

送入 VAE decoder 解码:

隐向量→RGB 图片(0∼255)

这就是你最终看到的图。


四、完整生成流程(标准步骤,1:1 对应代码)

步骤 1:准备文本提示

plaintext

prompt = "a cute cat, photorealistic"

negative_prompt = "blurry, ugly, disfigured"


步骤 2:文本编码(CLIP)

把提示变成文本特征:

plaintext

text_embeddings = clip_tokenizer.encode(prompt)


步骤 3:初始化随机隐空间噪声

plaintext

z = torch.randn(1, 4, latent_h, latent_w)


步骤 4:循环去噪(核心循环)

python运行

for t in reversed(timesteps):

    # 1. UNet 预测噪声

    noise_pred = unet(z, t, text_embeddings)


    # 2. 用预测噪声更新隐空间

    z = scheduler.step(z, noise_pred, t)


步数跑完,z 就是高质量隐图。

步骤 5:VAE 解码成像素图

python运行

image = vae.decode(z)

image = (image / 2 + 0.5).clamp(0, 1)


步骤 6:保存输出

转成 PIL / 保存为 PNG。


五、三大核心模块作用(超级清晰

1. CLIP 文本编码器

只干一件事:

把文字 → 语义向量

让模型知道画什么。

2. UNet

整个模型的大脑

输入:噪点 + 文本 + 步数

输出:应该减掉多少噪声

3. VAE

两个作用:

3.1 训练时:把图片压缩到小隐空间(快)

3.2 生成时:把隐空间还原为高清图


六、和语言模型的本质区别(一定要记住)

表格项目大语言模型(GPT/LLaMA)图像扩散模型(SD/SDXL/Flux)生成方式自回归,逐 token 生成并行去噪,固定步数结束输出单位字 /token整张图的隐空间特征结束方式eos token / 长度限制固定步数跑完就结束概率分布词表概率无词表,预测噪声顺序性强依赖前文全局并行,无顺序Embedding词 ID→向量文本→向量,图像不走 emb

语言模型是写字;图片模型是 “修图”,从马赛克修成高清。


七、如果你想,我可以继续讲

最简化可运行 SD 代码(100 行以内)

Latent Space 到底是什么,为什么要压缩图片

Classifier-Free Guidance 怎么做(提示词强度)

LoRA 原理、训练、合并

图生图、局部重绘、ControlNet 机制




CUDA的安装

点击查看安装方法

CUDA(Compute Unified Device Architecture)是由NVIDIA公司开发的一种并行计算平台和编程模型,主要应用于该公司生产的GPU(图形处理器)。它允许开发者使用支持CUDA的编程语言(如C、C++、Fortran等)来编写在GPU上运行的程序,以利用GPU强大的并行计算能力。

CUDA的主要特点和优势包括:

并行计算: CUDA允许在GPU上进行大规模并行计算,可以大幅提高某些类型任务(如科学计算、机器学习等)的运行速度。

易用性: CUDA提供了一组扩展的编程语言(如CUDA C/C++),使得开发人员可以较容易地编写和优化GPU程序。

可扩展性: CUDA程序可以在不同规模和性能的NVIDIA GPU上运行,具有良好的可扩展性。

生态系统: NVIDIA提供了丰富的CUDA工具和库(如cuBLAS、cuDNN等),加速了GPU程序的开发。

广泛应用: CUDA已被广泛应用于科学计算、机器学习、图像处理、视频编码等领域,尤其在深度学习领域发挥了重要作用。

总之,CUDA通过利用GPU的并行计算架构,为开发者提供了一种开发高性能应用程序的强大工具,极大地推动了GPU计算的发展和应用。它已成为许多领域不可或缺的加速计算平台。


CUDA实际上包含了SDK(Software Development Kit)和API(Application Programming Interface)两个部分。

  1. CUDA SDK:CUDA SDK是一套完整的开发工具包,包括编译器、调试器、性能分析工具、数学库等。它允许开发者在支持CUDA的硬件上开发、调试和优化基于GPU的应用程序。CUDA SDK提供了一个集成的开发环境,使开发人员能够更高效地开发CUDA应用程序。

  2. CUDA API:CUDA API是一组用于与GPU交互的编程接口。它包括一组扩展的编程语言(如CUDA C/C++)和函数库,允许开发者在GPU上分配内存、传输数据、启动内核函数等。CUDA API提供了对GPU硬件的抽象,使开发人员能够专注于并行算法的实现,而不必过多关注底层硬件细节。

因此,从开发者的角度来看,CUDA主要是一个SDK,因为它提供了一整套开发GPU应用程序所需的工具和组件。同时,从编程的角度来看,CUDA也提供了一组API,允许开发者在其应用程序中与GPU进行交互和数据传输。

总之,CUDA作为一个并行计算平台,包含了SDK和API两个紧密相关的部分,共同为GPU编程提供了强大的支持。


CUDNN(CUDA Deep Neural Network library)是NVIDIA提供的一个用于深度神经网络的GPU加速库。它是CUDA工具包的一部分,旨在提高深度学习应用程序的性能。CUDNN提供了一组经过优化的深度学习基元,如卷积、池化、归一化和激活函数等,可以显著加快深度神经网络的训练和推理速度。

CUDNN的主要特点和优势包括:

  1. 高性能: CUDNN提供了经过优化的深度学习基元实现,充分利用了GPU的并行计算能力,可以显著提高深度神经网络的运行速度。

  2. 易用性: CUDNN提供了简单易用的API接口,可以方便地集成到现有的深度学习框架中,如TensorFlow、PyTorch、Caffe等。

  3. 多种神经网络支持: CUDNN支持各种类型的深度神经网络,包括卷积神经网络(CNN)、递归神经网络(RNN)、长短期记忆网络(LSTM)等。

  4. 自动优化: CUDNN可以根据硬件配置和网络结构自动选择最优的算法和参数,简化了性能优化的过程。

  5. 持续更新: NVIDIA会持续更新CUDNN,提供新的功能和性能改进,以跟上深度学习技术的发展。

CUDNN的工作原理是将深度学习基元的实现从深度学习框架中抽离出来,并提供了经过优化的GPU实现。当深度学习框架调用这些基元时,实际上是在调用CUDNN库提供的高度优化的GPU实现,从而获得显著的性能提升。

总之,CUDNN作为一个专用于深度学习的GPU加速库,通过提供经过优化的深度学习基元实现,显著提高了深度神经网络的性能。它已成为加速深度学习应用程序的重要工具,被广泛应用于学术研究和工业界。



关于NLP里tokens的解释

在自然语言处理(NLP)领域,特别是在基于 Transformer 架构的语言模型中,"tokens"(标记)通常是指构成输入序列的基本单元。它可以是一个字、一个词、一个子词或者一个字符,具体取决于所使用的分词方法。

在传统的 NLP 任务中,"token"通常指的是单个的词。例如,句子"I love AI"包含三个 tokens:"I"、"love"和"AI"。


当我们说"模型支持 8k tokens 上下文"时,这意味着:

假设你正在读一本书,现在你读到了第100页。为了真正理解第100页的内容,仅仅读这一页可能是不够的,你可能需要回顾前面的几页,甚至是前面的几章,以便更好地理解当前页面的内容。这些你需要回顾的前面的内容,就是所谓的"上下文"。

现在,假设你有一个超强的记忆力,你可以在读第100页时,同时考虑前面99页的内容。这意味着你有100页的"上下文"来帮助你理解第100页。显然,与只记得前面10页或20页相比,记住前面99页可以让你对第100页有更深入、更全面的理解。

将这个例子与语言模型联系起来:

每一页可以看作是一个"token"(假设每页只有一个词)。

你正在读的第100页就是模型当前要处理的 token。

你的"超强记忆力"就相当于模型的上下文长度。

因此,当我们说"模型支持 8k tokens 上下文"时,这就像说你在读第8000页时,可以同时记住并考虑前面的7999页。这是一个非常大的"记忆力",可以帮助模型更好地理解和生成文本。

当然,在实际应用中,模型处理的是更细粒度的 tokens(通常是词或子词),而不是整页的内容。但无论如何,更长的上下文意味着模型可以考虑更多的信息,从而做出更准确、更连贯的预测或生成。


关于tokens的计费

在大多数提供 AI 语言模型服务的平台中,按 tokens 计费通常包括用户的输入和 AI 的输出,也就是说,两者都会被计入费用。







人工智能书推荐

点击进入推荐

数学书推荐

TensorFlow中文文档  官方文档

Pytorch中文文档       官方文档







TensorFlow VS PyTorch

安装和配置

TensorFlow和PyTorch的安装和配置过程都相对简单。它们都支持多个操作系统,包括Windows、Linux和macOS。TensorFlow支持Python、C++、Java和Go等编程语言,而PyTorch主要使用Python。两个框架的文档和社区资源非常丰富,可以帮助用户解决安装和配置过程中遇到的问题。


模型定义和训练

TensorFlow和PyTorch在模型定义和训练方面有一些不同。在TensorFlow中,模型的定义和计算图建立在静态图的基础上,用户需要显式地定义图中的节点和操作。这种方式的好处是可以对图进行高级优化和部署。而在PyTorch中,模型的定义和计算图是动态的,用户可以根据需要灵活地定义和修改计算图。这种动态图的方式使得PyTorch更容易进行调试和实验。

在训练过程中,TensorFlow使用会话(Session)来管理计算图和变量。用户需要明确地指定变量的初始化、损失函数、优化器等。PyTorch则使用动态图来追踪变量和操作的计算过程,用户只需简单地定义前向传播过程,然后通过调用反向传播函数即可进行梯度计算和参数更新。


灵活性和可扩展性

在灵活性和可扩展性方面,PyTorch表现更加出色。PyTorch的设计理念强调易用性和灵活性,用户可以方便地对模型进行修改和扩展。PyTorch还提供了更多的高级特性,如动态图、自动微分和自定义操作等,使得用户可以更好地控制模型的计算过程。


TensorFlow虽然在初始学习成本上可能相对高一些,但它在大规模分布式训练和部署等方面表现出更高的可扩展性。TensorFlow的静态图设计使得其能够对计算图进行高效优化和分布式运算。此外,TensorFlow还提供了一系列用于大规模训练和部署的工具和库。


社区支持

TensorFlow和PyTorch都有庞大的用户社区和丰富的文档资源,这使得学习和使用这两个框架变得更加容易。TensorFlow在推出之初就受到了很多大公司的青睐,并得到了广泛应用。PyTorch则是由Facebook AI Research开发并开源的,近年来也得到了越来越多学术界和工业界的支持。两个框架都拥有活跃的社区,用户可以在社区中寻求帮助、交流经验和分享代码。此外,两个框架都有很多开源项目和示例代码可供学习和参考。




何为AI模型

AI模型是一种计算机程序,它通过学习和分析大量的数据,尤其是输入和输出的对应关系,来模拟人类的智能行为。它可以用于各种任务,如图像识别、语音识别、自然语言处理等。

简单来说,AI模型就像是一个智能工具,它可以通过大量的训练数据学习并理解事物的规律和模式。类似于我们人类学习新知识的过程,AI模型会通过观察和分析数据来提取特征,并建立一个能够预测和推理的模型。这个模型在训练完成后就可以被用来处理新的数据,并作出类似人类的决策或回答问题。

举个例子,如果我们想让AI模型学会识别猫的图片,我们可以给它展示大量的猫的图片,并告诉它这些图片都是猫。AI模型会通过分析这些图片的特征,比如猫的耳朵、眼睛、鼻子等,来学会辨别猫的图片。然后,当我们给它一张新的图片时,AI模型可以根据之前学到的知识判断这张图片是否是猫。

总的来说,AI模型就是一个能够通过学习数据来模拟人类智能行为的程序,它可以帮助我们解决各种复杂的问题,并提供智能化的服务。



学习AI模型开发需要掌握以下基础知识

1. 编程语言:首先,你需要熟悉至少一种编程语言,比如Python或Java。这些语言在AI开发中广泛使用,因为它们具有丰富的库和工具,可以简化开发过程。

2. 数据处理和分析:了解数据处理和分析的基本概念是非常重要的。你需要学会如何清洗、转换和准备数据,以便用于训练和评估AI模型。

3. 数学和统计学:AI模型的许多算法和技术都基于数学和统计学原理。掌握线性代数、微积分、概率论和统计学等基础数学概念对于理解和实现AI模型是必要的。

4. 机器学习算法:学习机器学习算法是开发AI模型的关键。你需要了解常见的机器学习算法,如线性回归、逻辑回归、决策树、支持向量机和神经网络等。掌握这些算法的原理、应用场景和实现方式将帮助你构建和训练AI模型。

5. 深度学习:深度学习是一种特殊的机器学习方法,它使用神经网络模型来处理复杂的任务。学习深度学习需要了解神经网络的基本原理、常见的深度学习架构(如卷积神经网络、循环神经网络)以及深度学习框架(如TensorFlow、PyTorch)的使用。

6. 数据集和训练:了解如何准备和使用数据集进行模型训练是至关重要的。你需要学习如何选择、标记和划分数据集,以及如何进行训练和验证。

7. 模型评估和优化:了解如何评估和优化AI模型的性能也是必不可少的。你需要学习如何选择合适的评估指标,如准确率、精确率、召回率等,并掌握调整模型参数、处理过拟合和欠拟合等常见问题的技巧。

除了上述基础知识,还可以学习一些特定领域的知识,如计算机视觉、自然语言处理或增强学习等,以应用AI模型于具体的应用场景中。

学习AI模型开发是一个不断深入和不断学习的过程。建议从基础知识开始,逐步深入学习和实践,通过阅读书籍、参与在线课程、实践项目等方式提升自己的技能。




AI模型的训练

AI模型训练是一个迭代的过程,其目的是通过给定的输入数据(也称为训练数据)来调整模型的参数,使其能够对未知数据做出准确的预测或执行特定任务。

训练过程可以分为以下几个步骤:

  1. 1.数据收集和准备:首先,我们需要收集与目标任务相关的训练数据。这些数据可以是图像、文本、音频等形式。然后,我们对数据进行预处理和清洗,以确保数据质量和一致性。        

  2. 2.模型选择和设计:根据任务的特点,我们选择适合的模型架构。不同的任务可能需要不同类型的模型,例如卷积神经网络(CNN)用于图像处理,循环神经网络(RNN)用于序列数据处理等。在选择模型后,我们设计模型的结构,包括层数、节点数量等。        

  3. 3.参数初始化:模型中的参数是在训练过程中需要学习和调整的。在开始训练之前,我们需要对模型的参数进行初始化,可以使用随机初始化的方法。        

  4. 4.前向传播:在训练过程中,我们将训练数据输入到模型中,通过前向传播的过程,模型根据当前的参数计算输出结果。        

  5. 5.计算损失:通过比较模型的输出结果和训练数据中的真实标签,我们可以计算出模型的损失值。损失值表示模型预测的输出与真实标签之间的差异。        

  6. 6.反向传播:在反向传播过程中,我们使用损失值来计算模型中每个参数对损失的贡献度,然后根据贡献度的方向调整参数的值。这个过程通过梯度下降算法来更新参数,使得模型的预测结果逐步接近真实标签。        

  7. 7.参数更新:根据反向传播计算得到的梯度信息,我们更新模型中的参数值,使其朝着降低损失的方向移动。        

  8. 8.重复迭代:重复进行前向传播、计算损失、反向传播和参数更新的过程,直到模型收敛或达到预设的停止条件(如训练轮数、损失阈值等)。        

训练的目的是通过不断调整模型的参数,使得模型能够在未见过的数据上做出准确的预测或执行任务。通过大量的训练数据和迭代优化的过程,模型可以学习到输入数据的特征和模式,从而具备泛化能力,能够对新的数据进行准确的预测或执行任务。



设计AI模型

设计AI模型的过程可以分为以下几个关键步骤,以便程序员能够理解:

1. 确定任务:首先,明确你要解决的具体任务。这可能是图像分类、目标检测、文本生成等。确保清楚地定义任务的输入和期望输出。

2. 收集和准备数据:收集适用于任务的训练数据。这些数据应该涵盖各种情况和场景,以确保模型的泛化能力。对数据进行预处理,包括标准化、归一化、去噪等,以提高模型的训练效果。

3. 选择模型架构:根据任务的特点和数据的特征,选择适当的模型架构。常见的模型架构包括卷积神经网络(CNN)、循环神经网络(RNN)、变压器模型(Transformer)等。了解不同模型架构的原理和适用场景,选择最适合任务的模型。

4. 设计模型结构:在选择模型架构后,设计模型的具体结构。这包括确定模型的层数、每层的节点数量、激活函数的选择等。合理的模型结构应该能够有效地提取输入数据中的特征,并产生准确的输出。

5. 初始化参数:在训练模型之前,需要对模型的参数进行初始化。可以使用随机初始化的方法,为模型的权重和偏置等参数赋予初始值。

6. 定义损失函数:选择适当的损失函数来度量模型的预测结果与实际标签之间的差异。常见的损失函数包括均方误差(MSE)、交叉熵损失等。确保选择与任务和数据类型相匹配的损失函数。

7. 选择优化算法:为了训练模型并调整参数,需要选择适当的优化算法。常见的优化算法包括随机梯度下降(SGD)、Adam、RMSProp等。了解这些算法的原理和特点,选择最适合模型训练的优化算法。

8. 训练和评估模型:使用准备好的训练数据对模型进行训练。通过将输入数据传递给模型,计算模型的输出,并将其与实际标签进行比较,计算损失并更新模型参数。重复这个过程,直到模型收敛或达到预设的停止条件。在训练过程中,使用验证数据集对模型进行评估,并监控模型的性能。

9. 调优和改进:根据训练和评估的结果,根据需要对模型进行调优和改进。可以尝试调整模型的结构、超参数的选择,或者增加更多的训练数据等,以提高模型的性能和泛化能力。

10. 测试和部署:在训练完成后,使用独立的测试数据集对模型进行最终评估。确保模型在未见过的数据上表现良好。最后,将训练好的模型部署到实际应用中,用于实际的预测或任务执行。

通过以上步骤,你可以设计和训练一个AI模型,以解决特定的任务,并实现准确的预测或执行。根据不同的任务和应用领域,设计AI模型的具体细节和技术会有所不同。因此,不断学习和实践,积累经验是提高AI模型设计和训练的关键。



Transformers 和PyTorch的关系

Transformers和PyTorch是两个不同但相关的概念。

Transformers是一种模型架构,用于处理序列数据,特别是在自然语言处理(NLP)任务中表现出色。它最早由Vaswani等人于2017年提出,并在2018年的论文《Attention Is All You Need》中引入了注意力机制。Transformers模型的核心是自注意力机制,通过对输入序列中的不同位置进行注意力计算,从而捕捉全局上下文信息。

PyTorch是一个深度学习框架,提供了用于构建、训练和部署神经网络模型的工具和接口。它由Facebook的研究团队开发,并在深度学习社区中广泛应用。PyTorch提供了丰富的API和工具,使得开发者可以方便地定义神经网络结构、处理数据、进行模型训练和推理等。

在实践中,Transformers模型通常是使用PyTorch等深度学习框架进行实现和训练的。PyTorch提供了强大的张量操作和自动求导功能,使得实现和训练复杂的Transformers模型变得更加容易。此外,PyTorch还提供了许多与深度学习相关的库和工具,如PyTorch Lightning和TorchText,可以进一步简化模型开发和训练的过程。

因此,可以说Transformers是一种模型架构,而PyTorch是一个用于实现和训练Transformers模型的深度学习框架。PyTorch为开发者提供了构建和训练Transformers模型所需的工具和环境,使得使用Transformers模型变得更加便捷和高效。





AI人工智能产品缺陷检测

要使用Python进行产品缺陷检测,可以利用计算机视觉和机器学习技术。以下是一个基本的思路和步骤:


收集并准备缺陷和非缺陷的产品样本图像数据集。这些图像应包含不同类型和程度的产品缺陷,以及正常的产品图像作为对比。


使用图像处理技术,例如调整大小、灰度化、增强对比度等,对图像进行预处理,以便更好地提取特征。

提取图像特征。可以使用传统的计算机视觉方法,例如边缘检测、角点检测、纹理特征提取等,或使用深度学习模型进行特征提取。

图像的特征提取是计算机视觉中的一个重要任务,它可以帮助我们捕捉图像中的关键信息和表征。以下是一些常用的图像特征提取方式:

1.颜色特征:提取图像的颜色信息,例如直方图、颜色矩、颜色梯度等。

2.纹理特征:捕捉图像的纹理信息,例如灰度共生矩阵(GLCM)、局部二值模式(LBP)、Gabor滤波器等。

3.形状特征:描述图像中的形状和边界信息,例如边缘检测、轮廓特征、形状描述子(如Hu矩、Zernike矩)等。

4.角点特征:检测图像中的关键点和角点,例如Harris角点检测、Shi-Tomasi角点检测、FAST角点检测等。

5.尺度不变特征变换(SIFT):通过检测图像中的局部特征点,并计算其描述子,从而实现对尺度、旋转、光照变化等的不变性。

6.领域知识特征:利用特定领域的先验知识,设计和提取与特定任务相关的特征,例如医学图像中的肿瘤形态学特征。

7.深度学习特征:使用深度卷积神经网络(CNN)等深度学习模型,通过从大规模数据集中进行端到端训练,自动学习图像的高级特征表示

以上仅列举了一些常见的图像特征提取方式,实际上还有很多其他方法和技术可供选择。特征的选择应该根据具体任务和数据集的特点来确定,有时也可以结合多种特征进行综合表示。此外,特征提取往往是图像处理和计算机视觉任务的前置步骤,后续的任务可以基于提取的特征进行分类、检测、定位等操作。


构建分类模型。使用准备好的样本数据集,训练一个分类模型,例如卷积神经网络(CNN)或支持向量机(SVM),来区分缺陷和非缺陷的产品。

在Python中,可以使用深度学习框架如TensorFlow、Keras、PyTorch等来构建和训练分类模型。这些框架提供了丰富的工具和API,以简化模型的构建、训练和评估过程。


对新的产品图像进行预测。使用训练好的模型,对新的产品图像进行预测,判断其是否存在缺陷。


根据预测结果进行处理。根据预测结果,可以自动化地处理有缺陷的产品,例如标记、分类、拒绝等。


定期评估和优化模型性能。对模型进行评估,根据反馈信息进行优化和改进,以提高缺陷检测的准确性和鲁棒性。


需要注意的是,以上步骤仅提供了一个基本的思路。实际应用中,可能需要根据具体情况进行调整和改进。例如,如果缺陷种类较多或样本不平衡,可能需要采用更复杂的模型或进行数据增强等处理。此外,还可以结合其他技术,如目标检测、图像分割等,来更精确地定位和识别产品缺陷。


综上所述,产品缺陷检测是一个复杂的任务,需要综合运用计算机视觉和机器学习技术。在实际应用中,可能需要进行多轮迭代和调优,以获得最佳的缺陷检测效果。



PyTorch深度学习快速入门教程

点击查看原视频

点击进入PyTorch主页



B站强推!2023公认最通俗易懂的【PyTorch】教程

点击查看原视频



人工智能与机器人|常用的数据集格式

点击查看原文



AI模型的格式有哪些文件后缀分别是啥及各种格式模型的使用方法

格式选择与应用场景

研究与微调:PyTorch 的.pt/.pth或 Hugging Face 的 Safetensors,灵活性高且生态丰富。

跨平台部署:ONNX 或 GGUF,兼容多框架和硬件,适合边缘计算和云服务。

硬件优化推理:昇腾 OM、TensorRT 或 Core ML,针对特定芯片架构提升性能。

移动端与低资源设备:TFLite、GGUF(量化版)或 Core ML,平衡速度与精度。

安全共享与协作:Safetensors 或 ONNX,避免安全漏洞并支持跨语言协作。

AI模型可以有多种不同的文件格式,每种格式都有自己的文件后缀和使用方法。以下是一些常见的AI模型格式及其文件后缀和使用方法:


TensorFlow模型:

文件后缀:.pb(Protocol Buffer格式)、.h5(HDF5格式)

使用方法:使用TensorFlow框架的API加载和使用模型。可以使用tf.saved_model.loader.load()函数加载.pb文件,使用tf.keras.models.load_model()函数加载.h5文件。


PyTorch模型:

文件后缀:.pt、.pth

使用方法:使用PyTorch框架的API加载和使用模型。可以使用torch.load()函数加载.pt或.pth文件。


pytorch使用pt模型

步骤1:导入必要的库和模块

在这一步中,我们需要导入PyTorch和其他必要的库和模块。通常,我们需要导入以下库和模块:

import torch

import torchvision


步骤2:加载.pt模型文件

在这一步中,我们将加载.pt模型文件。我们可以使用torch.load函数来加载.pt模型文件,并将其保存为一个变量。

model = torch.load('model.pt')

这里,model.pt表示.pt模型文件的路径。请确保.pt模型文件位于当前工作目录中,或者提供正确的文件路径。


步骤3:使用模型进行推理或训练

在这一步中,我们可以使用加载的模型进行推理或训练。根据具体的任务,我们可能需要做一些预处理或后处理的操作。

output = model(input)

这里,input表示输入数据。请根据具体的任务和模型的要求提供正确的输入。


步骤4:保存模型(可选)

在这一步中,我们可以选择将训练好的模型保存为.pt文件,以备将来使用。

torch.save(model, 'model.pt')


这里,model表示要保存的模型对象,model.pt表示保存的.pt文件的路径。请确保提供正确的文件路径。


一、做法

1.*.pt文件

.pt文件保存的是模型的全部,在加载时可以直接赋值给新变量model = torch.load("filename.pt")。

具体操作:

(1). 模型的保存

torch.save(model,"Path/文件名.pt")

这里的Path为你想将模型保存的位置,写完Path后加一个"/"表示进入目录内部,最后给出文件名.pt.


(2). 模型的加载

model = torch.load("文件名.pt")

注意:torch.load()的参数使用字符串参数。


2. .pth文件

.pth保存的是模型参数,通过字符字典进行保存,在加载该类文件时应该先实例化一个具体的模型,然后对新建立的空模型,进行参数赋予。

具体操作:

(1). 模型的保存

torch.save(model.state_dict(), PATH)

(2). 模型的加载

model = torch.nn.Module() # 这里要先实例化模型

model.load_state_dict(torch.load("xxx.pth"))

二 、操作实例

这里先定义一个模型作为例子

# Define model

class TheModelClass(nn.Module):

    # 类的初始化

    def __init__(self):

        # 继承父类 nn.Module 的属性和方法

        super(TheModelClass, self).__init__()

        # Inputs_channel, Outputs_channel, kernel_size

        self.conv1 = nn.Conv2d(3, 6, 5)

        # 最大池化层,池化核的大小

        self.pool = nn.MaxPool2d(2, 2)

        # 卷积层,池化层,卷积层

        self.conv2 = nn.Conv2d(6, 16, 5)

        # 最后接一个线性全连接层

        self.fc1 = nn.Linear(16 * 5 * 5, 120)

        self.fc2 = nn.Linear(120, 84)

        self.fc3 = nn.Linear(84, 10)


    def forward(self, x):

        # 卷积作用后,使用relu进行非线性化,最后使用池化操作进行特征个数,参数量的降低

        x = self.pool(F.relu(self.conv1(x)))

        x = self.pool(F.relu(self.conv2(x)))

        x = x.view(-1, 16 * 5 * 5)

        x = F.relu(self.fc1(x))

        x = F.relu(self.fc2(x))

        x = self.fc3(x)

        return x


# Initialize model

model = TheModelClass()


# Initialize optimizer

optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)


# Print model's state_dict

print("Model's state_dict:")

for param_tensor in model.state_dict():

    print(param_tensor, "\t", model.state_dict()[param_tensor].size())


# Print optimizer's state_dict

print("Optimizer's state_dict:")

for var_name in optimizer.state_dict():

    print(var_name, "\t", optimizer.state_dict()[var_name])



2. 现在开始进行模型的保存与加载


PATH = "E:/深度学习/model"

# ######################### 第一种模型保存和加载方式

torch.save(model.state_dict(), PATH+"/TheModuleClass.pth")

model = TheModelClass()

model.load_state_dict(torch.load("E:/深度学习/model/TheModuleClass.pth"))


for param_tensor in model.state_dict():

    print(f"{param_tensor}<<<{model.state_dict()[param_tensor].size()}")

print(model)


# ####### 输出结果

'''

conv1.weight<<<torch.Size([6, 3, 5, 5])

conv1.bias<<<torch.Size([6])

conv2.weight<<<torch.Size([16, 6, 5, 5])

conv2.bias<<<torch.Size([16])

fc1.weight<<<torch.Size([120, 400])

fc1.bias<<<torch.Size([120])

fc2.weight<<<torch.Size([84, 120])

fc2.bias<<<torch.Size([84])

fc3.weight<<<torch.Size([10, 84])

fc3.bias<<<torch.Size([10])

TheModelClass(

  (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))

  (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)

  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))

  (fc1): Linear(in_features=400, out_features=120, bias=True)

  (fc2): Linear(in_features=120, out_features=84, bias=True)

  (fc3): Linear(in_features=84, out_features=10, bias=True)

)

'''

# ########################### 第二种模型保存和加载方式


torch.save(model, PATH + "/the_module_class.pt")

model = torch.load(PATH + "/the_module_class.pt")


for param_tensor in model.state_dict():

    print(f"{param_tensor} <<< {model.state_dict()[param_tensor].size()}")

print(model)


# ####### 输出结果

'''

conv1.weight<<<torch.Size([6, 3, 5, 5])

conv1.bias<<<torch.Size([6])

conv2.weight<<<torch.Size([16, 6, 5, 5])

conv2.bias<<<torch.Size([16])

fc1.weight<<<torch.Size([120, 400])

fc1.bias<<<torch.Size([120])

fc2.weight<<<torch.Size([84, 120])

fc2.bias<<<torch.Size([84])

fc3.weight<<<torch.Size([10, 84])

fc3.bias<<<torch.Size([10])

TheModelClass(

  (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))

  (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)

  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))

  (fc1): Linear(in_features=400, out_features=120, bias=True)

  (fc2): Linear(in_features=120, out_features=84, bias=True)

  (fc3): Linear(in_features=84, out_features=10, bias=True)

)

'''

总结

这里推荐使用第二种方法,因为保存和加载文件简单,而且生成的二进制文件区分程度高。

torch.save() 保存模型的参数,为以后模型推理核模型恢复提供了更加方便更加灵活的方法。

一定要在模型评估时, 关闭批量规范化和丢弃法, 仅仅在模型训练时有用,模型推理时一定要关闭(所谓模型推理,指是使用模型进行的实际应用)

加载.pth 要先实例化,再进行参数的承接。


ONNX模型:

文件后缀:.onnx

使用方法:使用ONNX框架或支持ONNX的其他框架加载和使用模型。可以使用onnxruntime库加载和执行ONNX模型。


Keras模型:

文件后缀:.h5

使用方法:使用Keras框架的API加载和使用模型。可以使用keras.models.load_model()函数加载.h5文件。


Caffe模型:

文件后缀:.caffemodel、.prototxt

使用方法:使用Caffe框架的API加载和使用模型。可以使用caffe.Net()函数加载.caffemodel和.prototxt文件。


GGUF(GPT-Generated Unified Format)格式

文件后缀:.gguf

由 Georgi Gerganov(著名开源项目llama.cpp的创始人)定义发布的一种大模型文件格式。GGUF 继承自其前身 GGML,但 GGML 格式有一些缺点,已被完全弃用并被 GGUF 格式取代。GGUF 是一种二进制格式文件的规范,原始的大模型预训练结果经过转换后变成 GGUF 格式可以更快地被载入使用,也会消耗更低的资源。原因在于 GGUF 采用了多种技术来保存大模型预训练结果,包括采用紧凑的二进制编码格式、优化的数据结构、内存映射等。

GGUF 具有如下特性

单文件部署:它们可以轻松分发和加载,并且不需要任何外部文件来获取附加信息。

可扩展性:可以将新特征添加到基于 GGML 的执行器中/可以将新信息添加到 GGUF 模型中,而不会破坏与现有模型的兼容性。

mmap兼容性:可以使用mmap加载模型,以实现快速地加载和保存。

易于使用:无论使用何种语言,都可以使用少量代码轻松加载和保存模型,无需外部库。

信息完整:加载模型所需的所有信息都包含在模型文件中,用户不需要提供任何额外的信息。这大大简化了模型部署和共享的流程。


safetensors更侧重于安全性和效率,适合快速部署和对安全性有较高要求的场景,特别是在HuggingFace生态中。而gguf格式则是一种为大模型设计的二进制文件格式,优化了模型的加载速度和资源消耗,适合需要频繁加载不同模型的场景。



在大型深度学习模型的上下文中,.safetensors、.bin 和 .pth ckpt 文件的用途和区别如下:


.safetensors 文件:

这是由 Hugging Face 推出的一种新型安全模型存储格式,特别关注模型安全性、隐私保护和快速加载。

它仅包含模型的权重参数,而不包括执行代码,这样可以减少模型文件大小,提高加载速度。

加载方式:使用 Hugging Face 提供的相关API来加载 .safetensors 文件,例如 safetensors.torch.load_file() 函数。


ckpt文件:

ckpt 文件是 PyTorch Lightning 框架采用的模型存储格式,它不仅包含了模型参数,还包括优化器状态以及可能的训练元数据信息,使得用户可以无缝地恢复训练或执行推理。


.bin 文件:

通常是一种通用的二进制格式文件,它可以用来存储任意类型的数据。

在机器学习领域,.bin 文件有时用于存储模型权重或其他二进制数据,但并不特指PyTorch的官方标准格式。

对于PyTorch而言,如果用户自己选择将模型权重以二进制格式保存,可能会使用 .bin 扩展名,加载时需要自定义逻辑读取和应用这些权重到模型结构中。


.pth 文件:

是 PyTorch 中用于保存模型状态的标准格式。

主要用于保存模型的 state_dict,包含了模型的所有可学习参数,或者整个模型(包括结构和参数)。

加载方式:使用 PyTorch 的 torch.load() 函数直接加载 .pth 文件,并通过调用 model.load_state_dict() 将加载的字典应用于模型实例。

总结起来:


.safetensors 侧重于安全性和效率,适合于那些希望快速部署且对安全有较高要求的场景,尤其在Hugging Face生态中。

.ckpt 文件是 PyTorch Lightning 框架采用的模型存储格式,它不仅包含了模型参数,还包括优化器状态以及可能的训练元数据信息,使得用户可以无缝地恢复训练或执行推理。

.bin 文件不是标准化的模型保存格式,但在某些情况下可用于存储原始二进制权重数据,加载时需额外处理。

.pth 是PyTorch的标准模型保存格式,方便模型的持久化和复用,支持完整模型结构和参数的保存与恢复。


加载以及保存

- 加载.safetensors文件

# 用SDXL举例

import torch

from diffusers import StableDiffusionXLPipeline, UNet2DConditionModel, EulerDiscreteScheduler

from huggingface_hub import hf_hub_download

from safetensors.torch import load_file

 

base = "stabilityai/stable-diffusion-xl-base-1.0"

repo = "ByteDance/SDXL-Lightning"

ckpt = "/home/bino/svul/models/sdxl/sdxl_lightning_2step_unet.safetensors" # Use the correct ckpt for your step setting!

 

# Load model.

unet = UNet2DConditionModel.from_config(base, subfolder="unet").to("cuda", torch.float16)

unet.load_state_dict(load_file(ckpt, device="cuda"))

# unet.load_state_dict(load_file(hf_hub_download(repo, ckpt), device="cuda"))

pipe = StableDiffusionXLPipeline.from_pretrained(base, unet=unet, torch_dtype=torch.float16, variant="fp16").to("cuda")

 

# Ensure sampler uses "trailing" timesteps.

pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config, timestep_spacing="trailing")

 

# Ensure using the same inference steps as the loaded model and CFG set to 0.

pipe("A girl smiling", num_inference_steps=4, guidance_scale=0).images[0].save("output.png")


- 保存/加载.pth文件:

 # 保存模型状态字典

 torch.save(model.state_dict(), "model.pth")

 

 # 加载模型状态字典到已有模型结构中

 model = TheModelClass(*args, **kwargs)

 model.load_state_dict(torch.load("model.pth"))

 

 # 或者保存整个模型,包括结构

 torch.save(model, "model.pth")

 

 # 加载整个模型

 model = torch.load("model.pth", map_location=device)


- 保存/加载.ckpt文件

import pytorch_lightning as pl

 

# 定义一个 PyTorch Lightning 训练模块

class MyLightningModel(pl.LightningModule):

   def __init__(self):

       super().__init__()

       self.linear_layer = nn.Linear(10, 1)

       self.loss_function = nn.MSELoss()

 

   def forward(self, inputs):

       return self.linear_layer(inputs)

 

   def training_step(self, batch, batch_idx):

       features, targets = batch

       predictions = self(features)

       loss = self.loss_function(predictions, targets)

       self.log('train_loss', loss)

       return loss

 

# 初始化 PyTorch Lightning 模型

lightning_model = MyLightningModel()

 

# 配置 ModelCheckpoint 回调以定期保存最佳模型至 .ckpt 文件

checkpoint_callback = pl.callbacks.ModelCheckpoint(

   monitor='val_loss',

   filename='best-model-{epoch:02d}-{val_loss:.2f}',

   save_top_k=3,

   mode='min'

)

 

# 创建训练器并启动模型训练

trainer = pl.Trainer(

   callbacks=[checkpoint_callback],

   max_epochs=10

)

trainer.fit(lightning_model)

 

# 从 .ckpt 文件加载最优模型权重

best_model = MyLightningModel.load_from_checkpoint(checkpoint_path='best-model.ckpt')

 

# 使用加载的 .ckpt 文件中的模型进行预测

sample_input = torch.randn(1, 10)

predicted_output = best_model(sample_input)

print(predicted_output)

在此示例中,我们首先定义了一个 PyTorch Lightning 模块,该模块集成了模型训练的逻辑。然后,我们配置了 ModelCheckpoint 回调函数,在训练过程中按照验证损失自动保存最佳模型至 .ckpt 文件。接着,我们展示了如何加载 .ckpt 文件中的最优模型权重,并利用加载后的模型对随机输入数据进行预测,同样输出预测结果。值得注意的是,由于 .ckpt 文件完整记录了训练状态,它在实际应用中常被用于模型微调和进一步训练。


- 处理.bin文件:

如果.bin文件是纯二进制权重文件,加载时需要知道模型结构并且手动将权重加载到对应的层中,例如:


 # 假设已经从.bin文件中读取到了模型权重数据

 weights_data = load_binary_weights("weights.bin")

 

 # 手动初始化模型并加载权重

 model = TheModelClass(*args, **kwargs)

 for name, param in model.named_parameters():

     if name in weights_mapping:  # 需要预先知道权重映射关系

         param.data.copy_(weights_data[weights_mapping[name]])


模型之间的互相转换

pytorch-lightning 和 pytorch

由于 PyTorch Lightning 模型本身就是 PyTorch 模型,因此不存在严格意义上的转换过程。你可以直接通过 LightningModule 中定义的神经网络层来进行保存和加载,就像普通的 PyTorch 模型一样:


# 假设 model 是一个 PyTorch Lightning 模型实例

model = MyLightningModel()

 

# 保存模型权重

torch.save(model.state_dict(), 'lightning_model.pth')

 

# 加载到一个新的 PyTorch 模型实例

new_model = MyLightningModel()

new_model.load_state_dict(torch.load('lightning_model.pth'))

 

# 或者加载到一个普通的 PyTorch Module 实例(假设结构一致)

plain_pytorch_model = MyPlainPytorchModel()

plain_pytorch_model.load_state_dict(torch.load('lightning_model.pth'))


ckpt和safetensors

转换后的模型在stable-diffussion-webui中使用过没有问题,不知道有没有错误,或者没转换成功


import torch

import os

import safetensors

from typing import Dict, List, Optional, Set, Tuple

from safetensors.torch import _find_shared_tensors, _is_complete, load_file, save_file

 

def ckpt2safetensors():

    loaded = torch.load('v1-5-pruned-emaonly.ckpt')

    if "state_dict" in loaded:

        loaded = loaded["state_dict"]

    safetensors.torch.save_file(loaded, 'v1-5-pruned-emaonly.safetensors')

 

def st2ckpt():

    # 加载 .safetensors 文件

    data = safetensors.torch.load_file('v1-5-pruned-emaonly.safetensors.bk')

    data["state_dict"] = data

    # 将数据保存为 .ckpt 文件

    torch.save(data, os.path.splitext('v1-5-pruned-emaonly.safetensors')[0] + '.ckpt')



AI模型格式转换

模型格式互转的核心是:以通用格式(如 ONNX)为桥梁,结合框架 / 硬件专属工具链实现转换。简单模型可直接通过脚本完成,复杂模型需针对性处理算子和维度问题。实际操作中,建议先查阅目标格式的官方文档,确保算子支持度满足需求。



手里有一个AI大模型只知道扩展名,如何调用呢

####【豆包】

Q:手里有一个AI大模型只知道扩展名,如何调用呢

A:...

Q:如何调用它的训练和推理呢

A:...

核心结论:推理调用可直接按模型格式匹配工具链实现,训练调用仅支持原始权重格式(.pt/.pth、safetensors 等),量化 / 部署格式(GGUF、TensorRT 等)需先转回原始格式才能训练。

一、推理调用(最常用,步骤简单)

推理是加载模型后执行预测任务(文本生成、图像识别等),不同格式的核心调用逻辑的是 “格式→工具链→执行推理”,以下是高频格式的实操方法:

1. 原始权重格式(.pt/.pth、safetensors)

工具链:PyTorch + Hugging Face Transformers(大模型首选)

文本模型(如 Llama、Qwen)调用示例:

from transformers import AutoModelForCausalLM, AutoTokenizer


# 加载模型和Tokenizer(safetensors格式直接替换路径即可,无需改代码)

model = AutoModelForCausalLM.from_pretrained("模型文件夹路径", device_map="auto")  # auto自动用GPU/CPU

tokenizer = AutoTokenizer.from_pretrained("模型文件夹路径")


# 推理(文本生成)

prompt = "请介绍AI大模型的应用场景"

inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

outputs = model.generate(**inputs, max_new_tokens=200, temperature=0.7)

print(tokenizer.decode(outputs[0], skip_special_tokens=True))

2. GGUF 格式(量化模型,适合低资源设备)

工具链:llama.cpp(命令行 / Python)或 ollama(服务化)

命令行快速推理(CPU/GPU 通用):

bash

# 下载llama.cpp后,执行以下命令(-ngl 32 表示用32层GPU加速,0则纯CPU)

./llama.cpp/main -m 模型.gguf -p "请介绍AI大模型的应用场景" -ngl 32 -n 200


Python API 调用:

from llama_cpp import Llama

llm = Llama(model_path="模型.gguf", n_ctx=2048, n_gpu_layers=32)  # n_ctx是上下文长度

output = llm.create_completion(prompt="请介绍AI大模型的应用场景", max_tokens=200)

print(output["choices"][0]["text"])

3. ONNX 格式(跨框架通用)

工具链:ONNX Runtime

文本模型推理示例:

import onnxruntime as ort

import tokenizer  # 需对应模型的Tokenizer(如transformers的AutoTokenizer)


# 加载ONNX模型和Tokenizer

session = ort.InferenceSession("模型.onnx", providers=["CUDAExecutionProvider"])  # GPU加速

tokenizer = AutoTokenizer.from_pretrained("模型文件夹路径")


# 预处理输入

prompt = "请介绍AI大模型的应用场景"

inputs = tokenizer(prompt, return_tensors="np")  # ONNX Runtime默认用numpy数组


# 执行推理

output_names = [output.name for output in session.get_outputs()]

outputs = session.run(output_names, dict(inputs))

generated_ids = outputs[0].argmax(axis=-1)

print(tokenizer.decode(generated_ids[0], skip_special_tokens=True))

4. 部署格式(TensorRT/.trt、TFLite/.tflite)

仅用于推理,不支持训练,调用依赖硬件工具链:

TensorRT(NVIDIA GPU):用 TensorRT Python/C++ API 加载引擎,输入预处理后执行推理。

TFLite(移动端 / 边缘设备):用 TensorFlow Lite Interpreter,适合手机、嵌入式设备。

二、训练调用(需原始格式,步骤更复杂)

训练是更新模型权重(微调、全量训练),仅支持原始权重格式(.pt/.pth、safetensors),量化格式(GGUF)、部署格式(TensorRT、ONNX)需先转回原始格式才能训练。

1. 前提条件

模型格式:必须是含完整结构的原始权重(仅.pt文件可能需额外模型定义代码)。

环境:PyTorch/TensorFlow 框架、足够显存(微调需 16GB+ GPU,全量训练需 32GB+)。

数据:按模型任务准备数据集(如文本生成用 JSON 格式,每行含 "prompt" 和 "response")。

2. 微调训练示例(Hugging Face Transformers)

以文本模型微调为例,用 LoRA(低资源高效微调)方法:

from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer

from peft import LoraConfig, get_peft_model  # LoRA依赖peft库


# 1. 加载原始模型和Tokenizer

model = AutoModelForCausalLM.from_pretrained("模型文件夹路径", device_map="auto")

tokenizer = AutoTokenizer.from_pretrained("模型文件夹路径")

tokenizer.pad_token = tokenizer.eos_token  # 补全pad token(部分模型需手动设置)


# 2. 配置LoRA参数(减少显存占用)

lora_config = LoraConfig(

    r=8, lora_alpha=32, target_modules=["q_proj", "v_proj"], lora_dropout=0.05

)

model = get_peft_model(model, lora_config)


# 3. 准备训练数据(示例:简单文本对)

train_data = [

    {"prompt": "介绍AI", "response": "AI是人工智能的简称,用于模拟人类智能行为"},

    {"prompt": "AI的应用", "response": "AI可用于医疗诊断、自动驾驶、智能客服等场景"}

]

# 数据预处理(tokenize)

def process_data(examples):

    inputs = tokenizer(examples["prompt"], truncation=True, max_length=512)

    outputs = tokenizer(examples["response"], truncation=True, max_length=512)

    inputs["labels"] = outputs["input_ids"]

    return inputs

processed_data = process_data({"prompt": [d["prompt"] for d in train_data], "response": [d["response"] for d in train_data]})


# 4. 配置训练参数

training_args = TrainingArguments(

    output_dir="./train_output",  # 训练输出目录

    per_device_train_batch_size=2,  # 批次大小(根据显存调整)

    num_train_epochs=3,  # 训练轮次

    logging_steps=10,  # 日志输出间隔

    learning_rate=2e-4  # 学习率

)


# 5. 启动训练

trainer = Trainer(model=model, args=training_args, train_dataset=processed_data)

trainer.train()


# 6. 保存微调后的模型(LoRA权重,体积小)

model.save_pretrained("./lora_finetuned_model")

3. 关键注意事项

3.1量化格式无法直接训练:若模型是 GGUF 格式,需先用llama.cpp的反向转换脚本转回 PyTorch 格式(仅部分模型支持)。

3.2.存不足解决方案:用 LoRA、QLoRA(量化 LoRA)微调,或降低批次大小、启用梯度检查点(model.gradient_checkpointing_enable())。

3.3模型结构依赖:若仅有权重文件(.pt),需手动编写模型结构代码(如 Transformer 类),否则无法加载训练。

三、特殊场景处理

1.仅有权重文件,无模型结构:

优先用 Hugging Face AutoModel加载,自动匹配结构(需模型是标准架构,如 Llama、BERT)。

若失败,需查找模型原始发布地址,获取对应的模型定义代码。

2.训练后模型格式转换:

微调后的 PyTorch 模型可转成 safetensors(安全)、GGUF(量化部署)、ONNX(跨框架),参考之前的格式转换方法。

要不要我根据你手里的模型扩展名(比如.pt、gguf 等),生成一份专属的推理 + 训练(若支持)调用脚本,直接复制就能运行?



何为JSONL 文件

JSONL (JSON Lines) 是一种文本文件格式,其中每一行都是一个独立的 JSON 对象。它与传统的 JSON 文件不同,传统的 JSON 文件将所有数据存储在一个单一的对象或数组中。


JSONL 的优点:

易于解析: 每行都是独立的 JSON 对象,解析器可以逐行处理文件,而无需将整个文件加载到内存中。

流式处理: JSONL 文件非常适合处理流数据,因为数据可以逐行写入和读取。

易于追加: 可以轻松地将新的 JSON 对象追加到现有 JSONL 文件的末尾。


JSONL 的缺点:

可读性较差: 与格式化的 JSON 文件相比,JSONL 文件的可读性较差。

不适合嵌套数据: JSONL 文件不太适合存储高度嵌套的数据结构。


JSONL 文件样本

以下是一个包含用户信息的 JSONL 文件样本:

{"id": 1, "name": "John Doe", "age": 30, "city": "New York"}

{"id": 2, "name": "Jane Doe", "age": 25, "city": "Los Angeles"}

{"id": 3, "name": "Peter Pan", "age": 20, "city": "London"}


说明:

文件中的每一行代表一个用户。

每一行都是一个有效的 JSON 对象,包含用户的 ID、姓名、年龄和城市信息。



实际用Python调用OpenAI开发聊天程序,每次给OpenAI多少轮的对话最合理

在使用 Python 调用 OpenAI 开发聊天程序时,每次给 OpenAI 多少轮对话没有一个固定的 “最合理” 数量,因为这会受到多种因素的影响,以下是详细分析及相关建议:

影响因素

模型上下文窗口:不同模型的上下文窗口大小不同,如gpt - 3.5 - turbo是 4096 个 token,gpt - 3.5 - turbo - 16k是 16384 个 token。在决定传递多少轮对话时,需要确保总 token 数不超过模型的上下文窗口限制,否则请求会失败。

对话内容复杂度:如果每轮对话内容简短、信息密度低,能传递的轮数就相对较多;反之,如果每轮对话都是长篇大论、包含大量专业术语或复杂描述,能传递的轮数就会减少。

任务需求:如果聊天程序是用于简单的问答场景,可能只需保留最近几轮对话就能满足需求;但如果是用于复杂的故事续写、文档分析等场景,可能需要传递更多轮对话以提供足够的上下文。

不同场景下的建议

简单问答场景

对于日常简单的问答,如查询天气、询问常识等,通常保留最近 3 - 5 轮对话即可。这样既能让模型了解当前对话的上下文,又不会占用过多的上下文窗口资源。例如:

python

import openai


openai.api_key = "your_api_key"


# 初始化对话历史

conversation_history = [

    {"role": "system", "content": "你是一个简单问答助手。"}

]


# 模拟3轮对话

for _ in range(3):

    user_input = input("你: ")

    conversation_history.append({"role": "user", "content": user_input})

    response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo",

        messages=conversation_history

    )

    assistant_reply = response.choices[0].message.content

    conversation_history.append({"role": "assistant", "content": assistant_reply})

    print(f"助手: {assistant_reply}")


    # 只保留最近5轮对话

    if len(conversation_history) > 5:

        conversation_history = conversation_history[-5:]

复杂交互场景

在进行故事续写、多步骤问题解决等复杂交互时,可能需要保留 10 - 20 轮对话甚至更多。不过要密切关注 token 数量,避免超出模型的上下文窗口。可以使用tiktoken库来监控 token 数,示例如下:

python

import openai

import tiktoken


openai.api_key = "your_api_key"

encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")


# 初始化对话历史

conversation_history = [

    {"role": "system", "content": "你是一个故事续写助手。"}

]


# 模拟15轮对话

for _ in range(15):

    user_input = input("你: ")

    conversation_history.append({"role": "user", "content": user_input})


    # 计算当前对话历史的总token数

    total_tokens = 0

    for message in conversation_history:

        total_tokens += len(encoding.encode(message["content"]))


    # 若接近上下文窗口限制,适当缩减对话历史

    while total_tokens > 3500:  # 预留一定空间

        conversation_history.pop(1)  # 移除较早的用户消息

        total_tokens = 0

        for message in conversation_history:

            total_tokens += len(encoding.encode(message["content"]))


    response = openai.ChatCompletion.create(

        model="gpt-3.5-turbo",

        messages=conversation_history

    )

    assistant_reply = response.choices[0].message.content

    conversation_history.append({"role": "assistant", "content": assistant_reply})

    print(f"助手: {assistant_reply}")

总之,要根据具体的应用场景和模型的上下文窗口大小,灵活调整传递给 OpenAI 的对话轮数,以达到最佳的对话效果。


####

Q:那么大模型第一个输出token如何确定的后续才有下个字的概率啊

A:...


这一问问到最根部了

模型明明要 “上文” 才预测下文,那第一个 token 是怎么来的?

我用最直白、最硬核、程序员一听就懂的方式讲清楚。

一句话结论

大模型根本没有 “第一个输出 token” 这种东西。

它永远是:给一段上文 → 预测下一个

你看到的 “第一句话”,上文其实是 <bos> + 你的提示词。

1. 模型从诞生起,就只会做一件事

P (下一个 token | 前面所有 token)

不会从头开始创作

它只会接着你给的东西往下写

你输入:

plaintext

你好

模型看到的不是 “凭空开始”,而是:

plaintext

<bos> 你 好

然后预测:

plaintext

下一个token = ?

这就是第一个输出字的来源

2. 超清晰流程(你问的 “第一个输出 token 怎么来”)

步骤 0:你输入提示

为什么天空是蓝色的?

步骤 1:分词 → ID 序列

[101, 200, 305, 678, ... ](一共 10 个 ID)

步骤 2:送入模型

模型立刻计算最后一个位置的输出向量

→ 投影词表

得到第一个输出 token 的概率

步骤 3:选出第一个输出字

比如模型选出:因

这就是你看到的第一个字

3. 关键真相

第一个输出 token = 提示词最后一个字的下一个预测

不是凭空生成。

结构是这样:

plaintext

[提示词全部token]

            ↓

      模型预测下一个

            ↓

      第一个输出token

4. 然后才是 “后续不断生成”

第一个字出来后,把它拼到原文后面,变成新上文:

plaintext

[提示词] + [第一个输出字]

                    ↓

              模型再预测下一个

                    ↓

              第二个输出字

不断循环,直到结束。

5. 用最简单代码模拟(完全真实逻辑)

python

运行

# 初始输入(你的提示)

prompt_ids = [101, 200, 305, 678]


for i in range(20):  # 生成20个字

    # 1. 模型只做一件事:根据当前所有token,预测下一个

    next_id = model(prompt_ids)

    

    # 2. 输出第一个token

    print("第%d个字: %s" % (i+1, token_to_word(next_id)))

    

    # 3. 拼回去,变成新上文

    prompt_ids.append(next_id)

第一次循环输出的,就是你看到的 “第一个字”。

6. 终极总结(最关键)

6.1 模型永远不会 “从零开始生成”

6.2 永远是:上文 → 下一个

6.3 你看到的第一个输出字 = 提示词末尾的下一个预测

6.4 之后每一个字 = 前面所有内容的下一个预测

所以:

不存在 “第一个输出字怎么来” 的玄学,

它就是提示词的下一个字。
















Top