当前位置: 首页 > news >正文

深度学习入门 1 一个简单的反向传播

深度学习入门 1 一个简单的反向传播

作者简介

梳影揽溪柔,来自浙江杭州,西北大学大一学生,非计算机专业。

博客简介

主要记录自学CL/NLP的日常。

 

前言

MNIST是深度学习入门时的一个经典的数据集,本文介绍一个基于MNIST的反向传播代码实例。

 

引库

import numpy as np

深度学习中的数据,很多情况下用numpy运算。

numpy的底层用C写成,运算速度比较快。

numpy的二维数组可以存放矩阵,适合描述神经网络。

from torchvision.datasets import MNIST

用Pytorch下载MNIST数据集比较方便。

 

下载和预处理

def load_mnist(normalize=True, one_hot_label=True):train_set = MNIST(root='./data', train=True, download=True)test_set = MNIST(root='./data', train=False, download=True)

MNIST有训练集(60000张)和数据集(10000张)两个子数据集,通过train控制下载。

root是数据集存放的文件夹,这里‘./data’是博主Pycharm里的相对路径。

x_train = train_set.data.numpy().astype(np.float32)
t_train = train_set.targets.numpy()
x_test = test_set.data.numpy().astype(np.float32)
t_test = test_set.targets.numpy()

这里用train_set.data获取Pytorch张量,.numpy()准备用numpy进行操作。

转换后张量的形状和数值都不变。训练集张量的形状是(60000,28,28),每行每列都是28个像素。

而数值是[0,255] 之间的整数,0纯黑色,255纯白色。

因为下一步要归一化,所以把整数强制类型转换为32位浮点数。

targets是一维张量(向量),存放每张首写字母的标签。

if normalize:x_train/=255x_test/=255x_train = x_train.reshape(-1, 784)x_test = x_test.reshape(-1, 784)

神经网络要避免数值溢出,所以要/255“归一化”到[0,1]之间。

为便于numpy神经网络处理,将三维张量转为二维张量(矩阵)。

这里reshape里第一个参数-1,可以根据总元素一致,自动计算这个值。

if one_hot_label:def to_one_hot(y, num_class=10):return np.eye(num_class)[y]t_train = to_one_hot(t_train)t_test = to_one_hot(t_test)

用one-hot编码作为分类标签,便于进行后续计算。

np.eye(x)会生成 x 阶的单位矩阵,再通过[y]取出对应的行,得到one-hot编码。

所以targets被批量转成了二维张量,训练集标签形状是(60000,10),测试集是(10000,10)。

return (x_train, t_train), (x_test, t_test)

 

神经网络 

class TwoLayerNet:def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):self.params = {}self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)self.params['b1'] = np.zeros(hidden_size)self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)self.params['b2'] = np.zeros(output_size)

构建一个两层的神经网络的类,层的神经元个数可设置。用字典prams存放参数。

其中 randn 是 random normal(随机正态分布),固定生成若干随机小数。

这些小数需要满足,均值为0,方差为1。它们大多数都在(-3,3)之间。

层间矩阵W的权重都乘0.01,使得初始权重较小,但不过小。

过大会导致进入sigmoid的值过大,区域导数变化很小,不利于反向传播更新梯度。

过小或者直接设置为0,会导致神经元同质化,学习速度会很慢且效果下降。

def sigmoid(self, x):return 1 / (1 + np.exp(-x))

用sigmoid函数,可以把Wa+b算出的矩阵里的元素压在(0,1)内。

def softmax(self, x):if x.ndim == 2:x = x - np.max(x, axis=1, keepdims=True)return np.exp(x) / np.sum(np.exp(x), axis=1, keepdims=True)

用softmax函数实现最终输出,softmax函数可以把一组数转换成总和为1的概率分布。

由于训练集的数据量多达60000,一张张处理太慢了,所以引入批处理的概念。

比如100张照片为一个batch,最终输入给softmax的就会是一个二维张量(100,10)。

