Tensorflow之keras

keras

  • keras是基于python的高级神经网路API.keras必须有后端才可以运行,后端可以切换。它以特别方便快速试验,帮助用户以最少的时间验证自己的想法,帮助用户以最少的时间验证自己的想法。

  • Tf-keras和keras联系

    它们都基于同一套API,keras程序可以通过改导入方式轻松转为tf.keras程序
    反之不能成立,因为tf.keras有其他特性,而keras不能满足
    它们有相同的JOSN和HDF5模型序列化格式和语义
    
  • tf-keras和keras区别

    1.tf.keras全面支持动态图模式
    2.只用keras.Sequential和keras.Model时没影响。自定义Model内部运算逻辑的时候有影响
    3.TF.keras支持基于tf.data模型训练,支持TPU训练,支持tf.distribution中分布式策略。Tf.keras可以与tensorflow中estimator集成,tf.keras可以保存SavedModel
    

1.分类问题+回归问题

  • 分类问题其实是预测当前所属类别,通过模型输出的是它的概率分布,而回归问题预测的是值,模型输出的是一个实际值。

  • 回归问题,预测预测值与真实值之间差距。

  • 目标函数

    为什么需要目标函数?
    	这是机器学习特性所决定的,大部分机器学习都是逐步调整参数得到最优解,从而逼近目标值。而目标函数可以帮助衡量模型好坏程度。
    	比如一个分类问题:它能衡量目标类别与当前预测的差距。通过One-hot编码,把一个正整数变为向量表达(生成一个长度不小于正整数向量,只有正整数的位置处于1,其余处于0)。
    
  • 分类问题常用方式:

    • 平方差损失

      平方差损失距离:
      	预测值: [0.2, 0.7, 0.1]
      	真实值: [0, 0, 1]
      	损失函数值: [(0-0)^2 + (0.7-0)^2 + (0.1-1)^2]*0.5 = 0.65
      
    • 交叉熵损失

