Deep Learning with Python 系列笔记(六):深度学习实践进阶

Keras functional API

keras中常用的Sequential 模型,通常假设网络只有一个输入和一个输出,并且这些网络层之间是一种线性的堆叠。如下:
这里写图片描述
事实上,这种结构太过普通,我们需要把许多内容和实际操作都通过一个Sequential模型实现。但是,很多情况下运用都很复杂,需要用到几个独立的输入,有些网络则需要多输出,甚至有些网络在层与层之间通过内部的分支传递,而不是简单的层与层之间线性堆叠。

比如,有些任务需要多模式输入:它们把不同的输入合并在一起,用不同的神经网络层处理不同的数据。设想一个深度学习模型尝试预测一件二手衣服的市场价,将使用到以下输入:(1)用户提供的元数据(商标、年龄等),(2)用户提供的文字描述,(3)衣服的图片。如果我们仅仅使用元数据,我们可以使用one-hot编码并勇敢一个全连接层来预测价格。或者我们只用用户的文字描述,我们可以用一个RNN网络或者一个1D convnet。或者如果我们只用衣服的图片,我们可以用 2D convnet.

但是,怎么能够同时处理所有的这三种数据。一个很简单的方法是,分别用三种不同的模型训练他们,然后给他们的预测加以权重来获得最终的结果。然而,这很可能是次优的,因为模型提取的信息可能是高冗余的。一个更好的方法是,通过使用一个可以同时看到所有可用的输入方式的模型来联合学习一个更精确的数据模型:一个有三个输入分支的模型。
这里写图片描述
同样,有些任务需要预测输入数据的多个目标值。对于一篇小说或者短文,有些人可能想自动识别它是什么类型的文章,有些人可能想预测它出版的大概时间。当然,你可以简单的训练两个模型,一个是识别类型一个预测时间。然而,由于这些属性在统计上并不是独立的,我们可以通过学习共同预测类型和日期来建立一个更好的模型。这样一个联合模型将有两个输出。
这里写图片描述
另外,现在很多神经网络结构使用了一些非线性网络技术:网络结构为有向无环图。比如“Inception modules”系列的网络模型。当输入被几个平行的卷积分支处理后,它们的输出被合并成一个张量。最近的趋势是将“残差连接”添加到一个模型中,该模型从ResNet系列网络开始。一个残差连接(residual connection)仅仅是将以前的表示重新注入到数据的下游流中,通过将一个过去的输出张量添加到后面的输出张量中,这有助于防止数据处理流程中的信息丢失。

Inception modules

这里写图片描述

ResNet

这里写图片描述

Function API的介绍

在Function API中,你将直接处理张量,并且每层网络都将用作函数形式,读取张量数据并返回张量数据。

Calling layers as function in the functional API

from keras import Input, layers

# This is a tensor.
input_tensor = Input(shape=(32,))

# A layer is a function.
dense = layers.Dense(32, activation='relu')

# A layer may be called on a tensor, and it returns a tensor.
output_tensor = dense(input_tensor)

The functional API equivalent to a Sequential model

from keras.models import Sequential, Model
from keras import layers
from keras import Input

# A Sequential model, which you already know all about.
seq_model = Sequential()
seq_model.add(layers.Dense(32, activation='relu', input_shape=(64,)))
seq_model.add(layers.Dense(32, activation='relu'))
seq_model.add(layers.Dense(10, activation='softmax'))

# Its functional equivalent.
input_tensor = Input(shape=(64,))
x = layers.Dense(32, activation='relu')(input_tensor)
x = layers.Dense(32, activation='relu')(x)
output_tensor = layers.Dense(10, activation='softmax')(x)

# The Model class turns an input tensor and output tensor into a model
model = Model(input_tensor, output_tensor)

# Let's look at it!
model.summary()

Summary of the functional model

_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 64) 0
_________________________________________________________________
dense_1 (Dense) (None, 32) 2080
_________________________________________________________________
dense_2 (Dense) (None, 32) 1056
_________________________________________________________________
dense_3 (Dense) (None, 10) 330
=================================================================
Total params: 3,466
Trainable params: 3,466
Non-trainable params: 0
_________________________________________________________________

