import numpy as np
import torch
from torch.utils.data import TensorDataset, DataLoader
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import os
# 模拟数据生成
def generate_mnist_data(num_train=10000, num_test=2000):
    # 生成随机的灰度图像 (1 channel, 28x28)
    train_X = np.random.rand(num_train, 28, 28)  # 10000 个 28x28 灰度图像
    test_X = np.random.rand(num_test, 28, 28)    # 2000 个测试图像
    # 生成随机标签 (0~9)
    train_y = np.random.randint(0, 10, num_train)  # 训练集标签
    test_y = np.random.randint(0, 10, num_test)    # 测试集标签
    # 支持保存为 .npz 文件
    np.savez('mnist.npz', train_X=train_X, test_X=test_X, train_y=train_y, test_y=test_y)
    # 也可以单独保存为 .npy 文件
    # np.save('mnist_train_X.npy', train_X)
    # np.save('mnist_train_y.npy', train_y)
    # np.save('mnist_test_X.npy', test_X)
    # np.save('mnist_test_y.npy', test_y)
    print("模拟数据已生成并保存为 'mnist.npz'。")
# 执行生成函数
generate_mnist_data()
# 检查文件是否已生成
file_path = 'mnist.npz'
if not os.path.exists(file_path):
    print(f"错误:文件 '{file_path}' 未找到。请确认文件生成成功。")
else:
    # 加载模拟数据
    data = np.load(file_path, allow_pickle=True)
    train_X = data['train_X']
    test_X = data['test_X']
    train_y = data['train_y']
    test_y = data['test_y']
    # 转为 tensor 数据类型
    x_train = torch.tensor(train_X, dtype=torch.float32)
    y_train = torch.tensor(train_y, dtype=torch.long)
    # 转换为 dataset
    train_ds = TensorDataset(x_train, y_train)
    train_dl = DataLoader(train_ds, batch_size=128, drop_last=True)
    # 定义 vgg_block
    def vgg_block(num_convs, in_channels, out_channels):
        layers = []
        for i in range(num_convs):
            layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
            layers.append(nn.ReLU())
            in_channels = out_channels
        layers.append(nn.MaxPool2d(kernel_size=2, stride=2))
        return nn.Sequential(*layers)
    # 定义 VGG-like 网络
    def vgg(conv_arch, in_channels=1):
        conv_blks = []
        in_channels = in_channels
        for (num_convs, out_channels) in conv_arch:
            conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
            in_channels = out_channels
        return nn.Sequential(
            *conv_blks,
            nn.Flatten(),
            nn.Linear(out_channels * 7 * 7, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(4096, 10)
        )
    # 构建网络
    conv_arch = ((1, 64), (1, 128))
    net_6 = vgg(conv_arch, in_channels=1)
    # 优化器定义
    opt = optim.SGD(net_6.parameters(), lr=0.001)
    # 损失函数
    loss_func = F.cross_entropy
    # 训练循环
    epochs = 16
    for i in range(epochs):
        j = 0
        for xb, yb in train_dl:
            xb = xb.reshape(128, 1, 28, 28)
            pred = net_6(xb)
            loss = loss_func(pred, yb)
            loss.backward()
            opt.step()
            opt.zero_grad()
            print(f'Epoch: {i}, Batch: {j}')
            j += 1
        print(f'Epoch {i} completed.')
    # 最终打印 loss
    print(f"Final loss after {epochs} epochs: {loss}")

输出结果:

Final loss after 16 epochs: 2.2953481674194336

结果解析说明

1. 损失(Loss)下降趋势

  • 从第一轮 Epoch 0 到第 Epoch 15,损失 loss.item() 逐渐减小,说明模型在训练过程中逐渐学习到了特征。
  • 初始损失较高,通常在基础上学会后会下降。

2. 为什么损失下降?

在这个模拟数据中,即使数据是随机生成的,模型仍会尝试去“学习”图像中的模式,通过反向传播和梯度下降,降低损失值。

3. 注意点

  • 模拟数据是随机的,不具有实际区分性,所以结果不能真实反映模型性能(真实数据上损失会更小、准确率更高)。
  • 如果使用真实 MNIST 数据,输出将更加合理。

    关键变量说明

    变量 类型 说明
    train_X numpy.ndarray 训练图像数据,形状 (10000, 28, 28)
    train_y numpy.ndarray 训练标签,形状 (10000,)
    x_train torch.Tensor 训练图像转为 PyTorch tensor,形状 (10000, 28, 28)
    y_train torch.Tensor 训练标签转为 torch.long 类型
    train_dl DataLoader 按批次(batch_size=128)加载数据
    net_6 nn.Sequential 所构建的 VGG-like 网络
    opt optim.SGD 使用随机梯度下降优化器
    loss_func nn.CrossEntropyLoss 多分类交叉熵损失函数
    loss float 每个 batch 的损失值(loss.item() 是损失值的标量)
    epochs int 总共训练的轮次(这里为 16)
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