我使用这个Keras documentation example中的转换器进行多示例分类。每个示例的类依赖于一个包中的其他示例。我使用Transformer模型是因为:
它不对数据之间的时间/空间关系做出任何假设。这对于处理一组对象是理想的
例如,每个包可以具有最多5个示例,并且每个示例有3个特征。
# Generate data
max_length = 5
x_lst = []
y_lst = []
for _ in range(10):
num_instances = np.random.randint(2, max_length + 1)
x_bag = np.random.randint(0, 9, size=(num_instances, 3))
y_bag = np.random.randint(0, 2, size=num_instances)
x_lst.append(x_bag)
y_lst.append(y_bag)
前2个袋的特征和标签(包括5和2个示例):
x_lst[:2]
[array([[8, 0, 3],
[8, 1, 0],
[4, 6, 8],
[1, 6, 4],
[7, 4, 6]]),
array([[5, 8, 4],
[2, 1, 1]])]
y_lst[:2]
[array([0, 1, 1, 1, 0]), array([0, 0])]
接下来,用零填充特征,用-1填充目标:
x_padded = []
y_padded = []
for x, y in zip(x_lst, y_lst):
x_p = np.zeros((max_length, 3))
x_p[:x.shape[0], :x.shape[1]] = x
x_padded.append(x_p)
y_p = np.negative(np.ones(max_length))
y_p[:y.shape[0]] = y
y_padded.append(y_p)
X = np.stack(x_padded)
y = np.stack(y_padded)
其中X.shape
等于(10, 5, 3)
,y.shape
等于(10, 5)
。
我对原始模型做了两个改动:在输入层之后添加掩蔽层,并将最后一个致密层中的单元数设置为袋的最大尺寸(加上“S形”激活):
def transformer_encoder(inputs, head_size, num_heads, ff_dim, dropout=0):
# Attention and Normalization
x = layers.MultiHeadAttention(
key_dim=head_size, num_heads=num_heads, dropout=dropout
)(inputs, inputs)
x = layers.Dropout(dropout)(x)
x = layers.LayerNormalization(epsilon=1e-6)(x)
res = x + inputs
# Feed Forward Part
x = layers.Conv1D(filters=ff_dim, kernel_size=1, activation="relu")(res)
x = layers.Dropout(dropout)(x)
x = layers.Conv1D(filters=inputs.shape[-1], kernel_size=1)(x)
x = layers.LayerNormalization(epsilon=1e-6)(x)
return x + res
def build_model(
input_shape,
head_size,
num_heads,
ff_dim,
num_transformer_blocks,
mlp_units,
dropout=0,
mlp_dropout=0,
):
inputs = keras.Input(shape=input_shape)
inputs = keras.layers.Masking(mask_value=0)(inputs) # ADDED MASKING LAYER
x = inputs
for _ in range(num_transformer_blocks):
x = transformer_encoder(x, head_size, num_heads, ff_dim, dropout)
x = layers.GlobalAveragePooling1D(data_format="channels_first")(x)
for dim in mlp_units:
x = layers.Dense(dim, activation="relu")(x)
x = layers.Dropout(mlp_dropout)(x)
outputs = layers.Dense(5, activation='sigmoid')(x) # CHANGED ACCORDING TO MY OUTPUT
return keras.Model(inputs, outputs)
input_shape = (5, 3)
model = build_model(
input_shape,
head_size=256,
num_heads=4,
ff_dim=4,
num_transformer_blocks=4,
mlp_units=[128],
mlp_dropout=0.4,
dropout=0.25,
)
model.compile(
loss="binary_crossentropy",
optimizer=keras.optimizers.Adam(learning_rate=1e-4),
metrics=["binary_accuracy"],
)
model.summary()
看起来我的模特学不多。如果我使用每个包的真值的数量(y.sum(axis=1)
和Dense(1)
)作为目标,而不是每个示例的分类,模型学习得很好。我的错误在哪里?在这种情况下,我应该如何构建输出层?我是否需要自定义丢失函数?
更新:我做了一个自定义的损失函数:
def my_loss_fn(y_true, y_pred):
mask = tf.cast(tf.math.not_equal(y_true, tf.constant(-1.)), tf.float32)
y_true, y_pred = tf.expand_dims(y_true, axis=-1), tf.expand_dims(y_pred, axis=-1)
bce = tf.keras.losses.BinaryCrossentropy(reduction='none')
return tf.reduce_sum(tf.cast(bce(y_true, y_pred), tf.float32) * mask)
mask = (y_test != -1).astype(int)
pd.DataFrame({'n_labels': mask.sum(axis=1), 'preds': ((preds * mask) >= .5).sum(axis=1)}).plot(figsize=(20, 5))
看起来模型学习:
但它预测所有非掩蔽标签为1。
@thushv89这是my problem。我需要两个时间点:t1和t2,并查找在时间t1处于维护中的所有车辆和计划在时间t2处于维护中的所有车辆。这是我的物品袋。然后,我计算诸如t1车辆已经花费了多少时间进行维护,t2车辆从t1到计划开始的时间等特征。如果我试图预测在时间t2时维修车辆的数量,我的模型学习得很好,但我想预测哪些车辆会离开,哪些车辆会进来(对于包中的4辆车辆,3 vs [True,False,True,True])。
2条答案
按热度按时间k4aesqcs1#
有三个重要的改进:
1.将GlobalAveragePooling1D图层替换为Flatten图层。
1.添加一个自定义损失函数,以排除计算中的目标填充(已经添加到我的问题中)和一个自定义度量函数,如果你想看到真实的的度量。
1.将attention_mask添加到MultiHeadAttention(而不是Masking层)以掩蔽填充。
nzrxty8p2#
只是@Mykola_Zotko的一个简单的附加组件,它可以帮助那些正在使用
keras
和tensorflow
学习深度学习的新用户。删除GlobalAveragePooling 1D
对于上下文,这个
GlobalAveragePooling1D
基本上是时态数据的全局平均池化操作。所以基本上,当你删除这个方法调用时,你删除了“池化”操作,或者用更简单的术语,通过@Mykola_Zotko:……你得到了一个二维Tensor,它在第一维度(在我的例子中是5个)中免费输出
别名为:
这个方法的代码:
可以在以下网站找到此来源:
添加自定义损失函数
损失函数所做的只是“生成模型在训练时间内应该寻求最小化的量”。Source
或者换句话说:
在数学优化、统计学、机器学习和深度学习中,Loss Function(也称为成本函数或误差函数)是定义一系列值与真实的之间相关性的函数。该数字在概念上表示与事件或一组值相关联的成本。通常,优化过程的目标是使损失函数最小化。Towardsdatascience - custom loss function in tensorflow
将attention_mask添加到MultiHeadAttention
别名:
方法代码:
来源:
以前对代码进行的改进:
metrics=["accuracy"]
至metrics=["binary_accuracy"]
Crossentropy