深度学习入门-框架keras-3密集连接网络


参考:RNN及LSTM: https://blog.csdn.net/zhaojc1995/article/details/80572098

密集连接网络

该Sequential模型可能是实现这种网络的更好选择,但它有助于从非常简单的事情开始。

  • 图层实例可调用(在张量上),并返回张量
  • 然后可以使用输入张量和输出张量来定义Model
  • 这种模型可以像Keras Sequential模型一样进行训练。
from keras.layers import Input, Dense
from keras.models import Model
import keras
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

# 载入数据
batch_sizes = 10000
def loadData(filename):
    mnist = input_data.read_data_sets(filename, one_hot=True)
    mnist.train.cls = np.argmax(mnist.train.labels, axis=1)
    mnist.test.cls = np.argmax(mnist.test.labels, axis=1)
    mnist.validation.cls = np.argmax(mnist.validation.labels, axis=1)
    return mnist


datas = loadData(r'C:\Users\Cs\Desktop\深度学习\tf_day011\datas\mnist')
train_images, train_labels = datas.train.next_batch(batch_sizes)
# 返回一个张量,这个输入数据不包括数据数量维度
inputs = Input(shape=(784,))

# 一个层实例可以在一个张量上调用,并返回一个张量
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)

# 创建一个包含输入层和三个密集层的模型
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(train_images, train_labels)  # starts training
# # 与上面功能相同
# model = keras.Sequential()
# model.add( Dense(64, activation='relu',input_shape=(784,)))
# model.add( Dense(64, activation='relu'))
# model.add( Dense(10, activation='softmax'))
# model.compile(optimizer='rmsprop',
#               loss='categorical_crossentropy',
#               metrics=['accuracy'])
# model.fit(train_images, train_labels,batch_size=500,epochs=30)  # starts training

keras.layers.Input

输入接口,返回一个可以使用的张量。
使用功能API,可以轻松地重用经过训练的模型:通过在张量上调用,可以将任何模型视为一个层。请注意,通过调用模型,您不仅可以重用模型的体系结构,还可以重用其权重。
示例:

from keras.layers import Input,

# 生成一个Nx 784的Tensor
inputs = Input(shape=(784,))

例如,这可以允许快速创建可以处理输入序列的模型。您可以将图像分类模型转换为视频分类模型,只需一行。

from keras.layers import TimeDistributed
# 20个时间步序列的输入张量,每个包含784维向量
input_sequences = Input(shape=(20, 784))
# 这将把前面的模型应用到输入序列中的每个时间步。前一个模型的输出是一个10路softmax,所以下面这个层的输出将是一个由20个大小为10的向量组成的序列。
processed_sequences = TimeDistributed(model)(input_sequences)

keras.models.Model

功能和Sequential()差不多,都是生成模型的,不过上方式通过add增加图层,下方是设计了各图层之间的连接关系,然后再创建Model的时候使用最后一个图层
示例:

from keras.models import Model
# inputs为keras.layers.Input实例,
# predictions为连接图层,参考最上面的代码
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])
model.fit(data, labels)  # starts training

多输入和多输出模型

这是功能API的一个很好的用例:具有多个输入和输出的模型。功能API使操作大量交织在一起的数据流变得容易。

让我们考虑以下模型。我们试图预测有多少转推和喜欢新闻标题将在Twitter上收到。模型的主要输入将是标题本身,作为一系列单词,但为了增加趣味,我们的模型还将具有辅助输入,接收额外数据,例如标题发布时的时间等。该模型还将通过两个损失函数进行监督。使用模型中较早的主要损失函数是深度模型的良好正则化机制。
模型:
在这里插入图片描述
用功能API实现它。
主要输入接收新闻标题本身,即一个整数序列(每个整数编码一个词)。 这些整数在 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')
# 该嵌入层将输入序列编码为密集的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)

# 最后添加主要的逻辑回归层
main_output = Dense(1, activation='sigmoid', name='main_output')(x)

然后定义一个具有两个输入和两个输出的模型:

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

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

共享网络层

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

# 再在上面添加一个逻辑回归层
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=10)

让我们暂停一会,看看如何读取共享层的输出或输出尺寸。

层「节点」的概念

每当你在某个输入上调用一个层时,都将创建一个新的张量(层的输出),并且为该层添加一个「节点」,将输入张量连接到输出张量。当多次调用同一个图层时,该图层将拥有多个节点索引 (0, 1, 2…)。
在之前版本的 Keras 中,可以通过 layer.get_output()来获得层实例的输出张量,或者通过 layer.output_shape来获取其输出形状。现在你依然可以这么做(除了 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
>> AttributeError: 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_shapeoutput_shape这两个属性也是如此:只要该层只有一个节点,或者只要所有节点具有相同的输入/输出尺寸,那么「层输出/输入尺寸」的概念就被很好地定义,并且将由 layer.output_shape/ layer.input_shape返回。但是比如说,如果将一个 Conv2D 层先应用于尺寸为 (32,32,3) 的输入,再应用于尺寸为 (64, 64, 3) 的输入,那么这个层就会有多个输入/输出尺寸,你将不得不通过指定它们所属节点的索引来获取它们:

a = Input(shape=(32, 32, 3))
b = Input(shape=(64, 64, 3))

conv = Conv2D(16, (3, 3), padding='same')
conved_a = conv(a)

# 到目前为止只有一个输入,以下可行:
assert conv.input_shape == (None, 32, 32, 3)

conved_b = conv(b)
# 现在 `.input_shape` 属性不可行,但是这样可以:
assert conv.get_input_shape_at(0) == (None, 32, 32, 3)
assert conv.get_input_shape_at(1) == (None, 64, 64, 3)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值