手撕反向传播

 关于二分类的交叉熵损失部分数学推导过程。

有些地方加以注释,公式太多懒得MD格式了

#%%
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import datasets


iris_data =datasets.load_iris()
in_put_data = iris_data.data
correct = iris_data.target
print(correct)
n_data= len(in_put_data)
in_put_data#numpy array
#%%
avg_data=np.average(in_put_data,axis=0)#列平均
std_data=np.std(in_put_data,axis=0)
in_put_data=(in_put_data-avg_data)/std_data#归一化
print(in_put_data)
#%%
correct_data=np.zeros((n_data,3))
# print(correct_data)
for i in range(n_data):
    correct_data[i,correct[i]]=1#one-hot correct=0 就是第一列=1
print(correct_data)
#%%
index=np.arange(n_data)
index_train=index[index%2==0]
index_test=index[index%2!=0]

input_train=in_put_data[index_train,:]#:所有列
input_test=in_put_data[index_test,:]

correct_train=correct_data[index_train,:]#独热编码len行 3列
correct_test=correct_data[index_test,:]

n_train=len(index_train)
n_test=input_test.shape[0]
#%%
#神经网络参数
n_in=4
n_mid=10
n_out=3

wb_width=0.1#随机权重
eta=0.01#学习率
max_epoch=10

batch_size=10
interval=10#显示间隔

v_w=1
v_b=1


class BaseLayer:
    def __init__(self, n_upper, n):
        '''
        子类实例化传入MidLayer(n_in, n_mid)
        上一层的神经元个数和当前层的神经元个数,实例化指定了
        假设上层是2个这层是3,初始化矩阵为:
        xxx      b1
        xxx      b2
                 b3
        '''
        # 初始化权重和偏置
        self.w = wb_width * np.random.randn(n_upper, n)
        self.b = wb_width * np.random.randn(n)

    def update(self, eta):
        # 更新权重和偏置
        self.w = self.w - eta * self.grad_w
        self.b = self.b - eta * self.grad_b


class MidLayer(BaseLayer):
    '''
    forward_propagation(x):
    第一层 训练数据输入(10,4)
    mid_layer_1.forward(x)
    [10,4][4,10]=[10,10]

    第二层 输入第一层的(10,10)
    mid_layer_2.forward(mid_layer_1.y)#10,10
    [10,10][10,10]=[10,10]
    ---------------------------------------
    backward_propagation(t):
    倒数第二层 输入倒数第一的(10,10)


    '''
    def forward(self, x):
        self.x = x
        self.u = np.dot(x, self.w) + self.b
        self.y = np.where(self.u <= 0, 0.01 * self.u, self.u)  # Leaky ReLU

    def backward(self, grad_y):
        delta = grad_y * np.where(self.u <= 0, 0.01, 1.0)  # ReLU导数
        self.grad_w = np.dot(self.x.T, delta)  # 权重梯度
        self.grad_b = np.sum(delta, axis=0)  # 偏置梯度
        self.delta = np.dot(delta, self.w.T)  # 将梯度传播回前一层
        return self.delta


class OutLayer(BaseLayer):
    '''
    forward_propagation(x):
    第三层 输入第二层的(10,10)
    out_layer.forward(mid_layer_2.y)#10,3
    [10,10][10,3]=[10,3]
    ------------------------------------
    backward_propagation(t):
    #方向第一层 标签数据输入(10,3)
    out_layer.backward(t)#(10,10)
    grad_w[10,10][10,3]=[10,3]
    grad_b(3,)
    [10,3][3,10]=[10,10]
    '''
    def forward(self, x):
        self.x = x
        u = np.dot(x, self.w) + self.b
        self.y = np.exp(u) / np.sum(np.exp(u), axis=1, keepdims=True)  # Softmax

    def backward(self, t):
        delta = self.y - t  # 交叉熵损失函数 对每个类别yi的偏导数为 (y - t)
        self.grad_w = np.dot(self.x.T, delta)  #  Loss 对 w 的导数. 权重梯度 x.T 依然是【10,10】
        self.grad_b = np.sum(delta, axis=0)  # Loss 对 b 的导数.    偏置梯度 (列和)
        self.delta = np.dot(delta, self.w.T)  # 将梯度传播回前一层 w.T[3,10]
        return self.delta