2.Tf.kears分类模型示例

  • 我们采用tensorflow内置图片数据集进行示例:fashion_mnist

    • 导包:
    # tf.keras 分类模型
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    %matplotlib inline
    import numpy as np
    import sklearn
    import pandas as pd
    import os
    import sys
    import time
    import tensorflow as tf
    from tensorflow import keras
    # 打印版本
    print(tf.__version__)
    print(sys.version_info)
    for module in mpl,np,pd,sklearn,tf,keras:
        print(module.__name__, module.__version__)
    """
    2.1.0
    sys.version_info(major=3, minor=7, micro=5, releaselevel='final', serial=0)
    matplotlib 3.3.3
    numpy 1.19.5
    pandas 1.2.1
    sklearn 0.24.0
    tensorflow 2.1.0
    tensorflow_core.keras 2.2.4-tf
    """
    
    • 数据导入
    # 导入内置图片数据集
    fashion_mnist = keras.datasets.fashion_mnist
    #           训练集            测试集
    (x_train_all,y_train_all),(x_test,y_test) = fashion_mnist.load_data() 
    # 拆分前5000张作为验证集,剩下作为训练集
    x_valid, x_train = x_train_all[:5000], x_train_all[5000:]
    y_valid, y_train = y_train_all[:5000], y_train_all[5000:]
    # 打印大小
    print(x_valid.shape, y_valid.shape)
    print(x_train.shape, y_train.shape)
    print(x_test.shape, y_test.shape)
    """
    (5000, 28, 28) (5000,)
    (55000, 28, 28) (55000,)
    (10000, 28, 28) (10000,)
    """
    
    • 展示一张图片
    def show_single_image(img_arr):
        """
        展示查看一张图片
        """
        plt.imshow(img_arr,cmap="binary")
                
    show_single_image(x_train[0])
    

    • 展示多个图片集合
    def show_imgs(n_rows, n_cols,x_data,y_data,class_names):
        """
        展示图片集
        class_names 索引
        """
        # 
        assert len(x_data) == len(y_data)
        # 验证行和列的乘积不能大于样本数
        assert n_rows * n_cols < len(x_data)
        # 定义图大小
        plt.figure(figsize=(n_cols * 1.4, n_rows * 1.6))
        # 对每行每列放图片
        for row in range(n_rows):
            for col in range(n_cols):
                index = n_cols * row + col
                # 绘制子图
                plt.subplot(n_rows, n_cols, index+1)
                # 展示数据  interpolation缩放图片
                plt.imshow(x_data[index], cmap="binary",interpolation="nearest")
                # 关闭坐标系
                plt.axis("off")
                # 配置title
                plt.title(class_names[y_data[index]])
        plt.show()
    class_names = ["T-shirt","Trouser","Pullover","Dress","Coat","Sandal","Shirt","Sneaker","Bag", "Ankle boot"]
    # 显示3行5列
    show_imgs(3, 5,x_train,y_train,class_names)
    
    

    • 使用tf.keras.models.Sequential 进行分类
    # 使用tf.keras.models.Sequential 进行分类
    # 写法1:
    # Sequential对象
    model = keras.models.Sequential()
    # 往对象添加层次:
    # 添加输入层,并将其展开  : 我输入的是28*28矩阵,用Flatten进行展平,成为一个一维向量
    model.add(keras.layers.Flatten(input_shape=[28,28]))
    # 添加全连接层 单元数:300(它是用层次发掘神经网络,上一层神经单元和下一层神经单元一一进行连接)  activation表示激活函数
    model.add(keras.layers.Dense(300, activation="relu"))
    # 再添加全连接层 单元数:100
    model.add(keras.layers.Dense(100, activation="relu"))
    model.add(keras.layers.Dense(10, activation="softmax"))
    # relu: y = max(0,x)
    # softmax: 将向量变成概率分布输出  
        # x=[x1,x2,x3]
        # y = [e^x1/sum , e^x2/sum, e^x3/sum], sum = e^x1 + e^x2 + e^x3
    
    # 写法2:
    # model = keras.models.Sequential([
    #     keras.layers.Flatten(input_shape=[28,28]),
    #     keras.layers.Dense(300, activation="relu"),
    #     keras.layers.Dense(100, activation="relu"),
    #     keras.layers.Dense(10, activation="softmax")
    # ])
        
        
        
    # 因为y是一个index值,我们需要将y 经过one_hot 变成一个向量
    # 如果y是一个向量用categorical_crossentropy即可
    # optimizer 为求解优化器方法: 这里使用adam
    # metrics : 把损失函数,优化方法加入 keras.optimizers.SGD(lr = 0.1)
    model.compile(loss="sparse_categorical_crossentropy",optimizer="adam", metrics=["accuracy"])
    
    • 查看模型层数
    # 查看模型层数
    model.layers
    """
    [<tensorflow.python.keras.layers.core.Flatten at 0x7fa359641750>,
     <tensorflow.python.keras.layers.core.Dense at 0x7fa359641950>,
     <tensorflow.python.keras.layers.core.Dense at 0x7fa359645490>,
     <tensorflow.python.keras.layers.core.Dense at 0x7fa359645050>]
    """
    
    • 查看模型概况
    # 查看模型概况
    model.summary()
    """
    Model: "sequential_7"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    flatten_7 (Flatten)          (None, 784)               0         
    _________________________________________________________________
    dense_21 (Dense)             (None, 300)               235500    
    _________________________________________________________________
    dense_22 (Dense)             (None, 100)               30100     
    _________________________________________________________________
    dense_23 (Dense)             (None, 10)                1010      
    =================================================================
    Total params: 266,610
    Trainable params: 266,610
    Non-trainable params: 0
    _________________________________________________________________
    """
    
    • 开始训练
    # 整个层数解析:
        # 第一层:是样本数 乘以 784 矩阵
        # 第二层:进入全连接层  将其变成样本数 * 300 矩阵  (变换过程: 【样本数 乘以 784 】 * W(权重, W为[784,300]矩阵) + b(偏执, b为300长的向量))
        # 第三层,第四层也是如上方式实现
    # 训练模型
    # epochs:将训练集运行10次
    # validation_data:对训练集进行验证
    history = model.fit(x_train,y_train, epochs=10,validation_data=(x_valid,y_valid))
    """
    Train on 55000 samples, validate on 5000 samples
    Epoch 1/10
    55000/55000 [==============================] - 5s 95us/sample - loss: 2.0006 - accuracy: 0.7321 - val_loss: 0.6174 - val_accuracy: 0.8032
    Epoch 2/10
    55000/55000 [==============================] - 4s 81us/sample - loss: 0.5339 - accuracy: 0.8135 - val_loss: 0.4758 - val_accuracy: 0.8424
    Epoch 3/10
    55000/55000 [==============================] - 5s 99us/sample - loss: 0.4774 - accuracy: 0.8339 - val_loss: 0.4359 - val_accuracy: 0.8538
    Epoch 4/10
    55000/55000 [==============================] - 5s 91us/sample - loss: 0.4468 - accuracy: 0.8447 - val_loss: 0.4878 - val_accuracy: 0.8392
    Epoch 5/10
    55000/55000 [==============================] - 5s 95us/sample - loss: 0.4269 - accuracy: 0.8511 - val_loss: 0.4067 - val_accuracy: 0.8642
    Epoch 6/10
    55000/55000 [==============================] - 5s 93us/sample - loss: 0.4076 - accuracy: 0.8551 - val_loss: 0.3962 - val_accuracy: 0.8728
    Epoch 7/10
    55000/55000 [==============================] - 5s 97us/sample - loss: 0.4024 - accuracy: 0.8594 - val_loss: 0.3951 - val_accuracy: 0.8690
    Epoch 8/10
    55000/55000 [==============================] - 5s 98us/sample - loss: 0.3881 - accuracy: 0.8627 - val_loss: 0.4112 - val_accuracy: 0.8626
    Epoch 9/10
    55000/55000 [==============================] - 5s 95us/sample - loss: 0.3734 - accuracy: 0.8691 - val_loss: 0.4331 - val_accuracy: 0.8550
    Epoch 10/10
    55000/55000 [==============================] - 5s 95us/sample - loss: 0.3594 - accuracy: 0.8727 - val_loss: 0.3709 - val_accuracy: 0.8800
    history.history
    """
    
    • 查看训练结果
    def plot_learning_curves(history):
        """
        查看训练结果图
        """
        # 设置图像大小
        pd.DataFrame(history.history).plot(figsize=(8,5))
        # 显示网格
        plt.grid(True)
        # 坐标轴范围
        plt.gca().set_ylim(0,1)
        plt.show()
    plot_learning_curves(history)
    

