keras_keras gpu - CSDN
keras 订阅
Keras是一个由Python编写的开源人工神经网络库,可以作为Tensorflow、Microsoft-CNTK和Theano的高阶应用程序接口,进行深度学习模型的设计、调试、评估、应用和可视化 [1]  。Keras在代码结构上由面向对象方法编写,完全模块化并具有可扩展性,其运行机制和说明文档有将用户体验和使用难度纳入考虑,并试图简化复杂算法的实现难度 [1]  。Keras支持现代人工智能领域的主流算法,包括前馈结构和递归结构的神经网络,也可以通过封装参与构建统计学习模型 [2]  。在硬件和开发环境方面,Keras支持多操作系统下的多GPU并行计算,可以根据后台设置转化为Tensorflow、Microsoft-CNTK等系统下的组件 [3]  。Keras的主要开发者是谷歌工程师François Chollet,此外其GitHub项目页面包含6名主要维护者和超过800名直接贡献者 [4]  。Keras在其正式版本公开后,除部分预编译模型外,按MIT许可证开放源代码 [1]  。 展开全文
Keras是一个由Python编写的开源人工神经网络库,可以作为Tensorflow、Microsoft-CNTK和Theano的高阶应用程序接口,进行深度学习模型的设计、调试、评估、应用和可视化 [1]  。Keras在代码结构上由面向对象方法编写,完全模块化并具有可扩展性,其运行机制和说明文档有将用户体验和使用难度纳入考虑,并试图简化复杂算法的实现难度 [1]  。Keras支持现代人工智能领域的主流算法,包括前馈结构和递归结构的神经网络,也可以通过封装参与构建统计学习模型 [2]  。在硬件和开发环境方面,Keras支持多操作系统下的多GPU并行计算,可以根据后台设置转化为Tensorflow、Microsoft-CNTK等系统下的组件 [3]  。Keras的主要开发者是谷歌工程师François Chollet,此外其GitHub项目页面包含6名主要维护者和超过800名直接贡献者 [4]  。Keras在其正式版本公开后,除部分预编译模型外,按MIT许可证开放源代码 [1]  。
信息
开发者
François Chollet 等 [4]
类    型
神经网络库,应用程序接口
平    台
Linux,macOS,Windows
许可协议
MIT License(不包含预编译模型)
初始版本
0.1.0/2015年6月13日 [5]
外文名
Keras
编程语言
Python
稳定版本
2.3.0/2019年09月17日 [5]
Keras历史与命名
Keras的前身是François Chollet为ONEIROS(Open-ended Neuro-Electronic Intelligent Robot Operating System)项目所的编写的代码,在2015年分离成为开源的人工神经网络工具。Keras的最初版本以Theano为后台,设计理念参考了Torch但完全由Python编写 [5]  。2015年11月的Keras测试版本0.3.0,Tensorflow被加入了后台选项。2016年4月,Keras在PIPy上发布了第一个稳定版本1.0.0 [5]  。2017年5月,Keras版本2.0.0发布 [5]  。同年6月,Keras版本2.0.5测试性地将Microsoft-CNTK加入后台选项 [5]  。自2017年起,Keras得到了Tensorflow团队的支持,其大部分组件被整合至Tensorflow的Python API中。在2018年Tensorflow 2.0.0公开后,Keras被正式确立为Tensorflow高阶API,即tf.keras [6]  。此外自2017年7月开始,Keras也得到了CNTK 2.0的后台支持 [7]  。在2019年9月17日Keras稳定版本2.3.0的更新文档中,Keras团队宣布了计划调整:在该版本之后,Keras将集中于Tensoflow后台的有关内容,多后台Keras的开发优先度被降低,且更新将仅包含补丁(bug fix),不会有新的功能性内容移植/加入 [5]  。Keras的命名来自古希腊语“κέρας (牛角)”或 “κραίνω(实现)”,意为将梦境化为现实的“牛角之门” [1]  。由荷马史诗《奥德赛》第19卷佩涅罗佩与奥德修斯的对话,无法挽留的梦幻拥有两座门,一座门由牛角制成,一座门由象牙制成,象牙之门内光彩夺目,却仅是无法实现的梦境;唯有走进牛角之门,才能由梦境看见真实 [8]  。
收起全文
精华内容
参与话题
  • 通过大量实战,掌握Tensorflow和Keras经常用到的各种建模方式,参数优化方法,自定义参数和模型的手段,以及对训练结果评估与分析的技巧。 2 从机器学习基础算法开始,然后进入到图像分类领域,使用MNIST...
  • keras 入门上

    千次阅读 多人点赞 2018-04-26 17:55:17
    1. 什么是 KerasKeras 是基于 Theano 或 TensorFlow 的一个深度学习...安装 Keras使用 Keras 前还需要安装 Numpy、Scipy 等 Python 包,建议直接安装 Python 科学计算环境 Anaconda,一步到位。然后直接通过 pip...

    1. 什么是 Keras

    Keras 是基于 Theano 或 TensorFlow 的一个深度学习框架,它的设计参考了 Torch,用 Python 语言编写,是一个高度模块化的神经网络库,支持 GPU 和 CPU。

    安装 Keras

    使用 Keras 前还需要安装 Numpy、Scipy 等 Python 包,建议直接安装 Python 科学计算环境 Anaconda,一步到位。然后直接通过 pip install keras 安装 Keras 就可以了,非常的方便。

    在 Theano 和 TensorFlow 间切换

    Keras 的底层库使用 Theano 或 TensorFlow,这两个库也称为 Keras 的后端。无论是 Theano 还是 TensorFlow,都是一个“符号式”的库,这也使得 Keras 的编程与传统的 Python 代码有所差别。笼统的说,符号主义的计算首先定义各种变量,然后建立一个“计算图”,计算图规定了各个变量之间的计算关系。建立好的计算图需要编译以确定其内部细节,但是此时的计算图只是一个“空壳子”,里面没有任何实际的数据,只有当你把需要运算的输入放进去后,才能在整个模型中形成数据流,从而形成输出值。Keras 的模型搭建形式就是这种方法,搭建好的 Keras 模型只是一个空壳子,只有实际生成可调用的函数后(K.function),输入数据,才会形成真正的数据流。

    使用计算图的语言,如 Theano,以难以调试而闻名,当 Keras 的 Debug 进入 Theano 这个层次时,往往也令人头痛。但大多数的深度学习框架使用的都是符号计算这一套方法,因为符号计算能够提供关键的计算优化、自动求导等功能。

    Keras 会根据环境自动设置后端为 Theano 或 TensorFlow,我们也可以通过修改 Keras 配置文件来设置。Keras 配置文件位于用户目录下的 .keras 目录中,名称为 keras.json

    {
        "epsilon": 1e-07,
        "backend": "tensorflow",
        "floatx": "float32",
        "image_data_format": "channels_last"
    }
    

    其中 backend 字段设定 Keras 的后端,这里选择的是 tensorflow,也可以设定为 theano

    data_format

    在如何表示一组彩色图片的问题上,Theano 和 TensorFlow 发生了分歧:Theano 会把 100 张 RGB 三通道的 16×32 彩色图表示为 (100,3,16,32),第 0 维是样本维,代表样本的数目,第 1 维是通道维,代表颜色通道数,后面两个就是高和宽了,这种数据组织方法,称为 channels_first,即通道维靠前;而 TensorFlow 的表达形式是 (100,16,32,3),即把通道维放在了最后,因而称为 channels_last

    Keras 默认的数据组织形式也在配置文件 keras.json 中规定,由 image_data_format 一项设定,也可在代码中通过 K.image_data_format() 函数返回,请在网络的训练和测试中保持维度顺序一致。对 2D 数据来说,channels_last 设定维度顺序为 (rows,cols,channels) 而 channels_first 设定维度顺序为 (channels, rows, cols)。对 3D 数据而言,channels_last 设定为 (conv_dim1, conv_dim2, conv_dim3, channels),而 channels_first 则是 (channels, conv_dim1, conv_dim2, conv_dim3)

    2. 一些基本概念

    下面介绍几个使用 Keras 过程中经常会遇到的词汇:

    张量

    张量(tensor)可以看作是向量、矩阵的自然推广,用来表示广泛的数据类型。0 阶张量即标量,也就是一个数;1 阶张量就是一个向量;2 阶张量就是一个矩阵;3 阶张量可以称为一个立方体,具有 3 个颜色通道的彩色图片就是一个这样的立方体;把立方体摞起来就是 4 阶张量了,不同去想像 4 阶张量是什么样子,它就是个数学上的概念。

    张量的阶数有时候也称为维度,或者轴,轴这个词翻译自英文 axis。譬如一个矩阵 [[1,2],[3,4]],是一个 2 阶张量,有两个维度或轴,沿着第 0 个轴(为了与 python 的计数方式一致,维度和轴从 0 算起)你看到的是 [1,2],[3,4] 两个向量,沿着第 1 个轴你看到的是 [1,3],[2,4] 两个向量。要理解“沿着某个轴”是什么意思,不妨试着运行一下下面的代码:

    import numpy as np
    a = np.array([[1,2],[3,4]])
    sum0 = np.sum(a, axis=0)
    sum1 = np.sum(a, axis=1)
    print sum0
    print sum1
    

    函数式模型

    在 Keras 0.x 中有两种模型,一种是 Sequential 模型,又称为序贯模型,也就是单输入单输出,一条路通到底,层与层之间只有相邻关系,没有跨层连接。这种模型编译速度快,操作上也比较简单。第二种模型称为 Graph,即图模型,这个模型支持多输入多输出,层与层之间想怎么连怎么连,但是编译速度慢。可以看到,Sequential 其实是 Graph 的一个特殊情况。

    在 Keras 1 和 Keras 2 中,图模型被移除,从而增加了“functional model API”这个东西,更加强调了 Sequential 模型是特殊的一种。一般的模型就称为 Model。

    由于 functional model API 在使用时利用的是“函数式编程”的风格,这里将其称为函数式模型。总而言之,只要这个东西接收一个或一些张量作为输入,然后输出的也是一个或一些张量,但不管它是什么,统统都叫做“模型”。

    batch

    深度学习的优化算法,说白了就是梯度下降。每次的参数更新有两种方式。

    第一种,遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度。这种方法每更新一次参数都要把数据集里的所有样本都看一遍,计算量开销大,计算速度慢,不支持在线学习,这称为批梯度下降(Batch gradient descent)

    另一种,每看一个数据就算一下损失函数,然后求梯度更新参数,这个称为随机梯度下降(stochastic gradient descent)。这个方法速度比较快,但是收敛性能不太好,可能在最优点附近晃来晃去,达不到最优点。两次参数的更新也有可能互相抵消掉,造成目标函数震荡的比较剧烈。

    为了克服两种方法的缺点,现在一般采用的是一种折中手段,小批的梯度下降(mini-batch gradient decent),这种方法把数据分为若干个批,按批来更新参数,这样,一个批中的一组数据共同决定了本次梯度的方向,下降起来就不容易跑偏,减少了随机性。另一方面因为批的样本数与整个数据集相比小了很多,所以计算量也不是很大。基本上现在的梯度下降都是基于 mini-batch 的,所以 Keras 的模块中经常会出现 batch_size,就是指这个。

    Keras 中用的优化器 SGD 是 stochastic gradient descent 的缩写,但不代表是一个样本就更新一回,而是基于 mini-batch 的。

    epochs

    简单说,epochs 指的就是训练过程中数据将被“轮询”多少次,就这样。

    3. 快速上手 Keras

    Keras 的核心数据结构是“模型”,模型是一种组织网络层的方式。Keras 中主要的模型是 Sequential 模型,Sequential 是一系列网络层按顺序构成的栈。你也可以查看函数式模型来学习建立更复杂的模型。

    Sequential 模型如下:

    from keras.models import Sequential
    model = Sequential()
    

    将一些网络层通过 .add() 堆叠起来,就构成了一个模型:

    from keras.layers import Dense, Activation
    
    model.add(Dense(units=64, input_dim=100))
    model.add(Activation("relu"))
    model.add(Dense(units=10))
    model.add(Activation("softmax"))
    

    完成模型的搭建后,我们需要使用 .compile() 方法来编译模型:

    model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
    

    编译模型时必须指明损失函数和优化器,如果你需要的话,也可以自己定制损失函数。Keras 的一个核心理念就是简明易用同时,保证用户对 Keras 的绝对控制力度,用户可以根据自己的需要定制自己的模型、网络层,甚至修改源代码。例如,我们使用自定义的 SGD 优化器:

    from keras.optimizers import SGD
    model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.01, momentum=0.9, nesterov=True))
    

    完成模型编译后,我们在训练数据上按 batch 进行一定次数的迭代来训练网络:

    model.fit(x_train, y_train, epochs=5, batch_size=32)
    

    当然,我们也可以手动将一个个 batch 的数据送入网络中训练,这时候需要使用:

    model.train_on_batch(x_batch, y_batch)
    

    随后,我们可以使用一行代码对我们的模型进行评估,看看模型的指标是否满足我们的要求:

    loss_and_metrics = model.evaluate(x_test, y_test, batch_size=128)
    

    或者,我们可以使用我们的模型,对新的数据进行预测:

    classes = model.predict(x_test, batch_size=128)
    

    搭建一个问答系统、图像分类模型,或神经图灵机、word2vec 词嵌入器就是这么快。支撑深度学习的基本想法本就是简单的,现在让我们把它的实现也变的简单起来!

    为了更深入的了解 Keras,接下来我们介绍一下 Sequntial 模型和函数式模型的使用方法。

    4. Sequntial 模型

    构建序贯(Sequential)模型

    序贯模型是多个网络层的线性堆叠,也就是“一条路走到黑”。可以通过向 Sequential 模型传递一个 layer 的 list 来构造该模型:

    from keras.models import Sequential
    from keras.layers import Dense, Activation
    
    model = Sequential([
    Dense(32, units=784),
    Activation('relu'),
    Dense(10),
    Activation('softmax'),
    ])
    

    也可以通过 .add() 方法一个个的将 layer 加入模型中:

    model = Sequential()
    model.add(Dense(32, input_shape=(784,)))
    model.add(Activation('relu'))
    

    指定输入数据的 shape

    模型需要知道输入数据的 shape,因此,Sequential 模型的第一层需要接受一个关于输入数据 shape 的参数,后面的各个层则可以自动的推导出中间数据的 shape,因此不需要为每个层都指定这个参数。有几种方法来为第一层指定输入数据的 shape:

    • 传递一个 input_shape 的关键字参数给第一层,input_shape 是一个 tuple 类型的数据,其中也可以填入 None,如果填入 None 则表示此位置可能是任何正整数。数据的 batch 大小不应包含在其中。
    • 有些 2D 层,如 Dense,支持通过指定其输入维度 input_dim 来隐含的指定输入数据 shape。一些 3D 的时域层支持通过参数 input_dim 和 input_length 来指定输入shape。
    • 如果你需要为输入指定一个固定大小的 batch_size(常用于 stateful RNN 网络),可以传递 batch_size 参数到一个层中,例如你想指定输入张量的 batch 大小是 32,数据 shape 是 (6,8),则你需要传递 batch_size=32 和 input_shape=(6,8)
    model = Sequential()
    model.add(Dense(32, input_dim=784))
    
    model = Sequential()
    model.add(Dense(32, input_shape=784))
    

    编译

    在训练模型之前,我们需要通过 compile 来对学习过程进行配置。compile 接收三个参数:

    • 优化器 optimizer:该参数可指定为已预定义的优化器名,如 rmspropadagrad,或一个 Optimizer 类的对象。
    • 损失函数 loss:该参数为模型试图最小化的目标函数,它可为预定义的损失函数名,如categorical_crossentropymse,也可以为一个损失函数。
    • 指标列表 metrics:对分类问题,我们一般将该列表设置为 metrics=['accuracy']。指标可以是一个预定义指标的名字,也可以是一个用户定制的函数。指标函数应该返回单个张量,或一个完成 metric_name - > metric_value 映射的字典。
    # 对于一个多分类问题
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    
    # 对于一个二分类问题
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    # 对于一个均方误差回归问题
    model.compile(optimizer='rmsprop',
                  loss='mse')
    
    # 用户自定义指标列表
    import keras.backend as K
    
    def mean_pred(y_true, y_pred):
        return K.mean(y_pred)
    
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy', mean_pred])
    

    训练

    Keras以Numpy数组作为输入数据和标签的数据类型。训练模型一般使用 fit 函数。下面是一些例子:

    # 对于一个单输入模型的二分类问题
    model = Sequential()
    model.add(Dense(32, activation='relu', input_dim=100))
    model.add(Dense(1, activation='sigmoid'))
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    # 创建虚假数据
    import numpy as np
    data = np.random.random((1000, 100))
    labels = np.random.randint(2, size=(1000, 1))
    
    # 训练模型, 以每批次32样本迭代数据
    model.fit(data, labels, epochs=10, batch_size=32)
    
    # 对于一个单输入模型的10分类问题
    model = Sequential()
    model.add(Dense(32, activation='relu', input_dim=100))
    model.add(Dense(10, activation='softmax'))
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    
    # 创建虚假数据
    import numpy as np
    data = np.random.random((1000, 100))
    labels = np.random.randint(10, size=(1000, 1))
    
    # 将标签转换为one-hot表示
    one_hot_labels = keras.utils.to_categorical(labels, num_classes=10)
    
    # 训练模型, 以每批次32样本迭代数据
    model.fit(data, one_hot_labels, epochs=10, batch_size=32)
    

    5. Sequntial 模型示例

    基于多层感知器的 softmax 多分类:

    from keras.models import Sequential
    from keras.layers import Dense, Dropout, Activation
    from keras.optimizers import SGD
    
    # 创建虚假数据
    import numpy as np
    x_train = np.random.random((1000, 20))
    y_train = keras.utils.to_categorical(np.random.randint(10, size=(1000, 1)), num_classes=10)
    x_test = np.random.random((100, 20))
    y_test = keras.utils.to_categorical(np.random.randint(10, size=(100, 1)), num_classes=10)
    
    model = Sequential()
    # Dense(64) 是一个含有64个隐单元的全连接层
    # 在第一层,你必须指定预期的输入数据shape:
    # 这里是一个20维的向量.
    model.add(Dense(64, activation='relu', input_dim=20))
    model.add(Dropout(0.5))
    model.add(Dense(64, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(10, activation='softmax'))
    
    sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
    model.compile(loss='categorical_crossentropy',
                  optimizer=sgd,
                  metrics=['accuracy'])
    
    model.fit(x_train, y_train,
              epochs=20,
              batch_size=128)
    score = model.evaluate(x_test, y_test, batch_size=128)
    

    MLP的二分类:

    import numpy as np
    from keras.models import Sequential
    from keras.layers import Dense, Dropout
    
    # 创建虚假数据
    x_train = np.random.random((1000, 20))
    y_train = np.random.randint(2, size=(1000, 1))
    x_test = np.random.random((100, 20))
    y_test = np.random.randint(2, size=(100, 1))
    
    model = Sequential()
    model.add(Dense(64, input_dim=20, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(64, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy',
                  optimizer='rmsprop',
                  metrics=['accuracy'])
    model.fit(x_train, y_train,
              epochs=20,
              batch_size=128)
    score = model.evaluate(x_test, y_test, batch_size=128)
    

    类似VGG的卷积神经网络:

    import numpy as np
    import keras
    from keras.models import Sequential
    from keras.layers import Dense, Dropout, Flatten
    from keras.layers import Conv2D, MaxPooling2D
    from keras.optimizers import SGD
    
    # 创建虚假数据
    x_train = np.random.random((100, 100, 100, 3))
    y_train = keras.utils.to_categorical(np.random.randint(10, size=(100, 1)), num_classes=10)
    x_test = np.random.random((20, 100, 100, 3))
    y_test = keras.utils.to_categorical(np.random.randint(10, size=(20, 1)), num_classes=10)
    
    model = Sequential()
    # 输入: 100x100的3通道图像 -> 张量 (100, 100, 3).
    # 在每块3x3的区域应用32个卷积过滤器.
    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(100, 100, 3)))
    model.add(Conv2D(32, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))
    
    model.add(Flatten())
    model.add(Dense(256, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(10, activation='softmax'))
    
    sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
    model.compile(loss='categorical_crossentropy', optimizer=sgd)
    
    model.fit(x_train, y_train, batch_size=32, epochs=10)
    score = model.evaluate(x_test, y_test, batch_size=32)
    

    使用LSTM的序列分类

    from keras.models import Sequential
    from keras.layers import Dense, Dropout
    from keras.layers import Embedding
    from keras.layers import LSTM
    
    model = Sequential()
    model.add(Embedding(max_features, output_dim=256))
    model.add(LSTM(128))
    model.add(Dropout(0.5))
    model.add(Dense(1, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy',
                  optimizer='rmsprop',
                  metrics=['accuracy'])
    
    model.fit(x_train, y_train, batch_size=16, epochs=10)
    score = model.evaluate(x_test, y_test, batch_size=16)
    

    使用1D卷积的序列分类

    from keras.models import Sequential
    from keras.layers import Dense, Dropout
    from keras.layers import Embedding
    from keras.layers import Conv1D, GlobalAveragePooling1D, MaxPooling1D
    
    model = Sequential()
    model.add(Conv1D(64, 3, activation='relu', input_shape=(seq_length, 100)))
    model.add(Conv1D(64, 3, activation='relu'))
    model.add(MaxPooling1D(3))
    model.add(Conv1D(128, 3, activation='relu'))
    model.add(Conv1D(128, 3, activation='relu'))
    model.add(GlobalAveragePooling1D())
    model.add(Dropout(0.5))
    model.add(Dense(1, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy',
                  optimizer='rmsprop',
                  metrics=['accuracy'])
    
    model.fit(x_train, y_train, batch_size=16, epochs=10)
    score = model.evaluate(x_test, y_test, batch_size=16)
    

    用于序列分类的栈式LSTM

    在该模型中,我们将三个 LSTM 堆叠在一起,是该模型能够学习更高层次的时域特征表示。开始的两层 LSTM 返回其全部输出序列,而第三层 LSTM 只返回其输出序列的最后一步结果,从而其时域维度降低(即将输入序列转换为单个向量):

    1

    from keras.models import Sequential
    from keras.layers import LSTM, Dense
    import numpy as np
    
    data_dim = 16
    timesteps = 8
    num_classes = 10
    
    # 预期输入数据shape: (batch_size, timesteps, data_dim)
    model = Sequential()
    model.add(LSTM(32, return_sequences=True,
                   input_shape=(timesteps, data_dim)))  # 返回一个32维向量的序列
    model.add(LSTM(32, return_sequences=True))  # 返回一个32维向量的序列
    model.add(LSTM(32))  # 返回一个独立的32维的向量
    model.add(Dense(10, activation='softmax'))
    
    model.compile(loss='categorical_crossentropy',
                  optimizer='rmsprop',
                  metrics=['accuracy'])
    
    # 创建虚假的训练数据
    x_train = np.random.random((1000, timesteps, data_dim))
    y_train = np.random.random((1000, num_classes))
    
    # 创建虚假的验证数据
    x_val = np.random.random((100, timesteps, data_dim))
    y_val = np.random.random((100, num_classes))
    
    model.fit(x_train, y_train,
              batch_size=64, epochs=5,
              validation_data=(x_val, y_val))
    

    采用stateful LSTM的相同模型

    stateful LSTM 的特点是,在处理过一个 batch 的训练数据后,其内部状态(记忆)会被作为下一个 batch 的训练数据的初始状态。状态 LSTM 使得我们可以在合理的计算复杂度内处理较长序列:

    from keras.models import Sequential
    from keras.layers import LSTM, Dense
    import numpy as np
    
    data_dim = 16
    timesteps = 8
    num_classes = 10
    batch_size = 32
    
    # 预期输入批shape: (batch_size, timesteps, data_dim)
    # 注意我们需要提供完整的 batch_input_shape 因为网络是有状态的.
    # 第k批中的样本i跟踪第k-1批中的样本i.
    model = Sequential()
    model.add(LSTM(32, return_sequences=True, stateful=True,
                   batch_input_shape=(batch_size, timesteps, data_dim)))
    model.add(LSTM(32, return_sequences=True, stateful=True))
    model.add(LSTM(32, stateful=True))
    model.add(Dense(10, activation='softmax'))
    
    model.compile(loss='categorical_crossentropy',
                  optimizer='rmsprop',
                  metrics=['accuracy'])
    
    # 创建虚假的训练数据
    x_train = np.random.random((batch_size * 10, timesteps, data_dim))
    y_train = np.random.random((batch_size * 10, num_classes))
    
    # 创建虚假的验证数据
    x_val = np.random.random((batch_size * 3, timesteps, data_dim))
    y_val = np.random.random((batch_size * 3, num_classes))
    
    model.fit(x_train, y_train,
              batch_size=batch_size, epochs=5, shuffle=False,
              validation_data=(x_val, y_val))
    

    6. Functional 模型

    在 Keras 2 里我们将 Functional 译为“函数式”,对函数式编程有所了解的同学应能够快速 get 到该类模型想要表达的含义。函数式模型称作 Functional,但它的类名是 Model,因此我们有时候也用 Model 来代表函数式模型。

    Keras 函数式模型接口是用户定义多输出模型、非循环有向模型或具有共享层的模型等复杂模型的途径。一句话,只要你的模型不是类似 VGG 一样一条路走到黑的模型,或者你的模型需要多于一个的输出,那么你总应该选择函数式模型。函数式模型是最广泛的一类模型,序贯模型(Sequential)只是它的一种特殊情况。

    让我们从简单一点的模型开始:

    第一个模型:全连接网络

    Sequential 模型当然是实现全连接网络的最好方式,但我们从简单的全连接网络开始,有助于我们学习这部分的内容。在开始前,有几个概念需要澄清:

    • 层对象接受张量为参数,返回一个张量。
    • 输入是张量,输出也是张量的一个框架就是一个模型,通过 Model 定义。
    • 这样的模型可以被像 Keras 的 Sequential 一样被训练。
    from keras.layers import Input, Dense
    from keras.models import Model
    
    # 这会返回一个张量
    inputs = Input(shape=(784,))
    
    # 层对象接受张量为参数,返回一个张量
    x = Dense(64, activation='relu')(inputs)
    x = Dense(64, activation='relu')(x)
    predictions = Dense(10, activation='softmax')(x)
    
    # 这会创建一个模型,包含输入层和三个Dense层
    model = Model(inputs=inputs, outputs=predictions)
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    model.fit(data, labels)  # 开始训练
    

    所有的模型都是可调用的,就像层一样

    利用函数式模型的接口,我们可以很容易的重用已经训练好的模型:你可以把模型当作一个层一样,通过提供一个 tensor 来调用它。注意当你调用一个模型时,你不仅仅重用了它的结构,也重用了它的权重。

    x = Input(shape=(784,))
    # 这会返回我们之前定义的 10-way softmax.
    y = model(x)
    

    这种方式可以允许你快速的创建能处理序列信号的模型,你可以很快将一个图像分类的模型变为一个对视频分类的模型,只需要一行代码:

    from keras.layers import TimeDistributed
    
    # 20个时间步序列的输入张量,每个包含一个784维的向量
    input_sequences = Input(shape=(20, 784))
    
    # 这会应用我们之前定义的模型到输入序列的每一个时间步
    # 之前模型的输出是一个 10-way softmax,
    # 所以下面这个层的输出会是一个含有20个10维向量的序列
    processed_sequences = TimeDistributed(model)(input_sequences)
    

    多输入和多输出模型

    使用函数式模型的一个典型场景是搭建多输入、多输出的模型。

    考虑这样一个模型。我们希望预测 Twitter 上一条新闻会被转发和点赞多少次。模型的主要输入是新闻本身,也就是一个词语的序列。但我们还可以拥有额外的输入,如新闻发布的日期等。这个模型的损失函数将由两部分组成,辅助的损失函数评估仅仅基于新闻本身做出预测的情况,主损失函数评估基于新闻和额外信息的预测的情况,即使来自主损失函数的梯度发生弥散,来自辅助损失函数的信息也能够训练 Embeddding 和 LSTM 层。在模型中早点使用主要的损失函数是对于深度网络的一个良好的正则方法。总而言之,该模型框图如下:

    2

    让我们用函数式模型来实现这个框图。

    主要的输入接收新闻本身,即一个整数的序列(每个整数编码了一个词)。这些整数位于 1 到 10,000 之间(即我们的字典有 10,000 个词)。这个序列有 100 个单词。

    from keras.layers import Input, Embedding, LSTM, Dense
    from keras.models import Model
    
    # 标题输入: 接收一个100个整数的序列,每个整数处于1到10000之间.
    # 注意我们可以通过"name"参数命名任何层.
    main_input = Input(shape=(100,), dtype='int32', name='main_input')
    
    # 这个embedding层会编码输入序列到一个512维的向量序列
    x = Embedding(output_dim=512, input_dim=10000, input_length=100)(main_input)
    
    # 一个LSTM会转化向量序列到一个单独的保存整个序列信息的向量
    lstm_out = LSTM(32)(x)
    

    然后,我们插入一个额外的损失,使得即使在主损失很高的情况下,LSTM 和 Embedding 层也可以平滑的训练。

    auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)
    

    再然后,我们将 LSTM 与额外的输入数据串联起来组成输入,送入模型中:

    auxiliary_input = Input(shape=(5,), name='aux_input')
    x = keras.layers.concatenate([lstm_out, auxiliary_input])
    
    # 我们堆叠一个深度的全连接网络
    x = Dense(64, activation='relu')(x)
    x = Dense(64, activation='relu')(x)
    x = Dense(64, activation='relu')(x)
    
    # 最后我们加上一个主要的logistic回归层
    main_output = Dense(1, activation='sigmoid', name='main_output')(x)
    

    最后,我们定义整个 2 输入,2 输出的模型:

    model = Model(inputs=[main_input, auxiliary_input], outputs=[main_output, auxiliary_output])
    

    模型定义完毕,下一步编译模型。我们给额外的损失赋 0.2 的权重。我们可以通过关键字参数 loss_weights 或 loss 来为不同的输出设置不同的损失函数或权值。这两个参数均可为 Python 的列表或字典。这里我们给 loss 传递单个损失函数,这个损失函数会被应用于所有输出上。

    model.compile(optimizer='rmsprop', loss='binary_crossentropy',
                  loss_weights=[1., 0.2])
    

    编译完成后,我们通过传递训练数据和目标值训练该模型:

    model.fit([headline_data, additional_data], [labels, labels],
              epochs=50, batch_size=32)
    

    因为我们输入和输出是被命名过的(在定义时传递了“name”参数),我们也可以用下面的方式编译和训练模型:

    model.compile(optimizer='rmsprop',
                  loss={'main_output': 'binary_crossentropy', 'aux_output': 'binary_crossentropy'},
                  loss_weights={'main_output': 1., 'aux_output': 0.2})
    
    model.fit({'main_input': headline_data, 'aux_input': additional_data},
              {'main_output': labels, 'aux_output': labels},
              epochs=50, batch_size=32)
    

    共享层

    另一个使用函数式模型的场合是使用共享层的时候。

    考虑微博数据,我们希望建立模型来判别两条微博是否是来自同一个用户,这个需求同样可以用来判断一个用户的两条微博的相似性。

    一种实现方式是,我们建立一个模型,它分别将两条微博的数据映射到两个特征向量上,然后将特征向量串联并加一个 logistic 回归层,输出它们来自同一个用户的概率。这种模型的训练数据是一对对的微博。

    因为这个问题是对称的,所以处理第一条微博的模型当然也能重用于处理第二条微博。所以这里我们使用一个共享的 LSTM 层来进行映射。

    首先,我们将微博的数据转为 (140,256) 的矩阵,即每条微博有 140 个字符,每个单词的特征由一个 256 维的词向量表示,向量的每个元素为 1 表示某个字符出现,为 0 表示不出现,这是一个 one-hot 编码。

    之所以是 (140,256) 是因为一条微博最多有 140 个字符,而扩展的 ASCII 码表编码了常见的 256 个字符。

    注:原文中此处为 Tweet,所以对外国人而言这是合理的。如果考虑中文字符,那一个单词的词向量就不止 256 了。

    import keras
    from keras.layers import Input, LSTM, Dense
    from keras.models import Model
    
    tweet_a = Input(shape=(140, 256))
    tweet_b = Input(shape=(140, 256))
    

    若要对不同的输入共享同一层,就初始化该层一次,然后多次调用它:

    # 该层会输入一个矩阵然后返回一个大小为64的向量
    shared_lstm = LSTM(64)
    
    # 当我们重用相同层的实例很多次,并且层的权值也是重用的
    # (这实际上完全是相同的层)
    encoded_a = shared_lstm(tweet_a)
    encoded_b = shared_lstm(tweet_b)
    
    # 我们可以连接这两个向量:
    merged_vector = keras.layers.concatenate([encoded_a, encoded_b], axis=-1)
    
    # 然后在最上面添加一个logistic回归层
    predictions = Dense(1, activation='sigmoid')(merged_vector)
    
    # 我们定义了一个可训练的模型,将tweet的输入连接起来,输出预测
    model = Model(inputs=[tweet_a, tweet_b], outputs=predictions)
    
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    model.fit([data_a, data_b], labels, epochs=10)
    

    层“节点”的概念

    无论何时,当你在某个输入上调用层时,你就创建了一个新的张量(即该层的输出),同时你也在为这个层增加一个“计算节点”。这个节点将输入张量映射为输出张量。当你多次调用该层时,这个层就有了多个节点,其下标分别为 0,1,2…

    在上一版本的 Keras 中,你可以通过 layer.get_output() 方法来获得层的输出张量,或者通过 layer.output_shape 获得其输出张量的 shape。这个版本的 Keras 你仍然可以这么做(除了 layer.get_output() 被 output 替换)。但如果一个层与多个输入相连,会出现什么情况呢?

    如果层只与一个输入相连,那没有任何困惑的地方。.output 将会返回该层唯一的输出:

    a = Input(shape=(140, 256))
    
    lstm = LSTM(32)
    encoded_a = lstm(a)
    
    assert lstm.output == encoded_a
    

    但当层与多个输入相连时,会出现问题:

    a = Input(shape=(140, 256))
    b = Input(shape=(140, 256))
    
    lstm = LSTM(32)
    encoded_a = lstm(a)
    encoded_b = lstm(b)
    
    lstm.output
    

    上面这段代码会报错:

    >> AssertionError: Layer lstm_1 has multiple inbound nodes,
    hence the notion of "layer output" is ill-defined.
    Use `get_output_at(node_index)` instead.
    

    通过下面这种调用方式即可解决:

    assert lstm.get_output_at(0) == encoded_a
    assert lstm.get_output_at(1) == encoded_b
    

    对于 input_shape 和 output_shape 也是一样,如果一个层只有一个节点,或所有的节点都有相同的输入或输出 shape,那么 input_shape 和 output_shape 都是没有歧义的,并也只返回一个值。但是,例如你把一个相同的 Conv2D 应用于一个大小为 (3,32,32) 的数据,然后又将其应用于一个 (3,64,64) 的数据,那么此时该层就具有了多个输入和输出的 shape,你就需要显式的指定节点的下标,来表明你想取的是哪个了。

    a = Input(shape=(3, 32, 32))
    b = Input(shape=(3, 64, 64))
    
    conv = Conv2D(16, (3, 3), padding='same')
    conved_a = conv(a)
    assert conv.input_shape == (None, 3, 32, 32)
    
    conved_b = conv(b)
    assert conv.get_input_shape_at(0) == (None, 3, 32, 32)
    assert conv.get_input_shape_at(1) == (None, 3, 64, 64)s
    

    7. Functional 模型示例

    inception模型

    inception的详细结构参见Google的这篇论文:Going Deeper with Convolutions

    from keras.layers import Conv2D, MaxPooling2D, Input
    
    input_img = Input(shape=(3, 256, 256))
    
    tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
    tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1)
    
    tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
    tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2)
    
    tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img)
    tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3)
    
    output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)
    

    卷积层的残差连接

    残差网络(Residual Network)的详细信息请参考这篇文章:Deep Residual Learning for Image Recognition

    from keras.layers import Conv2D, Input
    
    # 输入张量是一个3通道的256x256图像
    x = Input(shape=(3, 256, 256))
    # 3x3卷积,3输出通道 (与输入通道一样)
    y = Conv2D(3, (3, 3), padding='same')(x)
    # 返回 x + y.
    z = keras.layers.add([x, y])
    

    共享视觉模型

    该模型在两个输入上重用了图像处理的模型,用来判别两个 MNIST 数字是否是相同的数字

    from keras.layers import Conv2D, MaxPooling2D, Input, Dense, Flatten
    from keras.models import Model
    
    # 首先定义视觉模型
    digit_input = Input(shape=(1, 27, 27))
    x = Conv2D(64, (3, 3))(digit_input)
    x = Conv2D(64, (3, 3))(x)
    x = MaxPooling2D((2, 2))(x)
    out = Flatten()(x)
    
    vision_model = Model(digit_input, out)
    
    # 然后定义tell-digits-apart模型
    digit_a = Input(shape=(1, 27, 27))
    digit_b = Input(shape=(1, 27, 27))
    
    # 共享视觉模型
    out_a = vision_model(digit_a)
    out_b = vision_model(digit_b)
    
    concatenated = keras.layers.concatenate([out_a, out_b])
    out = Dense(1, activation='sigmoid')(concatenated)
    
    classification_model = Model([digit_a, digit_b], out)
    

    视觉问答模型

    在针对一幅图片使用自然语言进行提问时,该模型能够提供关于该图片的一个单词的答案。

    这个模型将自然语言的问题和图片分别映射为特征向量,将二者合并后训练一个 logistic 回归层,从一系列可能的回答中挑选一个。

    from keras.layers import Conv2D, MaxPooling2D, Flatten
    from keras.layers import Input, LSTM, Embedding, Dense
    from keras.models import Model, Sequential
    
    # 首先我们使用Sequential模型定义一个视觉模型
    # 该模型会将一个图像编码成一个向量
    vision_model = Sequential()
    vision_model.add(Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=(3, 224, 224)))
    vision_model.add(Conv2D(64, (3, 3), activation='relu'))
    vision_model.add(MaxPooling2D((2, 2)))
    vision_model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
    vision_model.add(Conv2D(128, (3, 3), activation='relu'))
    vision_model.add(MaxPooling2D((2, 2)))
    vision_model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
    vision_model.add(Conv2D(256, (3, 3), activation='relu'))
    vision_model.add(Conv2D(256, (3, 3), activation='relu'))
    vision_model.add(MaxPooling2D((2, 2)))
    vision_model.add(Flatten())
    
    # 现在我们获得视觉模型的输出张量
    image_input = Input(shape=(3, 224, 224))
    encoded_image = vision_model(image_input)
    
    # 接下来,我们定义一个语言模型把问题编码成一个向量
    # 每个问题最多包含100个词,并且每个词用从1到9999的整数表示
    question_input = Input(shape=(100,), dtype='int32')
    embedded_question = Embedding(input_dim=10000, output_dim=256, input_length=100)(question_input)
    encoded_question = LSTM(256)(embedded_question)
    
    # 我们连接问题向量和图像向量
    merged = keras.layers.concatenate([encoded_question, encoded_image])
    
    # 然后我们在1000个可能的回答词语上训练一个logistic回归
    output = Dense(1000, activation='softmax')(merged)
    
    # 这是我们最终的模型:
    vqa_model = Model(inputs=[image_input, question_input], outputs=output)
    
    # 下一阶段在真实的数据上训练这个模型
    

    视频问答模型

    在做完图片问答模型后,我们可以快速将其转为视频问答的模型。在适当的训练下,你可以为模型提供一个短视频(如 100 帧)然后向模型提问一个关于该视频的问题,如“what sport is the boy playing?”->“football”

    from keras.layers import TimeDistributed
    
    video_input = Input(shape=(100, 3, 224, 224))
    # 通过之前已经训练好的 vision_model (权重重用)为视频编码
    encoded_frame_sequence = TimeDistributed(vision_model)(video_input)  # 输出是一个向量的序列
    encoded_video = LSTM(256)(encoded_frame_sequence)  # 输出是一个向量
    
    # 这是一个模型层面的对问题的编码器表示,使用与之前相同的权值
    question_encoder = Model(inputs=question_input, outputs=encoded_question)
    
    # 使用编码器对问题进行编码
    video_question_input = Input(shape=(100,), dtype='int32')
    encoded_video_question = question_encoder(video_question_input)
    
    # 这是我们的视频问题回答模型
    merged = keras.layers.concatenate([encoded_video, encoded_video_question])
    output = Dense(1000, activation='softmax')(merged)
    video_qa_model = Model(inputs=[video_input, video_question_input], outputs=output)
    

    8. 常见问题

    保存 Keras 模型

    一般我们不推荐使用 pickle 或 cPickle 来保存 Keras 模型。Keras 自己就提供了 model.save(filepath) 函数将模型和权重保存在一个 HDF5 文件中,该文件将包含:

    • 模型的结构,以便重构该模型
    • 模型的权重
    • 训练配置(损失函数,优化器等)
    • 优化器的状态,以便于从上次训练中断的地方开始

    使用 keras.models.load_model(filepath) 来重新实例化你的模型,如果文件中存储了训练配置的话,该函数还会同时完成模型的编译。

    from keras.models import load_model
    
    model.save('my_model.h5')  # 创建一个HDF5文件'my_model.h5'
    del model  # 删除已经存在的model
    
    # 返回一个编译好的模型,与之前的完全相同
    model = load_model('my_model.h5')
    

    注意,在使用前需要确保你已安装了 HDF5 和其 Python 库 h5py

    如果你只是希望保存模型的结构,而不包含其权重或配置信息,可以使用:

    # 保存为JSON
    json_string = model.to_json()
    
    # 保存为YAML
    yaml_string = model.to_yaml()
    

    这项操作将把模型序列化为 json 或 yaml 文件,这些文件对人而言也是友好的,如果需要的话你甚至可以手动打开这些文件并进行编辑。当然,你也可以从保存好的 json 文件或 yaml 文件中载入模型:

    # 通过JSON重建模型:
    from keras.models import model_from_json
    model = model_from_json(json_string)
    
    # 通过YAML重建模型
    model = model_from_yaml(yaml_string)
    

    如果需要保存模型的权重,可通过下面的代码利用 HDF5 进行保存。

    model.save_weights('my_model_weights.h5')
    

    如果你需要在代码中初始化一个完全相同的模型,请使用:

    model.load_weights('my_model_weights.h5')
    

    如果你需要加载权重到不同的网络结构(有些层一样)中,例如 fine-tune 或 transfer-learning,你可以通过层名字来加载模型:

    model.load_weights('my_model_weights.h5', by_name=True)
    
    """
    假如原模型为:
        model = Sequential()
        model.add(Dense(2, input_dim=3, name="dense_1"))
        model.add(Dense(3, name="dense_2"))
        ...
        model.save_weights(fname)
    """
    # 新模型
    model = Sequential()
    model.add(Dense(2, input_dim=3, name="dense_1"))  # will be loaded
    model.add(Dense(10, name="new_dense"))  # will not be loaded
    
    # 从第一个模型加载权值; 只会影响第一层 dense_1.
    model.load_weights(fname, by_name=True)
    

    获取中间层的输出

    一种简单的方法是创建一个新的 Model,使得它的输出是你想要的那个输出:

    from keras.models import Model
    
    model = ...  # 创建原模型
    
    layer_name = 'my_layer'
    intermediate_layer_model = Model(input=model.input,
                                     output=model.get_layer(layer_name).output)
    intermediate_output = intermediate_layer_model.predict(data)
    

    此外,我们也可以建立一个 Keras 的函数来达到这一目的:

    from keras import backend as K
    
    # Sequential模型
    get_3rd_layer_output = K.function([model.layers[0].input],
                                      [model.layers[3].output])
    layer_output = get_3rd_layer_output([X])[0]
    

    在每个epoch后记录训练/测试的loss和正确率

    model.fit在运行结束后返回一个History对象,其中含有的history属性包含了训练过程中损失函数的值以及其他度量指标。

    hist = model.fit(X, y, validation_split=0.2)
    print(hist.history)
    展开全文
  • 深度学习:Keras入门(一)之基础篇

    万次阅读 多人点赞 2017-07-07 16:33:21
    1.关于Keras  1)简介  Keras是由纯python编写的基于theano/tensorflow的深度学习框架。  Keras是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果,如果有

    http://www.cnblogs.com/lc1217/p/7132364.html

    1.关于Keras

            1)简介          

             Keras是由纯python编写的基于theano/tensorflow的深度学习框架。

             Keras是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果,如果有如下需求,可以优先选择Keras:

                    a)简易和快速的原型设计(keras具有高度模块化,极简,和可扩充特性)

                    b)支持CNN和RNN,或二者的结合

                    c)无缝CPU和GPU切换

             2)设计原则

                   a)用户友好:Keras是为人类而不是天顶星人设计的API。用户的使用体验始终是我们考虑的首要和中心内容。Keras遵循减少认知困难的最佳实践:Keras提供一致而简洁的API, 能够极大减少一般应用下用户的工作量,同时,Keras提供清晰和具有实践意义的bug反馈。

                   b)模块性:模型可理解为一个层的序列或数据的运算图,完全可配置的模块可以用最少的代价自由组合在一起。具体而言,网络层、损失函数、优化器、初始化策略、激活函数、正则化方法都是独立的模块,你可以使用它们来构建自己的模型。

                  c)易扩展性:添加新模块超级容易,只需要仿照现有的模块编写新的类或函数即可。创建新模块的便利性使得Keras更适合于先进的研究工作。

                  d)与Python协作:Keras没有单独的模型配置文件类型(作为对比,caffe有),模型由python代码描述,使其更紧凑和更易debug,并提供了扩展的便利性。

     

    2.Keras的模块结构

       

     

    3.使用Keras搭建一个神经网络

     

    4.主要概念

       1)符号计算

            Keras的底层库使用Theano或TensorFlow,这两个库也称为Keras的后端。无论是Theano还是TensorFlow,都是一个“符号式”的库。符号计算首先定义各种变量,然后建立一个“计算图”,计算图规定了各个变量之间的计算关系。

           符号计算也叫数据流图,其过程如下(gif图不好打开,所以用了静态图,数据是按图中黑色带箭头的线流动的):

            

         2)张量

              张量(tensor),可以看作是向量、矩阵的自然推广,用来表示广泛的数据类型。张量的阶数也叫维度。

              0阶张量,即标量,是一个数。

              1阶张量,即向量,一组有序排列的数

              2阶张量,即矩阵,一组向量有序的排列起来

              3阶张量,即立方体,一组矩阵上下排列起来

              4阶张量......
              依次类推

              重点:关于维度的理解

              假如有一个10长度的列表,那么我们横向看有10个数字,也可以叫做10维度,纵向看只能看到1个数字,那么就叫1维度。注意这个区别有助于理解Keras或者神经网络中计算时出现的维度问题。

        3)数据格式(data_format)

            目前主要有两种方式来表示张量:
            a) th模式或channels_first模式,Theano和caffe使用此模式。
            b)tf模式或channels_last模式,TensorFlow使用此模式。

     
            下面举例说明两种模式的区别:
             对于100张RGB3通道的16×32(高为16宽为32)彩色图,
             th表示方式:(100,3,16,32)
             tf表示方式:(100,16,32,3)
             唯一的区别就是表示通道个数3的位置不一样。

         4)模型

              Keras有两种类型的模型,序贯模型(Sequential)和函数式模型(Model),函数式模型应用更为广泛,序贯模型是函数式模型的一种特殊情况。
              a)序贯模型(Sequential):单输入单输出,一条路通到底,层与层之间只有相邻关系,没有跨层连接。这种模型编译速度快,操作也比较简单
              b)函数式模型(Model):多输入多输出,层与层之间任意连接。这种模型编译速度慢。

     

    5.第一个示例

              这里也采用介绍神经网络时常用的一个例子:手写数字的识别。

              在写代码之前,基于这个例子介绍一些概念,方便大家理解。

              PS:可能是版本差异的问题,官网中的参数和示例中的参数是不一样的,官网中给出的参数少,并且有些参数支持,有些不支持。所以此例子去掉了不支持的参数,并且只介绍本例中用到的参数。

              1)Dense(500,input_shape=(784,))

                   a)Dense层属于网络层-->常用层中的一个层

                   b) 500表示输出的维度,完整的输出表示:(*,500):即输出任意个500维的数据流。但是在参数中只写维度就可以了,比较具体输出多少个是有输入确定的。换个说法,Dense的输出其实是个N×500的矩阵。

                  c)input_shape(784,) 表示输入维度是784(28×28,后面具体介绍为什么),完整的输入表示:(*,784):即输入N个784维度的数据

             2)Activation('tanh')

                  a)Activation:激活层

                  b)'tanh' :激活函数

             3)Dropout(0.5)

                  在训练过程中每次更新参数时随机断开一定百分比(rate)的输入神经元,防止过拟合。

             4)数据集

                 数据集包括60000张28×28的训练集和10000张28×28的测试集及其对应的目标数字。如果完全按照上述数据格式表述,以tensorflow作为后端应该是(60000,28,28,3),因为示例中采用了mnist.load_data()获取数据集,所以已经判断使用了tensorflow作为后端,因此数据集就变成了(60000,28,28),那么input_shape(784,)应该是input_shape(28,28,)才对,但是在这个示例中这么写是不对的,需要转换成(60000,784),才可以。为什么需要转换呢?

               

                  如上图,训练集(60000,28,28)作为输入,就相当于一个立方体,而输入层从当前角度看就是一个平面,立方体的数据流怎么进入平面的输入层进行计算呢?所以需要进行黄色箭头所示的变换,然后才进入输入层进行后续计算。至于从28*28变换成784之后输入层如何处理,就不需要我们关心了。(喜欢钻研的同学可以去研究下源代码)。

             并且,Keras中输入多为(nb_samples, input_dim)的形式:即(样本数量,输入维度)。

            5)示例代码

    复制代码
    from keras.models import Sequential  
    from keras.layers.core import Dense, Dropout, Activation  
    from keras.optimizers import SGD  
    from keras.datasets import mnist  
    import numpy 
    '''
        第一步:选择模型
    '''
    model = Sequential()
    '''
       第二步:构建网络层
    '''
    model.add(Dense(500,input_shape=(784,))) # 输入层,28*28=784  
    model.add(Activation('tanh')) # 激活函数是tanh  
    model.add(Dropout(0.5)) # 采用50%的dropout
    
    model.add(Dense(500)) # 隐藏层节点500个  
    model.add(Activation('tanh'))  
    model.add(Dropout(0.5))
    
    model.add(Dense(10)) # 输出结果是10个类别,所以维度是10  
    model.add(Activation('softmax')) # 最后一层用softmax作为激活函数
    
    '''
       第三步:编译
    '''
    sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) # 优化函数,设定学习率(lr)等参数  
    model.compile(loss='categorical_crossentropy', optimizer=sgd, class_mode='categorical') # 使用交叉熵作为loss函数
    
    '''
       第四步:训练
       .fit的一些参数
       batch_size:对总的样本数进行分组,每组包含的样本数量
       epochs :训练次数
       shuffle:是否把数据随机打乱之后再进行训练
       validation_split:拿出百分之多少用来做交叉验证
       verbose:屏显模式 0:不输出  1:输出进度  2:输出每次的训练结果
    '''
    (X_train, y_train), (X_test, y_test) = mnist.load_data() # 使用Keras自带的mnist工具读取数据(第一次需要联网)
    # 由于mist的输入数据维度是(num, 28, 28),这里需要把后面的维度直接拼起来变成784维  
    X_train = X_train.reshape(X_train.shape[0], X_train.shape[1] * X_train.shape[2]) 
    X_test = X_test.reshape(X_test.shape[0], X_test.shape[1] * X_test.shape[2])  
    Y_train = (numpy.arange(10) == y_train[:, None]).astype(int) 
    Y_test = (numpy.arange(10) == y_test[:, None]).astype(int)
    
    model.fit(X_train,Y_train,batch_size=200,epochs=50,shuffle=True,verbose=0,validation_split=0.3)
    model.evaluate(X_test, Y_test, batch_size=200, verbose=0)
    
    '''
        第五步:输出
    '''
    print("test set")
    scores = model.evaluate(X_test,Y_test,batch_size=200,verbose=0)
    print("")
    print("The test loss is %f" % scores)
    result = model.predict(X_test,batch_size=200,verbose=0)
    
    result_max = numpy.argmax(result, axis = 1)
    test_max = numpy.argmax(Y_test, axis = 1)
    
    result_bool = numpy.equal(result_max, test_max)
    true_num = numpy.sum(result_bool)
    print("")
    print("The accuracy of the model is %f" % (true_num/len(result_bool)))
    复制代码

     

    展开全文
  • 深度学习框架-Keras基础入门系列

    千人学习 2018-10-22 21:38:11
    Keras是一种高度模块化,使用简单上手快,合适深度学习初学者使用的深度学习框架。Keras由纯Python编写而成并以Tensorflow、Theano以及CNTK为后端。Keras为支持实验而生,能够把你的idea迅速转换为结果。 对于深度...
  • 人工智能框架实战精讲:Keras项目

    千人学习 2020-06-24 14:27:13
    Keras项目实战课程从实战的角度出发,基于真实数据集与实际业务需求,从零开始讲解如何进行数据处理,模型训练与调优,最后进行测试与结果展示分析。全程实战操作,以最接地气的方式详解每一步流程与解决方案。课程...
  • 想要将深度学习应用于小型图像数据集,一种常用且非常高效的方法是使用预训练网络。 预训练网络(pretrained network)是一个保存好的网络,之前已在大型数据集(通常是大规模图像分类任务)上训练好。...

    想要将深度学习应用于小型图像数据集,一种常用且非常高效的方法是使用预训练网络。 预训练网络(pretrained network)是一个保存好的网络,之前已在大型数据集(通常是大规模图像分类任务)上训练好。如果这个原始数据集足够大且足够通用,那么预训练网络学到的特征的空间层次结构可以有效地作为视觉世界的通用模型,因此这些特征可用于各种不同的计算机视觉问题,即使这些新问题涉及的类别和原始任务完全不同。举个例子,你在 ImageNet 上训练了一个网络(其类别主要是动物和日常用品),然后将这个训练好的网络应用于某个不相干的任务,比如在图像中识别家具。这种学到的特征在不同问题之间的可移植性,是深度学习与许多早期浅层学习方法相比的重要优势,它使得深度学习对小数据问题非常有效。

    本例中,假设有一个在 ImageNet 数据集(140 万张标记图像,1000 个不同的类别)上训练好的大型卷积神经网络。ImageNet 中包含许多动物类别,其中包括不同种类的猫和狗,因此可以认为它在猫狗分类问题上也能有良好的表现。

    我们将使用 VGG16 架构,它由 Karen Simonyan 和 Andrew Zisserman 在 2014 年开发。对于ImageNet,它是一种简单而又广泛使用的卷积神经网络架构。虽然 VGG16 是一个比较旧的模 型,性能远比不了当前最先进的模型,而且还比许多新模型更为复杂,但我之所以选择它,是因为它的架构与你已经熟悉的架构很相似,因此无须引入新概念就可以很好地理解。这可能是你第一次遇到这种奇怪的模型名称——VGG、ResNet、Inception、Inception-ResNet、Xception 等。 你会习惯这些名称的,因为如果你一直用深度学习做计算机视觉的话,它们会频繁出现。

    使用预训练网络有两种方法:特征提取(feature extraction)和微调模型(fine-tuning)。两种方法我们都会介绍。首先来看特征提取。

    特征提取

    特征提取是使用之前网络学到的表示来从新样本中提取出有趣的特征。然后将这些特征输入一个新的分类器,从头开始训练。

    如前所述,用于图像分类的卷积神经网络包含两部分:首先是一系列池化层和卷积层,最后是一个密集连接分类器。第一部分叫作模型的卷积基(convolutional base)。对于卷积神经网络而言,特征提取就是取出之前训练好的网络的卷积基,在上面运行新数据,然后在输出上面 训练一个新的分类器(见下图)。

     

    为什么仅重复使用卷积基?我们能否也重复使用密集连接分类器?一般来说,应该避免这么做。原因在于卷积基学到的表示可能更加通用,因此更适合重复使用。卷积神经网络的特征图表示通用概念在图像中是否存在,无论面对什么样的计算机视觉问题,这种特征图都可能很有用。但是,分类器学到的表示必然是针对于模型训练的类别,其中仅包含某个类别出现在整张图像中的概率信息。此外,密集连接层的表示不再包含物体在输入图像中的位置信息。密集连接层舍弃了空间的概念,而物体位置信息仍然由卷积特征图所描述。如果物体位置对于问题 很重要,那么密集连接层的特征在很大程度上是无用的。

    注意,某个卷积层提取的表示的通用性(以及可复用性)取决于该层在模型中的深度。模型中更靠近底部的层提取的是局部的、高度通用的特征图(比如视觉边缘、颜色和纹理),而更靠近顶部的层提取的是更加抽象的概念(比如“猫耳朵”或“狗眼睛”)。 因此,如果你的新数据集与原始模型训练的数据集有很大差异,那么最好只使用模型的前几层来做特征提取,而不是使用整个卷积基。

    本例中,由于 ImageNet 的类别中包含多种狗和猫的类别,所以重复使用原始模型密集连接层中所包含的信息可能很有用。但我们选择不这么做,以便涵盖新问题的类别与原始模型的类别不一致的更一般情况。

    我们来实践一下,使用在 ImageNet 上训练的 VGG16 网络的卷积基从 猫狗图像中提取有趣的特征,然后在这些特征上训练一个猫狗分类器。 VGG16 等模型内置于 Keras 中。你可以从 keras.applications 模块中导入。下面是keras.applications 中的一部分图像分类模型(都是在 ImageNet 数据集上预训练得到的):

    • Xception
    • Inception V3
    • ResNet50
    • VGG16
    • VGG19
    • MobileNet 我们将 VGG16 模型实例化。
    from keras.applications import VGG16
    
    conv_base = VGG16(weights='imagenet',
                      include_top=False,
                      input_shape=(150, 150, 3))
    
    
    model.summary()
    输出和为网络的层数

    这里向构造函数中传入了三个参数。

    • weights 指定模型初始化的权重检查点。
    • include_top 指定模型最后是否包含密集连接分类器。默认情况下,这个密集连接分类器对应于 ImageNet 的 1000 个类别。因为我们打算使用自己的密集连接分类器(只有 两个类别:cat 和 dog),所以不需要包含它。
    • input_shape 是输入到网络中的图像张量的形状。这个参数完全是可选的,如果不传入这个参数,那么网络能够处理任意形状的输入。 VGG16 卷积基的详细架构如下所示。它和你已经熟悉的简单卷积神经网络很相似。

    最后输出的特征图形状为 (4, 4, 512)。我们将在这个特征上添加一个密集连接分类器。 接下来,下一步有两种方法可供选择。

    • 在你的数据集上运行卷积基,将输出保存成硬盘中的 Numpy 数组,然后用这个数据作 为输入,输入到独立的密集连接分类器中(与本书第一部分介绍的分类器类似)。这种 方法速度快,计算代价低,因为对于每个输入图像只需运行一次卷积基,而卷积基是目 前流程中计算代价最高的。但出于同样的原因,这种方法不允许你使用数据增强。
    • 在顶部添加 Dense 层来扩展已有模型(即 conv_base),并在输入数据上端到端地运行 整个模型。这样你可以使用数据增强,因为每个输入图像进入模型时都会经过卷积基。但出于同样的原因,这种方法的计算代价比第一种要高很多。

    这两种方法我们都会介绍。首先来看第一种方法的代码:保存你的数据在 conv_base 中的输出,然后将这些输出作为输入用于新模型。

    import os
    import numpy as np
    from keras.preprocessing.image import ImageDataGenerator
    
    base_dir = 'data/cats_and_dogs_small'
    
    train_dir = os.path.join(base_dir, 'train')
    validation_dir = os.path.join(base_dir, 'validation')
    test_dir = os.path.join(base_dir, 'test')
    
    datagen = ImageDataGenerator(rescale=1./255)
    batch_size = 20
    
    def extract_features(directory, sample_count):
        features = np.zeros(shape=(sample_count, 4, 4, 512))
        labels = np.zeros(shape=(sample_count))
        generator = datagen.flow_from_directory(
            directory,
            target_size=(150, 150),
            batch_size=batch_size,
            class_mode='binary')
        i = 0
        for inputs_batch, labels_batch in generator:
            features_batch = conv_base.predict(inputs_batch)
            features[i * batch_size : (i + 1) * batch_size] = features_batch
            labels[i * batch_size : (i + 1) * batch_size] = labels_batch
            i += 1
            if i * batch_size >= sample_count:
                # Note that since generators yield data indefinitely in a loop,
                # we must `break` after every image has been seen once.
                #注意,这些生成器在循环中不断生成数据,所以你必须在读取完所有图像后终止循环
                break
        return features, labels
    
    train_features, train_labels = extract_features(train_dir, 2000)
    validation_features, validation_labels = extract_features(validation_dir, 1000)
    test_features, test_labels = extract_features(test_dir, 1000)
    输出为:
    Found 2000 images belonging to 2 classes.
    Found 1000 images belonging to 2 classes.
    Found 1000 images belonging to 2 classes.

    目前,提取的特征形状为 (samples, 4, 4, 512)。我们要将其输入到密集连接分类器中, 所以首先必须将其形状展平为 (samples, 8192)。

    train_features = np.reshape(train_features, (2000, 4 * 4 * 512))
    validation_features = np.reshape(validation_features, (1000, 4 * 4 * 512))
    test_features = np.reshape(test_features, (1000, 4 * 4 * 512))

    现在你可以定义你的密集连接分类器(注意要使用 dropout 正则化),并在刚刚保存的数据和标签上训练这个分类器。

    from keras import models
    from keras import layers
    from keras import optimizers
    
    model = models.Sequential()
    model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(1, activation='sigmoid'))
    
    model.compile(optimizer=optimizers.RMSprop(lr=2e-5),
                  loss='binary_crossentropy',
                  metrics=['acc'])
    
    history = model.fit(train_features, train_labels,
                        epochs=30,
                        batch_size=20,
                        validation_data=(validation_features, validation_labels))

    部分迭代次数:

    训练速度非常快,因为你只需处理两个 Dense 层。即使在 CPU 上运行,每轮的时间也不到一秒钟。

    我们来看一下训练期间的损失曲线和精度曲线

    iimport matplotlib.pyplot as plt
    
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    
    epochs = range(len(acc))
    
    plt.plot(epochs, acc, 'bo', label='Training acc')
    plt.plot(epochs, val_acc, 'b', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    
    plt.figure()
    
    plt.plot(epochs, loss, 'bo', label='Training loss')
    plt.plot(epochs, val_loss, 'b', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    
    plt.show()

    我们的验证精度达到了约 90%,比上一节从头开始训练的小型模型效果要好得多。但从图中也可以看出,虽然 dropout 比率相当大,但模型几乎从一开始就过拟合。这是因为本方法没有使用数据增强,而数据增强对防止小型图像数据集的过拟合非常重要。

    下面我们来看一下特征提取的第二种方法,它的速度更慢,计算代价更高,但在训练期间可以使用数据增强。这种方法就是:扩展 conv_base 模型,然后在输入数据上端到端地运行模型。

    模型的行为和层类似,所以你可以向 Sequential 模型中添加一个模型(比如 conv_base),就像添加一个层一样。

    from keras import models
    from keras import layers
    
    model = models.Sequential()
    model.add(conv_base)
    model.add(layers.Flatten())
    model.add(layers.Dense(256, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))

    VGG16 的卷积基有 14 714 688 个参数,非常多。在其上添加的分类器有 200 万个参数。

    在编译和训练模型之前,一定要“冻结”卷积基。冻结(freeze)一个或多个层是指在训练 过程中保持其权重不变。如果不这么做,那么卷积基之前学到的表示将会在训练过程中被修改。 因为其上添加的 Dense 层是随机初始化的,所以非常大的权重更新将会在网络中传播,对之前学到的表示造成很大破坏。

    在 Keras 中,冻结网络的方法是将其 trainable 属性设为 False。

    print('This is the number of trainable weights '
          'before freezing the conv base:', len(model.trainable_weights))
    
    conv_base.trainable = False
    print('This is the number of trainable weights '
          'after freezing the conv base:', len(model.trainable_weights))

    如此设置之后,只有添加的两个 Dense 层的权重才会被训练。总共有 4 个权重张量,每层2 个(主权重矩阵和偏置向量)。注意,为了让这些修改生效,你必须先编译模型。如果在编译之后修改了权重的 trainable 属性,那么应该重新编译模型,否则这些修改将被忽略。

    现在你可以开始训练模型了,使用和前一个例子相同的数据增强设置。

    from keras.preprocessing.image import ImageDataGenerator
    
    train_datagen = ImageDataGenerator(
          rescale=1./255,
          rotation_range=40,
          width_shift_range=0.2,
          height_shift_range=0.2,
          shear_range=0.2,
          zoom_range=0.2,
          horizontal_flip=True,
          fill_mode='nearest')
    
    # Note that the validation data should not be augmented!
    # 注意,不能增强验证数据
    test_datagen = ImageDataGenerator(rescale=1./255)
    
    train_generator = train_datagen.flow_from_directory(
            # This is the target directory(目标目录)
            train_dir,
            # All images will be resized to 150x150(将所有图像的大小调整为 150×150)
            target_size=(150, 150),
            batch_size=20,
            # Since we use binary_crossentropy loss, we need binary labels
    #         因为使用了 binary_crossentropy损失,所以需要用二进制标签
            class_mode='binary')
    
    validation_generator = test_datagen.flow_from_directory(
            validation_dir,
            target_size=(150, 150),
            batch_size=20,
            class_mode='binary')
    model.compile(loss='binary_crossentropy',
                  optimizer=optimizers.RMSprop(lr=2e-5),
                  metrics=['acc'])
    
    history = model.fit_generator(
          train_generator,
          steps_per_epoch=100,
          epochs=30,
          validation_data=validation_generator,
          validation_steps=50,
          verbose=2)
    model.save('cats_and_dogs_small_3.h5')

    再次绘制结果看看。

    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    
    epochs = range(len(acc))
    
    plt.plot(epochs, acc, 'bo', label='Training acc')
    plt.plot(epochs, val_acc, 'b', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    
    plt.figure()
    
    plt.plot(epochs, loss, 'bo', label='Training loss')
    plt.plot(epochs, val_loss, 'b', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    
    plt.show()

    我们来再次绘制结果。如你所见,验证精度约为 96%。这比从头开始训练的小型卷积神经网络要好得多。

    微调模型

    另一种广泛使用的模型复用方法是模型微调(fine-tuning),与特征提取互为补充。对于用于特征提取的冻结的模型基,微调是指将其顶部的几层“解冻”,并将这解冻的几层和新增加的部分(本例中是全连接分类器)联合训练(见下图)。之所以叫作微调,是因为它只是略微调整了所复用模型中更加抽象的表示,以便让这些表示与手头的问题更加相关。

    前面说过,冻结 VGG16 的卷积基是为了能够在上面训练一个随机初始化的分类器。同理, 只有上面的分类器已经训练好了,才能微调卷积基的顶部几层。如果分类器没有训练好,那么训练期间通过网络传播的误差信号会特别大,微调的几层之前学到的表示都会被破坏。因此,微调网络的步骤如下。

    • (1) 在已经训练好的基网络(base network)上添加自定义网络。
    • (2) 冻结基网络。
    • (3) 训练所添加的部分。
    • (4) 解冻基网络的一些层。
    • (5) 联合训练解冻的这些层和添加的部分。 你在做特征提取时已经完成了前三个步骤。我们继续进行第四步:先解冻 conv_base,然后冻结其中的部分层。

    我们将微调最后三个卷积层,也就是说,直到 block4_pool 的所有层都应该被冻结,而block5_conv1、block5_conv2 和 block5_conv3 三层应该是可训练的。 为什么不微调更多层?为什么不微调整个卷积基?你当然可以这么做,但需要考虑以下几点。

    • 卷积基中更靠底部的层编码的是更加通用的可复用特征,而更靠顶部的层编码的是更专业化的特征。微调这些更专业化的特征更加有用,因为它们需要在你的新问题上改变用途。微调更靠底部的层,得到的回报会更少。
    • 训练的参数越多,过拟合的风险越大。卷积基有1500 万个参数,所以在你的小型数据集上训练这么多参数是有风险的。

    因此,在这种情况下,一个好策略是仅微调卷积基最后的两三层。我们从上一个例子结束的地方开始,继续实现此方法。

    onv_base.trainable = True
    
    set_trainable = False
    for layer in conv_base.layers:
        if layer.name == 'block5_conv1':
            set_trainable = True
        if set_trainable:
            layer.trainable = True
        else:
            layer.trainable = False

    现在你可以开始微调网络。我们将使用学习率非常小的 RMSProp 优化器来实现。之所以让学习率很小,是因为对于微调的三层表示,我们希望其变化范围不要太大。太大的权重更新可能会破坏这些表示。

    现在我们实施模型微调:

    model.compile(loss='binary_crossentropy',
                  optimizer=optimizers.RMSprop(lr=1e-5),
                  metrics=['acc'])
    
    history = model.fit_generator(
          train_generator,
          steps_per_epoch=100,
          epochs=100,
          validation_data=validation_generator,
          validation_steps=50)
    
    model.save('cats_and_dogs_small_4.h5')

    画精度图
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    
    epochs = range(len(acc))
    
    plt.plot(epochs, acc, 'bo', label='Training acc')
    plt.plot(epochs, val_acc, 'b', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    
    plt.figure()
    
    plt.plot(epochs, loss, 'bo', label='Training loss')
    plt.plot(epochs, val_loss, 'b', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    
    plt.show()

    这些曲线看起来包含噪声。为了让图像更具可读性,你可以将每个损失和精度都替换为指数移动平均值,从而让曲线变得平滑。下面用一个简单的实用函数来实现。

    def smooth_curve(points, factor=0.8):
      smoothed_points = []
      for point in points:
        if smoothed_points:
          previous = smoothed_points[-1]
          smoothed_points.append(previous * factor + point * (1 - factor))
        else:
          smoothed_points.append(point)
      return smoothed_points
    
    plt.plot(epochs,
             smooth_curve(acc), 'bo', label='Smoothed training acc')
    plt.plot(epochs,
             smooth_curve(val_acc), 'b', label='Smoothed validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    
    plt.figure()
    
    plt.plot(epochs,
             smooth_curve(loss), 'bo', label='Smoothed training loss')
    plt.plot(epochs,
             smooth_curve(val_loss), 'b', label='Smoothed validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    
    plt.show()

     

    验证精度曲线变得更清楚。可以看到,精度值提高了 1%,从约 96% 提高到 97% 以上。

    注意,从损失曲线上看不出与之前相比有任何真正的提高(实际上还在变差)。你可能感到奇怪,如果损失没有降低,那么精度怎么能保持稳定或提高呢?答案很简单:图中展示的是逐点(pointwise)损失值的平均值,但影响精度的是损失值的分布,而不是平均值,因为精度是模型预测的类别概率的二进制阈值。即使从平均损失中无法看出,但模型也仍然可能在改进。

    现在,你可以在测试数据上最终评估这个模型。

    test_generator = test_datagen.flow_from_directory(
            test_dir,
            target_size=(150, 150),
            batch_size=20,
            class_mode='binary')
    
    test_loss, test_acc = model.evaluate_generator(test_generator, steps=50)
    print('test acc:', test_acc)
    
    输出:Found 1000 images belonging to 2 classes.
    test acc: 0.938999991417

    我们得到了 97% 的测试精度。在关于这个数据集的原始 Kaggle 竞赛中,这个结果是最佳结果之一。但利用现代深度学习技术,你只用一小部分训练数据(约 10%)就得到了这个结果。 训练 20 000 个样本与训练 2000 个样本是有很大差别的!

    展开全文
  • keras神经网络做简单的回归问题

    千次阅读 2019-07-03 13:39:21
    咸鱼了半个多月了,要干点正经事了。 最近在帮老师用神经网络做多变量非线性的回归问题,没有什么心得,但是也要写个博文当个日记。 该回归问题是四个输入,一个输出。自己并不清楚这几个变量有什么关系,因为是跟...

    咸鱼了半个多月了,要干点正经事了。

    最近在帮老师用神经网络做多变量非线性的回归问题,没有什么心得,但是也要写个博文当个日记。

    该回归问题是四个输入,一个输出。自己并不清楚这几个变量有什么关系,因为是跟遥感相关的,就瞎做呗。

    • 数据预处理的选择

    刚开始选取了最大最小值的预处理方法,调了很久的模型但是最后模型的输出基本不变。

    换了z-score的预处理方法,模型的输出才趋于正常。

    • 损失函数的选择

    对于回归问题,常用的损失函数有三种,一个是平方误差函数,一个是绝对值误差函数,还有一个是交叉熵函数。

    在其他参数都不变的时候分别采用这三个损失函数:

    1.交叉熵

    2.绝对值误差函数

    3.平方误差函数

    结论:从上面三个图中国可以看出,相同条件下,绝对值误差函数得到的效果好一些。

    • batch_size大小的选择

    bach_size = 32

    bach_size = 64

    bach_size = 128

    batch_size = 256

     

    在两个不同的batch_size下,网络最后的loss值都差不多,但是在验证集上,当batch_size = 64/128时,loss曲线比较稳定。

    结论:一定范围内,batch_size越大,其确定的下降方向就越准,引起训练震荡越小.随着batch_size增大,处理相同的数据量的速度越快。但是随着batchsize增大,达到相同精度所需要的epoch数量越来越多。过大的batch_size的结果是网络很容易收敛到一些不好的局部最优点。同样太小的batch_size会使得训练速度很慢,训练不容易收敛。

    • 是否添Dropout层

    不加dropout层

    加了Dropout层

    加了Dropout层后模型的loss值反而升高,但是测试集上的loss下降能平稳一些。

    •  深层网络和浅层网络的选择

    我自己觉得这样一个简单的问题其实浅层网络就能解决,但是老师想搭一下深度学习的车,没办法只能用比较一下两个模型。

    含有一个隐层的全连接网络,64个神经元,最后模型的loss值为:0.1032

    含有两个隐层的全连接网络,第一层32个神经元,第二层16个神经元,最后的loss值为0.0995

    含有三个隐层的全连接网络,第一层32个神经元,第二层16个神经元,第三层8个神经元,最后模型的loss值为0.0986

    含有四个隐层的全连接网络,第一层32个神经元,第二层16个神经元,第三层8个神经元,第四层4个神经元,最后模型的loss值为0.0993

    含有五个隐层的全连接网络,第一层32个神经元,第二层16个神经元,第三层8个神经元,第四层4个神经元,第五层2个神经元,最后模型的loss值为0.0991

    含有五个隐层的全连接网络,第一层32个神经元,第二层16个神经元,第三层8个神经元,第四层4个神经元,第五层2个神经元,第六层2个神经元,最后模型的loss值为0.0988

    ........

    结论:在一定范围内,随着网络层的加深,模型的准确率升高。超过一定范围,随着网络层的加深,模型的准确率不但不升反而下降,测试集上的准确率也会下降,所以这并不是出现了过拟合。

    • 模型宽度的选择

    由于上一个实验中三层模型的loss值最低,所以我选择三层模型来做这个对于模型宽度选择的实验。

    1、含有三个隐层的全连接网络,第一层32个神经元,第二层16个神经元,第三层8个神经元,最后模型的loss值为0.0986

     

    2、含有三个隐层的全连接网络,第一层32个神经元,第二层32个神经元,第三层16个神经元,最后模型的loss值为0.0986

     

    3、含有三个隐层的全连接网络,第一层32个神经元,第二层32个神经元,第三层32个神经元,最后模型的loss值为0.0960

    4、含有三个隐层的全连接网络,第一层32个神经元,第二层64个神经元,第三层32个神经元,最后模型的loss值为0.0967

    5、含有三个隐层的全连接网络,第一层32个神经元,第二层64个神经元,第三层64个神经元,最后模型的loss值为0.0967

    结论:在一定范围内,网络模型越宽,模型的准确率越高,但是超过某一阈值后,模型的准确率不再提高,测试集上loss下降震荡越来越明显,说明模型的复杂度已经高于回归问题真是模型的复杂度。

    • 尝试残差网络

    第一种残差网络:

    def identity_block(x):
            out = Dense(32)(x)
            #out = BatchNormalization()(out)
            out = Activation('tanh')(out)
            #out = Dropout(0.1)(out)
            out = Dense(32)(x)
            #out = Dropout(0.1)(out)
            #out = BatchNormalization()(out)
            out = Activation('tanh')(out)
    
            out = Dense(4)(out)
            #out = BatchNormalization()(out)
    
            out = merge([out,x],mode='sum')
            out = Activation('tanh')(out)
            return out
    

      

     

    结论:和全连接网络相比,残差网络loss下降很快,测试集上loss下降曲线很平滑,但是模型的准确率却不如普通三层的全连接网络,最终的loss值为0.1021。

    第二种残差网络:

    def fc_block(x):
            out = Dense(32)(x)
            out = Activation('tanh')(out)
            out = Dense(32)(x)
            out = Dropout(0.1)(out)
            out = Activation('tanh')(out)
            out = Dense(32)(out)
    
            x = Dense(32)(x)
    
            out = merge([out, x], mode = 'sum')
            out = Activation('tanh')(out)
            return out
    

      

    结论:第二种残差网络的loss值为0.1016,比第一种残差网络的效果能好一点。在ResNet中,这两个模块是交替使用的。

    将两个模块叠加之后,模型的准确率并没有提升,应该是模型过度复杂了,最后模型的loss值为0.1027。

    •  relu还是tanh

    由于输出值的范围是[-1, 1],因此模型的输出层的激活函数只能选择tanh。

    在隐藏层中,可以选择relu和tanh作为隐藏层的激活函数。

    模型结构为3层,神经元分别是32,32,32。就是上一个步骤中loss最低的网络结构,在上一个步骤中隐层的激活层使用的是tanh,loss值为0.0960

    将tanh换成relu:

    采用relu作为激活函数,模型的计算速度会加快,因为求导很简单。在这个问题只使用relu会使模型的准确率下降。一般在复杂的模型中使用relu比较多。

    转载于:https://www.cnblogs.com/catpainter/p/8891091.html

    展开全文
  • 本文介绍了如何使用Keras框架,搭建一个小型的神经网络-多层感知器,并通过给定数据进行计算训练,最好将训练得到的模型提取出参数,放在51单片机上进行运行。
  • 基于Keras的卷积神经网络(CNN)可视化

    万次阅读 多人点赞 2018-01-20 11:09:53
    基于Keras的卷积神经网络(CNN)可视化 标签(空格分隔): 深度学习 卷积神经网络可视化 本文整理自Deep Learning with Python,书本上完整的代码在 这里的5.4节,并陪有详细的注释。 深度学习一直被人们...
  • ​​其中:1、VGG 网络以及从 2012 年以来的 AlexNet 都遵循现在的基本卷积网络的原型布局:一系列卷积层、最大池化层和激活层,最后还有一些全连接的分类层。2、ResNet 的作者将这些问题归结成了一个单一的假设:...
  • 深度学习(十)keras学习笔记

    万次阅读 2016-03-26 12:25:04
    keras与torch7的使用非常相似,是最近才火起来的深度学习开源库,底层是用了theano。keras可以说是python版的torch7,对于快速构建CNN模型非常方便。同时也包含了一些最新文献的算法,比如Batch Noramlize,文档教程...
  • Keras入门

    千次阅读 多人点赞 2018-08-28 11:01:11
    注解:关于Keras本人是小白,此次也是因为学习其他东西,需要了解Keras的相关知识,所以稍微整理一下........ http://www.cnblogs.com/lc1217/p/7132364.html 为何要用Keras 如今在深度学习大火的时候,第三方...
  • Keras

    千次阅读 2018-08-11 14:45:57
    Keras是由纯python编写的基于theano/tensorflow的深度学习框架。Keras是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果,如果有如下需求,可以优先选择Keras: a)简易和快速的原型设计(keras...
  • 什么是Keras

    千次阅读 2019-09-04 21:33:03
    今天开始读一本关于Keras的深度学习书籍,计划每天记录一些所得。 直奔主题,既然要学Keras,那什么是KerasKeras和其他机器学习、深度学习库有什么区别? 让我们看看Keras中文文档中的定义: Keras是一个模型库,...
  • Keras和TensorFlow的关系和区别

    万次阅读 多人点赞 2017-12-21 18:40:54
    TensorFlow和theano以及Keras都是深度学习框架,TensorFlow和theano比较灵活,也比较难学,它们其实就是一个微分器 Keras其实就是TensorFlow和Keras的接口(Keras作为前端,TensorFlow或theano作为后端),它也很...
  • pip安装指定keras版本

    万次阅读 2018-03-30 10:25:07
    pip install --upgrade keras==2.1.0 升级到指定版本pip install keras==2.0.9安装指定版本
  • 安装 keras-contribpip install git+https://www.github.com/keras-team/keras-contrib.git[参考文献]https://blog.csdn.net/qq_16912257/article/details/78969966
  • 查看keras版本

    万次阅读 2018-03-30 10:23:40
    打开终端依次输入以下两个命令。我的默认是2.1.1版本的python print(keras.__version__)
  • Keras安装与测试

    万次阅读 2018-08-19 12:22:55
    Keras是高度封装的包,适合初学者学习深度学习网络框架,比如我这个小白,一切都在尝试中,每天都在安装各种库各种API!!! Keras 安装: 环境 anconda(含pip,python3.6) 本人是在cmd中使用pip安装的keras,...
  • keras中查看各类版本号

    万次阅读 2017-04-05 13:39:27
    因为在使用keras中难免要升级,所以我们经常要查看自己使用的版本号,命令如下: 1.查看keras版本 >>> import keras >>> print keras.__version__ 1.2.0 2.查看theano版本 >>> import theano as th >>> ...
1 2 3 4 5 ... 20
收藏数 59,297
精华内容 23,718
关键字:

keras