游乐游手机版
首页/AI教程/文章详情

计算神经网络训练中的数据读取与完成教程

时间:2026-06-10 14:59
采用MNIST手写数字集,二进制读取后拆分训练集、验证集(各50000和10000样本)及测试集。初始化网络参数,利用平方差损失和梯度下降法按批次训练,最终完成神经网络的一次训练并用验证集评估损失。

先聊聊我们这次用的数据集——大名鼎鼎的 MNIST 手写数字集。根据官方介绍,这个数据集一共有 70000 个样本,其中 60000 个用于训练,10000 个用于测试。下载下来之后,文件被分成了四个部分:训练集图片、训练集标签、测试集图片、测试集标签。所有数据都以二进制格式存储。

1

具体来说,训练集图片文件的前 16 个字节存放了图片数量、行数、列数等信息;训练集标签文件的前 8 个字节存放了标签数量等。测试集的两个文件结构完全一致。

2_jpeg

文摘菌下载好的文件存储地址

读取数据

train_img_path=r'C:UsersDellMNISTtrain-images.idx3-ubyte'
train_lab_path=r'C:UsersDellMNISTtrain-labels.idx1-ubyte'
test_img_path=r'C:UsersDellMNISTt10k-images.idx3-ubyte'
test_lab_path=r'C:UsersDellMNISTt10k-labels.idx1-ubyte'

根据文件在本地解压后的存储地址,生成四个路径。上面代码中的 r 是转义字符——因为反斜杠在 Python 中有特殊含义,所以需要用 raw string 来明确文件地址。

为了让模型表现更好,我们把训练集进一步拆分:50000 个样本用于训练,10000 个样本作为验证集。

注:验证集是模型训练过程中单独留出来的样本集,用于调整超参数,以及对模型能力进行初步评估。

import struct
train_num=50000
valid_num=10000
test_num=10000
with open(train_img_path,'rb') as f:
    struct.unpack('>4i',f.read(16))
    tmp_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28)
train_img=tmp_img[:train_num]
valid_img=tmp_img[train_num:]
with open(test_img_path,'rb') as f:
    struct.unpack('>4i',f.read(16))
    test_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28)
with open(train_lab_path,'rb') as f:
    struct.unpack('>2i',f.read(8))
    tmp_lab=np.fromfile(f,dtype=np.uint8)
train_lab=tmp_lab[:train_num]
valid_lab=tmp_lab[train_num:]
with open(test_lab_path,'rb') as f:
    struct.unpack('>2i',f.read(8))
    test_lab=np.fromfile(f,dtype=np.uint8)

文件是以二进制格式存储的,所以读取方式要用 rb。为了让数据以数值方式显示,这里用到了 Python 的 struct 包。struct.unpack('>4i', f.read(16)) 中的 > 代表字节存储方向,i 表示整数,4 表示需要前 4 个整数。f.read(16) 读取 16 个字节(一个整数 4 个字节,共 4 个整数)。reshape(-1, 28*28) 中,-1 表示该维度由其他参数决定,这里是将一维数组转换为二维矩阵,第二个参数指定每行的元素个数。

注:np.fromfile 的用法:np.fromfile(frame, dtype=np.float, count=-1, sep=''),其中 frame 是文件或字符串,dtype 是读取的数据类型,count 是读入元素个数(-1 表示读入整个文件),sep 是数据分割字符串。

文件读取完,接下来把数据显示成图片的样子:

import matplotlib.pyplot as plt
def show_train(index):
    plt.imshow(train_img[index].reshape(28,28),cmap='gray')
    print('label:{}'.format(train_lab[index]))
def show_test(index):
    plt.imshow(train_img[index].reshape(28,28),cmap='gray')
    print('label:{}'.format(test_lab[index]))
def valid_train(index):
    plt.imshow(valid_img[index].reshape(28,28),cmap='gray')
    print('label:{}'.format(valid_lab[index]))

注意,如果不定义 cmap='gray',图片的底色会非常奇怪。

3

测试一下,定义完函数之后显示的效果就是这样~

数据显示和读取完成后,接下来开始训练参数。

训练数据

在开始之前,先把第一次课程的代码贴上来,方便上下衔接:

def tanh(x):
    return np.tanh(x)
def softmax(x):
    exp = np.exp(x-x.max())
    return exp/exp.sum()
dimensions = [28*28,10]
activation = [tanh,softmax]
distribution=[{'b':[0,0]},{'b':[0,0],'w':[-math.sqrt(6/(dimensions[0] + dimensions[1])),math.sqrt(6/(dimensions[0] + dimensions[1]))]}]

