学习顺序说明:本文是AI学习路线的第7篇,建议按顺序学习:
- 01 入门基础 → 02 机器学习 → 03 深度学习 → 04 NLP基础 → 05 Transformer进阶 → 06 大模型应用 → 07 RAG系统(本文)→ 08 AI工具链
RAG (Retrieval-Augmented Generation) 是将检索与生成结合的技术,让大模型能够利用外部知识库。
大语言模型存在以下局限:
RAG通过检索相关知识,增强模型的回答能力。
用户查询 → 向量化 → 检索相关文档 → 构建Prompt → LLM生成 → 返回答案
↓
知识库 → 文档切分 → 向量化 → 存入向量数据库
参考资源:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks - RAG原始论文
from sentence_transformers import SentenceTransformer
# 加载嵌入模型
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
# 生成向量
texts = ["机器学习是人工智能的核心技术", "深度学习是机器学习的分支"]
embeddings = model.encode(texts)
print(f"向量维度: {embeddings.shape}") # (2, 1024)
# 计算相似度
from numpy import dot
from numpy.linalg import norm
similarity = dot(embeddings[0], embeddings[1]) / (norm(embeddings[0]) * norm(embeddings[1]))
print(f"相似度: {similarity:.4f}")
常用嵌入模型:
| 模型 | 维度 | 特点 |
|---|---|---|
| text-embedding-ada-002 | 1536 | OpenAI |
| bge-large-zh-v1.5 | 1024 | 中文效果好 |
| m3e-base | 768 | 轻量级 |
ChromaDB
import chromadb
# 创建客户端
client = chromadb.Client()
collection = client.create_collection("documents")
# 添加文档
collection.add(
documents=["机器学习是AI的核心", "深度学习是机器学习的分支"],
metadatas=[{"source": "doc1"}, {"source": "doc2"}],
ids=["id1", "id2"]
)
# 查询
results = collection.query(
query_texts=["什么是AI的核心技术"],
n_results=2
)
print(results)
FAISS
import faiss
import numpy as np
# 创建索引
dimension = 768
index = faiss.IndexFlatL2(dimension)
# 添加向量
vectors = np.random.randn(1000, dimension).astype('float32')
index.add(vectors)
# 搜索
query = np.random.randn(1, dimension).astype('float32')
distances, indices = index.search(query, k=5)
Milvus
from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType
# 连接
connections.connect("default", host="localhost", port="19530")
# 创建集合
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768)
]
schema = CollectionSchema(fields, "documents")
collection = Collection("docs", schema)
# 创建索引
index_params = {"metric_type": "L2", "index_type": "IVF_FLAT", "params": {"nlist": 1024}}
collection.create_index("embedding", index_params)
参考资源:ChromaDB文档 Milvus文档
from langchain.document_loaders import PyPDFLoader, TextLoader, DirectoryLoader
# PDF加载
pdf_loader = PyPDFLoader("document.pdf")
pdf_docs = pdf_loader.load()
# 文本加载
text_loader = TextLoader("document.txt")
text_docs = text_loader.load()
# 目录批量加载
dir_loader = DirectoryLoader("./docs", glob="**/*.pdf", loader_cls=PyPDFLoader)
all_docs = dir_loader.load()
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 创建切分器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块大小
chunk_overlap=50, # 重叠大小
separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""]
)
# 切分文档
chunks = text_splitter.split_documents(pdf_docs)
print(f"原始文档数: {len(pdf_docs)}")
print(f"切分后块数: {len(chunks)}")
切分策略对比:
| 策略 | 适用场景 | 特点 |
|---|---|---|
| 按字符数 | 通用 | 简单直接 |
| 按段落 | 结构化文档 | 保持语义完整 |
| 递归切分 | 混合文档 | 智能分割 |
| 语义切分 | 高精度需求 | 按语义边界分割 |
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
# 初始化嵌入模型
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")
# 创建向量存储
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
# 创建检索器
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4}
)
# 创建Prompt模板
prompt_template = """
请根据以下上下文回答问题。如果上下文中没有相关信息,请说"我不知道"。
上下文:
{context}
问题:{question}
回答:
"""
PROMPT = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
# 创建RAG链
qa_chain = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model="gpt-4", temperature=0),
chain_type="stuff",
retriever=retriever,
return_source_documents=True,
chain_type_kwargs={"prompt": PROMPT}
)
# 查询
result = qa_chain({"query": "什么是机器学习?"})
print(result["result"])
print("\n来源文档:", result["source_documents"])
混合检索 (Hybrid Search)
from langchain.retrievers import EnsembleRetriever
from langchain.retrievers import BM25Retriever
# BM25检索器 (关键词)
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 4
# 向量检索器 (语义)
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# 混合检索
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6]
)
重排序 (Reranking)
from sentence_transformers import CrossEncoder
# 加载重排序模型
reranker = CrossEncoder('BAAI/bge-reranker-large')
def rerank_results(query, documents, top_k=5):
# 计算重排序分数
pairs = [[query, doc.page_content] for doc in documents]
scores = reranker.predict(pairs)
# 按分数排序
scored_docs = list(zip(documents, scores))
scored_docs.sort(key=lambda x: x[1], reverse=True)
return [doc for doc, score in scored_docs[:top_k]]
class RAGApplication:
def __init__(self, docs_path, persist_directory="./chroma_db"):
self.embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")
self.vectorstore = None
self.qa_chain = None
# 加载或创建向量存储
if os.path.exists(persist_directory):
self.load_vectorstore(persist_directory)
else:
self.build_index(docs_path, persist_directory)
def build_index(self, docs_path, persist_directory):
"""构建索引"""
# 加载文档
loader = DirectoryLoader(docs_path, glob="**/*.pdf", loader_cls=PyPDFLoader)
docs = loader.load()
# 切分
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = text_splitter.split_documents(docs)
# 创建向量存储
self.vectorstore = Chroma.from_documents(
documents=chunks,
embedding=self.embeddings,
persist_directory=persist_directory
)
def query(self, question, k=4):
"""查询"""
retriever = self.vectorstore.as_retriever(search_kwargs={"k": k})
docs = retriever.get_relevant_documents(question)
# 重排序
reranked_docs = rerank_results(question, docs, top_k=k)
# 生成回答
context = "\n\n".join([doc.page_content for doc in reranked_docs])
return self.generate_answer(question, context)
def generate_answer(self, question, context):
"""生成回答"""
# 使用LLM生成
pass
# Prompt优化
prompt = """
你是一个专业的问答助手。请根据提供的上下文准确回答问题。
要求:
1. 只使用上下文中的信息
2. 如果上下文不足以回答,明确说明
3. 回答要简洁准确
4. 引用相关的上下文片段
上下文:
{context}
问题:{question}
"""
| 指标 | 说明 |
|---|---|
| 召回率 | 检索到相关文档的比例 |
| 精确率 | 检索文档中相关的比例 |
| MRR | 第一个相关文档的排名倒数 |
| 答案相关性 | 答案与问题的相关程度 |
最后更新: 2026年4月10日
本文参考了 LangChain文档 和 RAG论文 整理
学习顺序说明:本文是AI学习路线的第6篇,建议按顺序学习:
- 01 入门基础 → 02 机器学习 → 03 深度学习 → 04 NLP基础 → 05 Transformer进阶 → 06 大模型应用(本文)→ 07 RAG系统 → 08 AI工具链
大语言模型(LLM)正在改变AI应用的构建方式。本文将介绍如何有效使用和定制大模型。
| 模型 | 参数量 | 特点 | 开源 |
|---|---|---|---|
| GPT-4 | ~1.8T | 多模态、推理能力强 | 否 |
| Claude 3 | ~175B | 长上下文、安全 | 否 |
| LLaMA 3 | 8B-70B | 高性能开源 | 是 |
| Qwen2 | 0.5B-72B | 多语言支持好 | 是 |
| DeepSeek | 7B-67B | 推理能力强 | 是 |
参考资源:Hugging Face Open LLM Leaderboard - 开源模型排行榜
角色设定
你是一位资深的Python开发工程师,擅长编写简洁高效的代码。
请用专业但易懂的方式回答问题。
任务分解
请按以下步骤分析问题:
1. 理解问题的核心需求
2. 列出可能的解决方案
3. 评估各方案的优缺点
4. 给出最佳推荐方案
输出格式控制
请以JSON格式输出结果:
{
"summary": "问题摘要",
"solutions": ["方案1", "方案2"],
"recommendation": "推荐方案"
}
# Few-shot Prompt示例
prompt = """
任务:判断文本的情感倾向
示例1:
文本:这个产品非常好用,我很满意!
情感:正面
示例2:
文本:服务态度太差了,再也不来了。
情感:负面
示例3:
文本:今天天气不错,适合出门散步。
情感:正面
现在请判断:
文本:{input_text}
情感:
"""
问题:小明有5个苹果,给了小红2个,又买了3个,现在有几个?
请一步步思考:
1. 小明最初有5个苹果
2. 给了小红2个,剩下 5-2=3个
3. 又买了3个,现在有 3+3=6个
答案:6个苹果
参考资源:Chain-of-Thought Prompting - CoT原始论文
import openai
from openai import OpenAI
client = OpenAI(api_key="your-api-key")
response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "你是一个AI助手"},
{"role": "user", "content": "请解释什么是机器学习"}
],
temperature=0.7,
max_tokens=500
)
print(response.choices[0].message.content)
参数说明:
| 参数 | 说明 | 建议值 |
|---|---|---|
| temperature | 随机性 | 0.7 (创意) / 0.2 (事实) |
| top_p | 核采样 | 0.9 |
| max_tokens | 最大输出 | 按需设置 |
| presence_penalty | 话题多样性 | 0.0-1.0 |
| frequency_penalty | 重复惩罚 | 0.0-1.0 |
LoRA通过低秩分解大幅减少微调参数量。
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
# 加载基础模型
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
# LoRA配置
lora_config = LoraConfig(
r=16, # 低秩维度
lora_alpha=32, # 缩放系数
target_modules=["q_proj", "v_proj"], # 应用LoRA的模块
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
# 应用LoRA
model = get_peft_model(model, lora_config)
# 查看可训练参数
model.print_trainable_parameters()
# 输出: trainable params: 4,194,304 || all params: 6,742,609,920 || trainable%: 0.06%
LoRA原理:
\[W' = W + \Delta W = W + BA\]其中 B ∈ R^(d×r), A ∈ R^(r×k), r « min(d, k)
参考资源:LoRA论文 - LoRA原始论文
QLoRA结合量化和LoRA,进一步降低显存需求。
from transformers import BitsAndBytesConfig
# 量化配置
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True
)
# 加载4-bit量化模型
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=bnb_config,
device_map="auto"
)
from transformers import TrainingArguments, Trainer
from datasets import load_dataset
# 加载数据集
dataset = load_dataset("your_dataset")
# 训练参数
training_args = TrainingArguments(
output_dir="./output",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
fp16=True,
logging_steps=10,
save_steps=100,
evaluation_strategy="steps"
)
# 训练
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
tokenizer=tokenizer
)
trainer.train()
# 8-bit量化
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
load_in_8bit=True,
device_map="auto"
)
# 4-bit量化 (GPTQ/AWQ)
from auto_gptq import AutoGPTQForCausalLM
model = AutoGPTQForCausalLM.from_quantized("model_path", device_map="auto")
from vllm import LLM, SamplingParams
# 加载模型
llm = LLM(model="meta-llama/Llama-2-7b-hf")
# 批量推理
prompts = ["你好", "天气如何", "介绍一下AI"]
sampling_params = SamplingParams(temperature=0.7, max_tokens=100)
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(output.outputs[0].text)
from transformers import TextIteratorStreamer
from threading import Thread
streamer = TextIteratorStreamer(tokenizer, skip_special_tokens=True)
# 在单独线程中生成
generation_kwargs = {
"input_ids": input_ids,
"streamer": streamer,
"max_new_tokens": 100
}
thread = Thread(target=model.generate, kwargs=generation_kwargs)
thread.start()
# 流式输出
for text in streamer:
print(text, end="", flush=True)
class ChatBot:
def __init__(self, model_path):
self.tokenizer = AutoTokenizer.from_pretrained(model_path)
self.model = AutoModelForCausalLM.from_pretrained(model_path)
self.history = []
def chat(self, user_input, max_history=5):
# 构建对话历史
self.history.append({"role": "user", "content": user_input})
# 限制历史长度
if len(self.history) > max_history * 2:
self.history = self.history[-max_history * 2:]
# 生成回复
input_text = self.tokenizer.apply_chat_template(
self.history, tokenize=False, add_generation_prompt=True
)
inputs = self.tokenizer(input_text, return_tensors="pt")
outputs = self.model.generate(**inputs, max_new_tokens=512)
response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
# 更新历史
self.history.append({"role": "assistant", "content": response})
return response
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class ChatRequest(BaseModel):
message: str
history: list = []
@app.post("/chat")
async def chat(request: ChatRequest):
response = bot.chat(request.message)
return {"response": response}
# 启动: uvicorn app:app --host 0.0.0.0 --port 8000
上一篇:05 Transformer进阶 - 深入理解注意力机制
最后更新: 2026年4月10日
本文参考了 Hugging Face文档 和 PEFT文档 整理
学习顺序说明:本文是AI学习路线的第5篇,建议按顺序学习:
- 01 入门基础 → 02 机器学习 → 03 深度学习 → 04 NLP基础 → 05 Transformer进阶(本文)→ 06 大模型应用 → 07 RAG系统 → 08 AI工具链
本文将深入探讨Transformer架构的各个组件,帮助读者理解这一革命性架构的设计原理。
Encoder端:
输入 → 词嵌入 → 位置编码 → [多头自注意力 → Add&Norm → 前馈网络 → Add&Norm] × N
Decoder端:
输出 → 词嵌入 → 位置编码 → [掩码多头自注意力 → Add&Norm → 编码器-解码器注意力 → Add&Norm → 前馈网络 → Add&Norm] × N → 线性 → Softmax
参考资源:Attention Is All You Need - Transformer原论文
为什么要除以√d_k?
当d_k很大时,点积的结果会变得很大,导致softmax函数的梯度变得很小(饱和区)。除以√d_k可以防止这种情况。
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
class ScaledDotProductAttention(nn.Module):
"""缩放点积注意力"""
def __init__(self, d_k):
super().__init__()
self.scale = math.sqrt(d_k)
def forward(self, Q, K, V, mask=None):
# Q: (batch, heads, seq_len, d_k)
# K: (batch, heads, seq_len, d_k)
# V: (batch, heads, seq_len, d_v)
# 计算注意力分数
scores = torch.matmul(Q, K.transpose(-2, -1)) / self.scale
# 应用掩码(用于解码器)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
# Softmax归一化
attention_weights = F.softmax(scores, dim=-1)
# 加权求和
output = torch.matmul(attention_weights, V)
return output, attention_weights
为什么需要多头?
单头注意力只能学习一种”关联模式”,多头可以让模型同时关注不同位置的不同表示子空间。
class MultiHeadAttention(nn.Module):
"""多头注意力机制"""
def __init__(self, d_model, num_heads):
super().__init__()
assert d_model % num_heads == 0
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads
# Q, K, V 的线性变换
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
# 输出线性变换
self.W_o = nn.Linear(d_model, d_model)
self.attention = ScaledDotProductAttention(self.d_k)
def forward(self, query, key, value, mask=None):
batch_size = query.size(0)
# 线性变换并分割多头
Q = self.W_q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
K = self.W_k(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
V = self.W_v(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
# 注意力计算
attn_output, attention_weights = self.attention(Q, K, V, mask)
# 合并多头
attn_output = attn_output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
# 输出变换
output = self.W_o(attn_output)
return output, attention_weights
三种注意力类型:
| 类型 | Query来源 | Key/Value来源 | 应用场景 |
|---|---|---|---|
| 自注意力 | 输入序列 | 输入序列 | 编码器、解码器 |
| 掩码自注意力 | 输出序列 | 输出序列 | 解码器 |
| 交叉注意力 | 解码器输入 | 编码器输出 | 编码器-解码器 |
参考资源:The Annotated Transformer - 带注释的Transformer实现
由于Transformer没有循环结构,需要位置编码来注入位置信息。
\(PE_{(pos, 2i)} = \sin(pos / 10000^{2i/d_{model}})\) \(PE_{(pos, 2i+1)} = \cos(pos / 10000^{2i/d_{model}})\)
class PositionalEncoding(nn.Module):
"""正弦位置编码"""
def __init__(self, d_model, max_len=5000, dropout=0.1):
super().__init__()
self.dropout = nn.Dropout(p=dropout)
# 计算位置编码
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0) # (1, max_len, d_model)
self.register_buffer('pe', pe)
def forward(self, x):
# x: (batch, seq_len, d_model)
x = x + self.pe[:, :x.size(1), :]
return self.dropout(x)
class LearnedPositionalEncoding(nn.Module):
"""可学习位置编码"""
def __init__(self, d_model, max_len=512):
super().__init__()
self.pos_embedding = nn.Embedding(max_len, d_model)
def forward(self, x):
batch_size, seq_len, _ = x.size()
positions = torch.arange(seq_len, device=x.device).unsqueeze(0).expand(batch_size, -1)
return x + self.pos_embedding(positions)
RoPE是LLaMA等现代大模型使用的位置编码方式。
class RotaryPositionalEmbedding(nn.Module):
"""旋转位置编码 (RoPE)"""
def __init__(self, dim, max_seq_len=2048, base=10000):
super().__init__()
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
self.register_buffer('inv_freq', inv_freq)
# 预计算cos和sin
self.max_seq_len = max_seq_len
self._set_cos_sin_cache(max_seq_len)
def _set_cos_sin_cache(self, seq_len):
t = torch.arange(seq_len, device=self.inv_freq.device, dtype=self.inv_freq.dtype)
freqs = torch.outer(t, self.inv_freq)
emb = torch.cat((freqs, freqs), dim=-1)
self.register_buffer('cos_cached', emb.cos())
self.register_buffer('sin_cached', emb.sin())
def forward(self, x, seq_len=None):
return self.cos_cached[:seq_len], self.sin_cached[:seq_len]
参考资源:RoFormer论文 - RoPE原始论文
class FeedForward(nn.Module):
"""前馈网络"""
def __init__(self, d_model, d_ff, dropout=0.1):
super().__init__()
self.linear1 = nn.Linear(d_model, d_ff)
self.linear2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
self.activation = nn.GELU() # 或 nn.ReLU()
def forward(self, x):
return self.linear2(self.dropout(self.activation(self.linear1(x))))
激活函数选择:
class LayerNorm(nn.Module):
"""层归一化"""
def __init__(self, d_model, eps=1e-6):
super().__init__()
self.gamma = nn.Parameter(torch.ones(d_model))
self.beta = nn.Parameter(torch.zeros(d_model))
self.eps = eps
def forward(self, x):
mean = x.mean(-1, keepdim=True)
std = x.std(-1, keepdim=True)
return self.gamma * (x - mean) / (std + self.eps) + self.beta
Pre-LN vs Post-LN:
| 方式 | 公式 | 特点 |
|---|---|---|
| Post-LN | x + Sublayer(LN(x)) | 原始Transformer,训练不稳定 |
| Pre-LN | LN(x + Sublayer(x)) | 现代模型常用,训练稳定 |
class TransformerBlock(nn.Module):
"""Pre-LN Transformer块"""
def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
super().__init__()
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.attention = MultiHeadAttention(d_model, num_heads)
self.ffn = FeedForward(d_model, d_ff, dropout)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask=None):
# Pre-LN结构
# 自注意力
attn_out, _ = self.attention(self.norm1(x), self.norm1(x), self.norm1(x), mask)
x = x + self.dropout(attn_out)
# 前馈网络
ffn_out = self.ffn(self.norm2(x))
x = x + self.dropout(ffn_out)
return x
class TransformerEncoder(nn.Module):
"""Transformer编码器"""
def __init__(self, vocab_size, d_model, num_heads, num_layers, d_ff, max_seq_len, dropout=0.1):
super().__init__()
self.token_embedding = nn.Embedding(vocab_size, d_model)
self.position_encoding = PositionalEncoding(d_model, max_seq_len, dropout)
self.layers = nn.ModuleList([
TransformerBlock(d_model, num_heads, d_ff, dropout)
for _ in range(num_layers)
])
self.norm = nn.LayerNorm(d_model)
def forward(self, x, mask=None):
# 词嵌入 + 位置编码
x = self.token_embedding(x)
x = self.position_encoding(x)
# Transformer层
for layer in self.layers:
x = layer(x, mask)
return self.norm(x)
上一篇:04 NLP基础 - 从词向量到Transformer
最后更新: 2026年4月10日
本文参考了 Attention Is All You Need 和 The Annotated Transformer 整理
学习顺序说明:本文是AI学习路线的第4篇,建议按顺序学习:
- 01 入门基础 → 02 机器学习 → 03 深度学习 → 04 NLP基础(本文)→ 05 Transformer进阶 → 06 大模型应用 → 07 RAG系统 → 08 AI工具链
自然语言处理(NLP)是人工智能中让计算机理解和生成人类语言的领域。本文将系统介绍NLP的核心技术和最新发展。
词袋模型(1950s) → 统计方法(1990s) → 神经网络(2010s) → Transformer(2017) → 大语言模型(2020+)
参考资源:Speech and Language Processing - Dan Jurafsky经典教材
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
documents = [
"机器学习是人工智能的核心",
"深度学习是机器学习的分支",
"自然语言处理是深度学习的应用"
]
# 词袋模型
bow_vectorizer = CountVectorizer()
bow_matrix = bow_vectorizer.fit_transform(documents)
# TF-IDF
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(documents)
将词映射到低维稠密向量,捕捉语义关系。
from gensim.models import Word2Vec
# 训练Word2Vec模型
sentences = [
['机器学习', '是', '人工智能', '核心'],
['深度学习', '是', '机器学习', '分支'],
['自然语言处理', '是', '深度学习', '应用']
]
model = Word2Vec(sentences, vector_size=100, window=5, min_count=1, workers=4)
# 获取词向量
vector = model.wv['机器学习']
# 找相似词
similar = model.wv.most_similar('机器学习', topn=3)
参考资源:Word2Vec论文 - Efficient Estimation of Word Representations
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
class SelfAttention(nn.Module):
"""自注意力实现"""
def __init__(self, embed_size, heads):
super(SelfAttention, self).__init__()
self.embed_size = embed_size
self.heads = heads
self.head_dim = embed_size // heads
self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.fc_out = nn.Linear(heads * self.head_dim, embed_size)
def forward(self, values, keys, query, mask):
N = query.shape[0]
value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1]
# 分割多头
values = values.reshape(N, value_len, self.heads, self.head_dim)
keys = keys.reshape(N, key_len, self.heads, self.head_dim)
queries = query.reshape(N, query_len, self.heads, self.head_dim)
# 注意力分数
energy = torch.einsum("nqhd,nkhd->nhqk", [queries, keys])
if mask is not None:
energy = energy.masked_fill(mask == 0, float("-1e20"))
attention = torch.softmax(energy / (self.embed_size ** 0.5), dim=3)
out = torch.einsum("nhql,nlhd->nqhd", [attention, values])
out = out.reshape(N, query_len, self.heads * self.head_dim)
return self.fc_out(out)
参考资源:The Illustrated Transformer - Jay Alammar的图解Transformer
输入嵌入 → 位置编码 → [多头自注意力 → Add&Norm → 前馈网络 → Add&Norm] × N → 输出
关键组件:
| 组件 | 作用 |
|---|---|
| 位置编码 | 注入位置信息 |
| 多头注意力 | 并行计算多组注意力 |
| 层归一化 | 稳定训练 |
| 前馈网络 | 非线性变换 |
| 残差连接 | 缓解梯度消失 |
参考资源:Attention Is All You Need - Transformer原论文
BERT是双向Transformer编码器,通过掩码语言模型预训练。
from transformers import BertTokenizer, BertModel, BertForSequenceClassification
# 加载预训练BERT
model_name = 'bert-base-chinese'
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertModel.from_pretrained(model_name)
# 文本编码
text = "自然语言处理是人工智能的重要领域"
inputs = tokenizer(text, return_tensors='pt', padding=True, truncation=True)
# 获取BERT输出
with torch.no_grad():
outputs = model(**inputs)
# [CLS] token的表示 (用于分类任务)
cls_embedding = outputs.last_hidden_state[:, 0, :]
BERT预训练任务:
参考资源:BERT论文
GPT是单向Transformer解码器,通过自回归语言模型预训练。
from transformers import GPT2LMHeadModel, GPT2Tokenizer
model_name = 'gpt2'
tokenizer = GPT2Tokenizer.from_pretrained(model_name)
model = GPT2LMHeadModel.from_pretrained(model_name)
# 文本生成
input_text = "Natural language processing is"
input_ids = tokenizer.encode(input_text, return_tensors='pt')
output = model.generate(input_ids, max_length=50, temperature=0.7)
generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
GPT vs BERT对比:
| 特性 | BERT | GPT |
|---|---|---|
| 架构 | 编码器 | 解码器 |
| 方向 | 双向 | 单向 |
| 预训练 | MLM + NSP | 语言模型 |
| 适用任务 | 理解类 | 生成类 |
参考资源:GPT-3论文
from transformers import pipeline
# 情感分析
sentiment_analyzer = pipeline("sentiment-analysis", model="bert-base-chinese")
result = sentiment_analyzer("这个产品非常好用!")
# 问答系统
qa_pipeline = pipeline("question-answering")
result = qa_pipeline(question="什么是机器学习?",
context="机器学习是人工智能的一个分支...")
# 命名实体识别
ner_pipeline = pipeline("ner", aggregation_strategy="simple")
result = ner_pipeline("比尔·盖茨是微软公司的创始人")
参考资源:Hugging Face文档
下一篇:05 Transformer进阶 - 深入理解注意力机制
最后更新: 2026年4月10日
本文参考了 Hugging Face文档 和 CS224N课程 整理
学习顺序说明:本文是AI学习路线的第3篇,建议按顺序学习:
- 01 入门基础 → 02 机器学习 → 03 深度学习(本文)→ 04 NLP基础 → 05 Transformer进阶 → 06 大模型应用 → 07 RAG系统 → 08 AI工具链
深度学习是机器学习的一个子领域,通过多层神经网络自动学习数据的层次化表示。本文将介绍深度学习的核心概念和主流架构。
感知机(1958) → 多层感知机(1986) → CNN(1998) → 深度学习复兴(2012) → Transformer(2017) → 大模型时代(2020+)
参考资源:Deep Learning Book - Ian Goodfellow等人所著的深度学习圣经
感知机是最简单的神经网络,模拟单个神经元的工作方式。
import numpy as np
class Perceptron:
"""简单感知机实现"""
def __init__(self, input_size, learning_rate=0.1, epochs=100):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = learning_rate
self.epochs = epochs
def activation(self, x):
"""阶跃激活函数"""
return 1 if x >= 0 else 0
def predict(self, x):
"""前向传播"""
z = np.dot(x, self.weights) + self.bias
return self.activation(z)
def train(self, X, y):
"""训练感知机"""
for epoch in range(self.epochs):
for i in range(len(X)):
y_pred = self.predict(X[i])
error = y[i] - y_pred
self.weights += self.lr * error * X[i]
self.bias += self.lr * error
# 示例:实现AND逻辑门
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 0, 0, 1])
perceptron = Perceptron(input_size=2)
perceptron.train(X, y)
多层感知机(MLP)通过添加隐藏层解决非线性问题。
import torch
import torch.nn as nn
class MLP(nn.Module):
"""多层感知机"""
def __init__(self, input_size, hidden_size, output_size):
super(MLP, self).__init__()
self.layer1 = nn.Linear(input_size, hidden_size)
self.activation = nn.ReLU()
self.layer2 = nn.Linear(hidden_size, output_size)
def forward(self, x):
x = self.layer1(x)
x = self.activation(x)
x = self.layer2(x)
return x
model = MLP(input_size=784, hidden_size=256, output_size=10)
激活函数引入非线性,使神经网络能够学习复杂的模式。
import torch
import matplotlib.pyplot as plt
x = torch.linspace(-5, 5, 100)
# 常用激活函数
sigmoid = torch.sigmoid(x)
tanh = torch.tanh(x)
relu = torch.relu(x)
leaky_relu = torch.nn.functional.leaky_relu(x, negative_slope=0.1)
gelu = torch.nn.functional.gelu(x)
激活函数对比:
| 函数 | 公式 | 优点 | 缺点 |
|---|---|---|---|
| Sigmoid | σ(x) = 1/(1+e⁻ˣ) | 输出[0,1] | 梯度消失、非零中心 |
| Tanh | tanh(x) | 零中心 | 梯度消失 |
| ReLU | max(0, x) | 计算快、无梯度消失 | 神经元死亡 |
| LeakyReLU | max(αx, x) | 解决死亡问题 | 需调参 |
| GELU | x·Φ(x) | 平滑、大模型常用 | 计算较慢 |
反向传播是训练神经网络的核心算法,通过链式法则计算梯度。
import torch
import torch.nn as nn
# PyTorch自动求导
x = torch.randn(10, 5, requires_grad=True)
y = torch.randn(10, 2)
model = nn.Sequential(
nn.Linear(5, 10),
nn.ReLU(),
nn.Linear(10, 2)
)
# 前向传播
output = model(x)
loss = nn.MSELoss()(output, y)
# 反向传播(自动计算梯度)
loss.backward()
# 查看梯度
print("第一层权重梯度形状:", model[0].weight.grad.shape)
参考资源:Calculus on Computational Graphs - Christopher Olah的博客
CNN是处理图像数据的核心架构,通过卷积操作提取局部特征。
import torch.nn as nn
# 单通道卷积示例
conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=1)
# 输入图像 (batch, channels, height, width)
x = torch.randn(1, 1, 28, 28)
output = conv(x)
print(f"输入形状: {x.shape}, 输出形状: {output.shape}")
# 多通道卷积
conv_multi = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)
x_rgb = torch.randn(1, 3, 224, 224)
output = conv_multi(x_rgb)
卷积参数详解:
| 参数 | 说明 | 影响 |
|---|---|---|
| kernel_size | 卷积核大小 | 感受野大小 |
| stride | 步长 | 输出尺寸 |
| padding | 填充 | 保持尺寸 |
| dilation | 空洞率 | 扩大感受野 |
ResNet残差块 (2015) - 解决深层网络训练问题
class ResidualBlock(nn.Module):
"""ResNet残差块"""
def __init__(self, in_channels, out_channels, stride=1):
super(ResidualBlock, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3,
stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3,
stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1,
stride=stride, bias=False),
nn.BatchNorm2d(out_channels)
)
def forward(self, x):
identity = self.shortcut(x)
out = self.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += identity # 残差连接
return self.relu(out)
参考资源:ResNet论文 - Deep Residual Learning for Image Recognition
RNN专门处理序列数据,如文本、时间序列等。
LSTM通过门控机制解决RNN的长期依赖问题。
class LSTMModel(nn.Module):
"""LSTM模型"""
def __init__(self, input_size, hidden_size, num_layers, output_size):
super(LSTMModel, self).__init__()
self.lstm = nn.LSTM(input_size, hidden_size, num_layers,
batch_first=True, dropout=0.2)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
out, (hn, cn) = self.lstm(x, (h0, c0))
return self.fc(out[:, -1, :])
LSTM门控机制:
遗忘门: f_t = σ(W_f · [h_{t-1}, x_t] + b_f)
输入门: i_t = σ(W_i · [h_{t-1}, x_t] + b_i)
细胞状态: C_t = f_t * C_{t-1} + i_t * C̃_t
输出门: o_t = σ(W_o · [h_{t-1}, x_t] + b_o)
隐藏状态: h_t = o_t * tanh(C_t)
RNN架构对比:
| 特性 | RNN | LSTM | GRU |
|---|---|---|---|
| 参数量 | 少 | 多 | 中 |
| 训练速度 | 快 | 慢 | 中 |
| 长期依赖 | 差 | 好 | 好 |
import torch.nn as nn
# Dropout
dropout = nn.Dropout(0.5)
# Batch Normalization
bn = nn.BatchNorm1d(20)
# Layer Normalization (Transformer常用)
ln = nn.LayerNorm(20)
# 权重衰减 (L2正则化)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-4)
from torch.optim.lr_scheduler import StepLR, CosineAnnealingLR, ReduceLROnPlateau
model = nn.Linear(10, 2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
# 阶梯式衰减
scheduler_step = StepLR(optimizer, step_size=30, gamma=0.1)
# 余弦退火
scheduler_cosine = CosineAnnealingLR(optimizer, T_max=100)
# 基于指标的自适应调整
scheduler_reduce = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10)
下一篇:04 NLP基础 - 从词向量到Transformer
最后更新: 2026年4月10日
本文参考了 PyTorch官方文档 和 Deep Learning Book 整理
学习顺序说明:本文是AI学习路线的第2篇,建议按顺序学习:
- 01 入门基础 → 02 机器学习(本文)→ 03 深度学习 → 04 NLP基础 → 05 Transformer进阶 → 06 大模型应用 → 07 RAG系统 → 08 AI工具链
机器学习是人工智能的核心领域之一,本文将系统性地介绍机器学习的主要算法类别、核心原理和实践方法。
机器学习是让计算机从数据中自动学习规律,而无需显式编程的技术。根据学习方式的不同,主要分为以下几类:
机器学习
├── 监督学习 (有标签数据)
│ ├── 分类 (离散输出)
│ └── 回归 (连续输出)
├── 无监督学习 (无标签数据)
│ ├── 聚类
│ └── 降维
├── 半监督学习 (部分标签)
└── 强化学习 (奖励反馈)
核心概念:
- 特征(Features): 输入数据的属性
- 标签(Labels): 需要预测的目标
- 训练集: 用于学习的数据
- 测试集: 用于评估的数据
- 模型: 学习得到的映射函数
参考资源:Scikit-learn官方文档 - Python机器学习标准库
监督学习是最常见的机器学习类型,每个训练样本都有对应的标签。
原理:寻找最佳拟合直线,使预测值与真实值的误差最小。
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
# 生成示例数据
np.random.seed(42)
X = np.random.randn(100, 1) * 10
y = 2 * X.ravel() + 5 + np.random.randn(100) * 2
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = LinearRegression()
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test)
# 评估
print(f"权重(w): {model.coef_[0]:.2f}")
print(f"偏置(b): {model.intercept_:.2f}")
print(f"均方误差(MSE): {mean_squared_error(y_test, y_pred):.2f}")
print(f"R²分数: {r2_score(y_test, y_pred):.2f}")
损失函数:均方误差 (MSE)
\[MSE = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2\]数学推导:详见斯坦福CS229讲义
原理:通过Sigmoid函数将线性输出映射到[0,1]区间,用于二分类问题。
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
# 生成分类数据
X, y = make_classification(n_samples=1000, n_features=2, n_redundant=0,
n_informative=2, random_state=42, n_clusters_per_class=1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 训练逻辑回归模型
model = LogisticRegression()
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test) # 预测概率
# 评估
print(f"准确率: {accuracy_score(y_test, y_pred):.2f}")
print("\n混淆矩阵:")
print(confusion_matrix(y_test, y_pred))
print("\n分类报告:")
print(classification_report(y_test, y_pred))
原理:通过一系列if-then规则对数据进行划分,形成树状结构。
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.datasets import load_iris
# 加载鸢尾花数据集
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 训练决策树
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
# 预测与评估
y_pred = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.2f}")
# 特征重要性
print("\n特征重要性:")
for name, importance in zip(iris.feature_names, model.feature_importances_):
print(f" {name}: {importance:.3f}")
关键参数:
max_depth: 树的最大深度(控制过拟合)min_samples_split: 分裂节点所需最小样本数min_samples_leaf: 叶节点最小样本数criterion: 划分标准(gini或entropy)参考资源:决策树算法详解 - 李航《统计学习方法》
原理:集成多棵决策树,通过Bagging方法降低方差,提高泛化能力。
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
# 生成数据
X, y = make_classification(n_samples=1000, n_features=20, n_informative=10,
n_redundant=5, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 训练随机森林
model = RandomForestClassifier(
n_estimators=100, # 树的数量
max_depth=10, # 最大深度
min_samples_split=5, # 分裂最小样本数
random_state=42,
n_jobs=-1 # 使用所有CPU核心
)
model.fit(X_train, y_train)
# 评估
y_pred = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.2f}")
# 特征重要性排序
importances = model.feature_importances_
indices = np.argsort(importances)[::-1]
print("\n特征重要性排序 (前5):")
for i in range(5):
print(f" 特征 {indices[i]}: {importances[indices[i]]:.3f}")
原理:找到最优超平面,使不同类别之间的间隔最大化。
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# SVM对特征缩放敏感,需要标准化
model = Pipeline([
('scaler', StandardScaler()),
('svm', SVC(kernel='rbf', C=1.0, gamma='scale'))
])
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(f"SVM准确率: {accuracy_score(y_test, y_pred):.2f}")
核函数选择:
linear: 线性核,适用于线性可分数据rbf: 高斯径向基核,适用于非线性数据poly: 多项式核sigmoid: 类似神经网络的核函数无监督学习处理没有标签的数据,发现数据内在结构。
原理:将数据划分为K个簇,使簇内样本尽可能相似。
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# 生成聚类数据
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=42)
# 训练K-Means
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
y_pred = kmeans.fit_predict(X)
# 获取聚类中心
centers = kmeans.cluster_centers_
# 肘部法则选择K值
inertias = []
K_range = range(1, 11)
for k in K_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(X)
inertias.append(kmeans.inertia_)
原理:线性降维,找到数据方差最大的方向。
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits
# 加载手写数字数据集
digits = load_digits()
X = digits.data # 64维特征
# PCA降维到2维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
print(f"原始维度: {X.shape[1]}")
print(f"降维后维度: {X_pca.shape[1]}")
print(f"解释方差比: {pca.explained_variance_ratio_}")
print(f"累计解释方差: {sum(pca.explained_variance_ratio_):.2%}")
原理:基于密度的聚类,可以发现任意形状的簇。
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons
# 生成月牙形数据
X, y = make_moons(n_samples=300, noise=0.05, random_state=42)
# DBSCAN聚类
dbscan = DBSCAN(eps=0.3, min_samples=5)
y_pred = dbscan.fit_predict(X)
from sklearn.metrics import (
accuracy_score, precision_score, recall_score,
f1_score, roc_auc_score, roc_curve, confusion_matrix
)
# 假设有真实标签和预测结果
y_true = np.array([0, 1, 0, 1, 0, 1, 1, 0, 1, 0])
y_pred = np.array([0, 1, 0, 1, 0, 0, 1, 0, 1, 1])
y_prob = np.array([0.1, 0.9, 0.2, 0.8, 0.1, 0.3, 0.7, 0.2, 0.9, 0.6])
# 计算各指标
print(f"准确率(Accuracy): {accuracy_score(y_true, y_pred):.3f}")
print(f"精确率(Precision): {precision_score(y_true, y_pred):.3f}")
print(f"召回率(Recall): {recall_score(y_true, y_pred):.3f}")
print(f"F1分数: {f1_score(y_true, y_pred):.3f}")
print(f"AUC-ROC: {roc_auc_score(y_true, y_prob):.3f}")
指标解释:
| 指标 | 公式 | 说明 |
|---|---|---|
| 准确率 | (TP+TN)/(TP+TN+FP+FN) | 预测正确的比例 |
| 精确率 | TP/(TP+FP) | 预测为正中真正为正的比例 |
| 召回率 | TP/(TP+FN) | 真正为正中被预测为正的比例 |
| F1分数 | 2PR/(P+R) | 精确率和召回率的调和平均 |
from sklearn.model_selection import cross_val_score, GridSearchCV
# K折交叉验证
model = RandomForestClassifier(n_estimators=100, random_state=42)
cv_scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
print(f"5折交叉验证结果: {cv_scores}")
print(f"平均准确率: {cv_scores.mean():.3f} (+/- {cv_scores.std():.3f})")
# 网格搜索调参
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [5, 10, 15],
'min_samples_split': [2, 5, 10]
}
grid_search = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1
)
grid_search.fit(X_train, y_train)
print(f"\n最佳参数: {grid_search.best_params_}")
print(f"最佳得分: {grid_search.best_score_:.3f}")
线性回归 → 逻辑回归 → 决策树 → 集成方法 → SVM → 无监督学习
| 书籍 | 作者 | 特点 |
|---|---|---|
| 《机器学习》 | 周志华 | 西瓜书,国内经典教材 |
| 《统计学习方法》 | 李航 | 算法推导详细 |
| 《Hands-On Machine Learning》 | Aurélien Géron | 实践导向 |
| 《机器学习实战》 | Peter Harrington | 代码实现 |
最后更新: 2026年4月10日
本文参考了 Scikit-learn官方文档 和 DeepSeek技术社区 的学习路线整理