This commit is contained in:
xiaowuhu
2019-04-01 17:05:03 +08:00
committed by Annbless
parent 511f9f2532
commit 7e76f58aa5
56 changed files with 596 additions and 72 deletions
@@ -176,9 +176,9 @@ def ToBool(YData):
num_example = YData.shape[1]
Y = np.zeros((1, num_example))
for i in range(num_example):
if YData[0,i] == 0: # 第一类的标签设为0
if YData[0,i] == 1: # 第一类的标签设为0
Y[0,i] = 0
elif YData[0,i] == 1: # 第二类的标签设为1
elif YData[0,i] == 2: # 第二类的标签设为1
Y[0,i] = 1
# end if
# end for
@@ -142,20 +142,19 @@ $$
$$\frac{\partial{Z2}}{\partial{A1}} = \frac{\partial{(W2 \cdot A1 + B2)}}{\partial{A1}}=W2^T$$
$$\frac{\partial{A1}}{\partial{Z1}}=\frac{\partial{(Sigmoid(Z1))}}{\partial{Z1}}=A1 \cdot (1-A1)$$
$$\frac{\partial{A1}}{\partial{Z1}}=\frac{\partial{(Sigmoid(Z1))}}{\partial{Z1}}=A1 \odot (1-A1)$$
所以:
$$dZ1=\frac{\partial{J}}{\partial{Z1}} = \frac{\partial{J}}{\partial{Z2}} \cdot \frac{\partial{Z2}}{\partial{A1}} \cdot \frac{\partial{A1}}{\partial{Z1}}$$
$$=W2^T \cdot (Z2-Y) \cdot A1 \cdot (1-A1)$$
$$=W2^T \cdot dZ2 \cdot A1 \cdot (1-A1) \tag{4}$$
$$=W2^T \times dZ2 \odot A1 \odot (1-A1) \tag{4}$$
### 求W1的梯度
$$\frac{\partial{Z1}}{\partial{W1}} = \frac{\partial{(W1 \cdot X+B1)}}{\partial{W1}} = X^T$$
$$
dW1=\frac{\partial{J}}{\partial{W1}} = \frac{\partial{J}}{\partial{Z1}} \frac{\partial{Z1}}{\partial{W1}}= dZ1 \cdot X^T \tag{5}
dW1=\frac{\partial{J}}{\partial{W1}} = \frac{\partial{J}}{\partial{Z1}} \frac{\partial{Z1}}{\partial{W1}}= dZ1 \times X^T \tag{5}
$$
### 求B1的梯度
@@ -4,7 +4,8 @@ Copyright © Microsoft Corporation. All rights reserved.
# 知识点
- [解决异或问题](09.1-实现逻辑异或门.md)
- [非线性多分类](09.1-非线性多分类.md)
- [理解工作原理](09.2-理解工作原理].md)
- [非线性多分类](09.3-非线性多分类.md)
- [结果可视化与模块化设计](09.2-结果可视化与模块化设计.md)
@@ -19,6 +20,30 @@ Copyright © Microsoft Corporation. All rights reserved.
单层神经网络只能实现线性分类,虽然可以用一些特征的高阶形式来拟合有限的曲线,但要想实现真正的非线性分类,必须使用两层以上的神经网络。
# 用于分类的双层神经网络
和我们前面学到的线性分类器一样,双层神经网络也有二分类和多分类两种分类器。
这是二分类器:
<img src='./Images/9/binary_classifier.png' width="800"/>
- 输入层可以是任意数量的特征值
- 隐层的神经元数量要大于等于输入层特征值数量,并且需要Sigmoid或Tanh等激活函数
- 输出层用一个神经元,后接Sigmoid分类函数
- 损失函数用二分类交叉熵函数
这是多分类器,图中所示为三分类:
<img src='./Images/9/multiple_classifier.png' width="800"/>
- 输入层可以是任意数量的特征值
- 隐层的神经元数量要大于等于输入层特征值数量,并且需要Sigmoid或Tanh等激活函数
- 输出层用N个神经元,神经元的数量等于分类的数量,后接Sigmoid分类函数
- 损失函数用多分类交叉熵函数
# 工作原理
在两层神经网络的输出层,可以用和单层神经网络一样的结构来完成分类任务,而用隐层来完成非线性到线性的转换工作。我们可以通过以下几张图的比较来理解一下非线性到线性的转换。
以下图片均来自于[Christopher Olah的博客](https://colah.github.io/posts/2014-03-NN-Manifolds-Topology/)。
@@ -3,16 +3,60 @@ Copyright © Microsoft Corporation. All rights reserved.
# 实现逻辑异或门
## 简单证明异或的可能性
在1969年,一本著名的书《Perceptrons》(感知器,Minsky、Papert,1969)证明了无法使用单层网络(当时称为感知器)来表示最基本的异或逻辑功能。这本书带来了毁灭性的影响,对于神经网络这一新生领域的资金支持及兴趣都消失了。
50年前的书,就不要去找了,咱们自己简单地证明一下。先看样本数据:
|样本|1|2|3|4|
|----|----|----|----|---|
|x1|0|0|1|1|
|x2|0|1|0|1|
|y|0|1|1|0|
用单个神经元(感知机)的话,就是下图:
|神经元|激活函数 Sigmoid|
|-|-|
|<img src='./Images/9/xor_prove.png' width="400"/>|<img src='./Images/7/sigmoid_seperator.png' width="430"/>|
前向计算公式:
$$Z = w1 \cdot x1 + w2 \cdot x2 + b \tag{1}$$
$$A = Sigmoid(Z) \tag{2}$$
对于第一个样本数据,x1=0, x2=0, 如果需要A=0的话,从Sigmoid函数曲线看,需要Z<0,于是有:
$$w1 \cdot x1 + w2 \cdot x2 + b < 0$$
因为x1=0, x2=0, 所以:
$$b < 0 \tag{3}$$
同理,第二个样本和第三个样本的y值为1,要求Z值大于0,不等式为:
$$w2 + b > 0 \tag{4}$$
$$w1 + b > 0 \tag{5}$$
第四个样本要求Z小于0
$$w1 + w2 + b < 0 \tag{6}$$
把公式6两边都加b,并把公式3接续:
$$(w1 + b) + (w2 + b) < b < 0 \tag{7}$$
再看公式(4)(5),不等式左侧两个因子都大于0,其和必然也大于0,不可能小于b。因此无论如何也不能满足所有的4个样本的条件,所以单个神经元做异或是不可能的。
## 脑补理想的分类结果
因为当时还没有BP算法,所以深层神经网络无法实现。进入到两层神经网络后,我们将可以轻松地解决这个问题。看下图:
<img src='./Images/9/xor_task.png'/>
因为单层神经网络只能做线性分割,而上图中所示红蓝两色样本,用一条直线是不能分开的,于是人们脑补了那条曲线的分割方式,相当的fancy。但是神经网络真的会这样工作吗?
我们前边学习过来如何实现与、与非、或、或非,我们看看如何用已有的逻辑搭建异或:
## 利用已有的知识解决问题
我们前边学习过如何实现与、与非、或、或非,我们看看如何用已有的逻辑搭建异或门:
<img src='./Images/9/xor_gate.png'/>
@@ -20,70 +64,96 @@ Copyright © Microsoft Corporation. All rights reserved.
|----|----|----|----|----|
|x1|0|0|1|1|
|x2|0|1|0|1|
|s1=NAND|1|1|1|0|
|s2=OR|0|1|1|1|
|y=AND|0|1|1|0|
|x1 AND x2|0|0|0|1|
|s1=x1 NAND x2|1|1|1|0|
|s2=x1 OR x1|0|1|1|1|
|y=s1 AND s2|0|1|1|0|
经过以上组合运算后,可以看到y的输出与x1,x2的输入相比,就是异或逻辑了。
经过以上组合运算后,可以看到y的输出与x1,x2的输入相比,就是异或逻辑了。所以,实践证明两层神经网络可以解决问题。我们可以模拟这个思路,用两层神经网络搭建如下模型:
所以,我们可以模拟这个思路,用两层神经网络搭建如下模型:
## 搭建神经网络
<img src='./Images/9/xor_nn_gate.png'/>
<img src='./Images/9/xor_nn.png'/>
隐层的两个神经元接收x1,x2的输入,输出层有一个神经元负责分类。
- 输入层两个特征值x1, x2
- 隐层2x2的权重矩阵和2x1的偏移矩阵
- 隐层由两个神经元构成
- 输出层有一个神经元使用Sigmoid函数进行分类
## 前向计算
根据网络结构,我们有了前向计算图:
<img src='./Images/9/binary_forward.png'/>
$$Z1 = W1 \cdot X + B1 \tag{10}$$
$$A1 = Sigmoid(Z1) \tag{11}$$
$$Z2 = W2 \cdot A1 + B2 \tag{12}$$
$$A2 = Sigmoid(Z2) \tag{13}$$
**注意:公式13的Sigmoid在这里不是激活函数,不是激活函数,不是激活函数(重要的概念说三遍),是用作分类函数。**
## 损失函数
我们把异或问题归类成二分类问题,所以使用二分类交叉熵损失函数:
$$
J(w,b) = -{1 \over m} \sum^m_{i=1}y_i \ln (a_i)+(1-y_i) \ln (1-a_i) \tag{14}
$$
可以简写为:
$$
J = -Y \ln A + (1-Y) \ln (1-A) \tag{15}
$$
## 反向传播
<img src='./Images/9/binary_backward.png'/>
|||
|---|---|
|<img src='./Images/9/binary_result_1.png'/>|<img src='./Images/9/binary_result_2.png'/>|
|<img src='./Images/9/binary_result_3.png'/>|<img src='./Images/9/binary_result_4.png'/>|
|<img src='./Images/9/binary_result_5.png'/>|<img src='./Images/9/binary_result_6.png'/>|
|<img src='./Images/9/binary_result_7.png'/>|<img src='./Images/9/binary_result_8.png'/>|
### 梯度生成
对损失函数求导,可以得到损失函数对输出层的梯度值,即上图中的Z2部分。
以下是隐层为两个神经元时的结果输出
根据公式15,求A2和Z2的导数
$${\partial{J} \over \partial{Z2}}={\partial{J} \over \partial{A2}} \cdot {\partial{A2} \over \partial{Z2}}$$
$$= {A2-Y \over A2(1-A2)} \cdot A2(1-A2)$$
$$=A2-Y \tag{15} => dZ2$$
### 求W2和B2的梯度
$${\partial{J} \over \partial{W2}}={\partial{J} \over \partial{Z2}}{\partial{Z2} \over \partial{W2}}=dZ2 \times A1^T => dW2\tag{16}$$
$${\partial{J} \over \partial{B2}}={\partial{J} \over \partial{Z2}}{\partial{Z2} \over \partial{B2}}=dZ2 => dB2 \tag{17}$$
### 求损失函数对隐层的梯度
$$
\frac{\partial{J}}{\partial{Z1}} = \frac{\partial{J}}{\partial{Z2}} \cdot \frac{\partial{Z2}}{\partial{A1}} \cdot \frac{\partial{A1}}{\partial{Z1}}
$$
$$=W2^T \times dZ2 \odot A1 \odot (1-A1)=>dZ1 \tag{18}$$
### 求W1和B1的梯度
$$
\frac{\partial{J}}{\partial{W1}} = \frac{\partial{J}}{\partial{Z1}} \frac{\partial{Z1}}{\partial{W1}}= dZ1 \times X^T => dW1\tag{19}
$$
$$
\frac{\partial{J}}{\partial{B1}} = \frac{\partial{J}}{\partial{Z1}} \frac{\partial{Z1}}{\partial{B1}}= dZ1 => dB1\tag{20}
$$
## 运行结果
```
epoch=6039, loss=0.005000
epoch=6040, loss=0.004999
epc=6040,ite=3,los=0.0050
w=[[-7.00777143 -7.01121059]
[ 5.51518649 5.51451102]]
b=[[ 2.86885647]
[-8.53863829]]
w=[[-12.0633545 -12.23675401]]
b=[[5.95925939]]
testing...
x=[[0] [0]] y=[[0]] output=[[0.00424183]]
True
x=[[0] [1]] y=[[1]] output=[[0.99453265]]
True
x=[[1] [0]] y=[[1]] output=[[0.99452718]]
True
x=[[1] [1]] y=[[0]] output=[[0.00476486]]
True
```
后面的testing...为测试结果,精度为1e-2。
<img src='./Images/9/binary_result_2.png'/>
||1|2|3|4|
|---|---|---|---|---|
|x1|0|0|1|1|
|x2|0|1|0|1|
|y|0|1|1|0|
|Z1|2.86885647|-4.14235412|-4.13891495|-11.15012554|
||-8.53863829|-3.02412727|-3.0234518|2.49105922|
|A1|9.46285253e-01|1.56370110e-02|1.56900366e-02 |1.43732759e-05|
||1.95718330e-04|4.63477089e-02|4.63775738e-02|9.23512657e-01|
|Z2|-5.45851003|5.20347907|5.20247396|-5.3417112|
|A2|0.00424183|0.99453265|0.99452718|0.00476486|
|||
|---|---|
|<img src='./Images/9/xor_x1x2.png'/>|<img src='./Images/9/xor_z1.png'/>|
|<img src='./Images/9/xor_a1.png'/>|<img src='./Images/9/xor_z2a2.png'/>|
代码位置:ch09, Level0, Level1
@@ -0,0 +1,147 @@
Copyright © Microsoft Corporation. All rights reserved.
适用于[License](https://github.com/Microsoft/ai-edu/blob/master/LICENSE.md)版权许可
# 理解工作原理
我们在上一节课的代码基础上再增加些东西,来理解神经网络针对这个异或问题的工作原理。
## 隐层神经元数量的选择
一般来说,隐层的神经元数量要大于等于输入特征的数量,在本例中是2。我们从下图可以看到,如果隐层只有一个神经元的话,是不能完成分类任务的。
|||
|---|---|
|<img src='./Images/9/binary_result_1.png'/>|<img src='./Images/9/binary_result_2.png'/>|
|1个神经元|2个神经元,迭代6040次到达精度要求|
|<img src='./Images/9/binary_result_3.png'/>|<img src='./Images/9/binary_result_4.png'/>|
|3个神经元,迭代5228次到达精度要求|4个神经元,迭代4331次到达精度要求|
|<img src='./Images/9/binary_result_5.png'/>|<img src='./Images/9/binary_result_6.png'/>|
|5个神经元,迭代4171次到达精度要求|6个神经元,迭代3903次到达精度要求|
|<img src='./Images/9/binary_result_7.png'/>|<img src='./Images/9/binary_result_8.png'/>|
|7个神经元,迭代5031次到达精度要求|8个神经元,迭代4107次到达精度要求|
## 隐层有两个神经元的工作原理
以下是隐层为两个神经元时的结果输出:
```
w=[[-7.00777143 -7.01121059]
[ 5.51518649 5.51451102]]
b=[[ 2.86885647]
[-8.53863829]]
```
我们使用上面的权重矩阵结果,把4个样本数据代入到前向计算公式中,依次求得Z1,A1,Z2,A2的值,并列表如下:
||1|2|3|4|
|---|---|---|---|---|
|x1|0|0|1|1|
|x2|0|1|0|1|
|y|0|1|1|0|
|Z1|2.86885647|-4.14235412|-4.13891495|-11.15012554|
||-8.53863829|-3.02412727|-3.0234518|2.49105922|
|A1|9.46285253e-01|1.56370110e-02|1.56900366e-02 |1.43732759e-05|
||1.95718330e-04|4.63477089e-02|4.63775738e-02|9.23512657e-01|
|Z2|-5.45851003|5.20347907|5.20247396|-5.3417112|
|A2|0.00424183|0.99453265|0.99452718|0.00476486|
|||
|---|---|
|<img src='./Images/9/xor_x1x2.png'/>|<img src='./Images/9/xor_z1.png'/>|
|<img src='./Images/9/xor_a1.png'/>|<img src='./Images/9/xor_z2a2.png'/>|
|损失函数值||
|---|---|
|<img src='./Images/9/xor_2_500_loss.png'/>|<img src='./Images/9/xor_2_800_loss.png'/>|
|500次迭代|800次迭代|
|<img src='./Images/9/xor_2_1000_loss.png'/>|<img src='./Images/9/binary_loss_2.png'/>|
|1000次迭代|6000次迭代|
|Z1||
|---|---|
|<img src='./Images/9/xor_2_500_z1.png'/>|<img src='./Images/9/xor_2_800_z1.png'/>|
|500次迭代|800次迭代|
|<img src='./Images/9/xor_2_1000_z1.png'/>|<img src='./Images/9/xor_z1.png'/>|
|1000次迭代|6000次迭代|
|A1||
|---|---|
|<img src='./Images/9/xor_2_500_a1.png'/>|<img src='./Images/9/xor_2_800_z1.png'/>|
|500次迭代|800次迭代|
|<img src='./Images/9/xor_2_1000_z1.png'/>|<img src='./Images/9/xor_z1.png'/>|
|1000次迭代|6000次迭代|
|Z1:A1||
|---|---|
|<img src='./Images/9/xor_2_500_z2a2.png'/>|<img src='./Images/9/xor_2_800_z2a2.png'/>|
|500次迭代|800次迭代|
|<img src='./Images/9/xor_2_1000_z2a2.png'/>|<img src='./Images/9/xor_z2a2.png'/>|
|1000次迭代|6000次迭代|
|分类结果||
|---|---|
|<img src='./Images/9/xor_2_500_result.png'/>|<img src='./Images/9/xor_2_800_result.png'/>|
|500次迭代|800次迭代|
|<img src='./Images/9/xor_2_1000_result.png'/>|<img src='./Images/9/binary_result_2.png'/>|
|1000次迭代|6000次迭代|
## 隐层有三个神经元的工作原理
最终输出的权重矩阵值:
```
[[ 6.70984241 -6.82710114]
[ 6.22781451 -5.99280808]
[-2.74806343 2.4870413 ]]
b=[[-3.51362288]
[ 3.15804745]
[-1.4773994 ]]
w=[[12.31224597 -9.738143 3.80483026]]
b=[[3.05151459]]
```
迭代5000次到达精度要求的各层的网络输出:
||1|2|3|4|
|---|---|---|---|---|
|x1|0|0|1|1|
|x2|0|1|0|1|
|y|0|1|1|0|
|Z1|3.51362288|-10.34072402|3.19621952|-3.63088162|
||3.15804745|-2.83476063|9.38586196|3.39305388|
||-1.4773994|1.00964189|-4.22546284|-1.73842154|
|A1|2.89270940e-02| 3.22898922e-05 |9.60691763e-01| 2.58090628e-02|
||9.59224645e-01| 5.54744264e-02| 9.99916105e-01| 9.67486745e-01|
||1.85820545e-01| 7.32950061e-01| 1.44079436e-02| 1.49513539e-01|
|Z2|-5.22637905| 5.30044483 | 5.19728163 |-5.48336852|
|A2|0.00534423 |0.9950354 | 0.99449885 |0.00413811|
我们可以把Z1,A1看作是一个三维的坐标点,并比较迭代200次与迭代5000次的结果,从而了解神经网络的工作过程:
||迭代200次|迭代5000次|
|---|---|---|
|初始|<img src='./Images/9/xor_x1x2.png'/>|<img src='./Images/9/xor_x1x2.png'/>
|Z1-1|<img src='./Images/9/xor_3_200_z1_1.png'/>|<img src='./Images/9/xor_3_5000_z1_1.png'/>|
||两个红色点距离较远|两个红色点距离很近|
|Z1-2|<img src='./Images/9/xor_3_200_z1_2.png'/>|<img src='./Images/9/xor_3_5000_z1_3.png'/>|
||绿色点从一开始就已经分得很开|绿色点的距离越来越远|
|Z1-3|<img src='./Images/9/xor_3_200_z1_3.png'/>|<img src='./Images/9/xor_3_5000_z1_2.png'/>|
||从某一角度看4个点在一条直线上||
|A1-1|<img src='./Images/9/xor_3_200_a1_1.png'/>|<img src='./Images/9/xor_3_5000_a1_1.png'/>|
||红点较散|红点缩到了一个角落里|
|A1-2|<img src='./Images/9/xor_3_200_a1_2.png'/>|<img src='./Images/9/xor_3_5000_a1_2.png'/>|
|A1-3|<img src='./Images/9/xor_3_200_a1_3.png'/>|<img src='./Images/9/xor_3_5000_a1_3.png'/>|
|Z2|<img src='./Images/9/xor_3_200_z2a2.png'/>|<img src='./Images/9/xor_3_5000_z2a2.png'/>|
||两种颜色的点没有分开|彻底分开了|
|A2|<img src='./Images/9/xor_3_200_result.png'/>|<img src='./Images/9/xor_3_5000_result.png'/>|
||没有完成|理想分类|
代码位置:ch09, Level2_HowXorGateEorks(两个神经元的情况), Level2_LogicXorGate3D(三个神经元的情况)
@@ -1,12 +1,12 @@
Copyright © Microsoft Corporation. All rights reserved.
适用于[License](https://github.com/Microsoft/ai-edu/blob/master/LICENSE.md)版权许可
# 非线性多分类实现
# 非线性多分类
# 提出问题
前面我们学习了线性二分类与多分类。升级为两层的神经网络之后,我们看看如何用它来做非线性的二分类与多分类。
前面用异或问题学习了二分类,现在我们看看如何用它来做非线性多分类。
我们有如下1000个样本和标签:
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@@ -0,0 +1,127 @@
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import math
from LossFunction import *
from Activators import *
from Level0_TwoLayerClassificationNet import *
from DataReader import *
from WeightsBias import *
# x1=0,x2=0,y=0
# x1=0,x2=1,y=1
# x1=1,x2=0,y=1
# x1=1,x2=1,y=0
class XOR_DataReader():
def __init__(self):
pass
def ReadData(self):
self.X = np.array([0,0,1,1,0,1,0,1]).reshape(2,4)
self.Y = np.array([0,1,1,0]).reshape(1,4)
self.num_example = self.X.shape[1]
self.num_feature = self.X.shape[0]
self.num_category = 1
def GetBatchSamples(self, batch_size, iteration):
start = iteration * batch_size
end = start + batch_size
batch_X = self.X[0:self.num_feature, start:end].reshape(self.num_feature, batch_size)
batch_Y = self.Y[:, start:end].reshape(-1, batch_size)
return batch_X, batch_Y
def ShowAreaResult(net, wb1, wb2, title):
count = 50
x1 = np.linspace(0,1,count)
x2 = np.linspace(0,1,count)
for i in range(count):
for j in range(count):
x = np.array([x1[i],x2[j]]).reshape(2,1)
dict_cache = net.ForwardCalculationBatch2(x, wb1, wb2)
output = dict_cache["Output"]
if output[0,0] >= 0.5:
plt.plot(x[0,0], x[1,0], 's', c='m')
else:
plt.plot(x[0,0], x[1,0], 's', c='y')
# end if
# end for
# end for
plt.title(title)
#end def
def ShowData(X, Y):
for i in range(X.shape[1]):
if Y[0,i] == 0:
plt.plot(X[0,i], X[1,i], '^', c='r')
elif Y[0,i] == 1:
plt.plot(X[0,i], X[1,i], '.', c='g')
# end if
# end for
plt.xlabel("x1")
plt.ylabel("x2")
plt.show()
def Test(dataReader, net, wb1, wb2):
print("testing...")
for i in range(dataReader.num_example):
x,y = dataReader.GetBatchSamples(1, i)
dict_output = net.ForwardCalculationBatch2(x, wb1, wb2)
output = dict_output["Output"]
print(str.format("x={0} y={1} output={2}", x, y, output))
if np.abs(output - y) < 1e-2:
print("True")
else:
print("False")
#end if
#end for
def SaveWeights(wb1, wb2):
np.save("xor_w1_2_2.npy", wb1.W)
np.save("xor_w1_2_1.npy", wb1.B)
np.save("xor_w2_1_2.npy", wb2.W)
np.save("xor_w2_1_1.npy", wb2.B)
def train():
dataReader = XOR_DataReader()
dataReader.ReadData()
n_input, n_output = dataReader.num_feature, dataReader.num_category
n_hidden = 2
eta, batch_size, max_epoch = 0.1, 1, 10000
eps = 0.005
params = CParameters(n_input, n_hidden, n_output, eta, max_epoch, batch_size, eps, LossFunctionName.CrossEntropy2)
loss_history = CLossHistory()
net = TwoLayerClassificationNet()
#ShowData(XData, YData)
wb1, wb2 = net.train(dataReader, params, loss_history)
trace = loss_history.GetMinimalLossData()
print(trace.toString())
title = loss_history.ShowLossHistory(params)
print(wb1.toString())
print(wb2.toString())
print("wait for 10 seconds...")
ShowAreaResult(net, trace.wb1, trace.wb2, title)
ShowData(dataReader.X, dataReader.Y)
Test(dataReader, net, wb1, wb2)
SaveWeights(wb1, wb2)
if __name__ == '__main__':
train()
@@ -0,0 +1,145 @@
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import math
from LossFunction import *
from Activators import *
from Level0_TwoLayerClassificationNet import *
from DataReader import *
from WeightsBias import *
# x1=0,x2=0,y=0
# x1=0,x2=1,y=1
# x1=1,x2=0,y=1
# x1=1,x2=1,y=0
class XOR_DataReader():
def __init__(self):
pass
def ReadData(self):
self.X = np.array([0,0,1,1,0,1,0,1]).reshape(2,4)
self.Y = np.array([0,1,1,0]).reshape(1,4)
self.num_example = self.X.shape[1]
self.num_feature = self.X.shape[0]
self.num_category = 1
def GetBatchSamples(self, batch_size, iteration):
start = iteration * batch_size
end = start + batch_size
batch_X = self.X[0:self.num_feature, start:end].reshape(self.num_feature, batch_size)
batch_Y = self.Y[:, start:end].reshape(-1, batch_size)
return batch_X, batch_Y
def ShowAreaResult(net, wb1, wb2, title):
count = 50
x1 = np.linspace(0,1,count)
x2 = np.linspace(0,1,count)
for i in range(count):
for j in range(count):
x = np.array([x1[i],x2[j]]).reshape(2,1)
dict_cache = net.ForwardCalculationBatch2(x, wb1, wb2)
output = dict_cache["Output"]
if output[0,0] >= 0.5:
plt.plot(x[0,0], x[1,0], 's', c='m')
else:
plt.plot(x[0,0], x[1,0], 's', c='y')
# end if
# end for
# end for
plt.title(title)
#end def
def ShowData(X, Y):
for i in range(X.shape[1]):
if Y[0,i] == 0:
plt.plot(X[0,i], X[1,i], '^', c='r')
elif Y[0,i] == 1:
plt.plot(X[0,i], X[1,i], '.', c='g')
# end if
# end for
plt.xlabel("x1")
plt.ylabel("x2")
plt.show()
def LoadWeights(wb1, wb2):
wb1.W = np.load("xor_w1_2_2.npy")
wb1.B = np.load("xor_w1_2_1.npy")
wb2.W = np.load("xor_w2_1_2.npy")
wb2.B = np.load("xor_w2_1_1.npy")
def ShowZ1A1Z2A2():
wb1 = WeightsBias(2,2,0.1,InitialMethod.Xavier)
wb2 = WeightsBias(1,2,0.1,InitialMethod.Xavier)
LoadWeights(wb1, wb2)
print(wb1.toString())
print(wb2.toString())
dataReader = XOR_DataReader()
dataReader.ReadData()
Z1 = np.dot(wb1.W, dataReader.X) + wb1.B
A1 = Sigmoid().forward(Z1)
# layer 2
Z2 = np.dot(wb2.W, A1) + wb2.B
A2 = Sigmoid().forward(Z2)
print(Z1)
print(A1)
print(Z2)
print(A2)
for i in range(dataReader.num_example):
if dataReader.Y[0,i] == 0:
plt.plot(dataReader.X[0,i],dataReader.X[1,i],'^',c='r')
else:
plt.plot(dataReader.X[0,i],dataReader.X[1,i],'o',c='g')
plt.grid()
plt.title("X1:X2")
plt.show()
for i in range(dataReader.num_example):
if dataReader.Y[0,i] == 0:
plt.plot(Z1[0,i],Z1[1,i],'^',c='r')
else:
plt.plot(Z1[0,i],Z1[1,i],'o',c='g')
plt.grid()
plt.title("Z1")
plt.show()
for i in range(dataReader.num_example):
if dataReader.Y[0,i] == 0:
plt.plot(A1[0,i],A1[1,i],'^',c='r')
else:
plt.plot(A1[0,i],A1[1,i],'o',c='g')
plt.grid()
plt.title("A1")
plt.show()
x = np.linspace(-6,6)
a = Sigmoid().forward(x)
plt.plot(x,a)
for i in range(dataReader.num_example):
if dataReader.Y[0,i] == 0:
plt.plot(Z2[0,i],A2[0,i],'^',c='r')
else:
plt.plot(Z2[0,i],A2[0,i],'o',c='g')
plt.grid()
plt.title("Z2:A2")
plt.show()
if __name__ == '__main__':
# 每次运行之前,需要把level1中的Line 98, max_epoch的数字从小改到大,比如200,400,600,800,1000,...
# 每改一次max_epoch,运行一次level1,生成权重值并自动保存,再运行一次本程序绘图
ShowZ1A1Z2A2()
@@ -4,7 +4,7 @@
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import math
from mpl_toolkits.mplot3d import Axes3D
from LossFunction import *
from Activators import *
@@ -94,7 +94,7 @@ def train():
dataReader.ReadData()
n_input, n_output = dataReader.num_feature, dataReader.num_category
n_hidden = 2
n_hidden = 3
eta, batch_size, max_epoch = 0.1, 1, 10000
eps = 0.005
@@ -122,7 +122,7 @@ def train():
Test(dataReader, net, wb1, wb2)
SaveWeights(wb1, wb2)
def LoadWeights(wb1, wb2):
wb1.W = np.load("xor_w1_2_2.npy")
wb1.B = np.load("xor_w1_2_1.npy")
@@ -160,22 +160,28 @@ def ShowZ1A1Z2A2():
plt.title("X1:X2")
plt.show()
fig = plt.figure()
ax = Axes3D(fig)
for i in range(dataReader.num_example):
if dataReader.Y[0,i] == 0:
plt.plot(Z1[0,i],Z1[1,i],'^',c='r')
ax.scatter(Z1[0,i],Z1[1,i],Z1[2,i],c='r')
#ax.plot(Z1[0,i],Z1[1,i],Z1[2,i],c='r')
else:
plt.plot(Z1[0,i],Z1[1,i],'o',c='g')
ax.scatter(Z1[0,i],Z1[1,i],Z1[2,i],c='g')
#ax.plot(Z1[0,i],Z1[1,i],Z1[2,i],c='g')
plt.grid()
plt.title("Z1")
plt.show()
fig = plt.figure()
ax = Axes3D(fig)
for i in range(dataReader.num_example):
if dataReader.Y[0,i] == 0:
plt.plot(A1[0,i],A1[1,i],'^',c='r')
ax.scatter(A1[0,i],A1[1,i],A1[2,i],'^',c='r')
#plt.plot(A1[0,i],A1[1,i],A1[2,i],'^',c='r')
else:
plt.plot(A1[0,i],A1[1,i],'o',c='g')
ax.scatter(A1[0,i],A1[1,i],A1[2,i],'o',c='g')
#plt.plot(A1[0,i],A1[1,i],A1[2,i],'o',c='g')
plt.grid()
plt.title("A1")
plt.show()
@@ -195,4 +201,7 @@ def ShowZ1A1Z2A2():
if __name__ == '__main__':
train()
# 每次运行之前,需要把level1中的Line 98, max_epoch的数字从小改到大,比如200,400,600,800,1000,...
# 每改一次max_epoch,运行一次level1,生成权重值并自动保存,再运行一次本程序绘图
ShowZ1A1Z2A2()
@@ -8,7 +8,7 @@ import math
from LossFunction import *
from Activators import *
from Level1_TwoLayerClassificationNet import *
from Level0_TwoLayerClassificationNet import *
from DataReader import *
from WeightsBias import *
@@ -22,7 +22,7 @@ def ShowAreaResult(net, wb1, wb2, title):
for i in range(count):
for j in range(count):
x = np.array([x1[i],x2[j]]).reshape(2,1)
dict_cache = net.ForwardCalculationBatch(x, wb1, wb2)
dict_cache = net.ForwardCalculationBatch3(x, wb1, wb2)
output = dict_cache["Output"]
r = np.argmax(output, axis=0)
if r == 0:
@@ -4,7 +4,7 @@
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>3de29cfe-16a6-493d-97b3-e617074af796</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>Level2_LogicXorGate.py</StartupFile>
<StartupFile>Level3_Classifier.py</StartupFile>
<SearchPath>
</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
@@ -24,8 +24,10 @@
<Compile Include="Activators.py" />
<Compile Include="DataReader.py" />
<Compile Include="Level0_TwoLayerClassificationNet.py" />
<Compile Include="Level2_LogicXorGate.py" />
<Compile Include="Level2_Classifier.py" />
<Compile Include="Level2_LogicXorGate3D.py" />
<Compile Include="Level2_HowXorGateWorks.py" />
<Compile Include="Level1_LogicXorGate.py" />
<Compile Include="Level3_Classifier.py" />
<Compile Include="LossFunction.py" />
<Compile Include="Parameters.py">
<SubType>Code</SubType>