python深入方向4【人工智能 / 机器学习 → scikit-learn, PyTorch / TensorFlow】
·
人工智能 / 机器学习 Python 学习笔记
适用方向:人工智能 / 机器学习
核心库:scikit-learn, PyTorch, TensorFlow
学习路径:基础理论 → 传统机器学习 → 深度学习框架 → 项目实战
目录
1. 机器学习基础概念
1.1 机器学习分类
| 类型 | 说明 | 典型算法 |
|---|---|---|
| 监督学习 | 有标签数据,学习输入到输出的映射 | 线性回归、逻辑回归、SVM、决策树、神经网络 |
| 无监督学习 | 无标签数据,发现数据内在结构 | K-Means、PCA、DBSCAN、自编码器 |
| 强化学习 | 通过与环境交互学习最优策略 | Q-Learning、DQN、PPO |
| 半监督学习 | 少量标注 + 大量未标注数据 | 标签传播、伪标签 |
1.2 模型评估指标
分类任务
# 混淆矩阵基础概念
# TP (True Positive) 真正例:预测为正,实际为正
# TN (True Negative) 真负例:预测为负,实际为负
# FP (False Positive) 假正例:预测为正,实际为负
# FN (False Negative) 假负例:预测为负,实际为正
# 精确率 Precision = TP / (TP + FP)
# 召回率 Recall = TP / (TP + FN)
# F1-score = 2 * Precision * Recall / (Precision + Recall)
# 准确率 Accuracy = (TP + TN) / (TP + TN + FP + FN)
# AUC-ROC:受试者工作特征曲线下面积
回归任务
# MAE (平均绝对误差) = (1/n) * Σ|y_true - y_pred|
# MSE (均方误差) = (1/n) * Σ(y_true - y_pred)²
# RMSE (均方根误差) = √MSE
# R² (决定系数) = 1 - SS_res / SS_tot
1.3 过拟合与欠拟合
| 现象 | 表现 | 解决方法 |
|---|---|---|
| 欠拟合 | 训练集和测试集效果都差 | 增加模型复杂度、增加特征、减少正则化 |
| 过拟合 | 训练集效果好,测试集效果差 | 增加数据、正则化(L1/L2)、Dropout、早停 |
2. scikit-learn 传统机器学习
2.1 核心模块概览
sklearn
├── datasets # 内置数据集
├── preprocessing # 数据预处理
├── model_selection # 模型选择与评估
├── linear_model # 线性模型
├── svm # 支持向量机
├── tree # 决策树
├── ensemble # 集成学习
├── neighbors # K近邻
├── cluster # 聚类
├── decomposition # 降维
├── metrics # 评估指标
└── pipeline # 流水线
2.2 数据预处理
2.2.1 数据标准化与归一化
from sklearn.preprocessing import StandardScaler, MinMaxScaler, LabelEncoder, OneHotEncoder
import numpy as np
# StandardScaler:标准化 (均值0,方差1)
# 适用:对特征尺度敏感的算法(SVM、逻辑回归、神经网络)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test) # 注意:测试集只用transform
# MinMaxScaler:归一化 [0, 1]
# 适用:图像数据、需要 bounded output 的场景
minmax = MinMaxScaler(feature_range=(0, 1))
X_scaled = minmax.fit_transform(X)
# 标签编码(分类特征)
le = LabelEncoder()
y_encoded = le.fit_transform(y_categorical)
# 独热编码
onehot = OneHotEncoder(sparse=False)
X_onehot = onehot.fit_transform(X_categorical.reshape(-1, 1))
2.2.2 缺失值处理
from sklearn.impute import SimpleImputer
# 均值填充(数值型)
imputer = SimpleImputer(strategy='mean') # 'mean', 'median', 'most_frequent', 'constant'
X_imputed = imputer.fit_transform(X)
2.2.3 特征选择
from sklearn.feature_selection import SelectKBest, f_classif, RFE
from sklearn.linear_model import LogisticRegression
# 方法1:单变量特征选择
selector = SelectKBest(score_func=f_classif, k=10)
X_selected = selector.fit_transform(X, y)
# 方法2:递归特征消除 (RFE)
estimator = LogisticRegression()
selector = RFE(estimator, n_features_to_select=5, step=1)
X_selected = selector.fit_transform(X, y)
2.3 经典算法实现
2.3.1 线性回归
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.metrics import mean_squared_error, r2_score
# 普通线性回归
lr = LinearRegression()
lr.fit(X_train, y_train)
y_pred = lr.predict(X_test)
# 评估
print(f"系数: {lr.coef_}")
print(f"截距: {lr.intercept_}")
print(f"MSE: {mean_squared_error(y_test, y_pred)}")
print(f"R²: {r2_score(y_test, y_pred)}")
# Ridge回归 (L2正则化)
ridge = Ridge(alpha=1.0) # alpha越大,正则化越强
ridge.fit(X_train, y_train)
# Lasso回归 (L1正则化,可做特征选择)
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)
2.3.2 逻辑回归(分类)
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# 多分类默认使用 'multinomial' 或 'ovr'
log_reg = LogisticRegression(
penalty='l2', # 正则化类型: 'l1', 'l2', 'elasticnet', None
C=1.0, # 正则化强度的倒数,越小正则化越强
solver='lbfgs', # 优化算法
max_iter=1000,
multi_class='auto'
)
log_reg.fit(X_train, y_train)
y_pred = log_reg.predict(X_test)
y_prob = log_reg.predict_proba(X_test) # 概率输出
print(f"准确率: {accuracy_score(y_test, y_pred)}")
print(classification_report(y_test, y_pred))
print(confusion_matrix(y_test, y_pred))
2.3.3 支持向量机 (SVM)
from sklearn.svm import SVC, SVR
# 分类 SVM
svm = SVC(
kernel='rbf', # 'linear', 'poly', 'rbf', 'sigmoid'
C=1.0, # 惩罚参数
gamma='scale', # RBF核的gamma参数
probability=True # 启用概率估计
)
svm.fit(X_train, y_train)
# 回归 SVM
svr = SVR(kernel='rbf', C=1.0, epsilon=0.1)
svr.fit(X_train, y_train)
2.3.4 决策树与随机森林
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
# 决策树
dt = DecisionTreeClassifier(
max_depth=5, # 最大深度
min_samples_split=2, # 分裂最小样本数
min_samples_leaf=1, # 叶子节点最小样本数
criterion='gini' # 'gini' 或 'entropy'
)
dt.fit(X_train, y_train)
# 随机森林(Bagging集成)
rf = RandomForestClassifier(
n_estimators=100, # 树的数量
max_depth=10,
min_samples_split=2,
max_features='sqrt', # 每棵树考虑的特征数
random_state=42,
n_jobs=-1 # 使用所有CPU核心
)
rf.fit(X_train, y_train)
# 特征重要性
importances = rf.feature_importances_
# GBDT(Boosting集成)
gbdt = GradientBoostingClassifier(
n_estimators=100,
learning_rate=0.1,
max_depth=3,
random_state=42
)
gbdt.fit(X_train, y_train)
2.3.5 K近邻 (KNN)
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(
n_neighbors=5, # K值
weights='uniform', # 'uniform' 或 'distance'
metric='minkowski' # 距离度量
)
knn.fit(X_train, y_train)
2.4 无监督学习
2.4.1 K-Means 聚类
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
kmeans = KMeans(
n_clusters=3, # 聚类数量
init='k-means++', # 初始化方法
n_init=10, # 运行次数
random_state=42
)
kmeans.fit(X)
labels = kmeans.labels_ # 每个样本的聚类标签
centroids = kmeans.cluster_centers_ # 聚类中心
inertia = kmeans.inertia_ # 簇内平方和
# 轮廓系数评估(越接近1越好)
score = silhouette_score(X, labels)
print(f"轮廓系数: {score}")
# 选择最佳K值:肘部法则
inertias = []
for k in range(1, 11):
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(X)
inertias.append(kmeans.inertia_)
2.4.2 PCA 降维
from sklearn.decomposition import PCA
pca = PCA(n_components=2) # 保留的维度数,也可以是比例如 0.95
X_pca = pca.fit_transform(X)
print(f"解释方差比: {pca.explained_variance_ratio_}")
print(f"累计解释方差: {sum(pca.explained_variance_ratio_)}")
2.5 模型选择与调优
2.5.1 数据集划分
from sklearn.model_selection import train_test_split, cross_val_score
# 简单划分
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2, # 测试集比例
random_state=42, # 随机种子,保证可复现
stratify=y # 分层抽样(分类任务推荐)
)
# 交叉验证
scores = cross_val_score(
model, X, y,
cv=5, # 5折交叉验证
scoring='accuracy' # 评估指标
)
print(f"交叉验证得分: {scores.mean():.4f} ± {scores.std():.4f}")
2.5.2 网格搜索与随机搜索
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
# 网格搜索
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20],
'min_samples_split': [2, 5, 10]
}
grid_search = GridSearchCV(
estimator=RandomForestClassifier(random_state=42),
param_grid=param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1,
verbose=1
)
grid_search.fit(X_train, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳得分: {grid_search.best_score_}")
best_model = grid_search.best_estimator_
# 随机搜索(更快,适合大参数空间)
random_search = RandomizedSearchCV(
estimator=model,
param_distributions=param_dist,
n_iter=50, # 随机采样次数
cv=5,
random_state=42
)
2.6 Pipeline 流水线
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.svm import SVC
# 构建流水线:数据依次经过每一步
pipeline = Pipeline([
('scaler', StandardScaler()), # 第一步:标准化
('pca', PCA(n_components=0.95)), # 第二步:PCA降维
('svm', SVC()) # 第三步:SVM分类
])
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
# 流水线 + 网格搜索
param_grid = {
'pca__n_components': [0.9, 0.95, 0.99], # 注意双下划线
'svm__C': [0.1, 1, 10],
'svm__gamma': ['scale', 'auto']
}
grid = GridSearchCV(pipeline, param_grid, cv=5)
grid.fit(X_train, y_train)
3. PyTorch 深度学习框架
3.1 PyTorch 基础
3.1.1 张量 (Tensor) 操作
import torch
import numpy as np
# 创建张量
x = torch.tensor([1, 2, 3]) # 从列表创建
x = torch.randn(3, 4) # 标准正态分布
x = torch.rand(3, 4) # [0,1)均匀分布
x = torch.zeros(2, 3) # 全零
x = torch.ones(2, 3) # 全一
x = torch.eye(3) # 单位矩阵
x = torch.arange(0, 10, 2) # 序列
# 张量属性
print(x.shape) # 形状
print(x.dtype) # 数据类型
print(x.device) # 设备 (cpu/cuda)
# 张量运算
a = torch.randn(3, 4)
b = torch.randn(4, 5)
# 矩阵乘法
c = torch.matmul(a, b) # 或 a @ b
# 逐元素运算
c = a + b
c = a * b
c = torch.exp(a)
c = torch.sigmoid(a)
c = torch.relu(a)
# 形状操作
x = torch.randn(4, 4)
x_reshaped = x.reshape(2, 8) # 重塑形状
x_flat = x.flatten() # 展平
x_T = x.t() # 转置
x_unsqueezed = x.unsqueeze(0) # 增加维度
x_squeezed = x.squeeze() # 压缩维度
# GPU 运算
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
x = x.to(device) # 移动到GPU
# NumPy 互转
np_array = x.numpy()
tensor = torch.from_numpy(np_array)
3.1.2 自动求导 (Autograd)
import torch
# 启用梯度追踪
x = torch.tensor(2.0, requires_grad=True)
w = torch.tensor(3.0, requires_grad=True)
b = torch.tensor(1.0, requires_grad=True)
# 前向传播
y = w * x + b # y = 3*2 + 1 = 7
# 反向传播:计算梯度
y.backward()
# 查看梯度
print(x.grad) # dy/dx = w = 3.0
print(w.grad) # dy/dw = x = 2.0
print(b.grad) # dy/db = 1.0
# 清零梯度(防止累积)
x.grad.zero_()
w.grad.zero_()
b.grad.zero_()
# 关闭梯度计算(推理时使用,节省内存)
with torch.no_grad():
y = w * x + b
# 这里不会计算梯度
3.2 神经网络构建
3.2.1 自定义模型
import torch
import torch.nn as nn
import torch.nn.functional as F
# 方式1:继承 nn.Module
class SimpleNN(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
# 方式2:使用 nn.Sequential(简单模型)
model = nn.Sequential(
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
# 实例化模型
model = SimpleNN(input_size=784, hidden_size=128, num_classes=10)
print(model)
# 查看参数数量
total_params = sum(p.numel() for p in model.parameters())
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"总参数: {total_params}, 可训练参数: {trainable_params}")
3.2.2 常用层
import torch.nn as nn
# 全连接层
nn.Linear(in_features, out_features, bias=True)
# 卷积层
nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0)
nn.ConvTranspose2d() # 转置卷积(上采样)
# 池化层
nn.MaxPool2d(kernel_size, stride=None)
nn.AvgPool2d(kernel_size)
nn.AdaptiveAvgPool2d(output_size) # 自适应池化
# 归一化层
nn.BatchNorm1d(num_features)
nn.BatchNorm2d(num_features)
nn.LayerNorm(normalized_shape)
# Dropout
nn.Dropout(p=0.5)
nn.Dropout2d(p=0.5)
# 激活函数
nn.ReLU()
nn.LeakyReLU(negative_slope=0.01)
nn.Sigmoid()
nn.Tanh()
nn.Softmax(dim=None)
nn.GELU()
# 损失函数
nn.CrossEntropyLoss() # 多分类(包含Softmax)
nn.BCELoss() # 二分类(需先Sigmoid)
nn.BCEWithLogitsLoss() # 二分类(包含Sigmoid)
nn.MSELoss() # 回归
nn.NLLLoss() # 负对数似然
3.3 数据加载
from torch.utils.data import Dataset, DataLoader
from torchvision import datasets, transforms
# 内置数据集 + 变换
transform = transforms.Compose([
transforms.ToTensor(), # 转为张量 [0,1]
transforms.Normalize((0.1307,), (0.3081,)) # 标准化
])
train_dataset = datasets.MNIST(
root='./data',
train=True,
transform=transform,
download=True
)
# 自定义数据集
class CustomDataset(Dataset):
def __init__(self, data, labels, transform=None):
self.data = data
self.labels = labels
self.transform = transform
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
sample = self.data[idx]
label = self.labels[idx]
if self.transform:
sample = self.transform(sample)
return sample, label
# 数据加载器
train_loader = DataLoader(
dataset=train_dataset,
batch_size=64, # 批次大小
shuffle=True, # 打乱顺序
num_workers=4, # 多进程加载
pin_memory=True # 锁页内存(GPU训练时更快)
)
# 遍历数据
for images, labels in train_loader:
print(f"批次形状: {images.shape}, 标签形状: {labels.shape}")
break
3.4 训练流程
3.4.1 完整训练模板
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
def train_model(model, train_loader, val_loader, num_epochs=10, learning_rate=0.001):
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
# 损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# 学习率调度器
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)
best_acc = 0.0
for epoch in range(num_epochs):
# 训练阶段
model.train()
train_loss = 0.0
train_correct = 0
train_total = 0
for batch_idx, (images, labels) in enumerate(train_loader):
images = images.to(device)
labels = labels.to(device)
# 前向传播
outputs = model(images)
loss = criterion(outputs, labels)
# 反向传播和优化
optimizer.zero_grad() # 清零梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
# 统计
train_loss += loss.item()
_, predicted = torch.max(outputs.data, 1)
train_total += labels.size(0)
train_correct += (predicted == labels).sum().item()
# 验证阶段
model.eval() # 切换到评估模式(关闭Dropout、BatchNorm训练模式)
val_loss = 0.0
val_correct = 0
val_total = 0
with torch.no_grad(): # 不计算梯度
for images, labels in val_loader:
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels)
val_loss += loss.item()
_, predicted = torch.max(outputs.data, 1)
val_total += labels.size(0)
val_correct += (predicted == labels).sum().item()
# 更新学习率
scheduler.step()
# 打印结果
train_acc = 100 * train_correct / train_total
val_acc = 100 * val_correct / val_total
print(f'Epoch [{epoch+1}/{num_epochs}]')
print(f' Train Loss: {train_loss/len(train_loader):.4f}, Acc: {train_acc:.2f}%')
print(f' Val Loss: {val_loss/len(val_loader):.4f}, Acc: {val_acc:.2f}%')
# 保存最佳模型
if val_acc > best_acc:
best_acc = val_acc
torch.save(model.state_dict(), 'best_model.pth')
print(f'最佳验证准确率: {best_acc:.2f}%')
return model
3.4.2 优化器
import torch.optim as optim
# SGD
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9, weight_decay=1e-4)
# Adam(最常用)
optimizer = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999), weight_decay=0)
# AdamW(带权重衰减修正,Transformer常用)
optimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
# RMSprop
optimizer = optim.RMSprop(model.parameters(), lr=0.01, alpha=0.99)
3.5 模型保存与加载
# 保存模型参数(推荐)
torch.save(model.state_dict(), 'model_weights.pth')
# 加载模型参数
model = SimpleNN(input_size, hidden_size, num_classes)
model.load_state_dict(torch.load('model_weights.pth'))
model.eval() # 切换到评估模式
# 保存整个模型(不推荐,文件大,兼容性差)
torch.save(model, 'full_model.pth')
model = torch.load('full_model.pth')
# 保存检查点(包含优化器等信息)
checkpoint = {
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': loss,
}
torch.save(checkpoint, 'checkpoint.pth')
# 加载检查点
checkpoint = torch.load('checkpoint.pth')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
3.6 卷积神经网络 (CNN)
import torch
import torch.nn as nn
class CNN(nn.Module):
def __init__(self, num_classes=10):
super(CNN, self).__init__()
# 输入: (batch, 1, 28, 28) - MNIST
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
self.bn1 = nn.BatchNorm2d(32)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2) # 28x28 -> 14x14
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
self.bn2 = nn.BatchNorm2d(64)
# 再池化: 14x14 -> 7x7
self.fc1 = nn.Linear(64 * 7 * 7, 128)
self.dropout = nn.Dropout(0.5)
self.fc2 = nn.Linear(128, num_classes)
def forward(self, x):
# 卷积层1
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.pool(out)
# 卷积层2
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.pool(out)
# 展平
out = out.view(out.size(0), -1)
# 全连接层
out = self.fc1(out)
out = self.relu(out)
out = self.dropout(out)
out = self.fc2(out)
return out
# 测试
model = CNN()
x = torch.randn(1, 1, 28, 28) # batch=1, channel=1, 28x28
output = model(x)
print(f"输出形状: {output.shape}") # torch.Size([1, 10])
3.7 迁移学习
import torch
import torch.nn as nn
from torchvision import models
# 加载预训练模型
model = models.resnet18(pretrained=True)
# 方式1:微调所有层
for param in model.parameters():
param.requires_grad = True # 全部可训练
# 方式2:冻结特征提取层,只训练分类头
for param in model.parameters():
param.requires_grad = False # 冻结所有层
# 替换最后的全连接层
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, num_classes) # 新层默认 requires_grad=True
# 训练时只更新fc层的参数
optimizer = optim.Adam(model.fc.parameters(), lr=0.001)
# 常用预训练模型
models.resnet18(pretrained=True)
models.resnet50(pretrained=True)
models.vgg16(pretrained=True)
models.mobilenet_v2(pretrained=True)
models.efficientnet_b0(pretrained=True)
4. TensorFlow / Keras 深度学习框架
4.1 TensorFlow 基础
4.1.1 张量操作
import tensorflow as tf
import numpy as np
# 创建张量
x = tf.constant([1, 2, 3]) # 常量张量
x = tf.Variable([1.0, 2.0, 3.0]) # 变量张量(可训练)
x = tf.random.normal(shape=(3, 4)) # 标准正态
x = tf.random.uniform(shape=(3, 4)) # 均匀分布
x = tf.zeros(shape=(2, 3)) # 全零
x = tf.ones(shape=(2, 3)) # 全一
x = tf.eye(3) # 单位矩阵
# 张量属性
print(x.shape) # 形状
print(x.dtype) # 数据类型
print(x.device) # 设备
# 张量运算
a = tf.random.normal((3, 4))
b = tf.random.normal((4, 5))
# 矩阵乘法
c = tf.matmul(a, b)
# 逐元素运算
c = a + b
c = a * b
c = tf.exp(a)
c = tf.sigmoid(a)
c = tf.nn.relu(a)
# 形状操作
x = tf.random.normal((4, 4))
x_reshaped = tf.reshape(x, (2, 8))
x_flat = tf.reshape(x, [-1]) # 展平
x_T = tf.transpose(x)
x_expanded = tf.expand_dims(x, axis=0)
x_squeezed = tf.squeeze(x_expanded)
# GPU 运算
print("GPU可用:", tf.config.list_physical_devices('GPU'))
# NumPy 互转
np_array = x.numpy()
tensor = tf.convert_to_tensor(np_array)
4.1.2 自动求导
import tensorflow as tf
x = tf.Variable(2.0)
w = tf.Variable(3.0)
b = tf.Variable(1.0)
# 使用 GradientTape 记录计算过程
with tf.GradientTape() as tape:
y = w * x + b # 前向传播
# 计算梯度
gradients = tape.gradient(y, [w, x, b])
print(f"dy/dw = {gradients[0].numpy()}") # 3.0
print(f"dy/dx = {gradients[1].numpy()}") # 2.0
print(f"dy/db = {gradients[2].numpy()}") # 1.0
# 高阶导数
with tf.GradientTape() as tape2:
with tf.GradientTape() as tape1:
y = x ** 3
dy_dx = tape1.gradient(y, x)
d2y_dx2 = tape2.gradient(dy_dx, x)
print(f"二阶导数: {d2y_dx2.numpy()}") # 12.0 (x=2时,6x=12)
4.2 Keras 模型构建
4.2.1 Sequential API(顺序模型)
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
# 方式1:Sequential
model = keras.Sequential([
layers.Dense(256, activation='relu', input_shape=(784,)),
layers.Dropout(0.3),
layers.Dense(128, activation='relu'),
layers.Dropout(0.3),
layers.Dense(10, activation='softmax')
])
# 方式2:add方法
model = keras.Sequential()
model.add(layers.Dense(256, activation='relu', input_shape=(784,)))
model.add(layers.Dropout(0.3))
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary() # 查看模型结构
4.2.2 Functional API(函数式模型)
# 适合多输入、多输出、残差连接等复杂结构
inputs = keras.Input(shape=(784,))
x = layers.Dense(256, activation='relu')(inputs)
x = layers.Dropout(0.3)(x)
x = layers.Dense(128, activation='relu')(x)
x = layers.Dropout(0.3)(x)
outputs = layers.Dense(10, activation='softmax')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
model.summary()
4.2.3 子类化模型
class CustomModel(keras.Model):
def __init__(self, num_classes=10):
super(CustomModel, self).__init__()
self.dense1 = layers.Dense(256, activation='relu')
self.dropout1 = layers.Dropout(0.3)
self.dense2 = layers.Dense(128, activation='relu')
self.dropout2 = layers.Dropout(0.3)
self.dense3 = layers.Dense(num_classes, activation='softmax')
def call(self, inputs, training=False):
x = self.dense1(inputs)
x = self.dropout1(x, training=training)
x = self.dense2(x)
x = self.dropout2(x, training=training)
return self.dense3(x)
model = CustomModel(num_classes=10)
4.3 常用层与激活函数
from tensorflow.keras import layers
# 全连接层
layers.Dense(units, activation=None, use_bias=True)
# 卷积层
layers.Conv2D(filters, kernel_size, strides=(1,1), padding='valid', activation=None)
layers.Conv2DTranspose(filters, kernel_size, strides=(1,1), padding='valid')
# 池化层
layers.MaxPooling2D(pool_size=(2,2), strides=None)
layers.AveragePooling2D(pool_size=(2,2))
layers.GlobalAveragePooling2D()
# 归一化层
layers.BatchNormalization()
layers.LayerNormalization()
# Dropout
layers.Dropout(rate=0.5)
layers.SpatialDropout2D(rate=0.5)
# 循环层
layers.LSTM(units)
layers.GRU(units)
layers.SimpleRNN(units)
# 嵌入层
layers.Embedding(input_dim, output_dim, input_length=None)
# 激活函数(可作为层使用)
layers.ReLU()
layers.LeakyReLU(alpha=0.3)
layers.Softmax()
layers.Activation('sigmoid')
4.4 数据加载
import tensorflow as tf
from tensorflow.keras.datasets import mnist
# 内置数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 预处理
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
x_train = x_train.reshape(-1, 784)
x_test = x_test.reshape(-1, 784)
# 标签独热编码(可选,sparse_categorical_crossentropy不需要)
y_train_onehot = tf.keras.utils.to_categorical(y_train, 10)
y_test_onehot = tf.keras.utils.to_categorical(y_test, 10)
# tf.data.Dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64).prefetch(tf.data.AUTOTUNE)
# 图像数据生成器(数据增强)
from tensorflow.keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=15,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True,
rescale=1./255,
validation_split=0.2
)
train_generator = datagen.flow_from_directory(
'data/train',
target_size=(224, 224),
batch_size=32,
class_mode='categorical',
subset='training'
)
4.5 模型编译与训练
# 编译模型
model.compile(
optimizer='adam', # 优化器
loss='sparse_categorical_crossentropy', # 损失函数
metrics=['accuracy'] # 评估指标
)
# 自定义优化器和学习率
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
model.compile(
optimizer=optimizer,
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()]
)
# 训练
history = model.fit(
x_train, y_train,
epochs=10,
batch_size=64,
validation_split=0.1, # 从训练集划分验证集
# validation_data=(x_val, y_val), # 或使用指定验证集
verbose=1
)
# 评估
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print(f'测试准确率: {test_acc:.4f}')
# 预测
predictions = model.predict(x_test)
predicted_classes = tf.argmax(predictions, axis=1)
4.6 回调函数
from tensorflow.keras.callbacks import (
ModelCheckpoint, EarlyStopping, ReduceLROnPlateau, TensorBoard
)
callbacks = [
# 保存最佳模型
ModelCheckpoint(
'best_model.h5',
monitor='val_accuracy',
save_best_only=True,
mode='max',
verbose=1
),
# 早停
EarlyStopping(
monitor='val_loss',
patience=5, # 5个epoch没改善就停止
restore_best_weights=True,
verbose=1
),
# 学习率衰减
ReduceLROnPlateau(
monitor='val_loss',
factor=0.1, # 学习率乘以0.1
patience=3, # 3个epoch没改善就降低
min_lr=1e-7,
verbose=1
),
# TensorBoard 可视化
TensorBoard(log_dir='./logs')
]
# 训练时传入 callbacks
history = model.fit(
x_train, y_train,
epochs=50,
batch_size=64,
validation_split=0.1,
callbacks=callbacks
)
4.7 CNN 示例
import tensorflow as tf
from tensorflow.keras import layers, models
def create_cnn(input_shape=(28, 28, 1), num_classes=10):
model = models.Sequential([
# 卷积块1
layers.Conv2D(32, (3, 3), padding='same', input_shape=input_shape),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.MaxPooling2D((2, 2)),
# 卷积块2
layers.Conv2D(64, (3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.MaxPooling2D((2, 2)),
# 卷积块3
layers.Conv2D(128, (3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.GlobalAveragePooling2D(),
# 分类头
layers.Dense(128, activation='relu'),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
return model
model = create_cnn()
model.summary()
4.8 迁移学习
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.applications import ResNet50
# 加载预训练模型(不包含顶部分类层)
base_model = ResNet50(
weights='imagenet',
include_top=False,
input_shape=(224, 224, 3)
)
# 冻结基础模型
base_model.trainable = False
# 构建完整模型
model = models.Sequential([
base_model,
layers.GlobalAveragePooling2D(),
layers.Dense(256, activation='relu'),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
# 先训练顶部分类层
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(train_data, epochs=10, validation_data=val_data)
# 微调:解冻部分层
base_model.trainable = True
fine_tune_at = 100 # 解冻最后100层
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False
# 使用更小的学习率微调
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5),
loss='categorical_crossentropy',
metrics=['accuracy']
)
model.fit(train_data, epochs=20, initial_epoch=10, validation_data=val_data)
4.9 模型保存与加载
# 保存整个模型(架构+权重+优化器状态)
model.save('my_model.h5')
# 加载模型
model = tf.keras.models.load_model('my_model.h5')
# 只保存权重
model.save_weights('my_weights.h5')
# 加载权重(需要先构建相同结构的模型)
model.load_weights('my_weights.h5')
# SavedModel 格式(推荐,TensorFlow原生格式)
model.save('saved_model/my_model')
model = tf.keras.models.load_model('saved_model/my_model')
5. 三大框架对比与选型
5.1 框架对比
| 维度 | scikit-learn | PyTorch | TensorFlow/Keras |
|---|---|---|---|
| 定位 | 传统机器学习 | 深度学习研究/生产 | 深度学习生产/部署 |
| 学习曲线 | 简单 | 中等 | 较陡(Keras简单) |
| 灵活性 | 低(封装好) | 高(动态图) | 中(静态图,2.0后有eager) |
| 调试难度 | 简单 | 简单(Python原生调试) | 较难 |
| 生产部署 | 简单 | 中等(TorchScript/ONNX) | 强(TFLite/Serving) |
| 社区生态 | 传统ML最丰富 | 学术圈最火 | 工业界最成熟 |
| 数据量需求 | 小到中 | 大 | 大 |
| 适用场景 | 表格数据、传统ML | 研究、NLP、CV | 生产部署、移动端 |
5.2 选型建议
选择决策树:
├── 数据是表格型(结构化数据)
│ ├── 特征工程为主 → scikit-learn
│ └── 需要深度模型 → PyTorch / TensorFlow
│
├── 图像 / 计算机视觉
│ ├── 研究创新 → PyTorch
│ └── 生产部署 → TensorFlow
│
├── 自然语言处理
│ └── 绝大多数情况 → PyTorch(HuggingFace生态)
│
├── 移动端 / 嵌入式
│ └── TensorFlow Lite
│
└── 快速原型验证
└── Keras (TensorFlow)
5.3 学习路径建议
第一阶段:基础
├── Python 基础(numpy, pandas, matplotlib)
├── 机器学习基础理论
└── scikit-learn 实践
第二阶段:深度学习入门
├── 神经网络基础(BP、CNN、RNN)
├── PyTorch 或 TensorFlow 二选一
└── MNIST / CIFAR 分类实战
第三阶段:进阶
├── 选择主攻框架深入
├── 学习经典网络架构
├── 迁移学习、数据增强
└── 一个完整项目实战
第四阶段:专项深入
├── CV方向:目标检测、分割、生成模型
├── NLP方向:Transformer、BERT、大模型
└── 工程化:部署、优化、MLOps
6. 经典项目实战
6.1 项目1:房价预测(回归任务)
# 使用 scikit-learn
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
# 1. 数据加载与探索
# data = pd.read_csv('house_prices.csv')
# print(data.describe())
# 2. 特征工程(略)
# 处理缺失值、编码分类特征、特征组合...
# 3. 数据划分
# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 4. 模型训练
# scaler = StandardScaler()
# X_train_scaled = scaler.fit_transform(X_train)
# X_test_scaled = scaler.transform(X_test)
#
# model = RandomForestRegressor(n_estimators=100, random_state=42)
# model.fit(X_train_scaled, y_train)
# 5. 评估
# y_pred = model.predict(X_test_scaled)
# print(f'RMSE: {np.sqrt(mean_squared_error(y_test, y_pred))}')
# print(f'R²: {r2_score(y_test, y_pred)}')
6.2 项目2:手写数字识别(CNN分类)
# 使用 PyTorch
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 数据准备
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
train_dataset = datasets.MNIST('./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST('./data', train=False, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=1000, shuffle=False)
# 模型定义(CNN)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.dropout1 = nn.Dropout2d(0.25)
self.dropout2 = nn.Dropout(0.5)
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.conv1(x)
x = torch.relu(x)
x = self.conv2(x)
x = torch.relu(x)
x = torch.max_pool2d(x, 2)
x = self.dropout1(x)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = torch.relu(x)
x = self.dropout2(x)
x = self.fc2(x)
return x
# 训练
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = Net().to(device)
optimizer = optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
# 训练循环(参考3.4.1完整训练模板)
6.3 项目3:图像分类(迁移学习)
# 使用 TensorFlow/Keras
import tensorflow as tf
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras import layers, models
# 数据加载(ImageDataGenerator 或 tf.data)
# train_ds = tf.keras.utils.image_dataset_from_directory(
# 'data/train',
# image_size=(224, 224),
# batch_size=32
# )
# 基础模型
base_model = MobileNetV2(
weights='imagenet',
include_top=False,
input_shape=(224, 224, 3)
)
base_model.trainable = False
# 构建模型
model = models.Sequential([
base_model,
layers.GlobalAveragePooling2D(),
layers.Dense(128, activation='relu'),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
# 编译训练
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# model.fit(train_ds, epochs=10, validation_data=val_ds)
# 微调
base_model.trainable = True
fine_tune_at = 100
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5),
loss='categorical_crossentropy',
metrics=['accuracy']
)
# model.fit(train_ds, epochs=20, initial_epoch=10, validation_data=val_ds)
7. 学习资源推荐
7.1 在线课程
| 课程 | 平台 | 特点 |
|---|---|---|
| 吴恩达机器学习 | Coursera | 经典入门,理论扎实 |
| 吴恩达深度学习专项 | Coursera | 深度学习入门首选 |
| CS231n 计算机视觉 | Stanford | CV方向经典 |
| CS224n NLP | Stanford | NLP方向经典 |
| fast.ai | fast.ai | 实战导向,PyTorch |
7.2 书籍
- 《统计学习方法》 - 李航:传统机器学习经典,中文
- 《深度学习》 - Ian Goodfellow:深度学习圣经(花书)
- 《动手学深度学习》 - 李沐:实战导向,有PyTorch/TensorFlow版
- 《Python机器学习》 - Sebastian Raschka:scikit-learn实战
7.3 文档与教程
- scikit-learn 官方文档:https://scikit-learn.org/stable/
- PyTorch 官方教程:https://pytorch.org/tutorials/
- TensorFlow 官方教程:https://www.tensorflow.org/tutorials
- HuggingFace:https://huggingface.co/(NLP必备)
7.4 练习平台
- Kaggle:数据科学竞赛平台
- LeetCode:算法练习
- Papers With Code:论文+代码
- GitHub Awesome系列:各方向资源汇总
附录:常用代码片段速查
A.1 环境配置
# 创建虚拟环境
conda create -n ml python=3.9
conda activate ml
# 安装基础库
pip install numpy pandas matplotlib seaborn scikit-learn
# 安装 PyTorch (CUDA 11.8)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# 安装 TensorFlow
pip install tensorflow
# 验证安装
python -c "import torch; print('PyTorch:', torch.__version__); print('CUDA:', torch.cuda.is_available())"
python -c "import tensorflow as tf; print('TensorFlow:', tf.__version__)"
A.2 设置随机种子
# PyTorch
import torch
import numpy as np
import random
def set_seed(seed=42):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
set_seed(42)
# TensorFlow
import tensorflow as tf
tf.random.set_seed(42)
np.random.seed(42)
A.3 训练可视化
# 使用 matplotlib 绘制训练曲线
import matplotlib.pyplot as plt
def plot_history(history):
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
# 损失曲线
ax1.plot(history['loss'], label='train')
ax1.plot(history['val_loss'], label='val')
ax1.set_title('Loss')
ax1.set_xlabel('Epoch')
ax1.legend()
# 准确率曲线
ax2.plot(history['accuracy'], label='train')
ax2.plot(history['val_accuracy'], label='val')
ax2.set_title('Accuracy')
ax2.set_xlabel('Epoch')
ax2.legend()
plt.tight_layout()
plt.show()
学习建议:理论 + 实践相结合,每学一个算法都动手实现一遍,然后在真实数据集上验证。从简单的项目开始,逐步增加复杂度。遇到问题先查官方文档,再搜社区解决方案。坚持做项目,边做边学是最快的成长方式。
更多推荐

所有评论(0)