-
范数
范数是对向量大小的度量 ,可以反映权重的总影响力度,范数越大说明权重的累计影响越大,函数对于输入特征更敏感,可以拟合更复杂的模式。
L1范数:侧重非零权重的数量 。范数大可能意味着更多特征被激活,函数更 "繁琐"。限制L1范数,会让部分权重变为 0,实现 "特征选择",简化函数(只保留关键特征)。
L2范数:侧重权重的绝对大小 。范数大可能意味着部分权重数值极大,函数对个别特征过度依赖,容易 "过拟合"(即复杂性超出数据真实规律)。限制L2范数,会让权重数值整体变小,避免个别特征主导预测,让函数更 "稳健"。
权重衰减 (weight decay)是最广泛使用的正则化的技术之一, 它通常也被称为正则化。 这项技术通过函数与零的距离来衡量函数的复杂度。核心目的是通过对权重施加惩罚,使权重数值减小,减少对个别特征的过度依赖,控制函数复杂度,避免过拟合,同时提升模型的泛化能力和稳健性。
权重衰减代码实现:
pythonimport matplotlib matplotlib.use('TkAgg') # ✅ 让 PyCharm 可以显示图像窗口 import torch from torch import nn from d2l import torch as d2l n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5 true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05 train_data = d2l.synthetic_data(true_w, true_b, n_train) train_iter = d2l.load_array(train_data, batch_size) test_data = d2l.synthetic_data(true_w, true_b, n_test) test_iter = d2l.load_array(test_data, batch_size, is_train=False) def init_params(): w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True) b = torch.zeros(1, requires_grad=True) return [w, b] def l2_penalty(w): return torch.sum(w.pow(2)) / 2 def train(lambd): w, b = init_params() net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss num_epochs, lr = 100, 0.003 animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log', xlim=[5, num_epochs], legend=['train', 'test']) for epoch in range(num_epochs): for X, y in train_iter: # 增加了L2范数惩罚项, # 广播机制使l2_penalty(w)成为一个长度为batch_size的向量 l = loss(net(X), y) + lambd * l2_penalty(w) l.sum().backward() d2l.sgd([w, b], lr, batch_size) if (epoch + 1) % 5 == 0: animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss), d2l.evaluate_loss(net, test_iter, loss))) print('w的L2范数是:', torch.norm(w).item()) train(lambd=0) train(lambd=3) -
暂退法:"暂退" 体现在训练时随机 "暂时退出" 部分神经元(注入噪声的本质),目的是通过打破神经元间的固定依赖,提升模型泛化能力、防止过拟合。在前向传播中,给每一层的神经元加入噪声。
-
经典泛化理论认为,为了缩小训练和测试性能之间的差距,应该以简单的模型为目标 。 "简单模型",本质是 "复杂度匹配数据规律" 的模型,而非 "表面简单"------ 它能避免过拟合,自然缩小训练与测试差距,而 "复杂模型" 反而因拟合噪声导致差距扩大。简单性的另一个角度是平滑性,即函数不应该对其输入的微小变化敏感。注入噪声(如暂退法随机置零神经元、高斯噪声添加到激活值)的核心是 "迫使模型适应不确定性",最终抵消噪声的 "破坏性",形成平滑映射:
-
如何注入这种噪声 ? 一种想法是以一种无偏向 (unbiased)的方式注入噪声。 这样在固定住其他层时,每一层的期望值等于没有噪音时的值。噪声注入的 "无偏向(unbiased)",指训练时注入的噪声不会改变该层输出的 "数学期望" ------ 固定其他层时,含噪声的输出均值和无噪声时完全一致,避免给模型训练引入系统性偏差。
-
前向传播(forward propagation或forward pass) 指的是:按顺序(从输入层到输出层)计算和存储神经网络中每层的结果。
-
反向传播(backward propagation或backpropagation)指的是计算神经网络参数梯度的方法。言之,该方法根据微积分中的链式规则,按相反的顺序从输出层到输入层遍历网络。
-
隐藏变量是网络中间层的输出(连接输入和输出的 "过渡特征"),变换 f 是每一层对输入(前一层输出)的计算规则(含权重、激活函数等参数化操作),二者共同构成深层网络的 "分层特征传递" 逻辑。
-
梯度爆炸(gradient exploding)问题: 参数更新过大,破坏了模型的稳定收敛; 梯度消失(gradient vanishing)问题: 参数更新过小,在每次更新时几乎不会移动,导致模型无法学习。
-
协变量(Covariate):就是我们模型的输入特征(比如预测疾病时的 "年龄、血压、血糖",预测销量时的 "价格、推广费用"),是用来解释或预测标签的变量。
标签函数(Label Function):本质是 "特征→标签" 的条件分布 , 它代表了特征和标签之间的核心关联规律(比如 "血压≥180→高血压风险 80%" 这个规律)。
分布偏移(Distribution Shift):训练数据和测试数据的分布不一致(比如训练时用的是年轻人数据,测试时用的是老年人数据)。
协变量偏移:特征(血压值)的分布变了(年轻人→老年人),但特征到标签的规律(血压阈值判断高血压)没变。
- Kaggle预测房价
python# ========================================================= # Kaggle House Prices - Pure PyTorch Version # 每一行都有详细中文解释,适合学习 / 实验报告 # ========================================================= # ---------- Matplotlib 设置 ---------- import matplotlib matplotlib.use('TkAgg') # 使用 TkAgg 后端,保证 PyCharm 本地可以弹出图像窗口 # ---------- 常用科学计算库 ---------- import pandas as pd # 用于读取 CSV、表格数据处理 import numpy as np # 数值计算(主要辅助 pandas) # ---------- PyTorch 核心 ---------- import torch # PyTorch 主库 import torch.nn as nn # 神经网络模块(Linear、Loss 等) from torch.utils.data import TensorDataset, DataLoader # 数据集与批量加载器 # ---------- 其他工具 ---------- import hashlib # 用于校验文件完整性(SHA1) import os # 文件路径操作 import requests # 网络下载 import matplotlib.pyplot as plt # 绘图 # ========================================================= # 一、数据下载工具(来自 D2L 思想) # ========================================================= # DATA_HUB 用于存储:数据名称 -> (下载链接, SHA1 校验值) DATA_HUB = dict() # D2L 官方数据服务器地址 DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/' def download(name, cache_dir=os.path.join('..', 'data')): """ 根据数据名称下载文件,并缓存到本地。 如果文件已存在且校验正确,则直接使用缓存。 """ # 确保数据名称存在 assert name in DATA_HUB, f"{name} 不存在于 DATA_HUB 中" # 解包下载地址和校验码 url, sha1_hash = DATA_HUB[name] # 创建缓存目录 os.makedirs(cache_dir, exist_ok=True) # 本地文件路径 fname = os.path.join(cache_dir, url.split('/')[-1]) # 如果文件已经存在,则进行 SHA1 校验 if os.path.exists(fname): sha1 = hashlib.sha1() with open(fname, 'rb') as f: while True: data = f.read(1048576) # 每次读取 1MB if not data: break sha1.update(data) # 如果校验通过,直接返回文件路径 if sha1.hexdigest() == sha1_hash: return fname # 否则重新下载 print(f'正在从 {url} 下载 {fname}...') r = requests.get(url, stream=True) with open(fname, 'wb') as f: f.write(r.content) return fname # ========================================================= # 二、下载并读取 Kaggle 房价数据 # ========================================================= # 训练集 DATA_HUB['kaggle_house_train'] = ( DATA_URL + 'kaggle_house_pred_train.csv', '585e9cc93e70b39160e7921475f9bcd7d31219ce' ) # 测试集 DATA_HUB['kaggle_house_test'] = ( DATA_URL + 'kaggle_house_pred_test.csv', 'fa19780a7b011d9b009e8bff8e99922a8ee2eb90' ) # 读取 CSV 文件 train_data = pd.read_csv(download('kaggle_house_train')) test_data = pd.read_csv(download('kaggle_house_test')) # 打印数据规模,确认读取正确 print(train_data.shape, test_data.shape) # ========================================================= # 三、特征工程(核心步骤) # ========================================================= # 合并训练集和测试集的特征(不包含 Id 和 SalePrice) # 目的:保证 one-hot 编码后维度完全一致 all_features = pd.concat( (train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]) ) # 找出所有数值型特征(排除字符串) numeric_features = all_features.dtypes[ all_features.dtypes != 'object' ].index # 对数值特征进行标准化处理(均值 0,方差 1) all_features[numeric_features] = all_features[numeric_features].apply( lambda x: (x - x.mean()) / x.std() ) # 标准化后,缺失值用 0 填充(合理且稳定) all_features[numeric_features] = all_features[numeric_features].fillna(0) # 对类别型特征进行 One-Hot 编码 # dummy_na=True 表示将缺失值也作为一个类别 all_features = pd.get_dummies(all_features, dummy_na=True) # ========================================================= # 四、转换为 PyTorch Tensor # ========================================================= # 训练集样本数 n_train = train_data.shape[0] # 训练特征 train_features = torch.tensor( all_features[:n_train].values, dtype=torch.float32 ) # 测试特征 test_features = torch.tensor( all_features[n_train:].values, dtype=torch.float32 ) # 训练标签(房价) # reshape(-1, 1):转换为二维,适配 Linear 输出 train_labels = torch.tensor( train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32 ) # ========================================================= # 五、模型定义 # ========================================================= # 输入特征维度 in_features = train_features.shape[1] def get_net(): """ 定义一个线性回归模型: y = Wx + b """ return nn.Sequential( nn.Linear(in_features, 1) ) # 均方误差损失函数 loss = nn.MSELoss() # ========================================================= # 六、评价指标:对数 RMSE # ========================================================= def log_rmse(net, features, labels): """ 计算对数 RMSE,用于 Kaggle 官方评测 """ with torch.no_grad(): # 不计算梯度 preds = torch.clamp(net(features), 1, float('inf')) rmse = torch.sqrt( loss(torch.log(preds), torch.log(labels)) ) return rmse.item() # ========================================================= # 七、模型训练函数 # ========================================================= def train(net, train_features, train_labels, test_features, test_labels, num_epochs, lr, weight_decay, batch_size): train_ls, test_ls = [], [] # 构建 PyTorch 数据加载器 dataset = TensorDataset(train_features, train_labels) train_iter = DataLoader( dataset, batch_size=batch_size, shuffle=True ) # Adam 优化器 optimizer = torch.optim.Adam( net.parameters(), lr=lr, weight_decay=weight_decay ) # 训练循环 for epoch in range(num_epochs): for X, y in train_iter: optimizer.zero_grad() # 清空梯度 l = loss(net(X), y) # 前向传播 + 计算损失 l.backward() # 反向传播 optimizer.step() # 更新参数 # 记录训练误差 train_ls.append(log_rmse(net, train_features, train_labels)) # 如果有验证集,计算验证误差 if test_labels is not None: test_ls.append(log_rmse(net, test_features, test_labels)) return train_ls, test_ls # ========================================================= # 八、K 折交叉验证 # ========================================================= def get_k_fold_data(k, i, X, y): fold_size = X.shape[0] // k X_train, y_train = None, None for j in range(k): idx = slice(j * fold_size, (j + 1) * fold_size) X_part, y_part = X[idx], y[idx] if j == i: X_valid, y_valid = X_part, y_part elif X_train is None: X_train, y_train = X_part, y_part else: X_train = torch.cat([X_train, X_part], dim=0) y_train = torch.cat([y_train, y_part], dim=0) return X_train, y_train, X_valid, y_valid def k_fold(k, X_train, y_train, num_epochs, lr, weight_decay, batch_size): train_l_sum, valid_l_sum = 0, 0 for i in range(k): data = get_k_fold_data(k, i, X_train, y_train) net = get_net() train_ls, valid_ls = train( net, *data, num_epochs, lr, weight_decay, batch_size ) train_l_sum += train_ls[-1] valid_l_sum += valid_ls[-1] print(f'折 {i+1}:训练 log RMSE={train_ls[-1]:.4f},' f'验证 log RMSE={valid_ls[-1]:.4f}') return train_l_sum / k, valid_l_sum / k # ========================================================= # 九、执行训练 # ========================================================= k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64 train_l, valid_l = k_fold( k, train_features, train_labels, num_epochs, lr, weight_decay, batch_size ) print(f'\n{k}-折交叉验证结果:') print(f'平均训练 log RMSE: {train_l:.4f}') print(f'平均验证 log RMSE: {valid_l:.4f}') # ========================================================= # 十、最终训练并生成提交文件 # ========================================================= def train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size): net = get_net() train_ls, _ = train( net, train_features, train_labels, None, None, num_epochs, lr, weight_decay, batch_size ) # 绘制训练曲线 plt.plot(range(1, num_epochs + 1), train_ls) plt.xlabel('epoch') plt.ylabel('log rmse') plt.yscale('log') plt.show() print(f'最终训练 log RMSE: {train_ls[-1]:.4f}') # 对测试集进行预测 preds = net(test_features).detach().numpy() # 生成提交文件 test_data['SalePrice'] = preds.reshape(-1) submission = pd.concat( [test_data['Id'], test_data['SalePrice']], axis=1 ) submission.to_csv('submission.csv', index=False) print('✅ submission.csv 已成功生成') train_and_pred( train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size )
【深度学习6】多层感知机2
摘星观月2025-12-16 8:49
相关推荐
啊巴矲6 小时前
小白从零开始勇闯人工智能:机器学习初级篇(KNN算法)FL16238631296 小时前
[C#][winform]基于yolov11的水下目标检测系统C#源码+onnx模型+评估指标曲线+精美GUI界面todoitbo6 小时前
从零搭建 Dify AI 平台:一次跌宕起伏的部署之旅SCBAiotAigc6 小时前
一个github的proxy urlserve the people6 小时前
tensorflow 零基础吃透:TensorFlow 稀疏张量(SparseTensor)的核心用法jinxinyuuuus6 小时前
GTA 风格 AI 生成器:提示词工程、LLM创造性联想与模因的自动化生成free-elcmacom6 小时前
机器学习高阶教程<1>优化理论:破解优化器的底层密码Angelina_Jolie6 小时前
ICCV 2025 | 去模糊新范式!残差引导 + 图像金字塔,强噪声下核估计精度提升 77%,SOTA 到手瀚岳-诸葛弩6 小时前
对比tensorflow,从0开始学pytorch(五)--CBAM