首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Keras转移学习。最后一层的激活应该是什么?

用Keras转移学习。最后一层的激活应该是什么?
EN

Stack Overflow用户
提问于 2021-06-18 07:03:53
回答 2查看 207关注 0票数 1

我在这里引用Keras文档:学习/,它演示了一个典型的传输学习工作流。

首先,用预先训练的权重实例化一个基本模型.

代码语言:javascript
复制
base_model = keras.applications.Xception(
    weights='imagenet',  # Load weights pre-trained on ImageNet.
    input_shape=(150, 150, 3),
    include_top=False)  # Do not include the ImageNet classifier at the top.

然后,冻结基本模型。

代码语言:javascript
复制
base_model.trainable = False

在上面创建一个新模型。

代码语言:javascript
复制
inputs = keras.Input(shape=(150, 150, 3))
# We make sure that the base_model is running in inference mode here,
# by passing `training=False`. This is important for fine-tuning, as you will
# learn in a few paragraphs.
x = base_model(inputs, training=False)
# Convert features of shape `base_model.output_shape[1:]` to vectors
x = keras.layers.GlobalAveragePooling2D()(x)
# A Dense classifier with a single unit (binary classification)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

根据新数据对模型进行培训。

代码语言:javascript
复制
model.compile(optimizer=keras.optimizers.Adam(),
              loss=keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=[keras.metrics.BinaryAccuracy()])
model.fit(new_dataset, epochs=20, callbacks=..., validation_data=...)

我的问题是为什么这个例子没有在致密层中应用乙状结肠或softmax激活?

代码语言:javascript
复制
# A Dense classifier with a single unit (binary classification)
outputs = keras.layers.Dense(1)(x)

这个稠密的层在默认情况下具有线性激活,这会使模型输出成为一个回归值吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-06-18 08:13:06

注意,sigmoid和softmax只是压缩函数,即..。它们压缩[-inf, +inf][0, 1]之间的一个值。因此,当我们想要解释线性层的输出到概率时,我们使用了sigmoid/softmax层。

现在到了为什么不使用sigmoid/softmax层的问题,这是因为使用了损耗函数。

代码语言:javascript
复制
keras.losses.BinaryCrossentropy(from_logits=True)

如果您检查文档,当

  • from_logits=True,预期的y_pred在-inf,inf中。
  • from_logits=False,预期的y_pred在0,1

因此,如果在丢失函数中使用from_logits=False,则必须使用sigmoid/softmax。

票数 1
EN

Stack Overflow用户

发布于 2021-06-18 08:00:54

该模型将输出一个数值,然后将其与二进制值(1或0 )进行比较。这种差异将产生一个损失,然后通过反向传播减少损失,这将驱动模型输出到所需的值。不过,我认为更好的做法是使用乙状结肠激活层。在另一个层面上,他们总是警告你开始冻结基础模型的权重,因为初始训练是因为渐变。我已经运行了至少500种模式使用转移学习离开基础模式作为可培训。实际上,一般情况下,对于N个历元的整个模型,我的训练效果要好于先用M个历元不可训练的基模型训练模型,然后对K个年代的模型进行微调,即K+M=N,即在相同的历元数下,训练整个模型相对于相同次数的两步过程得到更好的训练结果。但是,在验证和测试准确性方面,两者之间的差别通常很小。此外,他们还说,如果您将基本模型从不可训练更改为可训练,则必须重新编译模型。基于下面的代码,我认为这不是真的。

代码语言:javascript
复制
from keras.utils.layer_utils import count_params
model_name='EfficientNetB1'
base_model=tf.keras.applications.EfficientNetB1(include_top=False, weights="imagenet",input_shape=img_shape, pooling='max') 
base_model.trainable=False
x=base_model.output
x = Dense(256, activation='relu')(x)       
output=Dense(10, activation='softmax')(x)
model=Model(inputs=base_model.input, outputs=output)
model.compile(Adamax(lr=.001), loss='categorical_crossentropy', metrics=['accuracy']) 
trcount = count_params(model.trainable_weights)
non_trcount = count_params(model.non_trainable_weights)
print ('trainable parameters: ',trcount, '  non-trainable parameters: ',non_trcount)

如果你运行这个打印输出是

代码语言:javascript
复制
trainable parameters:  330506   non-trainable parameters:  6575239

现在,在下面的代码中,我使基本模型可以训练。

代码语言:javascript
复制
base_model.trainable=True
trcount = count_params(model.trainable_weights)
non_trcount = count_params(model.non_trainable_weights)
print ('trainable parameters: ',trcount, '  non-trainable parameters: ',non_trcount)

结果是

代码语言:javascript
复制
trainable parameters:  6843690   non-trainable parameters:  62055

所以在我看来你不需要重新编译模型

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68030740

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档