文章目录
1. 神经网络的构建方式
- jupyter botebook 中可以使用shift + tab查看函数参数提示。
1.1 Sequential构建方式
只能构建序列模型
- 构建模型
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
model = keras.Sequential(
[
# 第一个隐藏层
layers.Dense(3, activation="relu", kernel_initializer='he_normal', name = "layer1",input_shape=(3,)),
layers.Dense(2, activation="relu", kernel_initializer='he_normal', name = "layer2"),
layers.Dense(2, activation="sigmoid", kernel_initializer='he_normal', name = "layer3"),
],
name = "my_Seq"
)
- 展示模型
model.summary()
1.2 利用function API构建
tf.keras提供了Function API,建立更为复杂的模型,使用方法是将层座位可调用的对象并返回张量,并将输入向量和输出向量提供给 tf.keras.Model 的 inputs 和 outputs 参数,实现方法如下:
inputs = keras.Input(shape=(3,), name = "my_input")
layer1 = keras.layers.Dense(2,activation="relu", kernel_initializer='he_normal', name = "layer1" )(inputs)
layer2 = keras.layers.Dense(2,activation="relu", kernel_initializer='he_normal', name = "layer2" )(layer1)
outputs = keras.layers.Dense(2,activation="sigmoid", kernel_initializer='he_normal', name = "layer3" )(layer2)
model = keras.Model(inputs = inputs, outputs = outputs, name="my_model")
效果
1.3 通过Model的子类构建
- 需要在子类的 __init__ 中定义神经网络的层,在 call 方法中定义网络的前向传播过程。实现方法如下:
class MyModel(keras.Model):
# 定义网络层结构
def __init__(self):
super(MyModel, self).__init__()
self.layer1 = keras.layers.Dense(3, activation="relu", kernel_initializer='he_normal', name = "layer1")
self.layer2 = keras.layers.Dense(2, activation="relu", kernel_initializer='he_normal', name = "layer2")
self.layer3 = keras.layers.Dense(2, activation="sigmoid", kernel_initializer='he_normal', name = "layer3")
# 定义网络前向传播过程
def call(self, inputs):
x = self.layer1(inputs)
x = self.layer2(x)
x = self.layer3(x)
return x
# 实例化模型
model = MyModel()
x = tf.ones((1, 3))
y = model(x) # 设置一个输入,调用模型,否则模型无法使用summay
model.summary()
2. 损失函数
- 损失函数用来衡量模型参数的质量的函数,衡量的方式是比较网络输出和真实输出的差异,损失函数在不同的文献中名称是不一样的,主要有以下几种命名方式:
- 损失函数
- 代价函数
- 目标函数
- 误差函数
2.1 分类任务中的损失函数
- 在分类任务中使用最多的是交叉熵损失函数,有多分类的交叉熵,也有二分类的交叉熵。
多分类任务
多分类中通常使用softmax转换成概率的形式,一般交叉熵一般在softmax后边,所以多分类的交叉熵损失也叫做softmax损失,它的计算方法是:
例子:
从概率论的角度理解,我们的目的是最小化正确类别所对应的预测概率的对数的负值,如下所示:
代码如下
# 设置真实值与预测值
y_true = [[0,1,0], [0,0,1]]
y_pre = [[0.05, 0.9, 0.05], [0.3, 0.2, 0.5]] # softmax输出的结果 sum == 1
# 实例化交叉熵损失函数
cce = keras.losses.CategoricalCrossentropy()
# 计算损失结果
cce(y_true, y_pre)
输出
0.39925388
此时,更改第二个预测值的概率分布,
# 设置真实值与预测值
y_true = [[0,1,0], [0,0,1]]
y_pre = [[0.05, 0.9, 0.05], [0.05, 0.05, 0.9]] # softmax输出的结果 sum == 1
# 实例化交叉熵损失函数
cce = keras.losses.CategoricalCrossentropy()
# 计算损失结果
cce(y_true, y_pre)
输出
0.105360545
可见,符合上边的那个曲线图,综合预测的概率越大(越接近真实值),损失函数越小
二分类任务
- 二分类任务时,不是用softmax激活函数,而是使用sigmoid函数,所以损失函数也要进行相应调整,是用二分类的交叉熵损失函数:
代码如下:
# 设置真实值与预测值
y_true = [[0], [1]] # 两个样本 原始标签:一个是 一个不是
y_pre = [[0.4], [0.6]]
# 实例化二分类的交叉熵损失函数
cce = keras.losses.BinaryCrossentropy()
# 计算损失结果
cce(y_true, y_pre)
输出:
0.5108254
此时,调整一下预测值
# 设置真实值与预测值
y_true = [[0], [1]] # 两个样本 原始标签:一个是 一个不是
y_pre = [[0.1], [0.9]]
# 实例化二分类的交叉熵损失函数
cce = keras.losses.BinaryCrossentropy()
# 计算损失结果
cce(y_true, y_pre)
输出:
0.10536041
可见,预测值越接近真实值,损失函数越小。
2.2 回归任务中的损失函数
- 回归任务中常用损失函数
- MAE损失(L1 损失)
- MSE损失(L2 损失)
- smooth L1损失
MAE(L1 loss)损失
MAE损失也叫 L1 loss,是以绝对误差作为距离:
曲线图如下:
特点:L1 loss具有稀疏性,为了惩罚较大的值,因此尝尝将其作为正则项添加到其他loss中作为约束。L1 loss的最大问题是梯度在零点不平滑(不可导),导致会跳过极小值。
# 设置真实值与预测值
y_true = [[0.], [1.]] # 两个样本
y_pre = [[1.], [0.]]
# 实例化MAE损失函数
mae = keras.losses.MeanAbsoluteError()
# 计算损失结果
mae(y_true, y_pre)
输出:
1.0
MSE(L2 loss)损失
也叫 L2 loss 或欧氏距离,它以误差的平方和作为距离:
曲线图如下:
特点是:L2 loss也常常作为正则项。当预测值与目标值相差很大时,梯度容易爆炸。
代码如下:
# 设置真实值与预测值
y_true = [[0.], [1.]] # 两个样本 float型
y_pre = [[1.], [1.]]
# 实例化MSE损失函数
mse = keras.losses.MeanSquaredError()
# 计算损失结果
mse(y_true, y_pre)
输出:
0.5
smooth L1 损失
平滑后的 L1 损失,结合了 L1 和 L2 的优点。|x| < 1时是L2,否则 是L1
曲线图如下:
从图可见,smooth L1是一个分段函数,在[-1, 1]之间是一个L2损失,其他范围是L1损失。
代码如下:
# 设置真实值与预测值
y_true = [[0], [1]] # 两个样本
y_pre = [[0.6], [0.4]]
# 实例化 smooth L1 损失函数
h = keras.losses.Huber()
# 计算损失结果
h(y_true, y_pre)
输出
0.18