3.分类模型归一化

  • 训练后数据的准确率达到81%-87%之间,而在图像分类有个很有效的方式用于提高准确率,那就是归一化
  • 这里使用sklearn进行归一化,采用x = (x - avg) /std方式进行归一化(avg是均值,std是方差)
  • 代码:
    • 导入图片数据集
# 这里使用sklearn进行归一化
# 导入内置图片数据集
fashion_mnist = keras.datasets.fashion_mnist
#           训练集            测试集
(x_train_all,y_train_all),(x_test,y_test) = fashion_mnist.load_data() 
# 拆分前5000张作为验证集,剩下作为训练集
x_valid, x_train = x_train_all[:5000], x_train_all[5000:]
y_valid, y_train = y_train_all[:5000], y_train_all[5000:]
print(x_valid.shape, y_valid.shape)
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
"""
(5000, 28, 28) (5000,)
(55000, 28, 28) (55000,)
(10000, 28, 28) (10000,)
"""
  • 打印训练集最大值
print(np.max(x_train), np.min(x_train))
# 255 0
  • 归一化:训练集,验证集,测试集
# 归一化
# 
# x = (x - avg) /std
# avg是均值
# std是方差
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
# 训练集做归一化
# 归一化只能进行二维矩阵归一化,因为x_train是三维矩阵,首先将它转为二维矩阵,然后归一化,然后再转回三维矩阵
x_train_scaled = scaler.fit_transform(x_train.astype(np.float32).reshape(-1,1)).reshape(-1,28,28)
# 验证集做归一化
x_valid_scaled = scaler.transform(x_valid.astype(np.float32).reshape(-1,1)).reshape(-1,28,28)
# 测试集做归一化
x_test_scaled = scaler.transform(x_test.astype(np.float32).reshape(-1,1)).reshape(-1,28,28)
  • 此时再打印训练集最大值
print(np.max(x_train_scaled), np.min(x_train_scaled))
# 2.0231433 -0.8105136
  • 使用tf.keras.models.Sequential 进行分类(同上)
  • 训练模型,这里训练集和验证集为归一化的数据集
history = model.fit(x_train_scaled,y_train, epochs=10,validation_data=(x_valid_scaled,y_valid))
"""
Train on 55000 samples, validate on 5000 samples
Epoch 1/10
55000/55000 [==============================] - 5s 95us/sample - loss: 0.4586 - accuracy: 0.8323 - val_loss: 0.3790 - val_accuracy: 0.8560
Epoch 2/10
55000/55000 [==============================] - 6s 104us/sample - loss: 0.3526 - accuracy: 0.8701 - val_loss: 0.3577 - val_accuracy: 0.8718
Epoch 3/10
55000/55000 [==============================] - 5s 95us/sample - loss: 0.3154 - accuracy: 0.8826 - val_loss: 0.3366 - val_accuracy: 0.8758
Epoch 4/10
55000/55000 [==============================] - 5s 93us/sample - loss: 0.2916 - accuracy: 0.8909 - val_loss: 0.3162 - val_accuracy: 0.8854
Epoch 5/10
55000/55000 [==============================] - 5s 91us/sample - loss: 0.2722 - accuracy: 0.8972 - val_loss: 0.3546 - val_accuracy: 0.8720
Epoch 6/10
55000/55000 [==============================] - 5s 92us/sample - loss: 0.2593 - accuracy: 0.9024 - val_loss: 0.3358 - val_accuracy: 0.8800
Epoch 7/10
55000/55000 [==============================] - 5s 90us/sample - loss: 0.2395 - accuracy: 0.9095 - val_loss: 0.3286 - val_accuracy: 0.8894
Epoch 8/10
55000/55000 [==============================] - 5s 91us/sample - loss: 0.2318 - accuracy: 0.9122 - val_loss: 0.3225 - val_accuracy: 0.8900
Epoch 9/10
55000/55000 [==============================] - 5s 88us/sample - loss: 0.2172 - accuracy: 0.9185 - val_loss: 0.3302 - val_accuracy: 0.8930
Epoch 10/10
55000/55000 [==============================] - 5s 89us/sample - loss: 0.2101 - accuracy: 0.9202 - val_loss: 0.3380 - val_accuracy: 0.8942
"""
  • 查看训练结果图

  • 由上面可以知道归一化的训练后结果准确率:达到最高92%

  • 验证准确率

    model.evaluate(x_test_scaled, y_test)
    """
    10000/10000 [==============================] - 0s 37us/sample - loss: 0.3633 - accuracy: 0.8853
    [0.3633375147640705, 0.8853]
    """
    loss 0.3633375147640705
    准确度:0.8853
    