在这一点上,唯一可能看起来有点神奇的部分是,仅使用输入张量和输出张量来实例化一个模型对象。在幕后,Keras将检索从input_tensor到output_tensor的每一层,将它们合并到一个类似图形的数据结构模型中。当然,它起作用的原因是由于output_tensor确实是通过反复转换input_tensor得到的。

当涉及到编译、训练或评估模型的实例时,Function API与Sequential API是一样的。
Training models built with the functional API: business as usual

# Compile the model
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')

# Generate dummy Numpy data to train on
import numpy as np
x_train = np.random.random((1000, 64))
y_train = np.random.random((1000, 10))

# Train the model for 10 epochs
model.fit(x_train, y_train, epochs=10, batch_size=128)

# Evaluate the model
score = model.evaluate(x_train, y_train)

多输入模型

Function API 可以搭建多输入的模型。通常,这些模型会在某个点“合并”它们不同的输入分支,使用一个可以组合多个张量的层,即通过adding、concatenating等。这些通常是使用Keras的合并操作,如keras.layers.add, keras.layers.concatenate,等。我们来看一下一个简单的多输入模型:一个问答模型

一个典型的问答模型会有两个输入:一个自热语言问题和一个文本摘要(比如一个新闻标题)用来给问题的回答提供信息。这个模型最后必须一个回答:在最简单的可能设置里,这可能是通过取得预先定义的词库中softmax来获得一个简单的单字回答。
这里写图片描述

这里是一个如何构建Function API模型的例子:我们建立两个独立的分支,将文本输入问题编码表示成张量,然后我们合并这些张量,最后我们添加一个softmax分类器。

from keras.models import Model
from keras import layers
from keras import Input

text_vocabulary_size = 10000
question_vocabulary_size = 10000
answer_vocabulary_size = 500

# Our text input is a variable-length sequence of integers.
# Note that we can optionally name our inputs!
text_input = Input(shape=(None,), dtype='int32', name='text')

# Which we embed into a sequence of vectors of size 64
embedded_text = layers.Embedding(64, text_vocabulary_size)(text_input)

# Which we encoded in a single vector via a LSTM
encoded_text = layers.LSTM(32)(embedded_text)

# Same process (with different layer instances) for the question
question_input = Input(shape=(None,), dtype='int32', name='question')
embedded_question = layers.Embedding(32, question_vocabulary_size)(question_input)
encoded_question = layers.LSTM(16)(embedded_question)

# We then concatenate the encoded question and encoded text
concatenated = layers.concatenate([encoded_text, encoded_question], axis=-1)

# And we add a softmax classifier on top
answer = layers.Dense(answer_vocabulary_size, activation='softmax')(concatenated)

# At model instantiation, we specify the two inputs and the output:
model = Model([text_input, question_input], answer)
model.compile(optimizer='rmsprop',
			loss='categorical_crossentropy',
			metrics=['acc'])

那么,如何训练这种双输入模型呢?有两种可能的APIs:可以将一个Numpy数组列表作为输入到模型中,或者可以为它提供一个字典映射输入名称到Numpy数组。当然,后一种选项只有在输入的时候才可用。

Feeding data to a multi-input model

import numpy as np

# Let's generate some dummy Numpy data
text = np.random.randint(1, text_vocabulary_size, size=(num_samples, max_length))
question = np.random.randint(1, question_vocabulary_size, size=(num_samples, max_length))

# Answers are one-hot encoded, not integers
answers = np.random.randint(0, 1, size=(num_samples, answer_vocabulary_size))

# Fitting using a list of inputs
model.fit([text, question], answers, epochs=10, batch_size=128)

# Fitting using a dictionary of inputs (only if inputs were named!)
model.fit({'text': text, 'question': question}, answers,
			epochs=10, batch_size=128)

多输出模型

同样,function API 可以用作搭建多输出模型。
这里写图片描述

Functional API implementation of a three-output model

from keras import layers
from keras import Input
from keras.models import Model

