Keras的泛型模型为Model,即广义的拥有输入和输出的模型
常用Model属性
- model.layers:组成模型图的各个层
- model.inputs:模型的输入张量列表
- model.outputs:模型的输出张量列表
常用Model方法
- compile,fit,evaluate等跟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)
# 下面代码创建包括输入层和三个全连接层的模型
model = Model(input=inputs, output=predictions)
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels) # 开始训练
#所有的模型都是可调用的,就像层一样,当你调用模型时,不仅重用了它的结构,也重用了它的权重
x = Input(shape=(784,))
# 下面一行代码就调用了上面的model模型
y = model(x)
#这种方式可以使你快速创建能处理序列信号的模型,你可很快将一个图像分类的模型变为一个对视频分类的模型,只需要一行代码:
from keras.layers import TimeDistributed
# 输入是20个timesteps的序列张量,每个timestep包含784-dimensional维向量
input_sequences = Input(shape=(20, 784))
# 这将对输入序列的每一timestep使用上面的model,下面代码的输出将是一个10 size的20 vectors
processed_sequences = TimeDistributed(model)(input_sequences)
第二个模型:多输入和多输出
我们希望预测Twitter上一条新闻会被转发和点赞多少次。模型的主要输入是新闻本身(一个词语序列)。但我们还可以拥有额外的输入(如新闻发布的日期等)。这个模型的损失函数将由两部分组成,辅助的损失函数评估仅仅基于新闻本身做出预测的情况,主损失函数评估基于新闻和额外信息的预测的情况,即使来自主损失函数的梯度发生弥散,来自辅助损失函数的信息也能够训练Embeddding
和LSTM
层。在模型中早点使用主要的损失函数是对于深度网络的一个良好的正则方法。总而言之,该模型框图如下:
from keras.layers import Input, Embedding, LSTM, Dense, merge
from keras.models import Model
# 主要的输入接收新闻本身,即一个整数的序列(每个整数编码了一个词)。这些整数位于1到10,000之间(即我们的字典有10,000个词)。这个序列有100个单词。
# 我们可以通过“name”定义任何层
main_input = Input(shape=(100,), dtype='int32', name='main_input')
# 这个embedding层将输入序列转化成512-dimensional向量
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 = merge([lstm_out, auxiliary_input], mode='concat')
# 我们在上面堆叠一个深度全连接层
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
# 然后我们添加main逻辑回归层
main_output = Dense(1, activation='sigmoid', name='main_output')(x)
#最后,我们定义整个2输入,2输出的模型:
model = Model(input=[main_input, auxiliary_input], output=[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],
nb_epoch=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},
nb_epoch=50, batch_size=32)
层“节点”的概念
所有的Keras层对象都有如下方法:
layer.get_weights():返回层的权重(numpy array)
layer.set_weights(weights):从numpy array中将权重加载到该层中,要求numpy array的形状与layer.get_weights()的形状相同
layer.get_config():返回当前层配置信息的字典,层也可以借由配置信息重构
如果层仅有一个计算节点(即该层不是共享层),则可以通过下列方法获得输入张量、输出张量、输入数据的形状和输出数据的形状:
layer.input
layer.output
layer.input_shape
layer.output_shape
如果该层有多个计算节点。可以使用下面的方法
layer.get_input_at(node_index)
layer.get_output_at(node_index)
layer.get_input_shape_at(node_index)
layer.get_output_shape_at(node_index)
无论何时,当你在某个输入上调用层时,你就创建了一个新的张量(即该层的输出),同时你也在为这个层增加一个“(计算)节点”。这个节点将输入张量映射为输出张量。当你多次调用该层时,这个层就有了多个节点,其下标分别为0,1,2…
你可以通过layer.output()
方法来获得层的输出张量,或者通过layer.output_shape
获得其输出张量的shape。
如果层只与一个输入相连,那没有任何困惑的地方。.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
上面这段代码会报错,可通过下面这种调用方式即可解决
assert lstm.get_output_at(0) == encoded_a
assert lstm.get_output_at(1) == encoded_b
对于input_shape
和output_shape
也是一样。
a = Input(shape=(3, 32, 32))
b = Input(shape=(3, 64, 64))
conv = Convolution2D(16, 3, 3, border_mode='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)