4.回调函数

  • 当你在训练模型时候,你中间可以做一些事情,常用回调函数:

    EarlyStopping	当模型训练时候当你的loss在不断下降时候,我们可以提前停掉
    ModelCheckpoint	 将在每个epoch后保存模型到filepath
    TensorBoard		模型训练过程中可以显示训练结果状态
    
  • 只需在model.fit调用回调函数

    # Tensorboard
    logdir = "./callbacks"
    # 创建目录
    if not os.path.exists(logdir):
        os.mkdir(logdir)
    # 定义输出文件
    output_model_file = os.path.join(logdir, "fashion_mnist_model.h5")
    callbacks = [
        keras.callbacks.TensorBoard(logdir),
        # save_best_only保存最好模型
        keras.callbacks.ModelCheckpoint(output_model_file, save_best_only=True),
        # patience 当下一次训练比上一次训练小的时候,连续发生多少次,就要停掉
        # min_delta 阈值, 当前次训练比上一次训练要低于这个值会停掉
        keras.callbacks.EarlyStopping( patience=5,min_delta=1e-3)
    ]
    
    history = model.fit(x_train_scaled,y_train, epochs=10,validation_data=(x_valid_scaled,y_valid),callbacks=callbacks)
    
  • 命令行中callbacks目录下执行tensorboard --logdir=callbacks --host=0.0.0.0获取详细信息

    • 可以调整Smoothing调整平滑度
    • GRAPHS查看训练模型

5.回归模型

??

6.神经网络如何进行训练

  • 采用训练方式为梯度下降方式,首先进行求导,找到每个变量变化方向,然后更新参数。上面我们的分类模型为一个三层,伴随层次越来越深。就成深度神经网络。

7.激活函数

  • 在我们构建模型层次时候,使用激活函数,激活函数有如下

    它们将非线性特性引入到我们的网络中。其主要目的是将模型中一个节点的输入信号转换成一个输出信号。该输出信号现在被用作堆叠中下一个层的输入。
    

8.归一化和批归一化

  • 其实它就是将输入输出数据进行规整,使它的均值为0,方差为1。常用归一化种类

    Min-max归一化: x*=(x-min)/(max-min)
    Z-score归一化:  x*=(x-μ)/σ
    
  • 批归一化

    将每层激活值都做归一化
    
  • 为什么归一化有效,如下图:

    图一没有做归一化处理导致theta1与theta2值是不一样的。这样由于theta1与theta2值是不一样,等高线看起来像是一个椭圆,(等高线解释:等高线表示在这条等高线的值都是一样的),但是目标函数值是一样的。因为它是椭圆,在计算法向量时候没有指向圆心,导致训练轨迹非常曲折。
    
    经过归一化如图二,当然训练速度也会更快
    

11.Dropout

  • Dropout是一种在深度学习环境中应用的正规化手段。它是这样运作的:在一次循环中我们先随机选择神经层中的一些单元并将其临时隐藏,然后再进行该次循环中神经网络的训练和优化过程。在下一次循环中,我们又将隐藏另外一些神经元,如此直至训练结束。Dropout

  • Droupout作用

    作用可以防止过拟合:
    (什么是过拟合:训练集上表现很好,测试集上不好)---造成这样原因可能模型参数比较多,容量太大,使得模型记住样本(测试集的样本和训练集样本是不一样),不能泛华
    

