IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> AI学习——自动微分算法 -> 正文阅读

[人工智能]AI学习——自动微分算法

前情回顾

在上一次的博文中,学习了感知机和BPNN算法,我们可以做一个简单的知识点总结:

  1. 激活函数非线性
  2. 深层网络比浅层网络拥有更强的表达能力
  3. 三层神经网络可以表达任意函数(足够多的隐藏单元)
  4. 神经网络与图灵机(现代计算机)等价
  5. 计算性能的发展带动神经网络的发展
  6. 深层神经网络可以充分利用计算机的性能
  7. 多层感知机就是神经网络

激活函数

  • sigmoid函数

在这里插入图片描述
s i g m o i d ( x ) = 1 1 + e ? x 函 数 的 取 值 范 围 : ( 0 , 1 ) 导 数 = s i g m o i d ( x ) ( 1 ? s i g m o i d ( x ) ) 导 数 的 取 值 范 围 ( 0 , 1 4 ) \begin{aligned} &sigmoid(x)=\frac{1}{1+e^{-x}} \\ &函数的取值范围:(0,1) \\ &导数=sigmoid(x)(1-sigmoid(x)) \\ &导数的取值范围(0,\frac{1}{4}) \end{aligned} ?sigmoid(x)=1+e?x1?:(0,1)=sigmoid(x)(1?sigmoid(x))(0,41?)?

特性:

  1. 由于该函数的取值范围为(0,1),所以我们可以很轻易地将其与概率对应起来
  2. 事实上,该函数常用于解决或反映二分类问题
  3. 该函数在反向传播的计算中会比较简单,因为其导数为
    f ′ ( x ) = f ( x ) ( 1 ? f ( x ) ) f'(x)=f(x)(1-f(x)) f(x)=f(x)(1?f(x))
  4. 但是该函数会存在梯度消失现象
  • tanh函数
    在这里插入图片描述
    t a n h ( x ) = e ( x ) ? e ( ? x ) e ( x ) + e ( ? x ) 函 数 的 取 值 范 围 : ( ? 1 , 1 ) 导 数 = 1 ? t a n h 2 ( x ) 导 数 的 取 值 范 围 : ( 0 , 1 ) \begin{aligned} &tanh(x)=\frac{e^{(x)}-e^{(-x)}}{e^{(x)}+e^{(-x)}} \\ &函数的取值范围:(-1,1) \\ &导数=1-tanh^2(x) \\ &导数的取值范围:(0,1) \end{aligned} ?tanh(x)=e(x)+e(?x)e(x)?e(?x)?:(?1,1)=1?tanh2(x):(0,1)?

