人工智能-作业2:例题程序复现

如图,

输入值:x1, x2 = 0.5,0.3

输出值:y1, y2 =0.23, -0.07

激活函数:sigmoid

损失函数:MSE(均方误差)

初始权值:0.2 -0.4 0.5 0.6 0.1 -0.5 -0.3 0.8(w1~w8)
在这里插入图片描述

前向传播

每一个h或o还要具体分为in和out:
普通的相乘求和后得到in_h或in_o,将in用sigmoid函数处理后得到out_h或out_o,
其他要说的都在注释里了。
在这里插入图片描述

# 前向传播:
# in = sum(w*x)
# out = sigmoid(in)
# 一个隐藏层
def forward_propagate(x1, x2, y1, y2, w1, w2, w3, w4, w5, w6, w7, w8):
    in_h1 = w1 * x1 + w3 * x2
    out_h1 = sigmoid(in_h1)
    in_h2 = w2 * x1 + w4 * x2
    out_h2 = sigmoid(in_h2)

    in_o1 = w5 * out_h1 + w7 * out_h2
    out_o1 = sigmoid(in_o1)
    in_o2 = w6 * out_h1 + w8 * out_h2
    out_o2 = sigmoid(in_o2)

    print("正向计算:o1 ,o2")    # 输出本轮进入损失函数之前的数值out1、out2
    print(round(out_o1, 5), round(out_o2, 5))   # round()舍入化整,round(x,y),y表保留小数后几位,此处保留5位小数

    # 损失函数MSE 均方误差:1/n * sum((y^-y)**2)
    # 此处只有2个y,所以n=2
    error = (1 / 2) * (out_o1 - y1) ** 2 + (1 / 2) * (out_o2 - y2) ** 2

    print("损失函数:均方误差")    # 输出本轮损失函数
    print(round(error, 5))

    return out_o1, out_o2, out_h1, out_h2   # 返回了两层out,用于反向传播

反向传播

已知计算导数是由拆分成多个导数相乘计算。
在这里插入图片描述

e

r

r

o

r

w

5

frac{partial error}{partial w_5}

w5error的计算为例:

e

r

r

o

r

w

5

=

e

r

r

o

r

o

u

t

_

o

1

o

u

t

_

o

1

i

n

_

o

1

i

n

_

o

1

w

5

frac{partial error}{partial w_5}= frac{partial error}{partial out_o_1}cdot frac{partial out_o_1}{partial in_o_1}cdot frac{partial in_o_1}{partial w_5}

w5error=out_o1errorin_o1out_o1w5in_o1

拆分计算,倒着看,先看

e

r

r

o

r

o

u

t

_

o

1

frac{partial error}{partial out_o_1}

out_o1error

e

r

r

o

r

o

u

t

_

o

1

frac{partial error}{partial out_o_1}

out_o1error

out→error用了MSE

M

S

E

=

1

m

i

=

1

m

(

y

i

y

^

i

)

²

MSE=frac{1}{m}sum_{i=1}^{m}(y_i-widehat{y}_i) ²

MSE=m1i=1m(yiy

i)²

反过来对这个过程求导,把y看做常数,最后得:

e

r

r

o

r

o

u

t

_

o

1

=

o

u

t

_

o

1

y

1

frac{partial error}{partial out_o_1}=out_o_1 - y_1

out_o1error=out_o1y1

 d_o1 = out_o1 - y1

o

u

t

_

o

1

i

n

_

o

1

frac{partial out_o_1}{partial in_o_1}

in_o1out_o1

用的激活函数是sigmoid,先看sigmoid函数求导:
在这里插入图片描述

o

u

t

_

o

1

i

n

_

o

1

=

o

u

t

_

o

1

(

1

o

u

t

_

o

1

)

frac{partial out_o_1}{partial in_o_1}=out_o_1 * (1-out_o_1)

in_o1out_o1=out_o1(1out_o1)

i

n

_

o

1

w

5

frac{partial in_o_1}{partial w_5}

w5in_o1

这个更简单了,单纯的相乘累加,out_h当做常量。

in_o1 = w5 * out_h1 + w7 * out_h2

求导得:

i

n

_

o

1

w

5

=

o

u

t

_

h

1

frac{partial in_o_1}{partial w_5}=out_h_1

w5in_o1=out_h1

代入

e

r

r

o

r

w

5

=

e

r

r

o

r

o

u

t

_

o

1

o

u

t

_

o

1

i

n

_

o

1

i

n

_

o

1

w

5

frac{partial error}{partial w_5}= frac{partial error}{partial out_o_1}cdot frac{partial out_o_1}{partial in_o_1}cdot frac{partial in_o_1}{partial w_5}