12.Keras实现深度神经网络

  • 还是以上面为例只不过我们添加学习网络时,增加20层

    # 使用tf.keras.models.Sequential 进行分类
    # Sequential对象
    model = keras.models.Sequential()
    # 往对象添加层次:
    # 添加输入层,并将其展开  : 我输入的是28*28矩阵,用Flatten进行展平,成为一个一维向量
    model.add(keras.layers.Flatten(input_shape=[28,28]))
    # 添加20层学习网络
    for _ in range(20):
        model.add(keras.layers.Dense(100, activation="relu"))
    model.add(keras.layers.Dense(10,activation="softmax"))
    
  • 此时打印训练结果图

    由上图我们发现,相对于之前学习曲线图在初期时候(x轴0到3之间),目标函数趋势是不怎么发生变化的。而把目标函数迭代到x轴为4时,目标函数才变化的陡峭,导致原因是:
    	1. 由于是深度学习,参数比较多,训练不充分。
    	2. 梯度消失:一般发生在深度学习网络里,导致发生原因为链式法则,(链式法则用于复合函数求导f(g(x)), 函数g(x)输出是f函数输入)。对于低层次神经网络,它的复合函数嵌套较多,梯度一层一层传导下去,到低层次因符合函数嵌套较多,就有可能导致梯度消失,导致训练结果比较平滑,梯度消失
    
  • 批归一化实现

    • 在keras实现批归一化较为简单,只需要在添加训练模型时候添加 如下代码
    model.add(keras.layers.BatchNormalization())
    
    • 批归一化添加也可以放在激活函数之前
    model.add(keras.layers.Dense(100))# 添加学习层次
    model.add(keras.layers.BatchNormalization())# 批归一化
    model.add(keras.layers.Activation('relu'))# 添加激活后面
    
    • 训练结果

    我们可以看到进行批归一化训练的模型,没有了上述问题。我们通过批归一化缓解梯度消失,通过归一化是数据更加规整,这样计算更加准确
    
  • 激活函数更改带来效果

    • selu 自带归一化的激活函数
    model.add(keras.layers.Dense(100, activation="selu"))
    
    • 训练效果 训练时间优于BatchNormalization
  • dropout添加

    • 一般我们添加dropout都是在最后几层添加
    # rate为添加单元比例
    # 添加AlphaDropout
    model.add(keras.layers.AlphaDropout(rate=0.5))
    # 添加普通Dropout方式
    model.add(keras.layers.Dropout(rate=0.5))
    

    AlphaDropout 比 Dropout更加强大,AlphaDropout优势:均值和方差不变,归一化的性质也不变。

  • Dropout使用,根据自己训练场景定,如果没有出现过拟合现象可以不用使用Dropout

13. wide和Deep模型

  • 用于分类和回归的模型,并应用到了 Google Play 的应用推荐中。wide and deep 模型的核心思想是结合线性模型的记忆能力(memorization)和 DNN 模型的泛化能力(generalization),在训练过程中同时优化 2 个模型的参数,从而达到整体模型的预测能力最优。

  • 稀疏特征:

    • 什么是稀疏特征:

      比如我们100维度的向量(x1,x2,....x100),我们通过x1,x2,x3来表示即可,其他参数约束为0,那么他就是一种稀疏表示思想。
      
    • 它是一个离散值特征,使用One-hot表示。而稀疏特征可以进行叉乘,叉乘可以有效刻画样本,通过稀疏特征做叉乘取出共现信息,实现模型记忆效果。

      有一个词表:  [你,他, 计算机]  经过one-hot ===>  他=[0,0,1,...]   计算机=[1,0,1,...]
      进行叉乘 : (他,计算机)  
      
    • 优缺点:

      优点:
      	降低表示复杂度,更直白的原因其实就是减少系数参数,通过稀疏表示,可以充分发挥数据所含有的信息,去掉冗余的数据信息,达到最大化利用数据,广泛用于工业界
      缺点:
      	需要人工设计
      	可能过拟合,所有特征都叉乘,相当于记住每一个样本
      
  • 密集特征

    • 用向量表达特征

      有一个词表:  [你,他, 计算机]  经过one-hot ===>  他=[0,0,1,...]   计算机=[1,0,1,...]
      他   用一个向量来表示 [0.2,0.5,0.3,...(n维向量)]
      
    • Word2vec工具就是词语转化成向量。

    • 优缺点

      优点:
      	带有语义信息,不同向量之间有相关性
      	兼容没有出现过的特征组合
      	更少的人工去设计
      缺点:
      	过度泛化,导致推荐不怎么相关的产品
      
  • wide 和deep模型结构

图像左侧为wide模型 
右侧为wide&deep模型

wide模型 
	它所有输入都连接输出上,输入就是系数特征(one-hot表达)


wide&deep
	左半部分是一个wide模型
	右半部分是deep模型,他是多层的模型。首先输入是稀疏特征,deep把说有输入数据作为一个密集的向量表达,然后进行多层的全连接网络,最后连接到输出。

14.wide 和deep模型实现

14.1函数API实现wide&deep模型

  • 导包

import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import sklearn
import pandas as pd
import os
import sys
import time
import tensorflow as tf
from tensorflow import keras
# 打印版本
print(tf.__version__)
print(sys.version_info)
for module in mpl,np,pd,sklearn,tf,keras:
    print(module.__name__, module.__version__)

  • 加载数据 使用sklearn fetch_californiz_hoursing
