手推反向传播+numpy实现

简介: 手推反向传播+numpy实现

      反向传播的重要性不必多说,手推也是必备基础,大厂面试要求用numpy实现一下BP也是经常的事。下面以一个简单的两层网络为例(简单到连bias都没有的那种),真·手推反向传播+numpy实现。


说明:


input:输入


net_h:隐层


S(x):sigmoid简写


SD(x):sigmoid导数的简写


out_h:隐层经过sigmoid激活的输出


net_o:输出层


out_o:经过经过sigmoid激活的输出层,也就是最后的输出


target(简写t1、t2):Ground Truth


L:损失函数,一个简单的MSE


gw:L在w的偏导数

2020080208425681.jpg


20200802092257515.jpg




下面是代码:


1.对以上手推图片的实现:

import numpy as np
 
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
def sigmoid_derivationx(y):
    return y * (1 - y)
def back():
    input = np.array([0.9, 0.1], dtype='float')
    weight_1 = np.array([[0.15, 0.20], [0.25, 0.30]], dtype='float')
    weight_2 = np.array([[0.40, 0.45], [0.50, 0.55]], dtype='float')
    target_output = np.array([0.11, 0.89], dtype='float')
    learning_rate = 0.5
    steps = 1000
    while steps > 0:
        steps -= 1
        # 正向传播
        # layer-1
        net_h1, net_h2 = np.dot(input, weight_1)  # 第一层的计算结果
        out_h1, out_h2 = [1 / (1 + np.exp(-net_h1)), 1 / (1 + np.exp(-net_h2))]  # sigmoid激活后的输出
        # layer-2
        layer_2_input = np.array([out_h1, out_h2], dtype='float')
        net_o1, net_o2 = np.dot(layer_2_input, weight_2)  # 第二层的计算结果
        out_o1, out_o2 = [1 / (1 + np.exp(-net_o1)), 1 / (1 + np.exp(-net_o2))]  # sigmoid激活后的输出
        # 计算梯度,反向传播
        total_loss = sum([pow(target_output-real_output, 2)/2 for target_output, real_output in zip(target_output, [out_o1, out_o2])])
        print('网络的输出:step:%d loss=%f out_o1=%f out_o2=%f ' % (steps, total_loss, out_o1, out_o2))
        # gradient for layer-2
        gradient_w5 = -1 * (target_output[0] - out_o1) * out_o1 * (1 - out_o1) * out_h1
        gradient_w6 = -1 * (target_output[0] - out_o1) * out_o1 * (1 - out_o1) * out_h2
        gradient_w7 = -1 * (target_output[1] - out_o2) * out_o2 * (1 - out_o2) * out_h1
        gradient_w8 = -1 * (target_output[1] - out_o2) * out_o2 * (1 - out_o2) * out_h2
 
        # gradient for layer-1
        gradient_w1 = -1 * (target_output[0] - out_o1) * out_o1 * (1 - out_o1) * weight_2[0][0] * out_h1 * \
                      (1 - out_h1)*input[0] - (target_output[1] - out_o2) * out_o2 * (1 - out_o2) * weight_2[1][0] * \
                      out_h1 * (1 - out_h1)*input[0]
 
        gradient_w2 = -1 * (target_output[0] - out_o1) * out_o1 * (1 - out_o1) * weight_2[0][0] * out_h1 * \
                      (1 - out_h1) * input[1] - (target_output[1] - out_o2) * out_o2 * (1 - out_o2) * weight_2[1][0] * \
                      out_h1 * (1 - out_h1)*input[1]
 
        gradient_w3 = -1 * (target_output[0] - out_o1) * out_o1 * (1 - out_o1) * weight_2[0][1] * out_h2 * \
                      (1 - out_h2) * input[0] - (target_output[1] - out_o2) * out_o2 * (1 - out_o2) * weight_2[1][1] * \
                      out_h2 * (1 - out_h2)*input[0]
 
        gradient_w4 = -1 * (target_output[0] - out_o1) * out_o1 * (1 - out_o1) * weight_2[0][1] * out_h2 * \
                      (1 - out_h2) * input[1] - (target_output[1] - out_o2) * out_o2 * (1 - out_o2) * weight_2[1][1] * \
                      out_h2 * (1 - out_h2)*input[1]
 
        # update weight
        # layer -1
        weight_1[0][0] = weight_1[0][0] - learning_rate * gradient_w1
        weight_1[1][0] = weight_1[1][0] - learning_rate * gradient_w2
        weight_1[0][1] = weight_1[0][1] - learning_rate * gradient_w3
        weight_1[1][1] = weight_1[1][1] - learning_rate * gradient_w4
back()

2.用矩阵相乘实现:

import numpy as np
 
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
def sigmoid_derivationx(y):
    return y * (1 - y)
