深度学习之神经网络

神经网络

有监督的算法。

神经网络算法既能做回归又能做分类。

我们说人工智能做的就是拟人,神经网络就做的最佳的拟人。

1.神经元介绍:

神经网络是由很多神经元组成。神经元的每个输入是机器学习中的每个特征维度X,每个连接是权重W,将特征维度和权重相乘再相加汇总,经过一个非线性变换(函数变换)后的结果,就是一个神经元的输出。也是下层神经元的输入。

也就是说对于一个神经元,有可能就是一个线性回归,也有可能就是一个逻辑回归这取决于加和后的非线性变换是什么函数。

那么整个神经网路就是每一个浅层的机器学习算法的组合。

2.激活函数(activition function)

在神经元中引入了激活函数,它的本质事项神经网络中引入非线性因素,通过激活函数,神经网络可以拟合各种曲线。通过引入激活函数那输出不再是线性组合,可以逼近任意函数。

将数据与权重相乘再加和汇总后,经过一个非线性变换。这个非线性变换就是激活函数。三种常见的激活函数,激活函数一般用在隐藏层,输出层一般叫做非线性变换。

(1)sigmoid

主要用于二分类。将数据缩放到0-1之间

 

(2)tanh将数据缩放到(-1,1)之间(在RNN循环神经网络隐藏层里面用的比较多)

 

(3)Relu:现在用relu的比较多。在(0,x)之间取值,大于0就去当前值,小于0就取0.

 (4)LeakReLu:Relu激活函数的改进,大量的Relu激活函数可能会导致神经元死亡的现象,LeakReLu就是为了避免这样的情况发生。(类似于加了一个平滑系数)

当用Relu效果不好的时候,可以尝试使用LeakRelu激活函数。

 

  (5)sofamax:用于多分类的输出层中,主要用于多分类。有多个概率结果,这些结果加和等于1,其中概率最大的就是我们要预测的类别。

 

 如何选择激活函数

神经元初始化参数

对于一个神经元来说,需要初始化的参数有两类,一类是权重,一类是偏置b(初始化0即可)

初始化方式:

1.随机初始化:均值为零,标准差为1的正态分布随机取值初始化方式(很少用)。

2.标准初始化:假设有n个输入,那么就根据均匀分布从-1导根号下n之间均匀取值(很少用)。

3.Xavier初始化:

 Glorot正态分布初始化器,是以0为中心,标准差为stddev=sqrt(2 / fan_in + fan_out)的正态分布抽样样本,fan_in输入神经元个数,fan_out输出神经元个数。

init = tf.keras.initializers.glorot_normal()
# 采样得到的数量9行1列
values = init(shape=(9, 1))
print(values)

Glorot均匀分布初始化器,是[-limit,limit]均匀分布中抽取样本,其中limit是sqrt(6/fan_in + fan_out)

init2 = tf.keras.initializers.glorot_uniform()
values = init2(shape=(9, 1))
print(values)

4.he初始化:

基本思想:正向传播时,激活值的方差保持不变 ,反向传播时,状态值梯度方差保持不变,

he正态分布初始化以0为中心,标准差为stddev=sqrt(2 / fan_in)

he标准化初始化是[-limit,limit]均匀分布中抽取样本,其中limit是sqrt(6/fan_in)

init3 = tf.keras.initializers.he_normal()
values = init3(shape=(9, 1))
print(values)

init4 = tf.keras.initializers.he_uniform()
values = init4(shape=(9, 1))
print(values)

常见的损失函数

损失函数就是衡量预测值与真实值之间的差异。真实值与预测值之间的差异越小,交叉熵损失越小。

1.多分类损失函数:交叉熵损失函数

y_true = [[0, 1, 0], [0, 0, 1]]
y_pred = [[0.05, 0.95, 0], [0.1, 0.1, 0.8]]
cce = tf.keras.losses.CategoricalCrossentropy()
print(cce(y_true, y_pred))

2.二分类损失函数:二分类交叉熵损失函数

y_ture = [[0], [1]]
y_pred = [[0.4], [0.6]]
bce = tf.keras.losses.BinaryCrossentropy()
print(bce(y_true, y_pred))

3.回归任务损失函数MAE最小绝对误差,MSE最小均方误差,smoothL1损失

