实现与训练import torch import torch.nn.functional as F from ch08_mlp.utils import Linear from ch08_mlp.utils import Sigmoid import numpy as np import pandas as pd import os import matplotlib.pyplot as plt import numpy as np from sklearn.datasets import make_blobs, make_circles, make_moons from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.linear_model import LogisticRegression def train_logit(data): 训练逻辑回顾模型 x, y data model LogisticRegression() model.fit(x, y) return model def generate_data(n): 产生数据 np.random.seed(12046) blobs make_blobs(n_samplesn, centers[[-2, -2], [2, 2]]) circles make_circles(n_samplesn, factor.4, noise.05) moons make_moons(n_samplesn, noise.05) blocks np.random.rand(n, 2) - 0.5 y (blocks[:, 0] * blocks[:, 1] 0) 0 blocks (blocks, y) # 由于神经网络对数据的线性变换不稳定因此对数据做归一化处理 scaler StandardScaler() blobs (scaler.fit_transform(blobs[0]), blobs[1]) circles (scaler.fit_transform(circles[0]), circles[1]) moons (scaler.fit_transform(moons[0]), moons[1]) blocks (scaler.fit_transform(blocks[0]), blocks[1]) return blobs, circles, moons, blocks def draw_data(ax, data): 将数据可视化 x, y data label1 x[y 0] ax.scatter(label1[:, 0], label1[:, 1], markero) label0 x[y 0] ax.scatter(label0[:, 0], label0[:, 1], marker^, colork) return ax def draw_model(ax, model): 将模型的分离超平面可视化 x1 np.linspace(ax.get_xlim()[0], ax.get_xlim()[1], 100) x2 np.linspace(ax.get_ylim()[0], ax.get_ylim()[1], 100) x1, x2 np.meshgrid(x1, x2) y model.predict_proba(np.c_[x1.ravel(), x2.ravel()])[:, 1] y y.reshape(x1.shape) ax.contourf(x1, x2, y, levels[0, 0.5], colors[gray], alpha0.4) return ax def visualize(data): 将结果可视化 # 创建一个图形框 fig plt.figure(figsize(10, 10), dpi80) fig1 plt.figure(figsize(10, 10), dpi80) # 在图形框里画四幅图 for i in range(len(data)): ax fig.add_subplot(2, 2, i1) ax1 fig1.add_subplot(2, 2, i1) draw_data(ax, data[i]) draw_data(ax1, data[i]) draw_model(ax1, train_logit(data[i])) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax1.get_xaxis().set_visible(False) ax1.get_yaxis().set_visible(False) plt.show() class Sequential: def __init__(self,layers): self.layerslayers def __call__(self, x): for l in self.layers: xl(x) self.out x return self.out def parameters(self): return [p for layer in self.layers for p in layer.parameters()] def predict_proba(self, x): 为了数据可视化计算模型输出的概率 if isinstance(x, np.ndarray): x torch.tensor(x).float() logits self(x) self.proba F.softmax(logits, dim1).detach().numpy() return self.proba fig plt.figure(figsize(10, 10), dpi80) for j in range(4): data generate_data(400) x, y torch.tensor(data[j][0]).float(), torch.tensor(data[j][1]) mlp Sequential([ Linear(2, 4), Sigmoid(), Linear(4, 4), Sigmoid(), Linear(4, 2) ]) lr 0.1 maxStep 20000 optimization torch.optim.SGD(mlp.parameters(), lrlr) loss [] batch_size 120 for i in range(maxStep): xi(i*batch_size)%len(x) xxx[xi:xibatch_size] yyy[xi:xibatch_size] rexmlp(xx) lossxF.cross_entropy(rex,yy.long()) optimization.zero_grad() lossx.backward() optimization.step() if i%200: print(lossx) loss.append(lossx) ax fig.add_subplot(2, 2, j 1) draw_data(ax, data[j]) draw_model(ax, mlp) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) # 将多层感知器的结果可视化 plt.savefig(mlp_result.png, dpi200) plt.show()解释说明数据准备数据生成与可视化# 将数据可视化 import matplotlib.pyplot as plt %matplotlib inline data generate_data(200) fig plt.figure(figsize(10, 10), dpi80) for i in range(len(data)): ax fig.add_subplot(2, 2, i1) draw_data(ax, data[i]) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) plt.show()函数将正负类数据分别用圆形和三角形标记绘制在2×2的子图中。代码结构遵循数据生成 → 标准化处理 → 可视化绘制的流程其原理是利用不同分布blobs、circles、moons、blocks作为模型训练的测试基准直观展示各类数据的空间分布特征为后续评估分类器性能提供视觉参考。模型定义class Sequential: def __init__(self,layers): self.layerslayers def __call__(self, x): for l in self.layers: xl(x) self.out x return self.out def parameters(self): return [p for layer in self.layers for p in layer.parameters()] def predict_proba(self, x): 为了数据可视化计算模型输出的概率 if isinstance(x, np.ndarray): x torch.tensor(x).float() logits self(x) self.proba F.softmax(logits, dim1).detach().numpy() return self.probaSequential 类采用模块化设计组织神经网络层__init__ 方法存储层列表__call__ 方法实现前向传播的链式调用parameters 方法递归收集所有层的可训练参数。额外的 predict_proba 方法将NumPy数组转换为张量后通过Softmax函数输出类别概率为后续可视化决策边界提供接口。这种设计借鉴了主流深度学习框架的容器思想将网络层视为可组合的组件统一管理前向计算和参数访问。模型训练for j in range(4): data generate_data(400) x, y torch.tensor(data[j][0]).float(), torch.tensor(data[j][1]) mlp Sequential([ Linear(2, 4), Sigmoid(), Linear(4, 4), Sigmoid(), Linear(4, 2) ]) lr 0.1 maxStep 20000 optimization torch.optim.SGD(mlp.parameters(), lrlr) loss [] batch_size 120 for i in range(maxStep): xi(i*batch_size)%len(x) xxx[xi:xibatch_size] yyy[xi:xibatch_size] rexmlp(xx) lossxF.cross_entropy(rex,yy.long()) optimization.zero_grad() lossx.backward() optimization.step() if i%200: print(lossx) loss.append(lossx) ax fig.add_subplot(2, 2, j 1) draw_data(ax, data[j]) draw_model(ax, mlp) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False)训练代码采用三层嵌套结构外层循环遍历四种不同的数据集中层构建2-4-4-2结构的MLP使用Sigmoid激活函数内层执行小批量随机梯度下降。每次迭代从400个样本中随机抽取120个作为批次计算交叉熵损失并执行反向传播更新参数。训练过程中每20步打印一次损失值以监控收敛情况最终调用 draw_model 函数将学习到的决策边界叠加到对应的数据子图上直观展示MLP对不同数据分布的拟合效果和潜在分类瓶颈。模型瓶颈当前 MLP 模型在四种数据集上表现出不同的拟合瓶颈对于线性可分的 blobs 数据2-4-4-2 结构配合 Sigmoid 激活函数能够较好收敛但对于非线性分布的 circles 和 moons 数据Sigmoid 函数在深层网络中容易引发梯度消失导致训练后期更新缓慢。blocks 数据因决策边界呈十字交叉状需要更复杂的非线性表达能力而当前网络深度和宽度均显不足。改进方向可考虑1) 将 Sigmoid 替换为 ReLU 及其变体以缓解梯度消失2) 增加网络层数或每层神经元数量以提升模型容量3) 引入残差连接或批量归一化来稳定训练过程4) 针对不同数据集调整学习率策略如余弦退火或使用自适应优化器如 Adam