keras函数式模型

Keras的函数式模型为Model,即广义的拥有输入和输出的模型,tf.keras.Sequential 模型是层的简单堆叠,无法表示任意模型。使用 Keras 函数式 API 可以构建复杂的模型拓扑。例如:

  • 多输入模型,

  • 多输出模型,

  • 具有共享层的模型(同一层被调用多次),

  • 具有非序列数据流的模型(例如,残差连接)。

全连接神经网络

对于全连接神经网络Sequential 模型可能更合适,这里只是用来做示例(可以用来做对比),因为简单的网络更容易理解。

import tensorflow as tf
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)                 # 第二层
outputs = Dense(10, activation='softmax')(x)        # 输出层
# 这部分创建了一个包含输入层和三个全连接层的模型
model = Model(inputs=inputs, outputs=outputs)

model.summary()
model.compile(optimizer, loss, metrics=None, loss_weights=None, sample_weight_mode=None, weighted_metrics=None, target_tensors=None)         # 编译模型
history = model.fit( x=None, y=None, batch_size=None, epochs=1, verbose=1, callbacks=None, validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0, steps_per_epoch=None, validation_steps=None)  # 开始训练
  • 网络层的实例是可调用的,它以张量为参数,并且返回一个张量
  • 输入和输出均为张量,它们都可以用来定义一个模型(Model)
  • 模型同 Keras 的 Sequential 模型一样,都可以被训练

多输入多输出模型

例如:试图预测一条新闻标题的转发和点赞数。模型的主要输入是新闻标题本身(一系列词语),还添加了其他辅助输入,例如新闻标题的发布的时间等。 该模型也将通过两个损失函数进行监督学习。较早地在模型中使用主损失函数,是深度学习模型的一个良好正则方法。
模型结构如下图所示:
[]

代码如下:

from keras.layers import Input, Embedding, LSTM, Dense
from keras.models import Model

# 标题输入:接收一个含有 100 个整数的序列,每个整数在 1 到 10000 之间。
# 通过传递一个 "name" 参数来命名任何层
main_input = Input(shape=(100,), dtype='int64', 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 层都能被平稳地训练。
output2 = Dense(1, activation='sigmoid', name='output2')(lstm_out) # output2
input2 = Input(shape=(5,), name='input2')                          # input2

# 将辅助输入数据与 LSTM 层的输出连接起来
x = keras.layers.concatenate([lstm_out, input2])

# 堆叠多个全连接网络层
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)

# 添加主要的逻辑回归层
main_output = Dense(1, activation='sigmoid', name='main_output')(x)
# 定义整个网络的2个输入和输出的模型
model = Model(inputs=[main_input, input2], outputs=[main_output, output2])

# 编译模型,并给辅助损失分配 0.2 的权重。如果要为不同的输出指定不同的 loss_weights 或 loss,可以使用列表或字典。 在这里,给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)

# 或者可以通过以下方式编译和训练
model.compile(optimizer='rmsprop',
              loss={'main_output': 'binary_crossentropy', 'output2': 'binary_crossentropy'},
              loss_weights={'main_output': 1., 'output2': 0.2})

# 然后使用以下方式训练:
model.fit({'main_input': headline_data, 'input2': additional_data},
          {'main_output': labels, 'output2': labels},
          epochs=50, batch_size=32)

共享网络层

函数式 API 的另一个用途是使用共享网络层的模型,来考虑推特推文数据集。我们想要建立一个模型来分辨两条推文是否来自同一个人(例如,通过推文的相似性来对用户进行比较)。
实现这个目标的一种方法是建立一个模型,将两条推文编码成两个向量,连接向量,然后添加逻辑回归层;这将输出两条推文来自同一作者的概率。模型将接收一对对正负表示的推特数据。
由于这个问题是对称的,编码第一条推文的机制应该被完全重用来编码第二条推文(权重及其他全部)。这里我们使用一个共享的 LSTM 层来编码推文。
首先我们将一条推特转换为一个尺寸为 (280, 256) 的矩阵,即每条推特 280 字符,每个字符为 256 维的 one-hot 编码向量 (取 256 个常用字符)。