mid_layer_1 = MidLayer(n_in, n_mid)#4,10
mid_layer_2 = MidLayer(n_mid, n_mid)#10,10
out_layer = OutLayer(n_mid, n_out)#10,3


def forward_propagation(x):
    #训练输入(10,4)
    mid_layer_1.forward(x)
    # print("mid_layer_1.forward(x)",mid_layer_1.y.shape)
    mid_layer_2.forward(mid_layer_1.y)#10,10
    # print("mid_layer_2.forward(mid_layer_1.y)",mid_layer_2.y.shape)
    out_layer.forward(mid_layer_2.y)#10,3
    # print("out_layer.forward(mid_layer_2.y)",out_layer.y.shape)
    return out_layer.y


def backward_propagation(t):
    #输入(10,3)
    out_layer.backward(t)#(10,10)
    # print("out_layer.backward(t)",out_layer.delta.shape)
    mid_layer_2.backward(out_layer.delta)
    mid_layer_1.backward(mid_layer_2.delta)


def update_wb():
    mid_layer_1.update(eta)
    mid_layer_2.update(eta)
    out_layer.update(eta)
#%%
#计算交叉熵损失
def get_error_rate(t,batch_size):
    return -np.sum(t*np.log(out_layer.y+1e-7))/batch_size

train_error_x=[]
train_error_y=[]
test_error_x=[]
test_error_y=[]

n_batch=n_train//batch_size#7
print(n_batch)

for i in range(10):
    print("epoch:", i)
    # #评估当前模型的性能 向前传播训练集和测试集合
    # forward_propagation(input_train)
    # error_train=get_error_rate(correct_train,n_train) # y,长度
    #
    # forward_propagation(input_test)
    # error_test=get_error_rate(correct_test,n_test)
    #
    # train_error_x.append(i) #[]
    # train_error_y.append(error_train)#[]
    #
    # test_error_x.append(i)
    # test_error_y.append(error_test)

    #开始训练
    # 随机打乱
    index_random=np.arange(n_train)
    np.random.shuffle(index_random)
    for j in range(n_batch):
        mb_index=index_random[j*batch_size:(j+1)*batch_size]#随机取batch_size个下标
        x=input_train[mb_index,:]
        t=correct_train[mb_index,:]
        # print(x.shape)#(10,4)
        # print("t:",t.shape)#(10,3)

        forward_propagation(x)
        backward_propagation(t)

        update_wb()
#%%
plt.plot(train_error_x,train_error_y,label='train')
plt.plot(test_error_x,test_error_y,label='test')
plt.legend()
# plt.show()

这是是全连接神经网络,输入2个神经元,1个中间层3个神经元,输出层2个神经元
 $$o _ { 1 } = \frac { e ^ { y _ { 1 } } } { e ^ { y _ { 1 } } + e ^ { y _ { 2 } } }$$
$$L o s s = - ( o _ { 1 } ^ { * } \log ( o _ { 1 } ) + o _ { 2 } ^ { * } \log ( o _ { 2 } ) )$$
$$\frac { \partial L o s s } { \partial w _ { 1 1 } ^ { ( 2 ) } } = \frac { \partial L o s s } { \partial y _ { 1 } } \cdot \frac { \partial y _ { 1 } } { \partial w _ { 1 1 } ^ { ( 2 ) } }=( \frac { \partial L o s s } { \partial o _ { 1 } } \cdot \frac { \partial o _ { 1 } } { \partial y _ { 1 } } + \frac { \partial L o s s } { \partial o _ { 2 } } \cdot \frac { \partial o _ { 2 } } { \partial y _ { 1 } } ) \cdot \frac { \partial y _ { 1 } } { \partial w _ { 1 1 } ^ { ( 2 ) } }$$
反向传播:损失函数对权重的梯度

