
《DLS》第二章笔记:感知机
2.1 感知机
2.1.1 神经元
对于生物学意义上的神经元,一个神经元具有多个树突接收输入信号,一个细胞主体处理输入信号,一个轴突传递输出信号,如下图:<br /><br /> 将神经元抽象为一个算法模型:<br /><br /> 我们将这个模型称为人工神经元,也称感知机。
2.1.2 感知机的组成
一个感知机由输入权值、激活函数、输出三部分组成。
%5C%5C%0A1%2C(b%2Bw%7B1%7Dx%7B1%7D%2Bw%7B2%7Dx%7B2%7D%2B…%2Bw%7Bn%7Dx%7Bn%7D%3E0)%5C%5C%0A%5Cend%7Bcases%7D%0A#card=math&code=y%3D%5Cbegin%7Bcases%7D%0A0%2C%28b%2Bw%7B1%7Dx%7B1%7D%2Bw%7B2%7Dx%7B2%7D%2B…%2Bw%7Bn%7Dx%7Bn%7D%5Cleq%200%29%5C%5C%0A1%2C%28b%2Bw%7B1%7Dx%7B1%7D%2Bw%7B2%7Dx%7B2%7D%2B…%2Bw%7Bn%7Dx%7Bn%7D%3E0%29%5C%5C%0A%5Cend%7Bcases%7D%0A&id=qjYZo)
输入权值:一个感知机可以接收多个输入#card=math&code=x_%7B1%7D%EF%BC%8Cx_%7B2%7D%EF%BC%8C...%EF%BC%8Cx_%7Bn%7D%28x_%7Bi%7D%5Cin%5Cmathbb%7BR%7D%29&id=Jf4Fp),每个输入上有一个权重值,此外还有一个偏置项,即。输入信号被送往神经元时会被分别乘以固定的权重。<br /> (权重是控制输入信号重要性的参数,偏置是调整神经元被激活的容易程度的参数)
激活函数:#card=math&code=f%28x%29&id=E9JAX) 决定如何来计算输入信号的总和。只有当总和超过某个界限时,才会输出1,即“神经元被激活”,这个界限值被称为阈值。
输出:输出 #card=math&code=y%3Df%28x%29&id=dnOwc),输出值只有两个,即0或1。总和超过阈值时输出1,总和未超过阈值时输出0。
2.1.3 神经元和感知机的对应关系
| 神经元 |
感知机 |
| 树突接收的信号 |
输入权值 |
| 细胞主体 |
激活函数 |
| 轴突输出的信号 |
输出 |
2.2 逻辑门
2.2.1 与门
与门对应逻辑运算“与”,真值表如下:<br /><br /> 用感知机实现与门,实际上就是寻找一组能满足与门真值表的、、的值。这样的值有无数多个,选择不同的值就是选择不同的权重。
Python实现:
import numpy as np
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.7
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
x1, x2 = map(int, input().split())
print(AND(x1, x2))
C++实现:
#include<iostream>
using namespace std;
bool AND(bool x1,bool x2);
int main()
{
bool x1,x2;
cin>>x1>>x2;
cout<<AND(x1,x2);
return 0;
}
bool AND(bool x1,bool x2)
{
double w1 = 0.5,w2 = 0.5,b = -0.7;
double tmp = x1*w1+x2*w2+b;
return tmp <= 0 ? 0 : 1;
}
2.2.2 与非门
与非门对应逻辑运算“与”和“非”,真值表如下:<br /><br /> 与非门的输出实际上就是颠倒了与门的输出,只要把实现与门的参数值、、取反就可以实现与非门。
Python实现:
import numpy as np
def NAND(x1,x2):
x = np.array([x1,x2])
w = np.array([-0.5,-0.5])
b = 0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
x1, x2 = map(int, input().split())
print(AND(x1, x2))
C++实现:
#include<iostream>
using namespace std;
bool NAND(bool x1,bool x2);
int main()
{
bool x1,x2;
cin>>x1>>x2;
cout<<NAND(x1,x2);
return 0;
}
bool NAND(bool x1,bool x2)
{
double w1 = -0.5,w2 = -0.5,b = 0.7;
double tmp = x1*w1+x2*w2+b;
return tmp <= 0 ? 0 : 1;
}
2.2.3 或门
或门对应逻辑运算“或”,真值表如下:<br /><br /> 用感知机实现或门,实际上就是寻找一组能满足或门真值表的、、的值。这样的值有无数多个,选择不同的值就是选择不同的权重。<br /> Python实现:
import numpy as np
def OR(x1,x2):
x = np.array([x1,x2])
w = np.array([0.5,0.5])
b = -0.2
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
x1, x2 = map(int, input().split())
print(AND(x1, x2))
C++实现:
#include<iostream>
using namespace std;
bool OR(bool x1,bool x2);
int main()
{
bool x1,x2;
cin>>x1>>x2;
cout<<OR(x1,x2);
return 0;
}
bool OR(bool x1,bool x2)
{
double w1 = 0.5,w2 = 0.5,b = -0.2;
double tmp = x1*w1+x2*w2+b;
return tmp <= 0 ? 0 : 1;
}
与门、与非门和或门是具有相同结构的感知机,区别只在于权重参数的值。
2.2.4 异或门
异或门对应逻辑运算“异或”,真值表如下:<br /><br /> 异或(XOR)的运算是特性是“相同为0,不同为1”,即仅当或中的一方为1时,才会输出1(“异或”是拒绝其他的意思)。简单实践就可发现,我们无法用单层感知机实现异或门。
2.3 多层感知机
2.3.1或门可视化
对于或门
def OR(x1,x2):
x = np.array([x1,x2])
w = np.array([0.5,0.5])
b = -0.2
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
表示$$y=\begin{cases}<br />0,(-0.5+x_{1}+w_{2}\leq 0)\<br />1,(-0.5+x_{1}+w_{2}>0)\<br />\end{cases} 即,坐标系被直线−0.5 + x1 + x2 = 0分割开的两个空间。其中一个空间输出1,另一个空间输出0。<br />
2.3.2异或门可视化
对于异或门<br /><br /> 显然,无法使用一条直线把三角和圆圈分割开来,考虑:<br /><br /> 即通过与门、或门、与非门的组合来实现异或门。<br /><br /> 寻找实现异或门的组合:

