Computer Science

TF01-05:Keras的Model模型使用

2019-07-12  本文已影响0人  杨强AT南京

本主题主要阐述下Keras框架中的模型Model的使用,主要包含的内容:
  1.模型的两种使用方式;
  2.经典模型的实现(定制模型);
  3.模型的定制训练;


一. 模型使用的两种方式

1. 函数式模型

  1. 函数式模型的示意图
函数式模型的示意图
  1. 函数式模型的示例代码 - 使用Layer的可调用运算
# Author:Louis Young
# Note:使用Iris数据集,构建的4-8-4-1的全链接神经网络
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import sklearn.datasets as datasets

# 1. 定义Layer层;
#   1.1. 输入层:必须是InputLayer或者Input创建的Tensor;
input_layer = keras.Input(shape=(4,))   # 4是Iris的特征维数(4个特征:可以参考sklearn中关于iris数据集的特征说明)
#   1.2. 隐藏层:8-4
hide1_layer = layers.Dense(units=8, activation='relu')
hide2_layer = layers.Dense(units=4, activation='relu')
#   1.3. 输出层:1
output_layer = layers.Dense(units=1, activation='sigmoid')

#  2. 构建Layer之间的函数链式关系
hide1_layer_tensor = hide1_layer(input_layer)      # <----------------------使用可调用特性
hide2_layer_tensor = hide2_layer(hide1_layer_tensor)
output_layer_tensor = output_layer(hide2_layer_tensor)

# 3. 使用inputs与outputs建立函数链式模型;
model = keras.Model(inputs=input_layer, outputs=output_layer_tensor)   # inputs与outputs一定是Layer调用输出的张量

# 4. 训练
#   4.1. 训练参数
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['mse'])
#   4.2. 训练
data, target = datasets.load_iris(return_X_y=True)
data = data[:100, :]   # 取前面100个样本(第一类与第二类)
target = target[:100]
model.fit(x=data, y=target, batch_size=10, epochs=1000, verbose=0)
#   4.3. 预测与评估
# 6.预测
pre_result = model.predict(data)
category = [0 if item<=0.5 else 1 for item in pre_result ]
accuracy = (target == category).mean()
print(F'分类准确度:{accuracy *100.0:5.2f}%', )
分类准确度:100.00%
  1. 函数式模型的示例代码-使用Layer的apply函数
    • apply函数实际是__call__运算符的别名。
# Author:Louis Young
# Note:使用Iris数据集,构建的4-8-4-1的全链接神经网络
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import sklearn.datasets as datasets

# 1. 定义Layer层;
#   1.1. 输入层:必须是InputLayer或者Input创建的Tensor;
input_layer = keras.Input(shape=(4,))   # 4是Iris的特征维数(4个特征:可以参考sklearn中关于iris数据集的特征说明)
#   1.2. 隐藏层:8-4
hide1_layer = layers.Dense(units=8, activation='relu')
hide2_layer = layers.Dense(units=4, activation='relu')
#   1.3. 输出层:1
output_layer = layers.Dense(units=1, activation='sigmoid')

#  2. 构建Layer之间的函数链式关系    
hide1_layer_tensor = hide1_layer.apply(input_layer)            # <----------------------使用apply
hide2_layer_tensor = hide2_layer.apply(hide1_layer_tensor)
output_layer_tensor = output_layer.apply(hide2_layer_tensor)
# 3. 使用inputs与outputs建立函数链式模型;
model = keras.Model(inputs=input_layer, outputs=output_layer_tensor)   # inputs与outputs一定是Layer调用输出的张量

# 4. 训练
#   4.1. 训练参数
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['mse'])
#   4.2. 训练
data, target = datasets.load_iris(return_X_y=True)
data = data[:100, :]   # 取前面100个样本(第一类与第二类)
target = target[:100]
model.fit(x=data, y=target, batch_size=10, epochs=1000, verbose=0)
#   4.3. 预测与评估
# 5.预测
pre_result = model.predict(data)
category = [0 if item<=0.5 else 1 for item in pre_result ]
accuracy = (target == category).mean()
print(F'分类准确度:{accuracy *100.0:5.2f}%', )
Tensor("dense_29/Identity:0", shape=(None, 1), dtype=float32)
分类准确度:100.00%

2. 顺序式模型

  1. 顺序式模型示意图
顺序式模型示意图
  1. 顺序式模型的示例代码-layers参数构建模型