ppt图片来源:1.2 卷积神经网络基础补充_哔哩哔哩_bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/898856.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第494题目标和

题目&#xff1a; 题解&#xff1a; func findTargetSumWays(nums []int, target int) int {sum : 0for _, v : range nums {sum v}diff : sum - targetif diff < 0 || diff%2 1 {return 0}neg : diff / 2dp : make([]int, neg1)dp[0] 1for _, num : range nums {for j …

【嵌入式Linux】Linux设备树详解

设备树是是Linux中一种用于描述硬件配置的数据结构&#xff0c;它在系统启动时提供给内核&#xff0c;以便内核能够识别和配置硬件资源。设备树在嵌入式Linux系统中尤其重要&#xff0c;因为这些系统通常不具备标准的硬件配置&#xff0c;需要根据实际的硬件配置来动态配置内核…

JMeter之mqtt-jmeter 插件介绍

前言 mqtt-jmeter插件是JMeter中的一个第三方插件&#xff0c;用于支持MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议的性能测试。MQTT是一种轻量级的发布/订阅消息传输协议&#xff0c;广泛应用于物联网和传感器网络中。 一、安装插件 mqtt-jmeter项目…

Java项目-基于springboot框架的时间管理系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

数据抓取时,使用动态IP要注意哪些?

在充满竞争和数据驱动的商业环境中&#xff0c;动态IP已成为数据抓取过程中不可或缺的工具。动态IP的应用能有效提高抓取成功率&#xff0c;但同时也伴随着一系列需要注意的问题。在本文中&#xff0c;我们将详细探讨在数据抓取时使用动态IP时应注意的事项&#xff0c;以确保抓…

git-合并连续两次提交(一个功能,备注相同)

前言&#xff1a; 场景是这样&#xff0c;由于我是实现一个功能&#xff0c;先进行了一次commit,然后我发现写的有些小问题&#xff0c;优化了一下功能并且把代码优化了一次&#xff0c;于是又提交了一次。两次的提交都是以相同的备注&#xff08;当然这个无所谓&#xff09;&a…

【设计模式系列】简单工厂模式

一、什么是简单工厂模式 简单工厂模式&#xff08;Simple Factory Pattern&#xff09;是一种设计模式&#xff0c;其中包含一个工厂类&#xff0c;根据传入的参数不同&#xff0c;返回不同类的实例。这个工厂类封装了对象的创建逻辑&#xff0c;使得客户端代码可以从直接创建…

CSDN Markdown 编辑器语法大全

Markdown 是一种轻量级标记语言&#xff0c;它以简洁、易读易写的特点&#xff0c;被广泛应用于技术文档、博客文章、笔记等领域。CSDN 的 Markdown 编辑器为用户提供了丰富的功能&#xff0c;让用户能够轻松地创建格式规范、内容丰富的文档。以下是一份详细的 CSDN Markdown 编…

Python 应用可观测重磅上线:解决 LLM 应用落地的“最后一公里”问题

作者&#xff1a;彦鸿 背景 随着 LLM&#xff08;大语言模型&#xff09;技术的不断成熟和应用场景的不断拓展&#xff0c;越来越多的企业开始将 LLM 技术纳入自己的产品和服务中。LLM 在自然语言处理方面表现出令人印象深刻的能力。然而&#xff0c;其内部机制仍然不明确&am…

本地大模型部署和基于RAG方案的私有知识库搭建

背景与目的 在人工智能领域&#xff0c;大语言模型如GPT系列、BERT等&#xff0c;以其强大的语言生成与理解能力&#xff0c;正在深刻改变着我们的工作与生活方式。这些模型通过海量数据训练而成&#xff0c;能够执行从文本生成、问答系统到代码编写等多种任务。然而&#xff…

目标检测——yolov5-3.1的环境搭建和运行