w5error=out_o1errorin_o1out_o1w5in_o1

把刚刚求得的值代进去:

d

_

w

5

=

e

r

r

o

r

w

5

=

(

o

u

t

_

o

1

y

1

)

o

u

t

_

o

1

(

1

o

u

t

_

o

1

)

o

u

t

_

h

1

d_w5 = frac{partial error}{partial w_5} = (out_o_1 - y_1) * out_o_1 * (1-out_o_1) * out_h_1

d_w5=w5error=(out_o1y1)out_o1(1out_o1)out_h1

以上代表了w5~w8的计算过程,同理可推w1:

因为w1的计算中同时穿过了w5和w6到达out_o1和out_o2

换句话说,w5和w5都是由h1出发的,在返回时也应该都返回到h1,

所以需要拆开计算:

e

r

r

o

r

w

1

=

e

r

r

o

r

o

u

t

_

o

1

o

u

t

_

o

1

w

1

+

e

r

r

o

r

o

u

t

_

o

2

o

u

t

_

o

2

w

1

frac{partial error}{partial w_1}= frac{partial error}{partial out_o_1}cdot frac{partial out_o_1}{partial w_1}+frac{partial error}{partial out_o_2}cdot frac{partial out_o_2}{partial w_1}

w1error=out_o1errorw1out_o1+out_o2errorw1out_o2

得:

 d_w1 = (d_w5 + d_w6) * out_h1 * (1 - out_h1) * x1

(写的有点草率,建议看mooc,详细解释了下图的推导)
在这里插入图片描述

更新权重

将算出的误差传递回去,更新w

w

=

w

+

η

e

r

r

o

r

w

w' = w + η * frac{partial error}{partial w}

w=w+ηwerror

η为学习率,也称作步长

def update_w(w1, w2, w3, w4, w5, w6, w7, w8):
    # 步长
    step = 5
    w1 = w1 - step * d_w1
    w2 = w2 - step * d_w2
    w3 = w3 - step * d_w3
    w4 = w4 - step * d_w4
    w5 = w5 - step * d_w5
    w6 = w6 - step * d_w6
    w7 = w7 - step * d_w7
    w8 = w8 - step * d_w8
    return w1, w2, w3, w4, w5, w6, w7, w8

好啦,这样就基本完成了一轮的计算,重复计算n轮就是修正n轮w的值,把这三个环节拼凑在一起,再加一个输入x、y和初始权重的主函数运行这三个函数就可以了。

全部代码及运行结果

import numpy as np


def sigmoid(z):
    a = 1 / (1 + np.exp(-z))
    return a

# 前向传播:
# in = sum(w*x)
# out = sigmoid(in)
# 两层传播
def forward_propagate(x1, x2, y1, y2, w1, w2, w3, w4, w5, w6, w7, w8):
    in_h1 = w1 * x1 + w3 * x2
    out_h1 = sigmoid(in_h1)
    in_h2 = w2 * x1 + w4 * x2
    out_h2 = sigmoid(in_h2)

    in_o1 = w5 * out_h1 + w7 * out_h2
    out_o1 = sigmoid(in_o1)
    in_o2 = w6 * out_h1 + w8 * out_h2
    out_o2 = sigmoid(in_o2)

    print("正向计算:o1 ,o2")    # 输出本轮进入损失函数之前的数值out1、out2
    print(round(out_o1, 5), round(out_o2, 5))   # round()舍入化整,round(x,y),y表保留小数后几位,此处保留5位小数

    # 损失函数MSE 均方误差:1/n * sum((y^-y)**2)
    # 此处只有2个y,所以n=2
    error = (1 / 2) * (out_o1 - y1) ** 2 + (1 / 2) * (out_o2 - y2) ** 2

    print("损失函数:均方误差")    # 输出本轮损失函数
    print(round(error, 5))

    return out_o1, out_o2, out_h1, out_h2   # 返回了两层out,用于反向传播


def back_propagate(out_o1, out_o2, out_h1, out_h2):
    # 反向传播
    d_o1 = out_o1 - y1
    d_o2 = out_o2 - y2
    # print(round(d_o1, 2), round(d_o2, 2))

    d_w5 = d_o1 * out_o1 * (1 - out_o1) * out_h1
    d_w7 = d_o1 * out_o1 * (1 - out_o1) * out_h2
    # print(round(d_w5, 2), round(d_w7, 2))
    d_w6 = d_o2 * out_o2 * (1 - out_o2) * out_h1
    d_w8 = d_o2 * out_o2 * (1 - out_o2) * out_h2
    # print(round(d_w6, 2), round(d_w8, 2))

    d_w1 = (d_w5 + d_w6) * out_h1 * (1 - out_h1) * x1
    d_w3 = (d_w5 + d_w6) * out_h1 * (1 - out_h1) * x2
    # print(round(d_w1, 2), round(d_w3, 2))

    d_w2 = (d_w7 + d_w8) * out_h2 * (1 - out_h2) * x1
    d_w4 = (d_w7 + d_w8) * out_h2 * (1 - out_h2) * x2
    # print(round(d_w2, 2), round(d_w4, 2))
    print("反向传播:误差传给每个权值")
    print(round(d_w1, 5), round(d_w2, 5), round(d_w3, 5), round(d_w4, 5), round(d_w5, 5), round(d_w6, 5),
          round(d_w7, 5), round(d_w8, 5))

    return d_w1, d_w2, d_w3, d_w4, d_w5, d_w6, d_w7, d_w8