def back_matrix():
    input = np.array([0.9, 0.1], dtype='float')
    weight_1 = np.array([[0.5, 0.5],
                         [0.5, 0.5]], dtype='float')
    weight_2 = np.array([[0.5, 0.5],
                         [0.5, 0.5]], dtype='float')
    target_output = np.array([0.11, 0.89], dtype='float')
    learning_rate = 0.5
    steps = 1000
    while steps > 0:
        steps -= 1
        # 正向传播
        # layer-1
        net_h = np.dot(input, weight_1)  # 第一层的计算结果
        out_h = sigmoid(net_h)  # sigmoid激活后的输出
        # layer-2
        layer_2_input = np.array(out_h, dtype='float')
        net_o = np.dot(layer_2_input, weight_2)  # 第二层的计算结果
        out_o = sigmoid(net_o)  # sigmoid激活后的输出
        # 计算梯度,反向传播
        total_loss = sum([pow(target_output-real_output, 2)/2 for target_output, real_output in zip(target_output, out_o)])
        print('网络的输出:step:%d loss=%f out_o1=%f out_o2=%f ' % (steps, total_loss, out_o[0], out_o[0]))
 
        gradient_weight_2 = np.zeros_like(weight_2)
        for i in range(gradient_weight_2.shape[1]):
            gradient_weight_2[:, i] = (out_o[i] - target_output[i]) * sigmoid_derivationx(out_o[i]) * out_h
 
        gradient_weight_1 = np.zeros_like(weight_1)
        for i in range(gradient_weight_1.shape[1]):
            dot1 = -1 * (target_output - out_o) * out_o * sigmoid_derivationx(out_h)
            dot2 = np.reshape(weight_2[:, i], (-1, 1))
            gradient_weight_1[:, i] = np.dot([dot1], dot2) * input
 
        # update weight
        # layer -1
        weight_1 = weight_1 - learning_rate * gradient_weight_1
 
        # layer-2
        weight_2 = weight_2 - learning_rate * gradient_weight_2
        if steps == 1:
            print('网络的输出:loss=%f out_o1=%f out_o2=%f ' % (total_loss, out_o[0], out_o[1]))
            break
back_matrix()

相关文章
|
存储 缓存 Java
【并发编程的艺术】详解指令重排序与数据依赖
本章详细描述了指令重排序的场景,条件,以及数据依赖、控制依赖对指令重排序的影响。总结如下: 单线程程序,对存在控制依赖的操作执行重排序,不会改变执行结果;但在多线程程序中,对存在控制依赖的操作执行重排序,可能会改变程序的执行结果!这就是多线程执行时出现并发问题的根本原因,切记。
388 0
|
自然语言处理 分布式计算 算法
淘宝用户体验VOC标签体系
淘宝用户体验VOC标签体系
925 0
|
物联网 数据处理 持续交付
Docker适合哪些场景
【10月更文挑战第18天】Docker适合哪些场景
|
机器学习/深度学习 分布式计算 调度
机器学习分布式框架Ray
Ray是UC Berkeley RISELab推出的一个高性能分布式执行框架,它比Spark更具计算优势,部署简单,支持机器学习和深度学习的分布式训练。Ray包括节点(head和worker)、本地调度器、object store、全局调度器(GCS),用于处理各种分布式计算任务。它支持超参数调优(Ray Tune)、梯度下降(Ray SGD)、推理服务(Ray SERVE)等。安装简单,可通过`pip install ray`。使用时,利用`@ray.remote`装饰器将函数转换为分布式任务,通过`.remote`提交并用`ray.get`获取结果。5月更文挑战第15天
2443 7
|
Java API 开发者
Spring揭秘:BeanDefinitionBuilder接口应用场景及实现原理!
BeanDefinitionBuilder类为Spring框架中的Bean定义提供了灵活且强大构建方式,通过API,开发者能够轻松创建和配置Bean,无需依赖繁琐的XML配置或注解。
480 2
Spring揭秘:BeanDefinitionBuilder接口应用场景及实现原理!
|
Python
python while true的语法和用法
python while循环语句的一般形式是while后面跟一个条件表达式,当该表达式的返回值为True,或经过布尔转换会返回True,比如1转换为bool布尔类型会为True,那么就执行一次while的循环。while True,即直接把表达式设置为True,那么无论如何,代码都将进行一次while的循环,直到遇到退出的条件,
731 4
|
计算机视觉 Windows
【解决方案】OSError: [WinError 1455] 页面文件太小,无法完成操作
今天在windows系统下调试yolov5,遇到的一个bug,特此记录,并附上解决方案,请往下看。
【解决方案】OSError: [WinError 1455] 页面文件太小,无法完成操作
|
芯片 异构计算