vocabulary_size = 50000
num_income_groups = 10

posts_input = Input(shape=(None,), dtype='int32', name='posts')
embedded_posts = layers.Embedding(256, vocabulary_size)(posts_input)
x = layers.Conv1D(128, 5, activation='relu')(embedded_posts)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.GlobalMaxPooling1D()(x)
x = layers.Dense(128, activation='relu')(x)

# Note that we are giving names to the output layers.
age_prediction = layers.Dense(1, name='age')(x)
income_prediction = layers.Dense(num_income_groups, activation='softmax', name='income')(x)
gender_prediction = layers.Dense(1, activation='sigmoid', name='gender')(x)

model = Model(input_posts, [age_prediction, income_prediction, gender_prediction])

当然,训练这么一个模型需要为不同的输出定义不同的损失函数,比如:年纪预测是回归任务,但是性别预测是二分类任务,需要不同的训练过程。

然而,由于梯度下降要求我们最小化一个标量,我们必须将这些损失合并为一个值,以便能够训练模型。组合不同损失最简单的方法就是把它们全部加起来。在Keras中,可以在编译中使用一个列表或一个字典来指定不同的输出对象,由此导致的损失值被总结为一个全局损失,这是在训练中最小化的目标。

model.compile(optimizer='rmsprop',
			loss=['mse', 'categorical_crossentropy', 'binary_crossentropy'])
			
# Equivalent (only possible if you gave names to the output layers!):
model.compile(optimizer='rmsprop',
			loss={'age': 'mse',
				'income': 'categorical_crossentropy',
				'gender': 'binary_crossentropy'})

请注意,也可以将不同的输入值分配给最终损失的损失值。这是很有用的,特别是如果不同的损失在不同的尺度上取值。例如,用于年龄回归任务的MSE损失可以取一个典型值3-5左右,而用于性别分类任务的交叉熵损失可低至0.1。在这样的情况下,为了使不同损失的贡献更加平衡,你会给交叉熵的损失分配一个10的权重,而对MSE损失的权重为0.25。非常不平衡的损失贡献将导致模型表示以最大的个体损失为代价优先优化,以牺牲其他任务为代价。

model.compile(optimizer='rmsprop',
			loss=['mse', 'categorical_crossentropy', 'binary_crossentropy'],
			loss_weights=[0.25, 1., 10.])

# Equivalent (only possible if you gave names to the output layers!):
model.compile(optimizer='rmsprop',
		loss={'age': 'mse',
			'income': 'categorical_crossentropy',
			'gender': 'binary_crossentropy'},
		loss_weights={'age': 0.25,
			'income': 1.,
			'gender': 10.})

就像在多输入模型的情况下,将Numpy数据传递给模型进行训练可以通过数组列表或数组的字典来完成:

# age_targets, income_targets and gender_targets are assumed to be Numpy arrays
model.fit(posts, [age_targets, income_targets, gender_targets],
		epochs=10, batch_size=64)

# Equivalent (only possible if you gave names to the output layers!):
model.fit(posts, {'age': age_targets,
				'income': income_targets,
				'gender': gender_targets},
			epochs=10, batch_size=64)

有向无环图的层

使用 Functional API,不仅能够构建多输入,多输出的模型,同样可以搭建一个复杂内部拓扑的网络,Keras中的神经网络被允许任意地向各层的非循环图。

INCEPTION MODULES

Inception是卷积神经网络中比较流行的一种神经网络结构,受到早期“network - in network”网络的影响。它由一堆模块组成,这些模块本身看起来就像小型的独立网络,分成几个并行的分支。先启模块最基本的形式有3到4个分支,从1x1卷积开始,接着是一个3x3的卷积,并以产生的特征的连接结束。这个设置帮助网络分别学习空间特征和通道特征,这比联合学习更有效。更复杂的初始模块也是可能的,通常涉及到池操作,不同的空间卷积大小(例如,在某些分支上是5x5而不是3x3),以及没有空间卷积的分支(只有1x1的卷积)。
Inception V3的结构如下:
这里写图片描述