# Author:Louis Young
# Note:使用Iris数据集,构建的4-8-4-1的全链接神经网络
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import sklearn.datasets as datasets


# 1. 构建Layer层
# 1. 定义Layer层;
#   1.1. 输入层:必须是InputLayer或者Input创建的Tensor;
input_layer = keras.Input(shape=(4,))   # 4是Iris的特征维数(4个特征:可以参考sklearn中关于iris数据集的特征说明)
#   1.2. 隐藏层:8-4
hide1_layer = layers.Dense(units=8, activation='relu')
hide2_layer = layers.Dense(units=4, activation='relu')
#   1.3. 输出层:1
output_layer = layers.Dense(units=1, activation='sigmoid')

# 2. 使用Sequential构建顺序模型
seq_model = keras.Sequential(layers=[input_layer, hide1_layer, hide2_layer, output_layer])

# -------------------下面部分与上面代码完全相同
# 3. 训练
#   3.1. 训练参数
seq_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['mse'])
#   3.2. 训练
data, target = datasets.load_iris(return_X_y=True)
data = data[:100, :]   # 取前面100个样本(第一类与第二类)
target = target[:100]
seq_model.fit(x=data, y=target, batch_size=10, epochs=1000, verbose=0)
#   3.3. 预测与评估
# 4.预测
pre_result = seq_model.predict(data)
category = [0 if item<=0.5 else 1 for item in pre_result ]
accuracy = (target == category).mean()
print(F'分类准确度:{accuracy *100.0:5.2f}%', )
分类准确度:100.00%
  1. 顺序式模型的示例代码-使用add方法构建模型
# Author:Louis Young
# Note:使用Iris数据集,构建的4-8-4-1的全链接神经网络
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import sklearn.datasets as datasets


# 1. 构建Layer层
# 1. 定义Layer层;
#   1.1. 输入层:必须是InputLayer或者Input创建的Tensor;
input_layer = keras.Input(shape=(4,))   # 4是Iris的特征维数(4个特征:可以参考sklearn中关于iris数据集的特征说明)
#   1.2. 隐藏层:8-4
hide1_layer = layers.Dense(units=8, activation='relu')
hide2_layer = layers.Dense(units=4, activation='relu')
#   1.3. 输出层:1
output_layer = layers.Dense(units=1, activation='sigmoid')

# 2. 使用Sequential构建顺序模型
seq_model = keras.Sequential()
seq_model.add(input_layer)
seq_model.add(hide1_layer)
seq_model.add(hide2_layer)
seq_model.add(output_layer)

# -------------------下面部分与上面代码完全相同
# 3. 训练
#   3.1. 训练参数
seq_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['mse'])
#   3.2. 训练
data, target = datasets.load_iris(return_X_y=True)
data = data[:100, :]   # 取前面100个样本(第一类与第二类)
target = target[:100]
seq_model.fit(x=data, y=target, batch_size=10, epochs=1000, verbose=0)
#   3.3. 预测与评估
# 4.预测
pre_result = seq_model.predict(data)
category = [0 if item<=0.5 else 1 for item in pre_result ]
accuracy = (target == category).mean()
print(F'分类准确度:{accuracy *100.0:5.2f}%', )
分类准确度:100.00%
  1. Layer类input与output属性的意义
# Author:Louis Young
# Note:使用Iris数据集,构建的4-8-4-1的全链接神经网络
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import sklearn.datasets as datasets


# 1. 构建Layer层
# 1. 定义Layer层;
#   1.1. 输入层:必须是InputLayer或者Input创建的Tensor;
input_layer = keras.Input(shape=(4,))   # 4是Iris的特征维数(4个特征:可以参考sklearn中关于iris数据集的特征说明)
#   1.2. 隐藏层:8-4
hide1_layer = layers.Dense(units=8, activation='relu')
hide2_layer = layers.Dense(units=4, activation='relu')
#   1.3. 输出层:1
output_layer = layers.Dense(units=1, activation='sigmoid')

# 2. 使用Sequential构建顺序模型
seq_model = keras.Sequential()
seq_model.add(input_layer)
seq_model.add(hide1_layer)
 
# seq_model = keras.Sequential([input_layer, hide1_layer])   与上面三个语句的作用一样。