def update_w(w1, w2, w3, w4, w5, w6, w7, w8):
    # 步长
    step = 5
    w1 = w1 - step * d_w1
    w2 = w2 - step * d_w2
    w3 = w3 - step * d_w3
    w4 = w4 - step * d_w4
    w5 = w5 - step * d_w5
    w6 = w6 - step * d_w6
    w7 = w7 - step * d_w7
    w8 = w8 - step * d_w8
    return w1, w2, w3, w4, w5, w6, w7, w8


if __name__ == "__main__":
    w1, w2, w3, w4, w5, w6, w7, w8 = 0.2, -0.4, 0.5, 0.6, 0.1, -0.5, -0.3, 0.8
    x1, x2 = 0.5, 0.3
    y1, y2 = 0.23, -0.07
    print("=====输入值:x1, x2;真实输出值:y1, y2=====")
    print(x1, x2, y1, y2)
    print("=====更新前的权值=====")
    print(round(w1, 2), round(w2, 2), round(w3, 2), round(w4, 2), round(w5, 2), round(w6, 2), round(w7, 2),
          round(w8, 2))

    for i in range(1000):
        print("=====第" + str(i) + "轮=====")
        out_o1, out_o2, out_h1, out_h2 = forward_propagate(x1, x2, y1, y2, w1, w2, w3, w4, w5, w6, w7, w8)
        d_w1, d_w2, d_w3, d_w4, d_w5, d_w6, d_w7, d_w8 = back_propagate(out_o1, out_o2, out_h1, out_h2)
        w1, w2, w3, w4, w5, w6, w7, w8 = update_w(w1, w2, w3, w4, w5, w6, w7, w8)

    print("更新后的权值")
    print(round(w1, 2), round(w2, 2), round(w3, 2), round(w4, 2), round(w5, 2), round(w6, 2), round(w7, 2),
          round(w8, 2))

运行结果

=输入值:x1, x2;真实输出值:y1, y2=
0.5 0.3 0.23 -0.07
=更新前的权值=
0.2 -0.4 0.5 0.6 0.1 -0.5 -0.3 0.8
=第0轮=
正向计算:o1 ,o2
0.47695 0.5287
损失函数:均方误差
0.20971
反向传播:误差传给每个权值
0.01458 0.01304 0.00875 0.00782 0.03463 0.08387 0.03049 0.07384
=第1轮=
正向计算:o1 ,o2
0.43556 0.42626
损失函数:均方误差
0.14427
反向传播:误差传给每个权值
0.0117 0.01039 0.00702 0.00623 0.02779 0.06674 0.02446 0.05873
………………
…………
……
=第998轮=
正向计算:o1 ,o2
0.23038 0.00955
损失函数:均方误差
0.00316
反向传播:误差传给每个权值
4e-05 3e-05 2e-05 2e-05 3e-05 0.00029 2e-05 0.00026
=第999轮=
正向计算:o1 ,o2
0.23038 0.00954
损失函数:均方误差
0.00316
反向传播:误差传给每个权值
4e-05 3e-05 2e-05 2e-05 3e-05 0.00029 2e-05 0.00026
更新后的权值
-0.84 -1.3 -0.13 0.06 -1.55 -7.31 -1.75 -5.23

——————————————————
参考:
【基础算法】损失函数——MSE与交叉熵 - 知乎
【人工智能导论:模型与算法】MOOC 8.3 误差后向传播(BP) 例题 编程验证 - HBU_DAVID - 博客园
【浙江大学】人工智能:模型与算法 8.3 误差后向传播(BP)

另外推荐一个,关于sigmoid在这里作为激活函数的局限性可以一看:
常见激活函数及其特点 - real-zhouyc - 博客园
用Markdown编辑器写公式,可以用富文本编辑器写好公式后左右两侧加$符号加入Markdown编辑器中,也可以直接敲公式如下:
Markdown数学公式语法 - 简书

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>