MAE(L1)损失函数在0点处不可导,所以用梯度下降不合适,一般用于L1正则化项加载损失函数后面。

y_true = [[0.], [1.]]
y_pred = [[1.], [0.]]
bce = tf.keras.losses.MeanAbsoluteError()
print(bce(y_true, y_pred))

 MSE最小均方误差(L2),一般当作L2正则项使用,使用的话容易出现梯度爆炸。

y_true = [[0.], [1.]]
y_pred = [[1.], [0.]]
bce = tf.keras.losses.MeanSquaredError()
print(bce(y_true, y_pred))

smoothL1损失,是一个分段函数,在[-1, 1]之间实际上是L2损失 ,解决了L1不光滑0点不可导的问题,在[-1,1]区间外实际上就是L1损失,解决了离群点梯度爆炸的问题。

y_true = [[0.], [1.]]
y_pred = [[1.], [0.]]
bce = tf.keras.losses.Huber()
print(bce(y_true, y_pred))

3.网络拓扑

神经元数量以及层数和他们的连接方式(DNN全连接,CNN局部链接)

 单层神经网络

输入层:对于输入层我们要有X特征,y标签

              输入层的数据假设有三个特征维度,那么输入层的第一条样本的三个数值输入与x1,x2,x3 进行相乘并汇总加和。

输出层:汇总加和的值经过function变换后就是输出。

4.单层神经网络逻辑回归多分类二分类

如果最后的function是sigmoid,那最后输出的值是概率。

如果输入层是批量输入,假设一次输入了三条样本,那么X1,X2,X3都是三个值,再与w1,w2,w3相乘加和后(注意这里加和是每条样本分别加和并不是所有都加在一起,例如第一条样本X11*w1+X12*w2+X13*w3,第二条样本X12*w1+X22*w2+X32*w3,第三条样本X13*w1+X23*w2+X33*w3)经过function变换得到y1,y2,y3

对于逻辑回归来说,如果做二分类,单层神经网络就会有一个输出节点(一个正例的概率,1-p得到负例的概率)

逻辑回归做多分类(OVR)就会有多个输出节点。比如做三分类就会有三个输出节点(三个类别的概率,也会有三个训练模型),在逻辑回归求梯度调整W参数的时候,每个输出的节点都会调整自己的W参数,不会调整别的W,这一点和softmax有本质差别。

5.单层神经网络softmax做多分类

softmax每个类别概率加在一起等于一

softmax=\frac{e^{\theta _{i}^{T}}}{e^{\theta _{1}^{T}}+e^{\theta _{2}^{T}}+e^{\theta _{3}^{T}}+..+e^{\theta _{i}^{T}}}

交叉熵损失函数 = \frac{1}{m}\sum_{i=1}^{m}\sum_{j=1}^{k}y_{ij}\cdot log(\hat{y_{ij}}))

由公式我们可以看出求出来的概率不仅要用到当前类别的的z,还要用到其他类别的z作为分母加和。

我们知道对于softmax真实值yij,如果有三个类别,其中真实值是第二个类别那么真实值就是  (0,1,0),有交叉熵损失函数\frac{1}{m}\sum_{i=1}^{m}\sum_{j=1}^{k}y_{ij}\cdot log(\hat{y_{ij}})),也就是说最终求得预测结果只有第二个值对loss有贡献。然后在反向求梯度。

但是尽管只有第二个对loss有贡献,他要调整的参数θ也是所有的θ,因为softmax公式决定了每个类别的概率是所有的的加和。

 6.网络拓扑层多一层网络

(1)输入层-->隐藏层-->输出层,隐藏层可以有多层。隐藏层的激活函数必须是非线性的激活函数。 

(2)隐藏层的意义:可以抽取更高阶的特征,让结果更准确。

(3)隐藏层越多,当然预测也会越准确,但是也意味着中间有更多的参数要去学习。也有可能过拟合。

(4)隐藏层每一层都要加上截距项。

神经网络每一层的神经元数量是可以由我们决定的,所以隐藏如果下一层神经元数量比上一层神经元数量少,可以起到降维的作用。相反,下一层神经元比上一层数量多,又可以起到升维的作用。

所以神经网络可已经数据预处理和求解参数当作一个整体。包括预处理也是需要调整和训练的,而机器学习是将数据预处理和训练分成两个阶段。

7.多节点输出网络

