Python-standard-library-only-AI
纯 Python 标准库实现的神经网络工具箱,零第三方依赖 。
零第三方依赖 : 仅依赖 math、random、json 等标准库
全栈组件 : 从全连接层到 CNN、RNN/LSTM/GRU、Transformer 一应俱全
双模式 API : 底层精细控制 + 高层 sklearn 风格封装
完整的训练管线 : Early Stopping、梯度裁剪、学习率调度、模型保存/加载
反向传播有数值梯度测试守着 : Layer / MultiHeadAttention / Conv2d / BatchNorm1d 的解析梯度都与数值梯度逐项比对
import random
from AI import *
random .seed (42 ) # 示例固定随机种子,输出可复现
# ── 分类:一行训练,零配置 ────────────────────
x = [[0.1 , 0.2 , 0.3 ], [0.4 , 0.5 , 0.6 ], [0.7 , 0.8 , 0.9 ],
[0.15 , 0.25 , 0.35 ], [0.45 , 0.55 , 0.65 ], [0.75 , 0.85 , 0.95 ]]
y = [0 , 1 , 2 , 0 , 1 , 2 ]
model = quick_train (x , y , task = 'classification' , epochs = 300 , verbose = False )
print (model .score (x , y )) # 准确率 → 1.0
# ── 回归:目标 y = [x0², x0·x1] ───────────────
vals = [0.2 + 1.1 * i / 19 for i in range (20 )] # 0.2 ~ 1.3
x_reg = [[v , v * 1.5 ] for v in vals ]
y_reg = [[v * v , v * v * 1.5 ] for v in vals ]
random .seed (42 )
model_reg = make_regressor (input_dim = 2 , output_dim = 2 , hidden_layers = (32 , 32 ), lr = 0.03 )
model_reg .fit (x_reg , y_reg , epochs = 1500 , patience = 100 , verbose = False )
print (model_reg .predict ([0.6 , 0.9 ])) # → [0.3605, 0.5393](真值 [0.36, 0.54],R² ≈ 0.9999)
# 手动构建(5 维输入 → 2 维输出)
x_train = [[0.1 , 0.2 , 0.3 , 0.4 , 0.5 ], [0.2 , 0.3 , 0.4 , 0.5 , 0.6 ],
[0.3 , 0.4 , 0.5 , 0.6 , 0.7 ], [0.4 , 0.5 , 0.6 , 0.7 , 0.8 ]]
y_train = [[0.5 , 1.0 ], [0.7 , 1.4 ], [0.9 , 1.8 ], [1.1 , 2.2 ]]
model = Model (MLP ([5 , 16 , 8 , 2 ]), loss_fn = 'mse' , optimizer = 'adam' , lr = 0.01 )
model .summary () # 打印模型结构
history = model .fit (x_train , y_train , epochs = 300 , batch_size = 2 , patience = 30 ,
lr_scheduler = StepLR (model .optimizer , step_size = 50 , gamma = 0.5 ),
grad_clip = 1.0 )
pred = model .predict (x_train )
score = model .score (x_train , y_train ) # 分类=准确率 / 回归=R²(多输出时对各输出维度取平均)
# 保存 & 加载
model .save ("model.json" )
model2 = Model .load ("model.json" )
方法 / 函数
说明
MLP.param_count()
可训练参数总数
MLP.sparsity()
权重中为 0 的比例
MLP.prune_magnitude(threshold)
幅度剪枝:|w| < 阈值置 0,返回剪掉个数
MLP.quantize_weights(bits)
全局 min/max 均匀分档定点量化,返回步长
MLP.merge_weights(other, w1, w2)
权重线性合并(K 折权重平均用,各折需同初值 )
distill(teacher, student, x, y)
蒸馏:用教师输出当软目标训练学生,返回一致率
it() 新增 early_stop_metric='val'|'train':默认盯验证损失;
选 'train' 时盯训练损失,且不依赖验证集 (原来没有验证集时 patience 完全不生效)。
函数
说明
make_classifier(input_dim, num_classes, ...)
创建分类模型(Softmax + CrossEntropy)
make_regressor(input_dim, output_dim, ...)
创建回归模型(Linear + MSE)
quick_train(x, y, task, ...)
一行代码自动创建并训练
参数
说明
epochs
训练轮数
batch_size
批次大小(-1 = 全批量)
val_split / val_data
验证集比例或自定义验证集(见下方说明)
patience
Early Stopping 耐心值(0 = 关闭)
lr_scheduler
StepLR / ExponentialLR / CosineAnnealingLR
grad_clip
梯度范数裁剪阈值
val_data 支持三种写法(会校验维度,维度不符直接报错):
model = make_regressor (2 , 1 , hidden_layers = (8 ,))
x_train = [[0.1 , 0.2 ], [0.3 , 0.4 ], [0.5 , 0.6 ], [0.7 , 0.8 ]]
y_train = [[0.3 ], [0.7 ], [1.1 ], [1.5 ]]
x_val , y_val = [[0.15 , 0.25 ], [0.35 , 0.45 ]], [[0.4 ], [0.8 ]]
model .fit (x_train , y_train , val_data = {'x' : x_val , 'y' : y_val }) # 显式并行数组(推荐,无歧义)
model .fit (x_train , y_train , val_data = (x_val , y_val )) # 并行数组
model .fit (x_train , y_train , val_data = [([0.15 , 0.25 ], [0.4 ]), ([0.35 , 0.45 ], [0.8 ])]) # 样本对列表
说明:恰好 2 个元素且结构上无法区分时,list 按「样本对」解释、tuple 按「并行数组」解释;拿不准就用 dict 写法。
组件
说明
Layer
全连接层 + 激活函数(He 初始化)
MLP
多层感知机容器
Conv2d
二维卷积层
MaxPool2d
二维最大池化
Flatten
展平(CNN → MLP)
Dropout
Dropout 正则化
BatchNorm1d
批归一化(训练用 forward_batch(batch),推理用 forward(x))
LayerNorm
层归一化
Embedding
嵌入层
ResidualBlock
残差块
Sequential
层序列容器
组件
说明
RNNCell / RNN
基础 RNN(含 BPTT)
LSTMCell / LSTM
长短期记忆网络
GRUCell / GRU
门控循环单元
组件
说明
MultiHeadAttention
多头注意力机制
FeedForward
前馈网络
TransformerEncoderLayer
单层 Encoder
TransformerEncoder
多层 Encoder 堆叠
PositionalEncoding
位置编码
优化器
说明
Adam
Adam(默认)
SGD
随机梯度下降
SGDMomentum
带动量的 SGD
RMSprop
RMSprop
函数
说明
mse_loss(pred, target)
均方误差(长度不一致会报错,不再静默截断)
cross_entropy_loss(pred, target_idx)
交叉熵
搭配约束:softmax 输出层的反向使用的是 softmax + cross_entropy 的联合梯度 ,
因此只能与 cross_entropy 搭配。Model(loss_fn='mse') + softmax 输出层会直接报错 ,
而不是静默用错误梯度训练;需要 MSE 时请把输出层激活设为 linear。
Model 的 CE 路径会自动规范化 target:类别索引、[0.0, 1.0] 这类浮点标签、
one-hot / 概率分布、长度为 1 的列表都可以直接传。
函数
说明
split_data(data, val_ratio, test_ratio)
数据集拆分
DataLoader
批量迭代器
train(model, loss_fn, optimizer, data, ...)
底层训练循环(Early Stopping + 验证集)
evaluate(model, loss_fn, data)
计算平均损失
save_model(model, path) / load_model(path)
MLP 的 JSON 持久化
save_conv_model(conv, fc, path) / load_conv_model(path)
CNN + MLP 的 JSON 持久化
clip_grad_by_norm(grads, max_norm)
梯度范数裁剪
clip_grad_by_value(grads, clip_val)
梯度值裁剪
compare_with_pytorch()
与 PyTorch 逐层数值对齐(可选,装了 torch 才跑)
调度器
说明
StepLR(optimizer, step_size, gamma)
阶梯衰减
ExponentialLR(optimizer, gamma)
指数衰减
CosineAnnealingLR(optimizer, T_max)
余弦退火
组件
说明
TextProcessor
字符级词表、one-hot 编码、滑动窗口
generate_text(network, tp, start, length)
自回归文本生成(generate_text_with_mlp 的别名,保留以兼容旧调用)
generate_text_with_mlp(model, tp, start, length, window_size, temp)
自回归文本生成(滑动窗口上下文,只需 forward)
_softmax_with_temp(logits, temperature)
带温度的 Softmax
sample_index(probs)
随机采样
conv = Conv2d (in_channels = 1 , out_channels = 2 , kernel_size = 2 , stride = 1 )
pool = MaxPool2d (kernel_size = 2 )
flatten = Flatten ()
fc = MLP ([2 , 4 , 2 ], activations = ["leaky_relu" , "softmax" ])
# 前向: img (1, 4, 4) → conv → pool → flatten → fc
x = conv .forward (img )
x = pool .forward (x )
x = flatten .forward (x )
probs = fc .forward (x )
d_model = 4
pos_enc = PositionalEncoding (d_model = d_model )
encoder = TransformerEncoder (d_model = d_model , num_heads = 2 , d_ff = 8 , num_layers = 1 )
x = pos_enc .forward (seq ) # 加位置编码
x = encoder .forward (x ) # 经过 Transformer
pooled = [sum (t [j ] for t in x ) / len (x ) for j in range (d_model )] # 全局平均池化
head = MLP ([d_model , 8 , 2 ], activations = ["leaky_relu" , "linear" ]) # 分类头
logits = head .forward (pooled )
rnn = RNN (input_size = 1 , hidden_size = 4 , num_layers = 1 )
lstm = LSTM (input_size = 1 , hidden_size = 4 , num_layers = 1 )
gru = GRU (input_size = 1 , hidden_size = 4 , num_layers = 1 )
outputs , _ = rnn .forward (seq ) # outputs: 每个时间步的隐藏状态
last_h = outputs [- 1 ] # 取最后一步做预测
BPTT 写法 :forward 会把每一步、每一层的 cell 缓存存进 step_cache,
反向时用 restore_cache 直接恢复即可,不需要再 forward 一次来"重建"缓存:
rnn = RNN (input_size = 1 , hidden_size = 4 , num_layers = 1 ) # 承接上例
seq = [[0.1 ], [0.2 ], [0.3 ], [0.4 ]]
outputs , _ = rnn .forward (seq )
rnn .cells [0 ].zero_grad () # 整个 BPTT 只清一次
dh = [0.1 ] * rnn .hidden_size
for t in reversed (range (len (seq ))):
rnn .cells [0 ].restore_cache (rnn .step_cache [t ][0 ]) # 复用前向缓存
_ , dh = rnn .cells [0 ].backward (dh )
grad_W_ih , grad_W_hh , grad_b_ih , grad_b_hh = rnn .cells [0 ].get_grads ()
两个容易踩的点:
backward() 会把梯度原地累加 到 cell 自己的缓冲区,所以整个 BPTT 只需 zero_grad() 一次;
get_grads() 返回的就是这些缓冲区本身 (不是副本),因此不要 再对它做手工求和/累加——
那等于把缓冲区加到它自己身上,梯度会按 2 的幂被放大(T=10 时实测放大 264 倍)。
tp = TextProcessor (text )
dataset = tp .prepare_data (text , window_size = 3 )
# 训练字符级语言模型...
model = MLP ([tp .vocab_size * window_size , 64 , tp .vocab_size ],
activations = ["leaky_relu" , "softmax" ])
# 自回归生成
generated = generate_text (model , tp , "君不见" , length = 15 , temp = 0.8 )
依次运行 12 段演示:回归(Model.fit)→ 分类(make_classifier + Softmax/CE)→ CNN(卷积→池化→展平→MLP)→ RNN & LSTM 序列预测 → 模型保存/加载 → GRU 序列预测 → Dropout + LayerNorm → 梯度裁剪 + StepLR → quick_train 一行训练 → Transformer 序列分类 → 字符级文本生成 → PyTorch 数值对齐。
python test_ai.py # 等价于 pytest test_ai.py
189 个测试覆盖所有组件,其中这几类是数值校验 而不是只查形状:
测试类
校验内容
TestLayerNumericalGradients
Layer / MLP 的 grad_w / grad_b、反向传播链(dL/dx)vs 数值梯度;含 softmax+CE 联合梯度约定
TestTransformerEncoderGradients
TransformerEncoderLayer / TransformerEncoder 的 d_x 与 LayerNorm 参数梯度 vs 数值梯度(seq_len>1 必须测 ,见下方实现说明)
TestAttentionGradients
MultiHeadAttention 的 W_q/W_k/W_v/W_o 解析梯度 vs 数值梯度
TestConv2dGradients
Conv2d 的 grad_w / grad_b / dx vs 数值梯度(含 padding 与 stride=2)
TestBatchNormTraining
BatchNorm1d 训练路径的 dx / gamma / beta vs 数值梯度,并与朴素实现逐位一致
TestStepCache / TestCellGradSemantics
restore_cache 与「重新前向」逐位一致;一次 zero_grad + 逐步 backward == 各步梯度之和
TestValDataFormats / TestCrossEntropyTargets
val_data 三种写法、CE 的 target 规范化
CI(GitHub Actions)执行 flake8 + pytest。
.
├── AI.py # 神经网络工具箱(Python 实现,所有代码)
├── test_ai.py # 177 个单元测试
└── README.md