# 导入fetch_california_housing类
from sklearn.datasets import fetch_california_housing 
# 实例化对象
housing = fetch_california_housing()
# 打印相关信息
print(housing.DESCR)
print(housing.data.shape)
# 输出:(20640, 8)
print(housing.target.shape)
# 输出:(20640,)
  • 数据预处理(划分训练集,测试集)
from sklearn.model_selection import train_test_split

#拆分训练集,测试集
x_train_all,x_test,y_train_all,y_test = train_test_split(
             housing.data , housing.target , random_state=7,test_size = 0.2)

# 拆分训练集,验证集
x_train,x_valid,y_train,y_valid = train_test_split(
                x_train_all , y_train_all , random_state=11)

"""
train_test_split类里面传入housing.data-(20640, 8),
                  housing.targget-(20640,)
                           随机种子-random.state

(train_test_split 默认划分比例是3:1 
也可以通过test_size,改变比例,
默认test_size = 0.25)  
"""
  • 打印划分结果
print(x_train.shape,y_train.shape)
print(x_valid.shape,y_valid.shape)
print(x_test.shape,y_test.shape)
  • 数据标准化
#导入StandardScaler类
from sklearn.preprocessing import StandardScaler
# 实例化
scaler = StandardScaler()
# 调用scaler。fit 或者scaler.transform方法
x_train_scaled = scaler.fit_transform(x_train)
x_valid_scaled = scaler.transform(x_valid)
x_test_scaled = scaler.transform(x_test)
  • 创建模型 使用函数式API功能实现
# 使用函数式API功能实现
# 定义输入层 将数据读取
input = keras.layers.Input(shape=x_train.shape[1:])
# 使用2层神经网络实现deep model 有点类似复合函数 fx(x) = h(g(x))
hidden1 = keras.layers.Dense(30, activation='relu')(input)# 第一层
hidden2 = keras.layers.Dense(30, activation='relu')(hidden1)# 第二层
# wide输入和神经网络层输出合并
concat = keras.layers.concatenate([input, hidden2])
# 最后输出
output = keras.layers.Dense(1)(concat)

# 定义model  函数式需要定义model
model = keras.models.Model(inputs=[input],outputs=[output])
model.compile(loss="mean_squared_error",optimizer="adam", metrics=["accuracy"])
  • 训练模型


callbacks = [
    keras.callbacks.EarlyStopping( patience=5,min_delta=1e-3)
]

history = model.fit(x_train_scaled,y_train, epochs=100,validation_data=(x_valid_scaled,y_valid), callbacks=callbacks)
    
  • 查看训练结果图
def plot_learning_curves(history):
    """
    查看训练结果图
    """
    # 设置图像大小
    pd.DataFrame(history.history).plot(figsize=(8,5))
    # 显示网格
    plt.grid(True)
    # 坐标轴范围
    plt.gca().set_ylim(0,1)
    plt.show()
plot_learning_curves(history)

14.2子类API实现wide & deep模型

# 子类API
class WideDeepModel(keras.models.Model):
    def __init__(self):
        super(WideDeepModel, self).__init__()
        # 定义模型层次
        self.hidden1_layer = keras.layers.Dense(30, activation="relu")# 全连接层1
        self.hidden2_layer = keras.layers.Dense(30, activation="relu")# 全连接层2
        self.output_layer = keras.layers.Dense(1)# 输出层 ,长度为1
    def call(self, input):
        """完成模型正向计算"""
        hideen1 = self.hidden1_layer(input)
        hideen2 = self.hidden2_layer(hideen1)
        concat = keras.layers.concatenate([input, hideen2])
        output = self.output_layer(concat)
        return output
# 构建model
# 方式1:
# model = WideDeepModel()
# 方式2:
model = keras.models.Sequential([
    WideDeepModel(),
])

model.build(input_shape=(None, 8))
    
model.compile(loss="mean_squared_error",optimizer="adam")

15.wide &deep模型多输入和多输出

  • 上面实现wide&deep模型的wide,deep部分输入都是用一样输入,其实真实情况下,wide&deep模型的输入和输出式不一样的

15.1多输入

  • 选择wide和deep输入:
# 多输入
# 函数式实现方法
input_wide = keras.layers.Input(shape=[5])# wide输入:选前5个当wide模型输入
input_deep = keras.layers.Input(shape=[6])# deep输入:选后6个 当deep模型输入

hidden1 = keras.layers.Dense(30, activation='relu')(input_deep)
hidden2 = keras.layers.Dense(30, activation='relu')(input_wide)
concat = keras.layers.concatenate([input_wide, hidden2])
# 输出
output = keras.layers.Dense(1)(concat)
# 实例模型
model = keras.models.Model(inputs=[input_wide,input_deep],outputs=[output])