1 * 1卷积(pointwise 卷积)的作用:
卷积提取输入张量中的每一个瓦片的空间补丁,并对每个补丁应用相同的转换。一个边界情况是当提取的补丁由一个单一的瓦片组成。卷积运算就相当于通过一个 Dense 层来运行每个瓦片向量:它将计算从输入张量的通道中混合信息的特征,但它不会在整个空间中混合信息(因为它一次只看一个瓦片)。这样的1x1卷积在Inception模块中是很重要的,它们有助于分解出信道的特征学习和空间的特征学习,如果你假设每个通道在空间上都是高度自动相关的,那么就可以进行合理的学习,但是不同的通道之间可能不会有高度的相关性。

Implementing an Inception module with the functional API

from keras import layers

# We assume the existence of a 4D input tensor `x`

# Every branch has the same stride value (2), which is necessary to keep all
# branch outputs the same size, so as to be able to concatenate them.
branch_a = layers.Conv2D(128, 1, activation='relu', strides=2)(x)

# In this branch, the striding occurs in the spatial convolution layer
branch_b = layers.Conv2D(128, 1, activation='relu')(x)
branch_b = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_b)

# In this branch, the striding occurs in the average pooling layer
branch_c = layers.AveragePooling2D(3, strides=2, activation='relu')(x)
branch_c = layers.Conv2D(128, 3, activation='relu')(branch_c)

branch_d = layers.Conv2D(128, 1, activation='relu')(x)
branch_d = layers.Conv2D(128, 3, activation='relu')(branch_d)
branch_d = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_d)

# Finally, we concatenate the branch outputs to obtain the module output
output = layers.concatenate([branch_a, branch_b, branch_c, branch_d], axis=-1)

注意,完整的 Inception V3架构在Keras keras.applications.inception_v3可用。InceptionV3,包括在ImageNet数据集上预先训练的权重。作为Keras应用程序模块的一部分,另一个紧密相关的模型是Xception。“Xception”是"extreme inception",的缩写,是Inception延伸而来的 Convnet结构,它利用了将 channel-wise 和 space-wise 特征分开学习的思想,并且用depthwise separable convolutions代替了Inception 结构,Xception和 Inception V3有相同的参数数量,却表现的更好。

RESIDUAL CONNECTIONS

残差连接是一个非常常见的图形网络组件,在许多2015年后的网络体系结构中发现,包括Xception。它解决了困扰任何大规模深度学习模型的两个常见问题:消失梯度和表征瓶颈。一般来说,在超过十层的模型中添加剩余连接可能是有益的。

一个残差连接仅仅是将一个较早的层的输出作为后一层的输入,有效地在一个序列网络中创建一个快捷方式。与其将其连接到后来的激活,更早的输出与后来的激活进行了总结,后者假定两个激活都具有相同的大小。在不同大小的情况下,可以使用线性变换将早期的激活转换成目标形状(例如没有激活的致密层,或者卷积特征图,一个没有激活的1x1卷积)。

Implementing a residual connection when feature map sizes are the same: using identity residual connections

from keras import layers

# We assume the existence of a 4D input tensor `x`
x = ...
# We apply some transformation to `x`
y = layers.Conv2D(128, 3, activation='relu')(x)
y = layers.Conv2D(128, 3, activation='relu')(y)
y = layers.Conv2D(128, 3, activation='relu')(y)

# We add the original `x` back to the output features
y = layers.add([y, x])

Implementing a residual connection when feature map sizes differ:using a linear residual connection

from keras import layers

# We assume the existence of a 4D input tensor `x`
x = ...
y = layers.Conv2D(128, 3, activation='relu')(x)
y = layers.Conv2D(128, 3, activation='relu')(y)
y = layers.MaxPooling2D(2, strides=2)(y)

# We use a 1x1 convolution to linearly downsample
# the original `x` tensor to the same shape as `y`
residual = layers.Conv2D(1, strides=2)(x)
# We add the residual tensor back to the output features
y = layers.add([y, residual])

Layer weight sharing

