精通数据科学笔记 神经网络

本章讨论一种全新的建模理念,它不关心模型的假设以及相应的数学推导,也就是说不关心模型的可解释性,其核心内容是模型实现,虽然到目前为止,人们还无法理解,但在某些特定场景里预测效果却非常好。我们把这种模型称为神经网络,深度学习,人工智能等。


神经元

模型的输入是数据里的自变量(x_{1},x_{2},...,x_{n})

接收输入变量的是一个线性模型\sum

接下来是一个非线性激活函数f(\cdot ),这是神经元模型的核心,常用的激活函数有很多,如sigmoid,ReLU,tanh,maxout等

模型各部分联结起来得到输出y_{i},传递给下一个神经元

sigmoid 神经元与二元逻辑回归

sigmoid 函数作为神经元激活函数的两个好处:

实用:能将任意实数映射到(0,1)区间

理论:模拟了两种效应的竞争关系,可近似表达正效应大于负效应的概率

当模型被用于二元分类时,sigmoid神经元模型就是逻辑回归

softmax 函数与多元逻辑回归

独热编码:对于k元分类问题,用一个k维行向量来表示它的类别

Softmax 函数:给定输入数据,输出这个数据的类别概率

P(y=l)=e^{Xw_{l}^{T}+b}/\sum_{j=0}^{k-1}e^{Xw_{j}^{T}+b_{j}}                       (softmax 函数)

对于k元逻辑回归,某个数据点的损失可以写成softmax函数与行向量的乘积形式

L_{i}=-\theta _{i}\ln \sigma (Z_{i})^{T}

其中\theta _{i}是独热编码向量,Z_{i}=(X_{i}w_{0}^{T}+b_{0},...,X_{i}w_{k-1}^{T}+b_{k-1})\sigma (\cdot )是Softmax函数


神经网络

神经元按层组织,每一层包含若干神经元,层内神经元相互独立,但相邻两层之间是全连接的

神经网络不同层按功能分为3类,分别是输入层,隐藏层,和输出层。

隐藏层里每一个圆圈包含线性模型和激活函数,统称神经元

输入层不对数据做处理

输出层只包含线性模型,没有激活函数

代码实现

借助第三方库tensorflow实现