model.compile(loss="mean_squared_error",optimizer="adam")
  • 训练输入数据拆分
callbacks = [
    keras.callbacks.EarlyStopping( patience=5,min_delta=1e-3)
]
# 训练数据拆分
# wide训练数据取前5个
x_train_scaled_wide = x_train_scaled[:,:5]
# deep训练数据取后5个
x_train_scaled_deep = x_train_scaled[:,2:]
# 测试数据拆分
x_test_scaled_deep = x_test_scaled[:,2:]
x_test_scaled_wide = x_test_scaled[:,:5]
# 验证数据拆分
x_valid_scaled_deep = x_valid_scaled[:,2:]
x_valid_scaled_wide = x_valid_scaled[:,:5]

history = model.fit([x_train_scaled_wide, x_train_scaled_deep],y_train, epochs=100,validation_data=([x_valid_scaled_wide, x_valid_scaled_deep],y_valid), callbacks=callbacks)

15.2多输出

  • 多输出一般用于多任务学习问题。比如我们预测当年房价和明年房价,这样就有2个任务。
# 上例中再定义个输出
# 输出hidden2
output2 = keras.layers.Dense(1)(hidden2)
# 实例模型加入输出
model = keras.models.Model(inputs=[input_wide,input_deep],outputs=[output, output2])
# 训练模型: y_train,y_valid 添加输出训练数据和验证数据
history = model.fit([x_train_scaled_wide, x_train_scaled_deep],[y_train, y_train], epochs=100,validation_data=([x_valid_scaled_wide, x_valid_scaled_deep],[y_valid,y_valid]), callbacks=callbacks)
# 验证增加 y_test验证数据集
model.evaluate([x_test_scaled_wide,x_test_scaled_deep], [y_test,y_test])

16.超参数搜索

  • 神经网络有很多训练过程中不变参数,比如
网络结构参数:有几层,每层宽度,每层激活函数
训练参数:batch_size,学习率,学习率衰减算法等
  • 而这些参数是不变的,如果手工去实验耗费人力。

  • 搜索策略:

    • 网格搜索

      把各种传参数离散化成几个值,吧这几个值一一组合起来,然后一个个去试。
      
    • 随机搜索

      相比网格搜索,网格搜索是将传参数离散化几个固定值,比如值为[0.2,0.4,0.6,0.8] 而最优解是一个0.2-0.4之间的值,这样无法得到最优解。随机搜索是随机的生成参数组合,就能确保最优解是有可能被搜索到的,但随机的组合会比网格搜索更多
      
    • 遗传算法搜索

      遗传算法是对自然界的模拟
      	1.首先初始化候选参数集合 -> 训练-> 得到模型指标作为生存概率
      	2.然后根据生存的概率做随机选择 -> 交叉(类似于DNA组合) -> 变异(参数进行微小调整) -> 产生下一代集合
      	3.重新回到1.
      
    • 启发式搜索

      使用循环神经网络来生成参数,使用强化学习来进行反馈,使用模型来训练生成参数。
      

17.超参数搜索实现

  • 使用regression数据集

17.1手动实现超参数搜索

# 定义 learning_rate
# W = W + grad + learning_rate
learning_rates = [1e-4,3e-4,1e-3,3e-3,1e-2,3e-2]
histories = []
for lr in learning_rates:
    # 实例化训练模型
    model = keras.models.Sequential([
        keras.layers.Dense(30, activation="relu",input_shape=x_train.shape[1:]),
        keras.layers.Dense(1),
    ])
    # 定义优化器
    optimizer = keras.optimizers.SGD(lr)
    model.compile(loss="mean_squared_error",optimizer=optimizer)# sgd  adam

    callbacks = [
        keras.callbacks.EarlyStopping( patience=5,min_delta=1e-3)
    ]
    # 训练模型
    history = model.fit(
        x_train_scaled, y_train, 
        validation_data=(x_valid_scaled, y_valid),
        epochs = 10,
        callbacks = callbacks
                       )
    histories.append(history)
  • 打印训练图

    def plot_learning_curves(history):
        """
        查看训练结果图
        """
        # 设置图像大小
        pd.DataFrame(history.history).plot(figsize=(8,5))
        # 显示网格
        plt.grid(True)
        # 坐标轴范围
        plt.gca().set_ylim(0,1)
        plt.show()
    for lr, history in zip(learning_rates, histories):
        print("Learning rate:", lr)
        plot_learning_curves(history)
    
  • 上述手动实现超参数搜索存在着以下问题

    1.当前我们只有一个参数,只用一层for循环,如果我们参数有20层,那就会有20层for循环
    2.使用for循环导致只能等上一个模型训练完毕才能开始下一个模型训练,没有一个并行化处理
    