Function API 的一个更重要的特征是,它能够多次运用一个层实例。当调用一个层实例两次,为每个调用实例化一个新层的实例时,将在每次调用中重用相同的权重。这允许构建共享多个分支的模型,这些分支共享相同的知识并执行相同的操作,即共享相同的表示,并同时学习不同的输入集。

一个例子就是试图评估两个句子之间的语义相似度的模型。该模型将有两个输入(两个句子进行比较),并输出一个0和1之间的分数,其中0是不相关的句子,1是句子,它们不是相同的,或者仅仅是对彼此的重新表述。

Layer weight sharing (i.e. layer reuse) with the functional API:implementing a siamese LSTM model

from keras import layers
from keras import Input
from keras.models import Model

# We instantiate a single LSTM layer, once
lstm = layers.LSTM(32)

# Building the left branch of the model
# -------------------------------------

# Inputs are variable-length sequences of vectors of size 128
left_input = Input(shape=(None, 128))
left_output = lstm(left_input)

# Building the right branch of the model
# --------------------------------------

right_input = Input(shape=(None, 128))
# When we call an existing layer instance,
# we are reusing its weights
right_output = lstm(right_input)

# Building the classifier on top
# ------------------------------

merged = layers.concatenate([left_output, right_output], axis=-1)
predictions = layers.Dense(1, activation='sigmoid')(merged)

# Instantiating and training the model
# ------------------------------------

model = Model([left_input, right_input], predictions)
# When you train such a model, the weights of the `lstm` layer
# are updated based on both inputs.
model.fit([left_data, right_data], targets)

Models as layers

重要的是,在function API中,可以使用模型来有效地使用层,可以认为模型是“更大的层”。顺序和模型类都是这样。这意味着可以在输入张量上调用一个模型,并检索一个输出张量。

Models as layers, i.e. models as functions

y = model(x)

Calling a multi-output, multi-input model

y1, y2 = model([x1, x2])

当调用一个模型实例时,你正在重新使用模型的权重,就像调用一个层实例时所发生的情况一样。简单地调用一个实例,无论它是一个层实例还是一个模型实例,都将总是重用实例的已有的已学习的表示,这是非常直观的。

一个简单的例子,你可以通过复用一个模型实例来建立一个视觉模型,它使用双摄像头作为它的输入:两个平行的摄像头,相距几厘米(一英寸)。这样的模型可以感知深度,这在许多应用中都很有用。在合并两个提要之前,你不需要两个独立的模型来从左边的摄像机和右边的摄像机中提取视觉特征。这样的低级处理可以在两个输入之间共享,即通过使用相同权重的层来完成,从而共享相同的表示。下面是如何在Keras中实现这个功能:

Implementing a siamese vision model (shared convolutional base)

from keras import layers
from keras import applications
from keras import Input

# Our base image processing model with be the Xception network
# (convolutional base only).
xception_base = applications.Xception(weights=None, include_top=False)

# Our inputs are 250x250 RGB images.
left_input = Input(shape=(250, 250, 3))
right_input = Input(shape=(250, 250, 3))

# We call the same vision model twice!
left_features = xception_base(left_input)
right_input = xception_base(right_input)

# The merged features contain information from both
# the right visual feed and the left visual feed
merged_features = layers.concatenate([left_features, right_input], axis=-1)

深度学习模式的监控:使用Keras callbacks和TensorBoard

当训练一个模型时,有很多事情你从一开始就无法预测。特别是,你无法判断需要多少个epochs才能获得最佳的验证损失。在我们的示例中,我们一直采用了足够的时间来进行训练,这样就会出现过拟合,用我们的第一次运行来计算出合适的时间来训练,然后用这个最优的数字从头开始一个新的训练。当然,这是相当浪费的。

一种更好的处理办法是,当确认损失停止改善时就停止训练网络,这可以使用 Keras 中的 callbacks实现。

Callbacks

Callbacks是一个对象(实现特定方法的类实例),该对象在调用中传递给模型,并在训练期间的不同点调用该模型,它可以访问所有关于模型状态和性能的数据,并且它能够采取行动,例如中断训练、保存模型、加载不同的权重集,或者改变模型的状态。