初始化参数b

def init_parameters_b(layer):
    dist = distribution[layer]['b']
    return np.random.rand(dimensions[layer])*(dist[1]-dist[0])+dist[0]

初始化参数w

def init_parameters_w(layer):
    dist = distribution[layer]['w']
    return np.random.rand(dimensions[layer-1],dimensions[layer])*(dist[1]-dist[0])+dist[0]

初始化参数方法

def init_parameters():
    parameter=[]
    for i in range(len(distribution)):
        layer_parameter={}
        for j in distribution[i].keys():
            if j=='b':
                layer_parameter['b'] = init_parameters_b(i)
                continue
            if j=='w':
                layer_parameter['w'] = init_parameters_w(i)
                continue
        parameter.append(layer_parameter)
    return parameter

预测函数

def predict(img,init_parameters):
    l0_in = img + parameters[0]['b']
    l0_out = activation[0](l0_in)
    l1_in = np.dot(l0_out,parameters[1]['w'])+ parameters[1]['b']
    l1_out = activation[1](l1_in)
    return l1_out

先定义两个激活函数的导数,导数的具体推导过程这里不展开,感兴趣的同学可以自行搜索。

def d_softmax(data):
    sm = softmax(data)
    return np.diag(sm)-np.outer(sm,sm)
def d_tanh(data):
    return 1/(np.cosh(data))**2
differential = {softmax:d_softmax,tanh:d_tanh}

其中 tanh 的导数本来是 np.diag(1/(np.cosh(data))**2),优化后直接写成 1/(np.cosh(data))**2diag 生成对角矩阵,outer 函数的作用是第一个参数挨个乘以第二个参数得到矩阵)。

再定义一个字典,并将数据解析为某一位置为1的一维矩阵:

differential = {softmax:d_softmax,tanh:d_tanh}
onehot = np.identity(dimensions[-1])

求平方差函数,其中 parameters 是第一次课程定义的那个初始化参数,在训练过程中会自动更新。

def sqr_loss(img,lab,parameters):
    y_pred = predict(img,parameters)
    y = onehot[lab]
    diff = y-y_pred
    return np.dot(diff,diff)

计算梯度:

def grad_parameters(img,lab,init_parameters):
    l0_in = img + parameters[0]['b']
    l0_out = activation[0](l0_in)
    l1_in = np.dot(l0_out,parameters[1]['w'])+ parameters[1]['b']
    l1_out = activation[1](l1_in)
    diff = onehot[lab]-l1_out
    act1 = np.dot(differential[activation[1]](l1_in),diff)
    grad_b1 = -2*act1
    grad_w1 = -2*np.outer(l0_out,act1)
    # 与上文优化d_tanh有关,将矩阵乘法化为数组乘以矩阵
    grad_b0 = -2*differential[activation[0]](l0_in)*np.dot(parameters[1]['w'],act1)
    return {'b1':grad_b1,'w1':grad_w1,'b0':grad_b0}

这次的梯度计算公式用到了 (y_predict - y)^2,根据复合函数求导,所以有 -2(y_predict - y) 乘以相关的导数——这也是 grad_b1 后面 -2 的来历。

按理说应该用导数的定义 [f(x+h) - f(x)] / h 验证下梯度求的对不对,为了照顾新手同学对神经网络的理解过程,这一步就省略了哈。

下面进入训练环节。我们将数据以 batch 的方式输入,每个 batch 包含 100 张图片(batch_size=100)。梯度的获取是用平均求得的,代码体现在 grad_accu[key] /= batch_size

def train_batch(current_batch,parameters):
    grad_accu = grad_parameters(train_img[current_batch*batch_size+0],train_lab[current_batch*batch_size+0],parameters)
    for img_i in range(1,batch_size):
        grad_tmp = grad_parameters(train_img[current_batch*batch_size+img_i],train_lab[current_batch*batch_size+img_i],parameters)
        for key in grad_accu.keys():
            grad_accu[key] += grad_tmp[key]
    for key in grad_accu.keys():
        grad_accu[key]/=batch_size
    return grad_accu

import copy
def combine_parameters(parameters,grad,learn_rate):
    parameter_tmp = copy.deepcopy(parameters)
    parameter_tmp[0]['b'] -= learn_rate*grad['b0']
    parameter_tmp[1]['b'] -= learn_rate*grad['b1']
    parameter_tmp[1]['w'] -= learn_rate*grad['w1']
    return parameter_tmp