import keras
from keras.layers import Input, LSTM, Dense
from keras.models import Model

tweet_a = Input(shape=(280, 256))
tweet_b = Input(shape=(280, 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)

# 再在上面添加一个逻辑回归层
predictions = Dense(1, activation='sigmoid')(merged_vector)

# 定义一个连接推特输入和预测的可训练的模型
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=100)

另外一个例子:

import tensorflow as tf
from tensorflow.keras import layers 
from keras.layers import Input

# 编码器网络
encode_input = keras.Input(shape=(28,28,1), name='img')
h1 = layers.Conv2D(16, 3, activation='relu')(encode_input)
h1 = layers.Conv2D(32, 3, activation='relu')(h1)
h1 = layers.MaxPool2D(3)(h1)
h1 = layers.Conv2D(32, 3, activation='relu')(h1)
h1 = layers.Conv2D(16, 3, activation='relu')(h1)
encode_output = layers.GlobalMaxPool2D()(h1)
encode_model = keras.Model(inputs=encode_input, outputs=encode_output, name='encoder')
encode_model.summary()

# 解码器网络
decode_input = keras.Input(shape=(16,), name='encoded_img')
h2 = layers.Reshape((4, 4, 1))(decode_input)
h2 = layers.Conv2DTranspose(16, 3, activation='relu')(h2)
h2 = layers.Conv2DTranspose(32, 3, activation='relu')(h2)
h2 = layers.UpSampling2D(3)(h2)
h2 = layers.Conv2DTranspose(16, 3, activation='relu')(h2)
decode_output = layers.Conv2DTranspose(1, 3, activation='relu')(h2)
decode_model = keras.Model(inputs=decode_input, outputs=decode_output, name='decoder')
decode_model.summary()

可以把以上两个网络当作一层网络使用

autoencoder_input = keras.Input(shape=(28,28,1), name='img') # 输入
h3 = encode_model(autoencoder_input)                         # 调用编码器网络
autoencoder_output = decode_model(h3)                        # 调用解码器网络
autoencoder = keras.Model(inputs=autoencoder_input, outputs=autoencoder_output,
                          name='autoencoder')
autoencoder.summary()

残差网络

有关残差网络 (Residual Network) 的更多信息,可以参阅深度残差学习进行图像识别

from keras.layers import Conv2D, Input

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

大家也可以参考一下tensorflow官网的教程(小型残差网络)

import tensorflow as tf
from tensorflow.keras import layers 
from keras.layers import Input
inputs = keras.Input(shape=(32,32,3), name='img')
h1 = layers.Conv2D(32, 3, activation='relu')(inputs)
h1 = layers.Conv2D(64, 3, activation='relu')(h1)
block1_out = layers.MaxPooling2D(3)(h1)

h2 = layers.Conv2D(64, 3, activation='relu', padding='same')(block1_out)
h2 = layers.Conv2D(64, 3, activation='relu', padding='same')(h2)
block2_out = layers.add([h2, block1_out])

h3 = layers.Conv2D(64, 3, activation='relu', padding='same')(block2_out)
h3 = layers.Conv2D(64, 3, activation='relu', padding='same')(h3)
block3_out = layers.add([h3, block2_out])

h4 = layers.Conv2D(64, 3, activation='relu')(block3_out)
h4 = layers.GlobalMaxPool2D()(h4)
h4 = layers.Dense(256, activation='relu')(h4)
h4 = layers.Dropout(0.5)(h4)
outputs = layers.Dense(10, activation='softmax')(h4)

model = keras.Model(inputs, outputs, name='small resnet')
model.summary()
keras.utils.plot_model(model, 'small_resnet_model.png', show_shapes=True)
(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype('float32') / 255
x_test = y_train.astype('float32') / 255
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)

model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
             loss='categorical_crossentropy',
             metrics=['acc'])
model.fit(x_train, y_train,
         batch_size=64,
         epochs=1,
         validation_split=0.2)
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值