感知机
接收多个输入信号,输出一个信号,每个输入信号都有相对应的权重,根据所有的输入值乘权重得到最后输出的结果。
设输入信号{x} = [x1, x2, … ,xn] = X
相应的权重{w} = [w1, w2, … ,wn] = W
乘积为 x1w1 + x2w2 + … +xnwn
再加上一个偏置b,最终为 x1w1 + x2w2 + … +xnwn + b
最终计算得得值可以写为 XT * W + b
再根据这个值来判断输出结果为0或1,这个函数为h(x),叫做激活函数,表达式为
def StepFunction(x):
if x > 0:
return 1
else:
return 0
整个感知机的方程为:
神经网络
神经元的定义就与上述感知机几乎一样,只有激活函数不同
Sigmoid函数
def Sigmoid(x):
return 1 / (1 + np.exp(-x))
Relu函数
Sigmoid函数会造成高值部分的梯度消失,所以有了Relu函数
def Relu(x):
return np.maximum(0, x)
后两种激活函数与节约函数不同的是,并不是非黑即白的结果,有了中间的“模棱两可”的状态,也是这种状态给了后续部分的可以学习的余地。
多维数组计算
有个记忆的诀窍:
1.两个矩阵AB相乘,结果的样子分别取AB的行列
2.计算的时候肯定为a1b1 + a2b2 + … +an*bn,那么a1b1等等的都怎么取呢。
例如要求得的矩阵的某一个空是第i行第j列,则分别取AB的第i行第j列,A横(行)着数,B竖(列)着数,对应项相乘,最后把他们求和,作为最终的解填入空里。
3.因为上一条里的anbn最后要同时结束,所以AB的第i行第j列数量要相等,也就是说,A和B的列和行要相等。
神经网络的内积
>>> X = np.array([1, 2]) # 一维数组的shape
>>> X.shape
(2,)
>>> W = np.array([[1, 3, 5], [2, 4, 6]])# 对于python中的二维数组而言
>>> print(W)
[[1 3 5]
[2 4 6]]
>>> W.shape # (a,b) 表示 a行b列
(2, 3)
>>> Y = np.dot(X, W)
>>> print(Y)
[ 5 11 17]
对于一维数组X而言应该为 (1,2) 表示一行两列,但是如果有更高维的话就表示为 (1,1,1,…,2),因为此处的是array([1, 2]) 而不是 array([[1, 2]]),所以就按照一维数组表示为 (2, )。而如果使用后面的格式定义则结果为 (1, 2) ,还是使用严格的格式比较好,这样的话在判断能否相乘的时候很简便
例如X * W 时看 (1,2) 的末位与 (2,3) 的首位是否相等就可以。
PS: 虽然X.shape == (2,) 时,使用X.shape[-1]也可以得到2
神经网络的层数
如图所示:为3 层神经网络:输入层(第 0 层)有 2 个神经元,第 1 个隐藏层(第 1 层)有 3 个神经元,第 2 个隐藏层(第 2 层)有 2 个神经元,输出层(第 3 层)有 2 个神经元
在每一层之间传递的时候,权重都放在了神经元的突触上,每一个神经元只是一个数字(或者说是“上一层来的所有输入累加的结果,经过激活函数,得到输出结果”的部分)。
层数的标志还好理解一些,这里的w12为什么时反着说的。
神经网络的识别过程
def identity_function(x): # 恒等函数,为了与其他激活函数保持格式一致
return x
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) # 这里就是激活函数sigmoid
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]
这里就是神经网络的识别过程,其实就是根据传入的参数,然后计算各个参数的权重,得到一个最终的解。而不断学习的过程就是不断调整它的权重来学得使用的结果。
神经网络的输出层
对于回归问题,前面的流程已经确定了一组模拟值,就不需要再对它进行怎样的改变,用恒等函数直接输出就可以。
对于分类问题,前置的流程得到的是一组模拟值,要根据这模拟值进行离散化分类,使用的是softmax函数(理解为应用于多维数据的sigmoid函数)
def Softmax(a):
c = np.max(a) # 因为分母可能过小,所以增加的c防止浮点数溢出
exp_a = np.exp(a - c) # 分子为数组a中的每一项进行exp操作得到的结果,根据每一项的不同而变化
sum_exp_a = np.sum(exp_a) # 分母为数组a进行exp操作之后的累加和,是保持不变的
y = exp_a / sum_exp_a
return y
但是对于大部分分类问题来说,只需要取输出中的最大项,因为输出的数组可以理解为“当前组的入参划分为每一类的概率”,则不需要经过softmax也可以得到。
小结
神经网络是由多个神经元组成的,每个神经元都是由感知机发展而来。
机器学习是人为的指定一些特征,然后使用数据让机器根据这些特征来判断相应的结果,其中如何判断的逻辑也是人为所指定的。而与机器学习不同的是,神经网络不需要人为指定特征值,只要全部都给它,他会自己选出其中的重要的特征值,而且学习的方法也不是能完全人为指定的,只能通过一些策略来把控大方向。