# add方法本质也是自动调用Layer的可调用对象,只有调用后,Layer才具有input与output属性
print(hide1_layer.input)    # 可以注销22行。会出现错误,就可以理解add函数的作用。

Tensor("input_17:0", shape=(None, 4), dtype=float32)

二. 经典的模型实现-定制模型Model

1. 子类化Model说明

    tf.keras.models.Model
        |- tensorflow.python.keras.engine.network.Network
            |- tensorflow.python.keras.engine.base_layer.Layer
                |- tensorflow.python.module.module.Module
                    |- tensorflow.python.training.tracking.tracking.AutoTrackable
                        

2. 使用定制Model构建模型

  1. 定制过程

    • 继承Model类;
    • 定制构造器,实现定制属性传递;
    • 定制call函数,实现模型的输出;
  2. 定制Model示例代码

# Author:Louis Young
# Note:使用Iris数据集,构建的4-8-4-1的全链接神经网络
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import sklearn.datasets as datasets


class ModelException(Exception):
    def __init__(self, msg='模型构建异常'):
        self.message = msg

# 1. 构建模型
class IrisModel(keras.Model):
    # 构造器
    def __init__(self, networks):
        super(IrisModel, self).__init__(name='iris_model')
        # 判定参数类型是否是list
        if not isinstance(networks, list):
            raise ModelException('networks指定网络结构,类型是列表')
        # 生成networks属性
        self.networks = networks
        # 构建层
        self._layers = []
        for _net in networks[:-1]:  # 不考虑输入层
            layer = layers.Dense(units=_net, activation='relu')
            self._layers.append(layer)

        # 最后一层使用sigmoid函数
        layer = layers.Dense(units=networks[-1], activation='sigmoid')
        self._layers.append(layer)

    # forward方法:构建网络模型
    def call(self, inputs, **kwargs):
        # 根据层构建模型输出
        # 第一层的输入来自参数inputs
        x = self._layers[0](inputs)
        for _layer in self._layers[1:]:
            # 上一层输出作为下一层输入调用参数
            x = _layer(x)

        # 返回最后一层作为输出
        return x


# 2. 创建模型实例
model = IrisModel([8, 4, 1])  # 不包含输入的层4
# ----------------------------------------< 以上为典型的模型构建方式。

# 3. 定义训练参数
model.compile(
    optimizer='adam',     # 指定优化器
    loss='binary_crossentropy',   # 指定损失函数
    metrics=['accuracy']
)

# 4. 数据加载
data, target = datasets.load_iris(return_X_y=True)
data = data[:100, :]   # 取前面100个样本(第一类与第二类)
target = target[:100]
# 5. 训练
model.fit(x=data, y=target, batch_size=10, epochs=100, verbose=0)

# 6.预测
# pre_result = model.predict(data)
pre_result = model(data)    # 与上一语句作用一样 predict函数等价于对象的调用
category = [0 if item <= 0.5 else 1 for item in pre_result ]
accuracy = (target == category).mean()
print(F'分类准确度:{accuracy *100.0:5.2f}%', )
分类准确度:100.00%

三. 模型的定制训练

1. 定义训练参数

1.1. 优化器对象

  1. Adam构造器说明

    __init__(
        learning_rate=0.001,      # 学习率
        beta_1=0.9,
        beta_2=0.999,
        epsilon=1e-07,
        amsgrad=False,
        name='Adam',
        **kwargs
    )
  1. 优化器的优化调用
    apply_gradients(             # 梯度更新
        grads_and_vars,  
        name=None
    )
  1. 优化器创建代码
import tensorflow.keras.optimizers as optimizers
optimizer = optimizers.Adam(learning_rate=0.0001)

1.2. 损失对象

- 该对象是可调用对象,用来实现损失计算。
  1. CategoricalCrossentropy损失类的构造器说明:


    __init__(
        from_logits=False,
        label_smoothing=0,
        reduction=losses_utils.ReductionV2.AUTO,
        name='categorical_crossentropy'
    )
    
  1. 可调用对象运算符说明
    __call__(
        y_true,        # 标签值
        y_pred,        # 预测值
        sample_weight=None
    )
  1. 损失对象构造
import tensorflow.keras.losses as losses
loss =losses.CategoricalCrossentropy()

1.3. 梯度计算