第一步&#xff1a;安装anaconda环境&#xff0c;并且配置好cuda&#xff0c;安装需要的基本包 查看对应cuda版本&#xff0c;后续下载cudatoolkit需要对应版本 nvcc -V 第二步&#xff1a;创建虚拟环境&#xff0c;激活环境&#xff0c;安装所需的包 conda create -n yolo…

V2X介绍

文章目录 什么是V2XV2X的发展史早期的DSRC后起之秀C-V2XC-V2X 和DSRC 两者的对比 什么是V2X 所谓V2X&#xff0c;与流行的B2B、B2C如出一辙&#xff0c;意为vehicle to everything&#xff0c;即车对外界的信息交换。车联网通过整合全球定位系统&#xff08;GPS&#xff09;导…

一个非常有趣的问题——链表带环问题

目录 前言 一、为什么快指针每次⾛两步&#xff0c;慢指针⾛⼀步可以相遇&#xff0c;有没有可能遇不上 二、快指针⼀次⾛3步&#xff0c;⾛4步&#xff0c;...n步⾏吗? 三、求环形链表中入环的节点 前言 在学习链表的时候我发现一个一个非常有趣的问题链表带环&#xff0c;…

重生之我爱上了k8s!

内容不全&#xff0c;待补充中...... 目录 一、k8s的部署 1.1.集群环境初始化 1.1.1.所有主机禁用swap 1.1.2.安装k8s部署工具 1.1.2.所有节点安装cri-docker 1.1.3.在master节点拉取K8S所需镜像 1.1.4.集群初始化 1.1.5.其他两台主机加入集群 1.1.6.安装flannel网络…

UE4 材质学习笔记12(水体反射和折射)

一.水体反射和折射 首先就是要断开所有连接到根节点的线&#xff0c;因为水有很多不同的节点成分&#xff0c;当所有其他节点都在用时 要分辨出其中一个是何效果是很难的。 虚幻有五种不同的方法可以创建反射&#xff0c;虚幻中的大多数场景使用多种这些方法 它们会同时运作。…

串口头汇总

1 网线头 1 4对应485A &#xff0c; 2 5对应485B &#xff0c;1 4 接在一起&#xff0c;2 5 接在一起转成2根线也可以。 ----------拓展中

简单介绍冯诺依曼体系

现代的计算机, 大多遵守冯诺依曼体系结构 CPU中央处理器&#xff1a;进行算术运算和逻辑判断。存储器&#xff1a;分为外存和内存&#xff0c;用于存储数据&#xff08;使用二进制方式存储&#xff09;。输入设备&#xff1a;用户给计算机发号施令。输出设备&#xff1a;计算机…

【记录】Android|安卓平板 猫游戏(四款,peppy cat,含下载教程和链接)

前言 网上大部分直接找到的都是 iPad 的猫游戏&#xff0c;安卓的要查英文才找得到&#xff0c;但质量也都一般&#xff0c;或不知道在哪里下载。 遂自己找。 下载测试时间&#xff1a;2024/10/20 文章目录 前言1 检索2 亲测2.1 ✅⭐⭐⭐⭐⭐Cat Alone 1 and 22.2 &#x1f4…

Qt中使用线程之moveToThread

步骤&#xff1a; 1、创建一个自定义Worker类&#xff0c;继承自QObject 2、主线程中创建QThread的对象&#xff0c;Worker类的对象 3、Worker类的对象调用moveToThread函数移动到QThread的对象中 4、主线程自定义一个信号&#xff0c;并使用信号槽连接到worker类对象的任务…

身份和访问管理平台(IAM)是数字身份管理的关键路径和重要方法

随着数字化转型不断推进&#xff0c;越来越多的企业选择通过身份和访问管理平台&#xff08;IAM&#xff09;来管理数字身份。IAM不只是传统的账号、认证、授权、审计产品&#xff0c;更是数字身份管理的创新领航者&#xff0c;以权威数字身份为基础&#xff0c;结合用户与数字…