为防止e的x次方溢出,可以令x减去行内最大的那个值,对softmax函数简单变形可知成立。

因为np.max是找每行最大,会返回一个一维的张量。所以用keepdims控制为(100,1)。

def cross_entropy_error(self, y, t):batch_size = y.shape[0]return -np.sum(t * np.log(y + 1e-7)) / batch_size

损失函数这里用交叉熵,对应的t和logy相乘求和。

注意这里不是点乘,t和y都是(100,10)的二维张量,直接对应元素相乘。

必须要加一个小的数避免log(0)。数学上不可能,但计算机上有限精度的浮点数有可能。

def predict(self, x):W1, W2 = self.params['W1'], self.params['W2']b1, b2 = self.params['b1'], self.params['b2']a1 = np.dot(x, W1) + b1z1 = self.sigmoid(a1)a2 = np.dot(z1, W2) + b2y = self.softmax(a2)return y

前向传播,这里不具体解释了。

def loss(self, x, t):y = self.predict(x)return self.cross_entropy_error(y, t)

定义损失函数。

def accuracy(self, x, t):y = self.predict(x)y = np.argmax(y, axis=1)t = np.argmax(t, axis=1)return np.sum(y == t) / float(x.shape[0])

精度函数。找y概率最大的索引,和标签所在位置的索引是否匹配。

这里np.argmax返回数组中最大数的索引。

def gradient(self, x, t):W1, W2 = self.params['W1'], self.params['W2']b1, b2 = self.params['b1'], self.params['b2']batch_num = x.shape[0]a1 = np.dot(x, W1) + b1z1 = self.sigmoid(a1)a2 = np.dot(z1, W2) + b2y = self.softmax(a2)dy = (y - t) / batch_numgrads = {}grads['W2'] = np.dot(z1.T, dy)grads['b2'] = np.sum(dy, axis=0)dz1 = np.dot(dy, W2.T)da1 = dz1 * z1 * (1 - z1)grads['W1'] = np.dot(x.T, da1)grads['b1'] = np.sum(da1, axis=0)return grads

反向传播。博主刚接触博客园,还没学会怎么在这里打LaTeX。

没有数学公式无法讲,下一篇文章大概是以这段代码为样例,详解反向传播的数学原理。

 

主程序

if __name__ == '__main__':(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)iters_num = 10000train_size = x_train.shape[0]batch_size = 100learning_rate = 0.1train_loss_list = []train_acc_list = []test_acc_list = []iter_per_epoch =600network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)for i in range(iters_num):batch_mask = np.random.choice(train_size, batch_size)x_batch = x_train[batch_mask]t_batch = t_train[batch_mask]grad = network.gradient(x_batch, t_batch)for key in ('W1', 'b1', 'W2', 'b2'):network.params[key] -= learning_rate * grad[key]loss = network.loss(x_batch, t_batch)train_loss_list.append(loss)if i % iter_per_epoch == 0:train_acc = network.accuracy(x_train, t_train)test_acc = network.accuracy(x_test, t_test)train_acc_list.append(train_acc)test_acc_list.append(test_acc)print(f"Epoch {int(i/iter_per_epoch)+1} | 训练精度:{train_acc:.4f} | 测试精度:{test_acc:.4f} | loss:{loss:.4f}")

下载数据,设置各种参数和用于存放得到数据的列表。

用训练集训练,随机选择batch个数据,反向传播更新梯度,记录损失函数变化,迭代10000次。

跑完一次整个数据集称为一个Epoch,每跑完一个Epoch用训练集和测试集的数据评估情况。

 

结果