- 使用`tf.GradientTape`计算梯度
  1. 上下文环境
    __enter__()
    
    __exit__(
        typ,
        value,
        traceback
)
  1. 计算梯度
    • 返回与sources一样的结构的梯度结构。
    gradient(
        target,                # 误差项
        sources,
        output_gradients=None,
        unconnected_gradients=tf.UnconnectedGradients.NONE
    )
  1. 梯度对象与梯度计算代码
with tf.GradientTape() as tape:
    gradients = tape.gradient(
        loss,      # 损失张量(不是对象)
        model.trainable_variables)    # 需要更新的可训练权重张量

1.4. 评估度量

- 评估方式用来计算准确率,精准率,召回率等。
- 下面是Accuracy类的说明
  1. Accuracy构造器
    __init__(
        name='accuracy',
        dtype=None
    )
    Accuracy
        |- MeanMetricWrapper
            |- Mean
                |- Reduce
                    |- Metric
                        |- tensorflow.python.keras.engine.base_layer.Layer
    def __call__(self, *args, **kwargs):
import tensorflow.keras.metrics as metrics
metric = metrics.Accuracy()

2. 训练过程实现

2.1. 训练准备-创建模型

# Author:Louis Young
# Note:使用Iris数据集,构建的4-8-4-1的全链接神经网络
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import tensorflow.keras.optimizers as optimizers
import tensorflow.keras.losses as losses
import tensorflow.keras.metrics as metrics
import sklearn.datasets as datasets


class ModelException(Exception):
    def __init__(self, msg='模型构建异常'):
        self.message = msg

# 1. 构建模型
class IrisModel(keras.Model):
    # 构造器
    def __init__(self, networks):
        super(IrisModel, self).__init__(name='iris_model')
        # 判定参数类型是否是list
        if not isinstance(networks, list):
            raise ModelException('networks指定网络结构,类型是列表')
        # 生成networks属性
        self.networks = networks
        # 构建层
        self._layers = []
        for _net in networks[:-1]:  # 不考虑输入层
            layer = layers.Dense(units=_net, activation='relu')
            self._layers.append(layer)

        # 最后一层使用sigmoid函数
        layer = layers.Dense(units=networks[-1], activation='sigmoid')
        self._layers.append(layer)

    # forward方法:构建网络模型
    def call(self, inputs, **kwargs):
        # 根据层构建模型输出
        # 第一层的输入来自参数inputs
        x = self._layers[0](inputs)
        for _layer in self._layers[1:]:
            # 上一层输出作为下一层输入调用参数
            x = _layer(x)

        # 返回最后一层作为输出
        return x


# 2. 创建模型实例
model = IrisModel([8, 4, 1])  # 不包含输入的层4
# ----------------------------------------< 以上为典型的模型构建方式。

2.2. 定义训练需要的对象

# 1. 优化器对象
optimizer = optimizers.Adam()
# 2. 损失计算对象
losser = losses.BinaryCrossentropy()
# 3. 准确率计算对象
accuracier = metrics.Accuracy()
# 4. 梯度计算对象  # GradientTape构建后只能调用一次,所以在with中使用
# tape = tf.GradientTape()

2.3. 训练实现

  1. 准备数据
# 准备数据
data, target = datasets.load_iris(return_X_y=True)
data = data[:100, :]   # 取前面100个样本(第一类与第二类)
target = target[:100]

  1. 训练
epochs = 100
batch_size = 10
batch_num = int(math.ceil(len(data) / batch_size))
for epoch in range(epochs):
    for i in range(len(data)):

        with tf.GradientTape() as tape:
            start_ = i * batch_size
            end_ = (i + 1) * batch_size
            # 计算输出
            predictions = model(data[start_: end_])
            # 计算损失
            loss_value = losser(target[start_: end_], predictions)
        # 计算梯度,不能在with中调用
        gradients = tape.gradient(loss_value, model.trainable_variables)
        # 更新权重
        optimizer.apply_gradients(zip(gradients, model.trainable_variables))

pre_result = model(data)
category = [0 if item <= 0.5 else 1 for item in pre_result ]
accuracy = (target == category).mean()
print(F'分类准确度:{accuracy *100.0:5.2f}%')
print(pre_result)
分类准确度:100.00%
tf.Tensor(
[[0.05429551]
 [0.06767229]
 [0.06427257]
 [0.06895139]

...省略  

 [0.99639302]
 [0.95713528]
 [0.99546698]], shape=(100, 1), dtype=float64)

上一篇 下一篇

猜你喜欢

热点阅读