Callbacks可以被用作:
1.Model checkpointing:在训练过程中,将模型的当前权重保存在不同的点。
2.Early stopping:当验证丢失停止改进时中断训练(当然会保存训练中最好的模型。)
3.在培训期间动态调整某些参数的值,例如优化器的学习速率。
4.在培训过程中记录培训和验证指标,或可视化模型在更新过程中学习到的表示。实际上,您熟悉的Keras进度条本身就是一个回调。

Some of the built-in Keras callbacks

keras.callbacks.ModelCheckpoint
keras.callbacks.EarlyStopping
keras.callbacks.LearningRateScheduler
keras.callbacks.ReduceLROnPlateau
keras.callbacks.CSVLogger

你可以使用 EarlyStopping 回调来中断训练,一旦被监控的目标指标停止了对固定数量的epochs的改进。例如,这个回调允许在开始过拟合的时候中断训练,从而允许避免重新训练模型,以适应更少的时代。这个回调通常与ModelCheckpoint结合使用,它允许在训练过程中不断地保存模型(也可以选择,只保存目前最好的模型,即在一个epoch结束时获得最佳性能的模型的版本)。

Using Callbacks: example with EarlyStopping and ModelCheckpoint

import keras

# Callbacks are passed to the model fit the `callbacks` argument in `fit`,
# which takes a list of callbacks. You can pass any number of callbacks.
callbacks_list = [
	# This callback will interrupt training when we have stopped improving
	keras.callbacks.EarlyStopping(
		# This callback will monitor the validation accuracy of the model
		monitor='acc',
		# Training will be interrupted when the accuracy
		# has stopped improving for *more* than 1 epochs (i.e. 2 epochs)
		patience=1,
),
# This callback will save the current weights after every epoch
keras.callbacks.ModelCheckpoint(
	filepath='my_model.h5', # Path to the destination model file
	# The two arguments below mean that we will not overwrite the
	# model file unless `val_loss` has improved, which
	# allows us to keep the best model every seen during training.
	monitor='val_loss',
	save_best_only=True,
	)
]

# Since we monitor `acc`, it should be part of the metrics of the model.
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])

# Note that since the callback will be monitor validation accuracy,
# we need to pass some `validation_data` to our call to `fit`.
model.fit(x, y,
		epochs=10,
		batch_size=32,
		callbacks=callbacks_list,
		validation_data=(x_val, y_val))

当验证损失停止改进时,可以使用这个回调来降低学习速率。在“损失高原”的情况下,减少或提高学习速度是在训练中脱离局部最小值的有效策略。

Using the ReduceLROnPlateau Callback

callbacks_list = [
	keras.callbacks.ReduceLROnPlateau(
		# This callback will monitor the validation loss of the model
		monitor='val_loss',
		# It will divide the learning by 10 when it gets triggered
		factor=0.1,
		# It will get triggered after the validation loss has stopped improving
		# for at least 10 epochs
		patience=10,
	)
]

# Note that since the callback will be monitor validation loss,
# we need to pass some `validation_data` to our call to `fit`.
model.fit(x, y,
		epochs=10,
		batch_size=32,
		callbacks=callbacks_list,
		validation_data=(x_val, y_val))

如果你需要在训练期间采取任何特定的操作,而不是内置回调,那么你应该编写自己的回调函数。

调是由子类keras.callbacks.Callback实现,然后可以实现以下罗列的任何数量的方法,这些方法在训练期间会被调用。

Overview of Callback methods

# Called at the start of every epoch
on_epoch_begin
# Called at the end of every epoch
on_epoch_end

# Called right before processing each batch
on_batch_begin
# Called right after processing each batch
on_batch_end

# Called at the start of training
on_train_begin
# Called at the end of training
on_train_end

这些方法都使用日志参数来调用,该字典包含关于前批、新时期或培训运行的信息:训练和验证指标等。此外,回调可以访问以下属性:
1.self.model,被调用回调的模型实例
2.self.validation_data, 传递作为验证数据的值。

