深度学习中的人工神经网络

人工神经网络

Posted by Mark on August 14, 2018

人工神经网络

  • 根据目标,去帮你做特征工程
  • 然后,做出了特征工程后,其实最后一层其实是一个简单的线性分类器

神经网络的来源

  • 只有一层的神经网络,是和线性回归是一样的

  • 添加少量的隐层,变成了浅层神经网络,也就是SNN

  • 增加中间层,变为深度神经网络,也就是DNN

神经网络为什么在分类问题效果比较好

原则上,神经网络是可以同时解决回归和分类问题的。只是回归类问题比较难做到高的准确度。

对于分类问题解决的比较好。

当LR和SVM对于非线性可分,怎么处理呢?其实做好特征映射或者特征工程,其实也是可以做的。

但是问题在于,你不知道特征映射怎么做。

我们希望机器自己能够去构建一些特征,而不是人或者遍历等很大开销去做这个事情。

例如下面:

当一条直线很难去分隔这4个点时,我们可以尝试使用两条直线来分割这4个数据。其中两条直线之间的为一类,两条直线之外的为一类。

神经网络理解

  • 两条线之间的交集,可以认为是一类。同样的,假如一条直线很难将数据集分来的话,我们可以构建很多条直线,并求交集,这样在这些交集内的就是一类,交集外的是另一类。
  • 那么直线的条数是多少呢,其实就是第一隐层的神经元数量。而由样本点连接第一隐层的线就待表对应的权重也就是参数。
  • 那么第二隐层做的是什么呢,他其实是把第一隐层划分出的分类,并集在一起。可以理解为第一隐层是交集,第二隐层的并集
  • 在进行计算是,每一个隐层的Loss Function都要经过一个sgmod函数的转化,得到Z值,而这个Z值是作为下一个隐层的输入进行的。
  • 而最终形成的决策边界是什么的,即是第一层隐层的w,b组成的很多条直线,而如果这些直线足够多,就形成了一条曲线,或者平面,或者等等的一个边界。
  • 最终的目标也就是通过反向传播和随机梯度下降的方法,不停的迭代,使得Loss Function小于一定的值,这样就代表收敛,也就是把样本库进行很好的分类的w和b已经求出,也就是这个模型已经求出。
  • 那么拿这个模型,对于新的数据,就可以根据这个分类器进行分类。

  • 线性的分类器做非线性的分割

神经元完成逻辑【与】

对于下面的两个直线,可以有两组权重组成两个神经元,在P1和P2之间的即是我们想要的数据,也就是P1和P2两个神经元的交集。

那么如何表示两个神经元的交集呢?如上面的逻辑与,我们可以对第一隐层的结果到输出层,设置权重z=20x1 + 20x2 -30 (此处只是假设参数是这样,代表肯定可以能够找到这样的一组数值来解释两个神经元之间的交集关系和交集结果 )

也就是说,第一次的从输入层到隐层的权重和输入的(x1, x2)计算出的结果,来代表输入的0或1,第二次的从隐层到输出层的权重代表的是对0和1做交集。也就是说第一次的从输入层到隐层做的是模拟出两条直线,第二次的从隐层到输出层做的是描述出这两个直线的方向,也就是这两条直线范围之间的数据。

神经元完成逻辑【或】

神经元分类的解释

逻辑【与】和逻辑【或】的组合

  • 像每一个绿色,其实是多个线性分类器的与
  • 而多个绿色,其实是多个色块的或
  • 我觉得这样的就是上述的神经元再加一个隐层,也就是输入层,逻辑与隐层,逻辑或隐层,输出层

image-20180812234752765

神经网络的结构

神经网络的激活函数

神经网络之BP算法

image-20180813001347884

  • Loss Function:算出的结果和真实结果之间的差距
  • 目标是不断的缩小 Loss Function
  • “正向传播”求损失,“反向传播”回传误差
  • SGD:随机梯度下降。梯度下降是在全部的范围内找下降梯度最大的方向。而随机梯度下降只是找了一批的样本。
  • 如果使用梯度下降,由于不是一个凸函数,所以可能有多个局部最优解,使用梯度下降有可能在一个局部最优解里就出来了。
  • 因为随机梯度是找的随机的一批,并非全部,所以只是这一批的的局部下降最快的方向,所以有可能会跳出凸函数的局部最优解。

人工神经网络例子

先制造一批数据

import numpy as np
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt

