深度学习之神经网络(一)

与大佬交流后,项目需要神经网络技术支撑。但恕本人才疏学浅,之前对这方面了解甚少,本贴就作为我的学习笔记。


1. 神经网络

神经网络是深度学习的重要算法,在图像(如图像的分类、检测)和自然语言处理(如文本分类、聊天)有很多应用。

 人工神经网络(Artificial Neural Network),也简称为神经网络,是一种模仿生物神经网络(大脑)结构和功能的计算模型。经典的神经网络结构包含三个层次,即输入层隐藏层输出层。 

其中,每层的圆圈代表一个“神经元”,“神经元”之间的连线对应不同的权重

2. 神经元

2.1 生物神经元

一个神经元通常具有多个树突,主要用来接受传入信息;而轴突只有一条,轴突尾端有许多轴突末梢可以给其他多个神经元传递信息。轴突末梢跟其他神经元的树突产生连接,从而传递信号。这个连接的位置在生物学上叫做“突触”。

查看源图像

2.2 人工神经元

人工神经元是神经网络的基本单元,也经常被称为“处理单元”,是一种对生物神经元的形式化描述。它将生物神经元的信息处理传递过程抽象化,并用数学语言描述。其模型通常包含输入、计算、输出。输入可类比为树突,输出可类比为轴突,而计算可类比为细胞核。下面介绍一个例子:

在这个神经元中,输入为\(x_1,x_2,x_3, w_1,w_2,w_3\)为权重。

它将输入乘以权重,然后相加:

\(x_1 \rightarrow x_1 * w_1\)

\(x_2 \rightarrow x_2 * w_2\)

\(x_3 \rightarrow x_3 * w_3\)

\(z = x_1 * w_1 + x_2 * w_2 + x_3 * w_3 \)

最后再经过激励函数\(f\)(activation function)处理,得到最后的输出:

\(output = f(z) \)

3. 神经网络的搭建

3.1 单层神经网络

单层神经网络,也被称为“感知机”,这是最早的“人造神经元”模型。它只有两个层次:输入层、输出层。

输入层:这层的单元只负责传输数据,不做计算。

输出层:这层的单元需要对前面一层的输入进行计算。

人们把需要计算的层次称之为“计算层”,并把拥有一个计算层的神经网络称为“单层神经网络”。有的文献会按照神经网络所拥有的层数,例如把“感知机”称为两层神经网络。

对于上图我们设置权重\(w\)和偏置\(b\),最后的结果可表示为\(z=f(w*x+b)\),其中\(x=[x_1,x_2,x_3],w=[w_1,w_2,w_3], f\)为激励函数。

 下面为简单的代码实现:

import numpy as np


# define activation function
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

# create my own netual 
class my_N(object):
    # set weights and biase
    def __init__(self, weights, biase):
        self.weights = weights
        self.biase = biase

    # calculate
    def output(self, inputs):
        y = np.dot(self.weights, inputs) + self.biase
        y = sigmoid(y)
        return y


weights = np.random.randint(-2, 5, 3)  # set w1, w2, w3 in [-2,5) randomly
print("weights:", weights)
biase = np.random.randn(1)  # set biase obeying the standard normal distribution
print("biases:", biase)

x = np.array([1, 2, 4])  # x1 = 1, x2 = 2, x3 = 4

n = my_NN(weights, biase)
result = n.output(x)
print("result:", result)

输出结果为:

weights: [-1  0  3]
biases: [1.18146466]
result: [0.99999488]

3.2 多层神经网络

由于单层神经网络的能力有限,无法解决更复杂的问题,多层神经网络就出现了。它通过增加计算层,使它可以更精准地表达抽象的逻辑或行为。如下图所示:

这个网络有3个输入,一个包含2个神经元的隐藏层,一个输出\(z\)。

我们在构建神经网络的时候,输入层和输出层往往都是固定的,而中间的隐藏层则需要我们去设计,这同时也是构建网络的关键部分。

为了方便,将第一层的权重都设置为\(w^{(1)}=[1,2,3]\),第二层权重为\(w^{(2)}=[0,1]\),偏置\(b=1\),激励函数都设置为\(sigmoid\)函数。下面为代码实现:

import numpy as np


# define activation function
def sigmoid(z):
    return 1 / (1 + np.exp(-z))