Writing a custom Callback
这里有一个简单的自定义回调示例,我们将其保存到磁盘(作为Numpy数组),在每个epoch的末尾,对模型的每一层进行激活,在验证集的第一个示例中计算:

import keras
import numpy as np

class ActivationLogger(keras.callbacks.Callback):
	def set_model(self, model):
		# This method is called by the parent model
		# before training, to inform the callback
		# of what model will be calling it
		self.model = model
		layer_outputs = [layer.output for layer in model.layers]
		# This is a model instance that returns the activations of every layer
		self.activations_model = keras.models.Model(model.input, layer_outputs)
		
	def on_epoch_end(self, epoch, logs=None):
		if self.validation_data is None:
			raise RuntimeError('Requires validation_data.')
			
		# Obtain first input sample of the validation data
		validation_sample = self.validation_data[0][0:1]
		activations = self.activations_model.predict(validation_sample)
		# Save arrays to disk
		f = open('activations_at_epoch_' + str(epoch) + '.npz', 'w')
		np.savez(f, activations)
		f.close()

the TensorFlow visualization framework

做一个好的研究,或者搭建一个好的模型,你应该对于你实验中的内容有足够的反馈。这就是实验的目的:获取模型表现结果尽可能多的信息。取得进展是一个循环往复的过程:你从一个想法开始,然后你把它作为一个实验来表达,试图验证或否定你的想法。运行这个实验,然后处理由实验产生的信息。这会激发你的下一个想法。这个循环的往复次数越多,你的想法就会变得越精炼和强大。Keras帮助你从一个想法到另一个实验,在最短的时间内,快速的gpu帮助你从实验中得到尽可能快的结果。但是如何处理实验结果呢?那就是TensorBoard。
这里写图片描述
TensorBoard的主要目的是帮助你在训练过程中,在视觉上监控你模型内的一切。如果你正在监视更多的信息,而不仅仅是模型的最终损失,那么你可以开发一个更清晰的模型,可以更快地取得进展。TensorBoard让你在你的浏览器内可以访问几个简洁的功能:
1.在训练期间直观地监控模型评定指标。
2.可视化模型结构
3.可视化激活和梯度的直方图
4.以3D视角探索 embeddings

A simple text classification model that we will use with a TensorBoard Callback

import keras
from keras import layers
from keras.datasets import imdb
from keras.preprocessing import sequence

max_features = 2000 # number of words to consider as features
max_len = 500 # cut texts after this number of words (among top max_features most common words)

(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
x_train = sequence.pad_sequences(x_train, maxlen=max_len)
x_test = sequence.pad_sequences(x_test, maxlen=max_len)

model = keras.models.Sequential()
model.add(layers.Embedding(max_features, 128, input_length=max_len, name='embed'))
model.add(layers.Conv1D(32, 7, activation='relu'))
model.add(layers.MaxPooling1D(5))
model.add(layers.Conv1D(32, 7, activation='relu'))
model.add(layers.GlobalMaxPooling1D())
model.add(layers.Dense(1))
model.summary()
model.compile(optimizer='rmsprop',
		loss='binary_crossentropy',
		metrics=['acc'])

在开始使用TensorBoard之前,我们需要创建一个目录,其中存储由TensorBoard生成的日志文件。

mkdir my_log_dir

让我们使用TensorBoard回调实例启动训练,此回调将在指定位置将日志事件写入磁盘。

callbacks = [
	keras.callbacks.TensorBoard(
		# Log files will be written at this location
		log_dir='my_log_dir',
		# We will record activation histograms every 1 epoch
		histogram_freq=1,
		# We will record embedding data every 1 epoch
		embeddings_freq=1,
	)
]
history = model.fit(x_train, y_train,
			epochs=20,
			batch_size=128,
			validation_split=0.2,
			callbacks=callbacks)

此时,可以从命令行启动TensorBoard服务器,指示它读取回调当前正在写入的日志。

tensorboard --logdir=my_log_dir

这里写图片描述

猜你喜欢

转载自blog.csdn.net/hanzy88/article/details/79632587