class ANN(object):
    
    def __init__(self, size, logPath):
        """
        创建一个神经网络
        """
        # 重置tensorflow的graph,确保神经网络可多次运行
        tf.reset_default_graph()
        tf.set_random_seed(1908)
        self.logPath = logPath
        self.layerNum = len(size)
        self.size = size

    def defineANN(self):
        """
        定义神经网络的结构
        """
        # self.input是训练数据里自变量
        prevSize = self.input.shape[1].value
        prevOut = self.input 
        # self.size是神经网络的结构,也就是每一层的神经元个数
        size = self.size
        layer = 1
        # 定义隐藏层
        for currentSize in size[:-1]:
            weights = tf.Variable(
                tf.truncated_normal([prevSize, currentSize],
                    stddev=1.0 / np.sqrt(float(prevSize))))
            # 记录隐藏层的模型参数
            tf.summary.histogram("hidden%s" % layer, weights)
            layer += 1
            biases = tf.Variable(tf.zeros([currentSize]))
            prevOut = tf.nn.sigmoid(tf.matmul(prevOut, weights) + biases)
            prevSize = currentSize
        # 定义输出层
        weights = tf.Variable(
            tf.truncated_normal([prevSize, size[-1]],
                stddev=1.0 / np.sqrt(float(prevSize))))
        biases = tf.Variable(tf.zeros([size[-1]]))
        self.out = tf.matmul(prevOut, weights) + biases
        return self

    def defineLoss(self):
        """
        定义神经网络的损失函数
        """
        # 定义单点损失,self.label是训练数据里的标签变量
        loss = tf.nn.softmax_cross_entropy_with_logits(
            labels=self.label, logits=self.out, name="loss")
        # 定义整体损失
        self.loss = tf.reduce_mean(loss, name="average_loss")
        return self

    def SGD(self, X, Y, learningRate, miniBatchFraction, epoch):
        """
        使用随机梯度下降法训练模型

        参数
        ----
        X : np.array, 自变量
        
        Y : np.array, 因变量
        """
        # 记录训练的细节
        tf.summary.scalar("loss", self.loss)
        summary = tf.summary.merge_all()
        method = tf.train.GradientDescentOptimizer(learningRate)
        optimizer= method.minimize(self.loss)
        batchSize = int(X.shape[0] * miniBatchFraction)
        batchNum = int(np.ceil(1 / miniBatchFraction))
        sess = tf.Session()
        init = tf.global_variables_initializer()
        sess.run(init)
        summary_writer = tf.summary.FileWriter(self.logPath, graph=tf.get_default_graph())
        step = 0
        while (step < epoch):
            for i in range(batchNum):
                batchX = X[i * batchSize: (i + 1) * batchSize]
                batchY = Y[i * batchSize: (i + 1) * batchSize]
                sess.run([optimizer],
                    feed_dict={self.input: batchX, self.label: batchY})
            step += 1
            # 将日志写入文件
            summary_str = sess.run(summary, feed_dict={self.input: X, self.label: Y})
            summary_writer.add_summary(summary_str, step)
            summary_writer.flush()
        self.sess = sess
        return self

    def fit(self, X, Y, learningRate=0.3, miniBatchFraction=0.1, epoch=2500):
        """
        训练模型

        参数
        ----
        X : np.array, 自变量
        
        Y : np.array, 因变量
        """
        self.input = tf.placeholder(tf.float32, shape=[None, X.shape[1]], name="X")
        self.label = tf.placeholder(tf.int64, shape=[None, self.size[-1]], name="Y")
        self.defineANN()
        self.defineLoss()
        self.SGD(X, Y, learningRate, miniBatchFraction, epoch)

    def predict_proba(self, X):
        """
        使用神经网络对未知数据进行预测
        """
        sess = self.sess
        pred = tf.nn.softmax(logits=self.out, name="pred")
        prob = sess.run(pred, feed_dict={self.input: X})
        return prob


反向传播算法(BP)

反向传播算法是神经网络的基石,但其本身却饱受质疑,因为没有生物学的支持,违背神经网络的建模理念,BP算法的核心是利用链式法则计算多元函数偏导数

计算的起点:\delta _{n}^{T}=\frac{\partial L}{\partial o_{n}^{T}}

反向传播:\delta _{n}^{l}=\sum _{m}\delta _{m}^{l+1}w_{n,m}^{l+1}{f}'(i_{n}^{l})

模型训练梯度:\frac{\partial L}{\partial b_{n}^{l}}=\delta _{n}^{l}                   \frac{\partial L}{\partial w_{m,n}^{l}}=\delta _{n}^{l}o_{m}^{l-1}

BP算法和最大期望EM算法类似,可分为向前计算和向后计算

  • 首先随机生成模型参数w_{m,n}^{l}b_{m}^{l}
  • 根据现有的模型参数和训练数据,计算每个神经元的i_{n}^{l}o_{n}^{l}
  • 根据随机梯度下降法更新参数(w_{m,n}^{l})_{j+1}-(w_{m,n}^{l})_{j}=-\gamma \frac{\partial L}{\partial w_{mn}^{l}}

提高神经网络的学习效率

改进激活函数

学习效率正比于激活函数的导数

sigmoid函数:非0中心;自变量远离0时导数接近0

tanh函数:以0为中心但是自变量远离0时导数接近0

ReLU函数:自变量小于0时,导数恒小于0,自变量大于0时,导数恒大于0

参数初始化:令w_{m,n}^{l}\sim N(0,\frac{1}{m}),其中m是上一层神经元个数,可以提高学习效率

梯度消失和梯度爆炸是同一个问题的两个极端,是神经网络的权重项叠加效应导致。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值