采用 copy 机制,是为了避免 parameters 变化影响全局训练。copy.deepcopy 可以重新拷贝,不影响原来的数据。这里用到的公式是:

4

然后定义学习率:

def learn_self(learn_rate):
    for i in range(train_num//batch_size):
        if i%100 == 99:
            print("running batch {}/{}".format(i+1,train_num//batch_size))
        grad_tmp = train_batch(i,parameters)
        global parameters
        parameters = combine_parameters(parameters,grad_tmp,learn_rate)

里面的 if 语句可以让我们看到神经网络训练的进度。

5

到这里,我们就完成了神经网络的一次训练。为了验证准确度,可以用验证集看看效果如何。

定义验证集的损失:

def valid_loss(parameters):
    loss_accu = 0
    for img_i in range(valid_num):
        loss_accu += sqr_loss(valid_img[img_i],valid_lab[img_i],parameters)
    return loss_accu

计算准确度:

def valid_accuracy(parameters):
    correct = [predict(valid_img[img_i],parameters).argmax()==valid_lab[img_i] for img_i in range(valid_num) ]
    print("validation accuracy:{}".format(correct.count(True)/len(correct)))

最后得到结果:

6

有 90% 的准确度,结果还好吧,毕竟没有怎么调学习率,也没有解决过拟合的问题。

好了,这一期的内容就到这儿了。内容有点多,大家多多消化。下一期我们聊聊怎么调节学习率,以及看看更复杂的神经网络。

来源:https://developer.aliyun.com/article/704625
上一篇阿里云轻量服务器宝塔面板搭建网站新手指南 下一篇剪映小助手添加字幕接口操作步骤详解
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Windows Docker Desktop RabbitMQ生产级部署完整指南
AI教程 · 2026-06-29

Windows Docker Desktop RabbitMQ生产级部署完整指南

前言 在 Windows 本地开发环境中,直接安装 RabbitMQ 确实颇为周折:需要单独配置 Erlang 运行环境、手动管理环境变量、服务启停全凭手工操作。更令人困扰的是,版本兼容冲突、端口占用、环境不一致等问题层出不穷。笔者见过不少开发者为搭建环境就得耗费整整半天时间。 相比之下,借助 Do

AI搜索重构制造业采购逻辑的阿里云企业级GEOCMS优化实践
AI教程 · 2026-06-29

AI搜索重构制造业采购逻辑的阿里云企业级GEOCMS优化实践

先分享一个切实感受。过去两年,我们与福建制造企业合作较为频繁,发现一个非常突出的现象:超过80%的企业官网,产品参数仍然存放在PDF或图片中。AI爬虫?根本无法抓取。这些企业技术实力不弱、资质证照齐全、应用案例也丰富,但在AI搜索这一全新战场上,它们几乎处于隐身状态。 一、一个正在发生的行业变化 A

阿里云Token Plan团队版功能价格与省钱购买指南
AI教程 · 2026-06-29

阿里云Token Plan团队版功能价格与省钱购买指南

阿里云百炼近期推出了名为“Token Plan 团队版”的全新服务,这一服务专为企业与开发者量身打造,定位为AI大模型订阅平台。通过引入Credits作为统一计量单位,将文本生成、图像生成等多模态AI能力纳入单一计费体系,同时无缝兼容主流AI编程工具及智能体(Agent)生态系统。其核心亮点包括:全

阿里云物联网.NET Core客户端位置信息上报
AI教程 · 2026-06-29

阿里云物联网.NET Core客户端位置信息上报

阿里云物联网平台的位置服务并非一个完全独立的功能模块。位置信息可包含二维坐标与三维坐标,而位置数据的来源本质上是借助设备属性进行上传。换言之,若要让设备上报位置,您需先将其视为一个普通属性进行处理。 1)添加二维位置数据 操作过程十分简洁。进入数据分析 → 空间数据可视化 → 二维数据,点击添加,将

年阿里云服务器选型配置与网站部署全攻略
AI教程 · 2026-06-29

年阿里云服务器选型配置与网站部署全攻略

2026年,阿里云服务器生态已高度成熟,形成了清晰的轻量应用服务器与ECS云服务器两大产品阵营。无论你是计划搭建个人博客、企业官网,还是运营电商平台、进行应用开发,基本都能找到理想的解决方案。本指南将从服务器选型、配置选择、部署流程到安全运维,系统梳理2026年最实用的操作要点,帮助你少走弯路,让网