二分类有一个输出节点

多分类有多个输出节点

做回归也可以有多个输出节点

其实输出层也可以同时做回归和分类。

8.神经网络有两个阶段:

正向传播:从输入经过隐藏层到输出层,这个过程叫做正向传播。正向传播要计算y_hat

反向传播(Backpropagation)

反向传播我们要求出梯度,所以如果loss对Wj求偏导,但是W有对y_hat有影响,所以根据链式求导法则, \frac{\partial loss}{\partial W_{j}}=\frac{\partial loss}{\partial y\hat{}}*\frac{\partial y\hat{}}{\partial W_{j}}

在前向传播后向传播过程中有求导的过程,我们用梯度下降法进行求导


9.使用tensorflow.keras构建神经

单个网络层构建方式

"""
activation激活函数
use_bias截距项
bias_initializer截距初始化
kernel_initializer参数初始化方式
"""
tf.keras.layers.Dense(units=True, activation=None, use_bias=True, 
kernel_initializer='glorot_uniform', bias_initializer='zero')

1.代码通过Sequential()快速构建一个神经网络模型,只能构建简单的网络结构

# sequential方式
model = tf.keras.Sequential([
    # 输入层
    tf.keras.layers.Dense(3, activation="relu", kernel_initializer="he_normal", name="layer1", input_shape=(3,)),
    # 隐藏层
    tf.keras.layers.Dense(2, activation="relu", kernel_initializer="he_normal", name="layer2"),
    # 输出层
    tf.keras.layers.Dense(2, activation="sigmoid", kernel_initializer="he_normal", name="layer3")
],
name="sequ"
)
# 展示模型结果
print(model.summary())
tf.keras.utils.plot_model(model)

2.通过函数式编程构建神经网络(用的最多)

# 函数式编程实现神经网络
# 定义输入层
inputs = tf.keras.Input(shape=(3,), name="input")
# 定义layer1
x = tf.keras.layers.Dense(3, activation="relu", name="layer1")(inputs)
# 定义layer2
x = tf.keras.layers.Dense(2, activation="relu", name="layer2")(x)
# 定义输出层
outputs = tf.keras.layers.Dense(2, activation="sigmoid", name="output")(x)
# 使用Model定义模型,指明输入和输出
model = tf.keras.Model(inputs=inputs, outputs=outputs, name="my_model")

# 展示模型结果
print(model.summary())
# show_shapes=True打印当前维度
tf.keras.utils.plot_model(model, show_shapes=True)

3.通过model子类构建神经网络


# 基于model子类实现神经网络
class MyModel(tf.keras.Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.layer1 = tf.keras.layers.Dense(3, activation="relu", kernel_initializer="he_normal", name="layer1", input_shape=(3,))
        self.layer2 = tf.keras.layers.Dense(2, activation="relu", kernel_initializer="he_normal", name="layer2")
        self.layer3 = tf.keras.layers.Dense(2, activation="relu", kernel_initializer="he_normal", name="layer3")

    def call(self, inputs):
        x = self.layer1(inputs)
        x = self.layer2(x)
        return self.layer3(x)

# 实例化
print("-------------------------")
model = MyModel()
print(model(tf.ones((1, 3))))
model.summary()

10.神经网络中的梯度下降算法,深度学习中SGD是直接用的小批量梯度下降。

opt = tf.keras.optimizers.SGD(learning_rate=0.1)
var = tf.Variable(1.0)
# 定义损失函数
loss = lambda:(var**2)/2.0
# 计算梯度,并进行参数更新,这一步就是把所有参数带入梯度下降公式进行计算
opt.minimize(loss, [var])
# 参数更新结果
print(var.numpy())

# 这里使用梯度下降法公式Wt = W(t-1) - 学习率*梯度
# 学习率已知,梯度是对自己定义的loss损失函数求导得到var
# 那么结果就是1.0 - 0.1*1.0 = 0.9

11.神经网络的优缺点

优点:

精度高,性能优于其他机器学习方法

可以近似任意非线性函数

随着计算机硬件的发展,近年来在学界和业界收到热捧,有大量的框架和库可供调用

缺点:

黑箱,很难解释模型是怎样工作的

训练时间长,需要大量的算力

网络结构复杂,需要调整超参数

小数据表现不佳,容易发生过拟合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值