2.3.3 异或门的实现
列出与门的真值表:
 |
 |
(AND) |
| 0 |
0 |
0 |
| 1 |
0 |
0 |
| 0 |
1 |
0 |
| 1 |
1 |
1 |
列出与非门的真值表:
 |
 |
(NAND) |
| 0 |
0 |
1 |
| 1 |
0 |
0 |
| 0 |
1 |
0 |
| 1 |
1 |
0 |
列出或门的真值表:
 |
 |
(OR) |
| 0 |
0 |
0 |
| 1 |
0 |
1 |
| 0 |
1 |
1 |
| 1 |
1 |
1 |
则可发现:
(NAND) |
(OR) |
(AND) |
| 1 |
0 |
0 |
| 1 |
1 |
1 |
| 1 |
1 |
1 |
| 0 |
1 |
0 |
因此可作如下组合:<br /><br /> Python实现:
import numpy as np
def AND(x1,x2):
x = np.array([x1,x2])
w = np.array([0.5,0.5])
b = -0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
def NAND(x1,x2):
x = np.array([x1,x2])
w = np.array([-0.5,-0.5])
b = 0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
def OR(x1,x2):
x = np.array([x1,x2])
w = np.array([0.5,0.5])
b = -0.2
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
x1, x2 = map(int, input().split())
print(XOR(x1, x2))
C++实现:
#include<iostream>
using namespace std;
bool AND(bool x1,bool x2);
bool NAND(bool x1,bool x2);
bool OR(bool x1,bool x2);
bool XOR(bool x1,bool x2);
int main()
{
bool x1,x2;
cin>>x1>>x2;
cout<<XOR(x1,x2);
return 0;
}
bool AND(bool x1,bool x2)
{
double w1 = 0.5,w2 = 0.5,b = -0.7;
double tmp = x1*w1+x2*w2+b;
return tmp <= 0 ? 0 : 1;
}
bool NAND(bool x1,bool x2)
{
double w1 = -0.5,w2 = -0.5,b = 0.7;
double tmp = x1*w1+x2*w2+b;
return tmp <= 0 ? 0 : 1;
}
bool OR(bool x1,bool x2)
{
double w1 = 0.5,w2 = 0.5,b = -0.2;
double tmp = x1*w1+x2*w2+b;
return tmp <= 0 ? 0 : 1;
}
bool XOR(bool x1,bool x2)
{
double s1 = NAND(x1, x2);
double s2 = OR(x1, x2);
double y = AND(s1,s2);
return y;
}
2.3.4 多层感知机
叠加了超过两层的感知机被称为多层感知机,异或门就是通过双层感知机实现的。多层感知机可以实现单层感知机实现不了的结构,通过叠加层(加深层),感知机能进行更加灵活的表示。<br /><br /> 上图所示的2层感知机中,先在第0层和第1层的神经元之间进行信号的传送和接收,然后在第1层和第2层之间进行信号的传送和接收,具体如下所示:
1.第0层的两个神经元接收输入信号,并将信号发送至第1层的神经元。
2.第1层的神经元将信号发送至第2层的神经元,第2层的神经元输出y。
2.4 感知机和计算机
两层感知机(使用sigmoid函数为激活函数)就可以表示任意函数。<br /> 《计算机系统要素:从零开始构建现代计算机》:以深入理解计算机为主题,论述了仅通过 NAND构建可运行俄罗斯方块的计算机的过程。