特性:

  1. 跟sigmoid函数非常像,可以看成sigmoid函数在竖直方向拉伸了两倍
  2. 解决了sigmoid函数收敛较慢的问题,提高了收敛速度
  3. 由于其导数的取值范围为(0,1),所以不用担心梯度爆炸的问题
  • ReLu函数
    (PS:画不出来,随便搜了一个)
    在这里插入图片描述
    R e L u ( x ) = { x if?x?>?0 0 if?x ≤ 0 x > 0 时 , 导 数 为 1 \begin{aligned} &ReLu(x)= \begin{cases} x& \text{if x > 0}\\ 0& \text{if x$\le$0} \end{cases} \\ &x>0时,导数为1 \end{aligned} ?ReLu(x)={x0?if?x?>?0if?x0?x>01?

特性:

  1. 虽然该函数的构造非常简单,但是在梯度下降里,该算法可以说是一个里程碑式的算法,对于深度学习性能的提升非常巨大
  2. 由于它的有效导数是1,所以ReLu函数可以完美避免梯度爆炸和梯度消失的问题
  3. 同时它的计算也非常的简单,只需要使用简单的判断就可以了,导数几乎不用计算
  4. ReLu函数的收敛速度相较于sigmoid函数和tanh函数要快很多
  5. 缺点是x<0的部分导数为0,这会导致一些节点失效,为计算带来影响

实验问题:自动微分算法的应用

  • 计算图:简单来理解,就是将计算通过图的形式表现出来。
  • 自动微分:是一种数值计算的方式,用来计算因变量对某个自变量的导数。

模型构建:

  • 计算图
    先计算出整体的局部微分,再将局部的微分根据我们的需要整合起来得到我们想要的结果。
    在这里插入图片描述

① ? u ? w 1 = 1 ② ? u ? w 2 = 1 ③ ? L ? u = w 3 = 1 ④ L = u ? w 3 = ( w 1 + w 2 ) ? w 3 \begin{aligned} &①\frac{\partial u}{\partial w_1}=1 \\ &②\frac{\partial u}{\partial w2}=1 \\ &③\frac{\partial L}{\partial u} =w3=1 \\ &④L=u*w3=(w_1+w_2)*w_3 \end{aligned} ??w1??u?=1?w2?u?=1?u?L?=w3=1L=u?w3=(w1?+w2?)?w3??

  • 链式法则

? c ? a = ? c ? b ? ? b ? a ? a n ? a 1 = ? a n ? a n ? 1 ? … … ? ? a 3 ? a 2 ? ? a 2 ? a 1 \begin{aligned} &\frac{\partial c}{\partial a}=\frac{\partial c}{\partial b}*\frac{\partial b}{\partial a} \\ & \frac{\partial a_n}{\partial a_1}=\frac{\partial a_n}{\partial a_{n-1}}*……*\frac{\partial a_3}{\partial a_{2}}*\frac{\partial a_2}{\partial a_{1}} \end{aligned} ??a?c?=?b?c???a?b??a1??an??=?an?1??an?????a2??a3????a1??a2???

  • 自动微分

设 f ( x , w , b ) = 1 e x p ( ? ( w x + b ) ) + 1 相 当 于 一 个 s i g m o i d 函 数 当 ( x , w , b ) = ( 1 , 0 , 0 ) 时 , f ( 1 , 0 , 0 ) = 1 2 \begin{aligned} &设f(x,w,b)=\frac{1}{exp(-(wx+b))+1} \\ &相当于一个sigmoid函数 \\ &当(x,w,b)=(1,0,0)时,f(1,0,0)=\frac{1}{2} \end{aligned} ?f(x,w,b)=exp(?(wx+b))+11?sigmoid(x,w,b)=(1,0,0)f(1,0,0)=21??
在这里插入图片描述

h 1 = w x = 0 h 2 = h 1 + b = 0 h 3 = ? 1 ? h 2 = 0 h 4 = e x p ( h 3 ) = 1 h 5 = h 4 + 1 = 2 h 6 = 1 / h 5 = 1 2 ① ? h 1 ? x = w = 0 ② ? h 1 ? w = x = 1 ③ ? h 2 ? h 1 = 1 ④ ? h 2 ? b = 1 ⑤ ? h 3 ? h 2 = ? 1 ⑥ ? h 4 ? h 3 = 1 ⑦ ? h 5 ? h 4 = 1 ⑧ ? h 6 ? h 5 = ? 1 h 5 2 = ? 1 4 \begin{aligned} &h_1=wx=0 \\ &h_2=h_1+b=0 \\ &h_3=-1*h_2=0 \\ &h_4=exp(h_3)=1 \\ &h_5=h_4+1=2 \\ &h_6=1/h_5=\frac{1}{2} \\ &①\frac{\partial h_1}{\partial x}=w=0 \\ &②\frac{\partial h_1}{\partial w}=x=1 \\ &③\frac{\partial h_2}{\partial h_1}=1 \\ &④\frac{\partial h_2}{\partial b}=1 \\ &⑤\frac{\partial h_3}{\partial h_2}=-1 \\ &⑥\frac{\partial h_4}{\partial h_3}=1 \\ &⑦\frac{\partial h_5}{\partial h_4}=1 \\ &⑧\frac{\partial h_6}{\partial h_5}=-\frac{1}{h_5^2}=-\frac{1}{4} \\ \end{aligned} ?h1?=wx=0h2?=h1?+b=0h3?=?1?h2?=0h4?=exp(h3?)=1h5?=h4?+1=2h6?=1/h5?=21??x?h1??=w=0?w?h1??=x=1?h1??h2??=1?b?h2??=1?h2??h3??=?1?h3??h4??=1?h4??h5??=1?h5??h6??=?h52?1?=?41??

? f ( x ; w , b ) ? w = ? f ( x ; w , b ) ? h 6 ? ? h 6 ? h 5 ? ? h 5 ? h 4 ? ? h 4 ? h 3 ? ? h 3 ? h 2 ? ? h 2 ? h 1 ? ? h 1 ? w = 0.25 \begin{aligned} \frac{\partial f(x;w,b)}{\partial w}=\frac{\partial f(x;w,b)}{\partial h_6}*\frac{\partial h_6}{\partial h_5}*\frac{\partial h_5}{\partial h_4}*\frac{\partial h_4}{\partial h_3}*\frac{\partial h_3}{\partial h_2}*\frac{\partial h_2}{\partial h_1}*\frac{\partial h_1}{\partial w} \\ =0.25 \end{aligned} ?w?f(x;w,b)?=?h6??f(x;w,b)???h5??h6????h4??h5????h3??h4????h2??h3????h1??h2????w?h1??=0.25?

由此可知,反向传播算法只是自动微分的一种特殊形式
优点: 计算复用,提高计算效率

  • 梯度消失:梯度消失是传统的神经网络训练中非常致命的一个问题,其本质是由于链式法则的乘法特性导致的。

例如一个只有三层的隐藏层的神经网络,当梯度消失发生时,靠近输出层的隐藏层的权值更新相对而言比较正常,但对于靠近输入层的隐藏层而言,其权值几乎不变或者变得很慢,仍十分接近初始化的权值,这就导致了靠近输入层的部分隐藏层其实只是一个映射层,只是对所有的输入起到了映射的作用。

在这里插入图片描述

实验过程

本次实验是为了更好地研究自动微分,我们做了不同的实验:

  1. 利用计算图和自动微分解决简单的逻辑问题,如异或问题
  2. 利用自动微分观察sigmoid函数存在的梯度消失问题
  3. 用ReLu函数代替sigmoid函数,看看是否能解决梯度消失的问题
  • 利用计算图和自动微分解决简单的异或问题
    在做第一个实验之前,我们需要研究异或问题的计算图
    关于感知机的一些理解可以参考我之前的文章:
    AI学习——感知机和BPNN算法
    在这里插入图片描述
    计算图的计算思路是:同路径的梯度作乘法,不同路径的梯度作加法
    分析如下:
    h 3 = h 1 ? 1 + h 2 ? 1 ? 1.5 h 2 = x ? ( ? 1 ) + y ? ( ? 1 ) + 1.5 h 1 = x ? 1 + y ? 1 ? 0.5 ? h 3 ? x = ? h 3 ? h 1 ? ? h 1 ? x + ? h 3 ? h 2 ? ? h 2 ? x ? h 3 ? y = ? h 3 ? h 1 ? ? h 1 ? y + ? h 3 ? h 2 ? ? h 2 ? y \begin{aligned} &h_3=h_1*1+h_2*1-1.5 \\ &h_2=x*(-1)+y*(-1)+1.5 \\ &h_1=x*1+y*1-0.5 \\ &\frac{\partial h_3}{\partial x}=\frac{\partial h_3}{\partial h_1}*\frac{\partial h_1}{\partial x}+\frac{\partial h_3}{\partial h_2}*\frac{\partial h_2}{\partial x} \\ &\frac{\partial h_3}{\partial y}=\frac{\partial h_3}{\partial h_1}*\frac{\partial h_1}{\partial y}+\frac{\partial h_3}{\partial h_2}*\frac{\partial h_2}{\partial y} \end{aligned} ?h3?=h1??1+h2??1?1.5h2?=x?(?1)+y?(?1)+1.5h1?=x?1+y?1?0.5?x?h3??=?h1??h3????x?h1??+?h2??h3????x?h2???y?h3??=?h1??h3????y?h1??+?h2??h3????y?h2???

从计算图和分析的结果可知,除了输入x,Y和我们最终所需要的预测值y,我们至少还需要 w 1 … … w 6 和 h 1 、 h 2 、 h 3 w_1……w_6和h_1、h_2、h_3 w1?w6?h1?h2?h3?共计9个参数。

那么,实验开始

  1. 利用自动微分的框架,我们首先需要定义一个激活函数,这里我们选用的是sigmoid函数。 因为我们前面提到过,sigmoid函数在解决二分类问题非常有效,且计算简单
    在这里插入图片描述

  2. 接下来我们开始定义输入的值,以及我们预测的值和另外9个参数,其中预测值需要根据我们之前分析的结果,代入9个参数进行迭代。 由于当时的能力不足,在最初做实验的时候我只能将值一个一个的输入,无法像之前的实验那样一次输入一个数组进行判断,这样的计算效率无疑是非常低的
    在这里插入图片描述

  3. 调用梯度下降函数,放入循环,不断地训练、迭代,并计算出其中的损失函数,直到预测值不断地接近我们想要的结果
    在这里插入图片描述
    在这里插入图片描述

  • 自动微分解决异或问题的优化
    在上面的实验中,我们提到过缺点,就是一次只能输入一个值进行计算,效率低下且笨拙,这次在老师的指导下,成功改良,能够输入一个数组了(其实就是抄的老师的方法)
    在这里插入图片描述
    在这里插入图片描述

核心思想依然没有改变,但是老师的代码看起来明显更加简单、清爽

  • 利用自动微分观察sigmoid函数存在的梯度消失问题
    为了更好地研究梯度消失,我们同样需要设计一个简单的神经网络,下面这个神经网络总共有四个隐藏层,但是每一层隐藏层都只含有一个单元节点,这就导致了这个神经网络尽管有较多的隐藏层,但依旧十分简单

在这里插入图片描述
y = w 5 h 4 = w 5 f ( w 4 h 3 ) = w 5 f ( w 4 f ( w 3 h 2 ) ) = w 5 f ( w 4 f ( w 3 f ( w 2 h 1 ) ) ) = w 5 f ( w 4 f ( w 3 f ( w 2 f ( w 1 x ) ) ) ) ? c ? w 1 = ? 1 2 ( y ? 3 ) 2 ? w 1 = ( y ? 3 ) w 5 ? h 4 ? w 1 = ( y ? 3 ) w 5 w 4 w 3 w 2 f ′ ( h 4 ) f ′ ( h 3 ) f ′ ( h 2 ) f ′ ( h 1 ) \begin{aligned} y&=w_5h_4=w_5f(w_4h_3)=w_5f(w_4f(w_3h_2)) \\ &=w_5f(w_4f(w_3f(w_2h_1)))=w_5f(w_4f(w_3f(w_2f(w_1x)))) \\ \frac{\partial c}{\partial w_1}&=\frac{\partial \frac{1}{2}(y-3)^2}{\partial w_1}=(y-3)w_5\frac{\partial h_4}{\partial w_1} \\ &=(y-3)w_5w_4w_3w_2f'(h_4)f'(h_3)f'(h_2)f'(h_1) \end{aligned} y?w1??c??=w5?h4?=w5?f(w4?h3?)=w5?f(w4?f(w3?h2?))=w5?f(w4?f(w3?f(w2?h1?)))=w5?f(w4?f(w3?f(w2?f(w1?x))))=?w1??21?(y?3)2?=(y?3)w5??w1??h4??=(y?3)w5?w4?w3?w2?f(h4?)f(h3?)f(h2?)f(h1?)?

根据梯度的值我们可以做一个简单的判断,判断其结果的取值范围,将其结果分为三个部分:

  1. ( y ? 3 ) (y-3) (y?3),由于不断的迭代,最后的预测值y一定会无限接近于3,所以这个值应该是无限接近于0
  2. w 5 w 4 w 3 w 2 w_5w_4w_3w_2 w5?w4?w3?w2?,这部分的权值是我们给定的,一般来说不会太大,通常情况下都为1
  3. f ′ ( h 4 ) f ′ ( h 3 ) f ′ ( h 2 ) f ′ ( h 1 ) f'(h_4)f'(h_3)f'(h_2)f'(h_1) f(h4?)f(h3?)f(h2?)f(h1?),由于我们使用的激活函数是sigmoid函数,我们知道其导数的取值范围是 ( 0 , 1 4 ) (0,\frac{1}{4}) (0,41?),所以该部分的取值范围应该是 ( 0 , 1 4 4 ) (0,\frac{1}{4^4}) (0,441?)

综上可知,其求导的结果的取值应该是小于0的,而我们的神经网络自动微分,是通过每一层的梯度自动运算,来求解其他的参数或权值,由于每一层的梯度太小,通过链式法则求到的值自然也是非常小的,这种细微的变化可以忽略不计,这就是我们之前提到的梯度消失,神经网络最靠近输入层的那部分隐藏层也就成了映射层

为了更好地观察到梯度消失的现象,在实验过程中我将神经网络设置了10层隐藏层
在这里插入图片描述
在这里插入图片描述

  • 移花接木,ReLu函数登场!
    之前我们就提到,ReLu函数可以完美地解决梯度爆炸和梯度消失的问题。
    在这里插入图片描述
    这种感觉,好似满腔热情扑了空。
    为什么带入了ReLu函数之后结果反而没有了。

经过反复的研究观察,我得出了结论:
由于我这次设计的神经网络过于简单,每层都只有一个节点,而ReLu函数的值在遇到<0的输入时,其导数是0,这也就意味之,只要其中一个节点的导数值为0,在链式法则求解出后续值的过程中,结果都为0。

解决办法:

  1. 将神经网络复杂化,每一层隐藏层多设置几个神经单元
  2. ReLu函数的改造,给<0的部分的函数同样设置一个系数,让其不等于0
  • 卷土重来,进化吧!ReLu函数!
  1. 这次我们将ReLu函数稍作修改,将其进化成leaky ReLu函数,x<0时,给其带上一个系数0.01
    在这里插入图片描述
  2. 接着按照之前的分析,我们让我们的神经网络复杂化,这里由于能力问题,我只能手动写了一个两层隐藏层,三个节点的神经网络

在这里插入图片描述
这个时候我们会发现,我们得到了一个杂乱无章的梯度
在这里插入图片描述
是的,虽然还会有个别的零值出现,但是同样是因为神经网络不够负复杂,训练次数不够多产生的个别影响,起码我们已经能够成功解决梯度消失的问题了

实验结果

  • 利用计算图和自动微分解决简单的异或问题
    在这里插入图片描述
  • 自动微分解决异或问题的优化
    在这里插入图片描述
  • 利用自动微分观察sigmoid函数存在的梯度消失问题
    在这里插入图片描述
  • 进化的ReLu函数(leaky ReLu)解决梯度消失问题
    在这里插入图片描述

小结

在本次对自动微分算法的学习过程中,我们学到了以下几个知识:

  1. 神经网络的本质——一个又一个的计算表达式
  2. 计算图和自动微分的原理
  3. Python编程能力的提升
  4. 逐渐学会使用计算机的思维来思考问题

作为一个AI小白,通过这次学习我能够感觉到自己的学识有了很大的提升,但是AI领域深似海,一望无际,我在其中飘荡,好似一叶扁舟,越是往深处走,越是发觉自己的无知,越要谦虚谨慎,我的代码仍有许多不足,我的理解也会有很多欠缺的、没有考虑到地方。

有新的想法,欢迎交流和指正!

在这里插入图片描述

代码

# 自动微分框架源码
from collections import defaultdict
import numpy as np


class Variable:
    def __init__(self, value, local_gradients=[]):
        self.value = value
        self.local_gradients = local_gradients

    def __add__(self, other):
        return add(self, other)

    def __mul__(self, other):
        return mul(self, other)

    def __sub__(self, other):
        return add(self, neg(other))

    def __neg__(self):
        return neg(self)

    def __truediv__(self, other):
        return mul(self, inv(other))

def add(a, b):
    value = a.value + b.value
    local_gradients = ((a, 1), (b, 1))
    return Variable(value, local_gradients)

def mul(a, b):
    value = a.value * b.value
    local_gradients = ((a, b.value), (b, a.value))
    return Variable(value, local_gradients)

def neg(a):
    value = -1 * a.value
    local_gradients = ((a, -1),)
    return Variable(value, local_gradients)

def inv(a):
    value = 1. / a.value
    local_gradients = ((a, -1 / a.value ** 2),)
    return Variable(value, local_gradients)

def exp(a):
    value = np.exp(a.value)
    local_gradients = ((a, value),)
    return Variable(value, local_gradients)


def get_gradients(variable):
    gradients = defaultdict(lambda: 0)  # 可以根据Variable变量地址索引对应的梯度
    def compute_gradients(variable, path_value):
        for child_variable, local_gradient in variable.local_gradients:  # 两条路径循环2次
            value_of_path_to_child = path_value * local_gradient  # 从后往前,乘以每条边的梯度
            gradients[child_variable] += value_of_path_to_child  # 不同路径的梯度相加,算的是局部偏微分
            compute_gradients(child_variable, value_of_path_to_child)  # 递归整个计算图

    compute_gradients(variable, path_value=1)  # path_value=1,输出对自己的偏微分为1
    return gradients



def sigmoid(z):
    ONE = Variable(1)
    return ONE / (ONE + exp(-z))

x = Variable(1)
w = Variable(0)
b = Variable(0)
Y = Variable(1)
y = sigmoid(w * x + b)
gradients = get_gradients(y)
print('dy/dw=%f, dy/db=%f' % (gradients[w], gradients[b]))
for i in range(1000):
    y = sigmoid(w * x + b)
    C = (y - Y) * (y - Y)
    print('Cost=%f,y=%f' % (C.value, y.value))
    gradients = get_gradients(C)
    w.value = w.value - 0.1 * gradients[w]
    b.value = b.value - 0.1 * gradients[b]

# 感知机初始代码,但是由于Variable类型,最开始只能一次输入一个值进行运算
from collections import defaultdict
import numpy as np


class Variable:
    def __init__(self, value, local_gradients=[]):
        self.value = value
        self.local_gradients = local_gradients

    def __add__(self, other):
        return add(self, other)

    def __mul__(self, other):
        return mul(self, other)

    def __sub__(self, other):
        return add(self, neg(other))

    def __neg__(self):
        return neg(self)

    def __truediv__(self, other):
        return mul(self, inv(other))

def add(a, b):
    value = a.value + b.value
    local_gradients = ((a, 1), (b, 1))
    return Variable(value, local_gradients)

def mul(a, b):
    value = a.value * b.value
    local_gradients = ((a, b.value), (b, a.value))
    return Variable(value, local_gradients)

def neg(a):
    value = -1 * a.value
    local_gradients = ((a, -1),)
    return Variable(value, local_gradients)

def inv(a):
    value = 1. / a.value
    local_gradients = ((a, -1 / a.value ** 2),)
    return Variable(value, local_gradients)

def exp(a):
    value = np.exp(a.value)
    local_gradients = ((a, value),)
    return Variable(value, local_gradients)


def get_gradients(variable):
    gradients = defaultdict(lambda: 0)  # 可以根据Variable变量地址索引对应的梯度
    def compute_gradients(variable, path_value):
        for child_variable, local_gradient in variable.local_gradients:  # 两条路径循环2次
            value_of_path_to_child = path_value * local_gradient  # 从后往前,乘以每条边的梯度
            gradients[child_variable] += value_of_path_to_child  # 不同路径的梯度相加,算的是局部偏微分
            compute_gradients(child_variable, value_of_path_to_child)  # 递归整个计算图

    compute_gradients(variable, path_value=1)  # path_value=1,输出对自己的偏微分为1
    return gradients

def sigmoid(z):
    ONE = Variable(1)
    return ONE / (ONE + exp(-z))
    
x1=Variable(1)
x2=Variable(0)
Y=Variable(1)
w1=  Variable(0)
w2=  Variable(0)
w3=  Variable(0)
w4=  Variable(0)
w5=  Variable(0)
w6=  Variable(0)
b1=  Variable(0)
b2=  Variable(0)
b3=  Variable(0)
y = sigmoid(w5*sigmoid(x1*w1+x2*w2+b1)+w6*sigmoid(x1*w3+x2*w4+b2)+b3)
gradients = get_gradients(y)
#print('dy/dw1=%f, dy/dw2=%f,dy/dw3=%f,dy/dw3=%f,dy/dw3=%f' % (gradients[w1], gradients[w2],gradients[w3]))
for i in range(1000):
    y = sigmoid(w5*sigmoid(x1*w1+x2*w2+b1)+w6*sigmoid(x1*w3+x2*w4+b2)+b3)
    C = (y - Y) * (y - Y)
    print('Cost=%f,Y=%f,y=%f' % (C.value,Y.value, y.value))
    gradients = get_gradients(C)
    w1.value = w1.value - 0.1 * gradients[w1]
    w2.value = w2.value - 0.1 * gradients[w2]
    w3.value = w3.value - 0.1 * gradients[w3]
    w4.value = w4.value - 0.1 * gradients[w4]
    w5.value = w5.value - 0.1 * gradients[w5]
    w6.value = w6.value - 0.1 * gradients[w6]
    b1.value = b1.value - 0.1 * gradients[b1]
    b2.value = b2.value - 0.1 * gradients[b2]
    b3.value = b3.value - 0.1 * gradients[b3]

print('x1=%f,x2=%f,w1=%f.w2=%f,w3=%f,w4=%f,w5=%f,w6=%f,b1=%f,b2=%f,b3=%f,y=%f' % (x1.value,x2.value,w1.value,w4.value,w3.value,w4.value,w5.value,w6.value,b1.value,b2.value,b3.value,y.value))

#感知机改良算法,成功的输入了数组,让计算更加简单便捷
from collections import defaultdict
import numpy as np


class Variable:
    def __init__(self, value, local_gradients=[]):
        self.value = value
        self.local_gradients = local_gradients

    def __add__(self, other):
        return add(self, other)

    def __mul__(self, other):
        return mul(self, other)

    def __sub__(self, other):
        return add(self, neg(other))

    def __neg__(self):
        return neg(self)

    def __truediv__(self, other):
        return mul(self, inv(other))

def add(a, b):
    value = a.value + b.value
    local_gradients = ((a, 1), (b, 1))
    return Variable(value, local_gradients)

def mul(a, b):
    value = a.value * b.value
    local_gradients = ((a, b.value), (b, a.value))
    return Variable(value, local_gradients)

def neg(a):
    value = -1 * a.value
    local_gradients = ((a, -1),)
    return Variable(value, local_gradients)

def inv(a):
    value = 1. / a.value
    local_gradients = ((a, -1 / a.value ** 2),)
    return Variable(value, local_gradients)

def exp(a):
    value = np.exp(a.value)
    local_gradients = ((a, value),)
    return Variable(value, local_gradients)


def get_gradients(variable):
    gradients = defaultdict(lambda: 0)  # 可以根据Variable变量地址索引对应的梯度
    def compute_gradients(variable, path_value):
        for child_variable, local_gradient in variable.local_gradients:  # 两条路径循环2次
            value_of_path_to_child = path_value * local_gradient  # 从后往前,乘以每条边的梯度
            gradients[child_variable] += value_of_path_to_child  # 不同路径的梯度相加,算的是局部偏微分
            compute_gradients(child_variable, value_of_path_to_child)  # 递归整个计算图

    compute_gradients(variable, path_value=1)  # path_value=1,输出对自己的偏微分为1
    return gradients



def sigmoid(z):
    ONE = Variable(1)
    return ONE / (ONE + exp(-z))



#自动微分实现异或
w = [Variable(np.random.randn()) for i in range(9)]
def f(x1,x2):
    x1 = Variable(x1)
    x2 = Variable(x2)
    h1 = sigmoid(x1*w[0]+x2*w[1]+w[2])
    h2 = sigmoid(x1*w[3]+x2*w[4]+w[5])
    ho = sigmoid(w[6]*h1+w[7]*h2+w[8])
    return ho

for i in range(30000):
    C = (f(0,0) - Variable(0)) * (f(0,0) - Variable(0))
    C = (f(0,1) - Variable(1)) * (f(0,1) - Variable(1)) + C
    C = (f(1,0) - Variable(1)) * (f(1,0) - Variable(1)) + C
    C = (f(1,1) - Variable(0)) * (f(1,1) - Variable(0)) + C
    print('Epoch %d, Cost=%f' % (i,C.value))
    gradients = get_gradients(C)
    for j in range(len(w)):
        w[j].value = w[j].value - 0.1 *gradients[w[j]]
        
print("f(0,0)=%f" % f(0,0).value)
print("f(0,1)=%f" % f(0,1).value)
print("f(1,0)=%f" % f(1,0).value)
print("f(1,1)=%f" % f(1,1).value)

# 研究我们之前提到的sigmoid函数存在的梯度消失现象
from collections import defaultdict
import numpy as np


class Variable:
    def __init__(self, value, local_gradients=[]):
        self.value = value
        self.local_gradients = local_gradients

    def __add__(self, other):
        return add(self, other)

    def __mul__(self, other):
        return mul(self, other)

    def __sub__(self, other):
        return add(self, neg(other))

    def __neg__(self):
        return neg(self)

    def __truediv__(self, other):
        return mul(self, inv(other))

def add(a, b):
    value = a.value + b.value
    local_gradients = ((a, 1), (b, 1))
    return Variable(value, local_gradients)

def mul(a, b):
    value = a.value * b.value
    local_gradients = ((a, b.value), (b, a.value))
    return Variable(value, local_gradients)

def neg(a):
    value = -1 * a.value
    local_gradients = ((a, -1),)
    return Variable(value, local_gradients)

def inv(a):
    value = 1. / a.value
    local_gradients = ((a, -1 / a.value ** 2),)
    return Variable(value, local_gradients)

def exp(a):
    value = np.exp(a.value)
    local_gradients = ((a, value),)
    return Variable(value, local_gradients)


def get_gradients(variable):
    gradients = defaultdict(lambda: 0)  # 可以根据Variable变量地址索引对应的梯度
    def compute_gradients(variable, path_value):
        for child_variable, local_gradient in variable.local_gradients:  # 两条路径循环2次
            value_of_path_to_child = path_value * local_gradient  # 从后往前,乘以每条边的梯度
            gradients[child_variable] += value_of_path_to_child  # 不同路径的梯度相加,算的是局部偏微分
            compute_gradients(child_variable, value_of_path_to_child)  # 递归整个计算图

    compute_gradients(variable, path_value=1)  # path_value=1,输出对自己的偏微分为1
    return gradients



def sigmoid(z):
    ONE = Variable(1)
    return ONE / (ONE + exp(-z))

#自动微分,sigmoid函数的梯度消失现象

w = [Variable(np.random.randn()) for i in range(10)]
x = Variable(1)
Y = Variable(3)
y = sigmoid(w[1]*x)
for i in range(10):
    y = sigmoid(w[i]*y)
    
C = (Y-y)*(Y-y)
gradients = get_gradients(C)

for i in range(10):
    print('dC/dw%d=%f' % (i,gradients[w[i]]))

# 使用leaky ReLu函数避免梯度下降
from collections import defaultdict
import numpy as np


class Variable:
    def __init__(self, value, local_gradients=[]):
        self.value = value
        self.local_gradients = local_gradients

    def __add__(self, other):
        return add(self, other)

    def __mul__(self, other):
        return mul(self, other)

    def __sub__(self, other):
        return add(self, neg(other))

    def __neg__(self):
        return neg(self)

    def __truediv__(self, other):
        return mul(self, inv(other))

def add(a, b):
    value = a.value + b.value
    local_gradients = ((a, 1), (b, 1))
    return Variable(value, local_gradients)

def mul(a, b):
    value = a.value * b.value
    local_gradients = ((a, b.value), (b, a.value))
    return Variable(value, local_gradients)

def neg(a):
    value = -1 * a.value
    local_gradients = ((a, -1),)
    return Variable(value, local_gradients)

def inv(a):
    value = 1. / a.value
    local_gradients = ((a, -1 / a.value ** 2),)
    return Variable(value, local_gradients)

def exp(a):
    value = np.exp(a.value)
    local_gradients = ((a, value),)
    return Variable(value, local_gradients)


def get_gradients(variable):
    gradients = defaultdict(lambda: 0)  # 可以根据Variable变量地址索引对应的梯度
    def compute_gradients(variable, path_value):
        for child_variable, local_gradient in variable.local_gradients:  # 两条路径循环2次
            value_of_path_to_child = path_value * local_gradient  # 从后往前,乘以每条边的梯度
            gradients[child_variable] += value_of_path_to_child  # 不同路径的梯度相加,算的是局部偏微分
            compute_gradients(child_variable, value_of_path_to_child)  # 递归整个计算图

    compute_gradients(variable, path_value=1)  # path_value=1,输出对自己的偏微分为1
    return gradients

def LReLu(x):
    if x.value > 0:
        return x
    else:
        x.value=0.01*x.value
        return x

k=10
print("leaky ReLu函数")
w = [Variable(np.random.randn()) for i in range(k)]
x = Variable(1)
Y = Variable(3)
y = LReLu(w[7]*LReLu(w[4]*LReLu(w[1]*x))+w[6]*ReLu(w[8]*LReLu(w[2]*x))+w[9]*ReLu(w[6]*LReLu(w[3]*x)))

for i in range(k):
    #print("y=%f" % y.value)
    y = LReLu(w[7]*LReLu(w[4]*LReLu(w[1]*y))+w[6]*ReLu(w[8]*LReLu(w[2]*y))+w[9]*ReLu(w[6]*LReLu(w[3]*y)))

C = (Y - y) * (Y - y)
gradients = get_gradients(C)

for i in range(k):
    print('dC/dw%d=%f' % (i, gradients[w[i]]))
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 23:10:15  更:2022-04-06 23:11:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/8 4:36:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码