Epoch 1 | 训练精度:0.0986 | 测试精度:0.0958 | loss:2.2925
Epoch 2 | 训练精度:0.7843 | 测试精度:0.7872 | loss:0.8092
Epoch 3 | 训练精度:0.8781 | 测试精度:0.8817 | loss:0.4142
Epoch 4 | 训练精度:0.8987 | 测试精度:0.9006 | loss:0.3482
Epoch 5 | 训练精度:0.9074 | 测试精度:0.9095 | loss:0.3546
Epoch 6 | 训练精度:0.9135 | 测试精度:0.9148 | loss:0.2072
Epoch 7 | 训练精度:0.9186 | 测试精度:0.9197 | loss:0.1746
Epoch 8 | 训练精度:0.9238 | 测试精度:0.9242 | loss:0.3122
Epoch 9 | 训练精度:0.9265 | 测试精度:0.9264 | loss:0.2824
Epoch 10 | 训练精度:0.9302 | 测试精度:0.9299 | loss:0.2427
Epoch 11 | 训练精度:0.9328 | 测试精度:0.9335 | loss:0.1280
Epoch 12 | 训练精度:0.9364 | 测试精度:0.9366 | loss:0.1714
Epoch 13 | 训练精度:0.9388 | 测试精度:0.9389 | loss:0.2182
Epoch 14 | 训练精度:0.9412 | 测试精度:0.9410 | loss:0.1086
Epoch 15 | 训练精度:0.9427 | 测试精度:0.9422 | loss:0.1967
Epoch 16 | 训练精度:0.9448 | 测试精度:0.9446 | loss:0.0969
Epoch 17 | 训练精度:0.9465 | 测试精度:0.9461 | loss:0.2837

随机跑的一次,可以看到损失函数并不是一直下降的。

这和我们设置的learning rate(学习率)是固定的有关。

http://www.jsqmd.com/news/804838/

相关文章:

  • 本地AI任务编排工具AgentForge:从看板管理到多代理协作
  • 从账单与用量看板分析团队大模型资源消耗模式
  • 数据分析实习面试准备全攻略:专业知识+项目深挖+行为面试,职卓科技的面试辅导体系
  • AI角色扮演引擎Anima:从LLM对话到图文生成的架构与实现
  • 中小企业技术团队的生存法则:用巧劲对抗资源不足
  • 厚街产后修复哪家值得推荐:秒杀产后修复服务优 - 13724980961
  • 微创式电子设备设计:从自动化到自主化的智能革命
  • HarnessGate:专为AI Agent设计的纯消息网关,实现多平台无缝桥接
  • IGF-I (30-41) (IGF-1 C-Peptide)
  • 开发 AI 应用时如何借助 Taotoken 实现模型路由与灾备
  • 别再乱打包了!手把手教你用Kali Linux和Metasploit生成免杀后门(附实战演示)
  • Hi3559AV100 MPP开发:从IMX334到HDMI输入,VI参数配置避坑指南(含/proc/umap解析)
  • Triton学习 Part 1 Hello, world!
  • 终极指南:10分钟快速上手Ghidra逆向工程工具安装与配置
  • 如何快速恢复加密压缩包密码:ArchivePasswordTestTool完整指南
  • Gemini 3.1 国内生产环境接入全指南:从 API 调用到高可用架构
  • ChatGPT对话转Markdown工具:自动化构建个人知识库
  • 政府招聘信息聚合搜索工具:从爬虫到搜索系统的技术实现
  • 频繁使用手机检测数据集分享(适用于YOLO系列深度学习分类检测任务)
  • keil 使用UTF8格式的文件,但是printf打印中文已经是乱码的问题
  • 现代差旅电力管理实战:从充电安全到设备续航全攻略
  • 通过Taotoken CLI工具一键配置多开发环境实践分享
  • Python量化交易实战:构建Nifty期权自动化交易系统
  • 相由心生:由填诗游戏引发的感悟
  • 从零到一:OWASP ZAP实战渗透测试全流程解析
  • 全自动Nifty期权交易系统:从架构设计到实盘部署的量化实战
  • 基于Next.js与TypeScript的2048游戏开发:状态管理与动画实现详解
  • 2026年南京25吨汽车吊租赁厂家推荐指南/起重吊装,吊机出租,吊车出租,汽车吊出租,50吨汽车吊出租 - 品牌策略师
  • 2025届学术党必备的五大降重复率方案横评
  • 孤心证道赋