class my_N(object):
    # set weights and biase
    def __init__(self, weights, biase):
        self.weights = weights
        self.biase = biase

    # calculate
    def output(self, inputs):
        y = np.dot(self.weights, inputs) + self.biase
        y = sigmoid(y)
        return y


class my_NN(object):
    def __init__(self, weights1, weights2, biase):
        self.weights = weights1
        self.biase = biase
        self.h1 = my_N(weights1, biase)  # one neuron in the hidden layer
        self.h2 = my_N(weights1, biase)  # another one
        self.y = my_N(weights2, biase)  # the neuron in the output layer

    def output(self, inputs):
        out_h1 = self.h1.output(inputs)
        out_h2 = self.h2.output(inputs)
        y = self.y.output([out_h1, out_h2])
        return y


weights1 = np.array([1, 2, 3])
weights2 = np.array([0, 1])
biase = 1
x = np.array([1, 1, 1])
network = my_NN(weights1, weights2, biase)
result = network.output(x)
print("result:", result)

输出结果为:

result: 0.8807013902565914

3.3激励函数

在我们搭建神经网络的过程中,激励函数是一个很重要的部分,在隐藏层和输出层都会使用到。它的作用是将多个线性输入转换为非线性的关系。如果不使用激励函数的话,无论你神经网络有多少层,输出都是输入的线性组合。(还是那句话,要想神经网络表达能力更强,必须引入非线性的激励函数)。

下面简单介绍4个比较常见的激励函数:

3.3.1 Sigmoid函数

Sigmoid函数应该是神经网络中出现最频繁的一个激励函数了,它的数学表达式如下:

 $$ g(z)=\frac {1} {1+ e^{-z}} $$

图像为:

Sigmoid函数能把一个实数压缩至0到1之间。当输入非常大时,输出就会接近1;当输入非常小时,输出则会接近于0。在早期的神经网络学习中使用得非常多,因为它很好地解释了神经元收到刺激后是否被激活的场景。但是它也有些缺点,例如使用Sigmoid函数容易出现梯度爆炸或梯度消失,由于本人正在学习中,这里不作详细解释。

3.3.2 tanh函数

tanh函数表达式为:

$$tanh(x)=\frac{e^x-e^{-x}} {e^x+e^{-x}}$$

图像为:

 tanh函数将输入值压缩至-1到1之间。它也存在着与Sigmoid同样的缺点。

3.3.3 Relu函数

 Relu函数表达式为:

$$f(x)=max(0,x), or$$

$$
    f(x) =
        \begin{cases}
            x,  & \text{if $x>0$ } \\
            0, & \text{if $x \leq 0$ } \\
        \end{cases}
$$

图像为:

Relu函数也称为线性整流函数。相比于Sigmoid函数和tanh函数,它更加简单,并且它避免了梯度爆炸和梯度消失问题;同时,它使得输出具有稀疏性,缓解了过拟合的问题。它的缺点是,随着训练的进行,可能会出现神经元死亡的情况,指的是某些神经元可能不会被激活,从而导致相应的参数不能被更新。如果发生这种情况,那么流经神经元的梯度从这一点开始将永远是0。

3.3.4 Leaky Relu函数 

Leaky Relu函数表达式为:

$$f(x)=max(\alpha x,x),or$$

$$
    f(x) =
        \begin{cases}
            x,  & \text{if $x>0$ } \\
            \alpha x, & \text{if $x \leq 0$ } \\
        \end{cases}
$$

图像为:

人们为了解决Relu函数中容易出现的问题, 就将Relu的前半段设置为\(\alpha x\),而非\(0\),通常\(\alpha = 0.01\)。当神经元处于非激活状态时,允许一个非\(0\)的梯度存在。

4. 神经网络的训练

向网络输入足够的样本,通过一定算法调整网络的结构(主要是调节权重),使得网络的输出与预期值相符,这样的过程就是神经网络训练。在开始讨论之前,我们需要了解“损失函数”这个东西。

4.1 损失函数

顾名思义,损失函数就是一个用来计算“损失”的函数,那么什么叫做“损失”呢?

简单来说,损失就是真实值与预测值的误差,是我们评估网络模型好坏的一个标准。损失越小,预测结果越好,神经网络训练的过程也就是求得损失最小化的过程。


未完待续...

同时欢迎大家补充与指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值