plt.ion()
np.random.seed()
X, y = make_moons(200, noise=0.20)
plt.scatter(X[:, 0], X[:, 1], s=40, c=y, cmap=plt.cm.Spectral)
plt.show()

使用传统的逻辑回归进行分类

from sklearn.linear_model import LogisticRegressionCV


def plot_descision_boundary(pred_func):
    #设定最大最小值,附加一点点边缘填充
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    h = 0.01

    xx, yy = np.meshgrid(
        np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    # 用预测函数预测一下
    Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)

    #画图
    plt.contour(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)


# 逻辑斯特回归的分类效果
clf = LogisticRegressionCV()
clf.fit(X, y)

# 决策边界
plot_descision_boundary(lambda x: clf.predict(x))
plt.title("Logistic Regression")
plt.show()

使用人工神经网络进行分类

num_examples = len(X)
nn_input_dim = 2
nn_output_dim = 2

# 梯度下降参数
epsilon = 0.01
reg_lambda = 0.01


# 定义损失函数
def calculate_loss(model):
    W1, b1, W2, b2 = model["W1"], model["b1"], model["W2"], model["b2"]
    # 向前推进,前向运算
    # 第一个隐层
    z1 = X.dot(W1) + b1
    # 激活函数
    a1 = np.tanh(z1)
    # 第二个隐层
    z2 = a1.dot(W2) + b2
    # 指数运算
    exp_scores = np.exp(z2)
    # 概率
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    # 计算损失
    corect_logprobs = -np.log(probs[range(num_examples), y])
    data_loss = np.sum(corect_logprobs)
    # 正则化
    data_loss += reg_lambda / 2 * (np.square(W1) + np.sum(np.square(W2)))
    return 1. / num_examples * data_loss


# 完整的训练建模函数定义
def build_model(nn_hdim, num_passes=20000, print_loss=False):
    '''
    参数:
    1.nn_hdim:隐层节点个数
    2.num_passes:梯度下降迭代次数
    3.print_loss:设定为True的话,每1000次迭代输出一次loss的当前值
    '''

    # 随机初始化权重
    np.random.seed(0)
    W1 = np.random.rand(nn_input_dim, nn_hdim) / np.sqrt(nn_input_dim)
    b1 = np.zeros((1, nn_hdim))
    W2 = np.random.rand(nn_hdim, nn_output_dim) / np.sqrt(nn_hdim)
    b2 = np.zeros((1, nn_output_dim))

    # 最后学到的模型
    model = {}
    # 开始梯度下降
    for i in xrange(0, num_passes):
        # 向前计算loss
        z1 = X.dot(W1) + b1
        a1 = np.tanh(z1)
        z2 = a1.dot(W2) + b2
        exp_scores = np.exp(z2)
        probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)

        # 反向传播
        delta3 = probs
        delta3[range(num_examples), y] -= 1
        dW2 = (a1.T).dot(delta3)
        db2 = np.sum(delta3, axis=0, keepdims=True)
        delta2 = delta3.dot(W2.T) * (1 - np.power(a1, 2))
        dW1 = np.dot(X.T, delta2)
        db1 = np.sum(delta2, axis=0)

        # 加上正则化项
        dW2 += reg_lambda * W2
        dW1 += reg_lambda * W1

        # 梯度下降更新参数
        W1 += -epsilon * dW1
        b1 += -epsilon * db1
        W2 += -epsilon * dW2
        b2 += -epsilon * db2

        # 得到的模型其实是这些权重
        model = {'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}

        # 打印中间过程
        # if print_loss and i % 1000 == 0:
        #     print 'Loss after interation %i: %f' % (i, calculate_loss(model))
    return model


# 定义判定结果的函数
def predict(model, x):
    W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
    # 前向运算
    z1 = x.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    exp_scores = np.exp(z2)

    # 计算概率输出最大概率对应的类别
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    return np.argmax(probs, axis=1)
# 建立3个隐层的神经网络
model = build_model(3, print_loss=True)

# 画出决策/判定边界
plot_descision_boundary(lambda x: predict(model, x))
plt.title('Decision Boundary for hidden layer size 3')
plt.show()

# 不同的隐层对结果的影响
plt.figure(figsize=(16, 32))
hidden_layer_dimensions = [1, 2, 3, 4, 5, 20, 50]
for i, nn_hdim in enumerate(hidden_layer_dimensions):
    plt.subplot(5, 2, i + 1)
    plt.title('Hidden Layer size %d' % nn_hdim)
    model = build_model(nn_hdim)
    plot_descision_boundary(lambda x: predict(model, x))
plt.show()