感知机接受多个输入信号,输出一个信号。这里说的信号可以想象成电流或河流具备“流动性”的东西。但是,和实际的电流不同的是,感知机的信号只有“流/不流”(1/0)两种取值。
如图:是一个接受两个输入信号的感知机。x1、x2是输入信号,y是输出信号,w1,w2是权重。 θ \theta θ被称为阈值。b是被称为偏置的参数,用于控制各个信号的重要性。
y = { 0 , b + w 1 x 1 + w 2 x 2 ≤ θ 1 , b + w 1 x 1 + w 2 x 2 > θ y = \begin{cases} 0, & \text {$b+w_1x_1 + w_2x_2\leq\theta$} \\ 1, & \text {$b+w_1x_1 + w_2x_2>\theta$} \end{cases} y={ 0,1,b+w1x1+w2x2≤θb+w1x1+w2x2>θ
y = h ( b + w 1 x 1 + w 2 x 2 ) y = h(b+w_1x_1+w_2x_2) y=h(b+w1x1+w2x2)
h ( x ) = { 0 , x ≤ 0 1 , x > 0 h(x) = \begin{cases} 0, & \text {$x\leq0$} \\ 1, & \text {$x>0$} \end{cases} h(x)={ 0,1,x≤0x>0
上面介绍的h(x)将输入信号的总和转换为输出信号,这种函数一般被称为激活函数。上面表示的激活函数以阈值为界,一旦输入超过阈值,就切换输出。这样的函数被称为“阶跃函数”。
h ( x ) = 1 1 + e x p ( − x ) h(x)=\frac{1}{1+exp(-x)} h(x)=1+exp(−x)1
def step_function(x):
if x > 0:
return 1;
else:
return 0;
上述代码参数x只能接受实数,不能接受numpy数组
def step_function(x):
y = x > 0
return y.astype(np.int)
对numpy数组进行不等号运算后,会生成一个布尔型数组。然后通过np.int将布尔型转换为int型
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
return np.array(x > 0, dtype=int)
x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1,1.1) # 指定y轴的范围
plt.show()
def sigmoid(x):
return 1 / (1 + np.exp(-x))
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1,1.1) # 指定y轴的范围
plt.show()
不同点:
相同点:
神经网络的激活函数必须使用非线性函数。
线性函数的问题在于,不管如何加深层数,总是存在与之等效的“无隐藏层的神经网络”。
更直观,我们将 h ( x ) = c x h(x) = cx h(x)=cx 作为激活函数,把 y = h ( h ( h ( x ) ) ) y=h(h(h(x))) y=h(h(h(x)))的运算对应3层神经网络,但是同样的处理可以由 y = a x y=ax y=ax 注意 a = c 3 a = c^3 a=c3这一次乘法运算来表示。因此为了发挥叠加层所带来的优势,激活函数必须使用非线性函数。
ReLU函数在输入大于0时,直接输出该值,在输入小于等于0时,输出0
h ( x ) = { 0 , x ≤ 0 x , x > 0 h(x) = \begin{cases} 0, & \text {$x\leq0$} \\ x, & \text {$x>0$} \end{cases} h(x)={ 0,x,x≤0x>0
def relu(x):
return np.maximum(0, x)
numpy的maximum函数。maximum函数会从输入的数值中选择较大的那个值进行输出。
X = np.array([1.0, 0.5])
W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])
print(W1.shape) # (2, 3)
print(B1.shape) # (3, )
print(X.shape) # (2,)
A1 = np.dot(X, W1) + B1
Z1 = sigmoid(A1)
print(A1) # [0.3, 0.7, 1.1]
print(Z1) # [0.57444252 0.66818777 0.75026011]
从第1层到第2层的信号传递
W2 = np.array([[0.1, 0.4],[0.2, 0.5],[0.3, 0.6]])
B2 = np.array([0.1, 0.2])
print(W2.shape) # (3, 2)
print(B2.shape) # (2,)
print(Z1.shape) # (3,)
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
从第2层到输出层的信号传递
def identity_function(x):
return x
W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
B3 = np.array([0.1, 0.2])
A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3)
identity_function()函数(也称为“恒等函数”)。并将其作为输出层的激活函数。输出层使用的激活函数,要根据求解问题的性质决定。一般地,回归问题可以使用恒等函数,二分类问题可以使用sigmoid函数,多元分类问题可以使用softmax函数。
代码小结:
def init_network():
network = {
}
network['w1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
network['b1'] = np.array([0.1, 0.2, 0.3])
network['w2'] = np.array([[0.1, 0.4],[0.2, 0.5],[0.3, 0.6]])
network['b2'] = np.array([0.1, 0.2])
network['w3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
network['b3'] = np.array([0.1, 0.2])
return network
def forward(network, x):
w1, w2, w3 = network['w1'],network['w2'],network['w3']
b1, b2, b3 = network['b1'],network['b2'],network['b3']
a1 = np.dot(x, w1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, w2) + b2
z2 = sigmoid(a2)
a3 = np.dot(z2, w3) + b3
y = identity_function(a3)
return y
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y) #[0.31682708 0.69627909]
这里出现了forward(前向)一词,它表示从输入到输出方向的传递处理。
回归问题可以使用恒等函数,二分类问题可以使用sigmoid函数,多元分类问题可以使用softmax函数
恒等函数会将输入按原样输出,对于输入的信息,不加以任何改动地直接输出。
softmax函数可以用
y k = e x p ( a k ) ∑ i = 1 n e x p ( a i ) y_k = \frac{exp(a_k)}{\sum^{n}_{i=1}exp(a_i)} yk=∑i=1nexp(ai)exp(ak)
输出层的各个神经元都受到所有输入信号的影响。
a = np.array([0.3, 2.9, 4.0])
exp_a = np.exp(a) # 指数函数
print(exp_a) # [ 1.34985881 18.17414537 54.59815003]
sum_exp_a = np.sum(exp_a)
print(sum_exp_a) # 74.1221542101633
y = exp_a / sum_exp_a
print(y) # [0.01821127 0.24519181 0.73659691]
def softmax(a):
exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
由于在softmax函数中涉及到指数运算,所以容易出现溢出的问题。
所以,我们将softmax的实现进行改进
def softmax(a):
c = np.max(a)
exp_a = np.exp(a - c)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
通过减去输入信号中的最大值,来使得指数运算不会溢出。
由于此函数的输出值的总和为1,故我们可以把输出值看出概率。
输出层的神经元数量需要根据待解决的问题来决定。对于分类问题,输出层的神经元数量一般设定为类别的数量。
此为本人学习《深度学习入门》的学习笔记,详情请阅读原书