17.2sklearn实现超参数搜索

  • 使用RandomizedSearchCV实现超参数搜索,整体步骤是首先将tf.model转化为sklearn的model,定义参数集合,实现超参数搜索

  • 常规导报

    
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    %matplotlib inline
    import numpy as np
    import sklearn
    import pandas as pd
    import os
    import sys
    import time
    import tensorflow as tf
    from tensorflow import keras
    # 打印版本
    print(tf.__version__)
    print(sys.version_info)
    for module in mpl,np,pd,sklearn,tf,keras:
        print(module.__name__, module.__version__)
    
    
  • 导入数据集

    # 导入fetch_california_housing类
    from sklearn.datasets import fetch_california_housing 
    # 实例化对象
    housing = fetch_california_housing()
    # 打印相关信息
    print(housing.DESCR)
    print(housing.data.shape)
    # 输出:(20640, 8)
    print(housing.target.shape)
    
  • 拆分训练集,测试集

    from sklearn.model_selection import train_test_split
    
    #拆分训练集,测试集
    x_train_all,x_test,y_train_all,y_test = train_test_split(
                 housing.data , housing.target , random_state=7,test_size = 0.2)
    
    # 拆分训练集,验证集
    x_train,x_valid,y_train,y_valid = train_test_split(
                    x_train_all , y_train_all , random_state=11)
    print(x_train.shape, y_train.shape)
    print(x_valid.shape, y_valid.shape)
    print(x_test.shape, y_test.shape)
    
  • 数据标准化

    #导入StandardScaler类
    from sklearn.preprocessing import StandardScaler
    # 实例化
    scaler = StandardScaler()
    # 调用scaler。fit 或者scaler.transform方法
    x_train_scaled = scaler.fit_transform(x_train)
    x_valid_scaled = scaler.transform(x_valid)
    x_test_scaled = scaler.transform(x_test)
    
  • 将tf.model转化为sklearn的model

    callbacks = [
            keras.callbacks.EarlyStopping( patience=5,min_delta=1e-3)
        ]
    # 将tf.model转化为sklearn的model
    def build_model(hidden_layers=1,layer_size=30,learning_rate=3e-3):
        """
        hidden_layers中间层的层数 
        layer_size 默认30
        learning_rate 学习率
        """
        # 实例化一个训练model
        model = keras.models.Sequential()
        # 添加全连接层
        model.add(keras.layers.Dense(layer_size, activation='relu', input_shape=x_train.shape[1:]))
        # 添加hidden_layers 个全连接层
        for _ in range(hidden_layers):
            model.add(keras.layers.Dense(layer_size, activation='relu'))
        # 添加输出层
        model.add(keras.layers.Dense(1))
        # 定义优化器
        optimizer = keras.optimizers.SGD(learning_rate)
        # mse为mean_squared_error简称
        model.compile(loss="mse",optimizer=optimizer)# sgd  adam
        return model
    
    # sklearn_model = keras.wrappers.scikit_learn.KerasRegressor(build_model)
    history = sklearn_model.fit(x_train_scaled, y_train, epochs=10, validation_data=(x_valid_scaled,y_valid),callbacks=callbacks)
    
  • 定义搜索空间

    param_distribution = {
        "hidden_layers": [1,2,3,4,5],
        "layer_size":np.arange(1,100),# 为1-100连续取值
        "learning_rate": reciprocal(1e-4,1e-2)# 为一个分布取值
    }
    

    scipy 的reciprocal

    from scipy.stats import reciprocal
    reciprocal.rvs(1e-4,1e-2,size=10)# 生成10的-4次方到10的-2次方 的 10个数
    """
    array([0.00407106, 0.00033841, 0.00018518, 0.00246045, 0.00991374,
           0.00079176, 0.00011086, 0.00023637, 0.00359715, 0.00372375])
    """
    
  • RandomizedSearchCV超参数搜搜

    from sklearn.model_selection import RandomizedSearchCV
    # 初始化对象
    # n_iter 从param_distribution 生成多少个集合
    # n_jobs 并行处理数量
    # cv  默认为3 使用了cross_validation: 训练集分成n份,n-1训练,最后一份验证
    random_search_cv = RandomizedSearchCV(sklearn_model,param_distribution,cv=3, n_iter=10,n_jobs=1)
    
    # 进行训练
    random_search_cv.fit(x_train_scaled,y_train,epochs=100,validation_data=(x_valid_scaled,y_valid), callbacks=callbacks)
    
    
  • 查看结果

    # 查看最好参数
    print(random_search_cv.best_params_)
    # 查看最好峰值
    print(random_search_cv.best_score_)
    # 最好model
    print(random_search_cv.best_estimator_)
    
  • 拿取最好model进行验证

    # 拿取最好model进行验证
    model = random_search_cv.best_estimator_.model
    model.evaluate(x_test_scaled, y_test)
    
原文地址:https://www.cnblogs.com/xujunkai/p/14322225.html