关于Pytorch中BCELoss调用binary_cross_entropy和Keras调用tf.binary_crossentropy的差异

问题来源:多标签的Pytorch实现

最近关注多标签学习,发现网上的开源代码基本都是keras实现的,比如TinyMind的多标签竞赛方法等,由于本人习惯于Pytorch,希望能够使用Pytorch实现,因此复现Pytorch版本,至此困惑即开始了。

问题:学习不收敛

根据自己的经验,搭建网络来学习TinyMind竞赛数据,并参考了网上的建议,采用二值交叉熵损失(Pytorch中BCELoss底层调用的是binary_cross_entropy),不幸的是网络始终不收敛,且预测F1指标在百分之十几不动了,所有图像的预测输出始终是固定的几个值。

解决:

1、分析数据,发现标签正负样本分布极其不均横,个人分析可能是数据分布不均的问题;但是,在这之前我用(竞赛第2名方案)复现,发现他们的方法是收敛的,且非常好。这就说明和数据是无关的。
2、我对比了个人实现代码和竞赛第2名方案,并逐一修改,使过程一致,但是始终学习训练不收敛,这就很尴尬了。最后,对损失前的输出打印发现两个基本都是一样的。最后我就怀疑上了损失函数的不同,因此,从Pytorch损失库中把所有可能的损失都拿出来,发现只有BCELoss对应的是binary_cross_entropy,与Keras调用tensorflow中的binary_crossentropy应该是一致的。本着怀疑的态度,我搜了一个google,竟然有人说tf.binary_crossentropy不是原始的方法,所以我直接怀疑BCELoss中的binary_cross_entropy估计也是不一样的,所以索性对着损失函数自己写,实验证明BCELoss还真的不是想象中的那样,真心愤怒啊!
3、更尴尬的是,发现有人论证了Pytorch的torch.nn.BCELoss()=F.binary_cross_entropy()是没错的,这就实在是尴尬的不行了。最后,对比发现BCELoss中有个参数reduction,其求平均的方法是对所有正式标签个数求平均,而非对样本个数求平均,因此,找到解决问题的关键所在——即令BCELoss中参数reduction=‘none’,然后自己对损失求和算样本平均。

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
import tensorflow as tf import tensorflow_hub as hub from tensorflow.keras import layers import bert import numpy as np from transformers import BertTokenizer, BertModel # 设置BERT模型的路径和参数 bert_path = "E:\\AAA\\523\\BERT-pytorch-master\\bert1.ckpt" max_seq_length = 128 train_batch_size = 32 learning_rate = 2e-5 num_train_epochs = 3 # 加载BERT模型 def create_model(): input_word_ids = tf.keras.layers.Input(shape=(max_seq_length,), dtype=tf.int32, name="input_word_ids") input_mask = tf.keras.layers.Input(shape=(max_seq_length,), dtype=tf.int32, name="input_mask") segment_ids = tf.keras.layers.Input(shape=(max_seq_length,), dtype=tf.int32, name="segment_ids") bert_layer = hub.KerasLayer(bert_path, trainable=True) pooled_output, sequence_output = bert_layer([input_word_ids, input_mask, segment_ids]) output = layers.Dense(1, activation='sigmoid')(pooled_output) model = tf.keras.models.Model(inputs=[input_word_ids, input_mask, segment_ids], outputs=output) return model # 准备数据 def create_input_data(sentences, labels): tokenizer = bert.tokenization.FullTokenizer(vocab_file=bert_path + "trainer/vocab.small", do_lower_case=True) # tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') input_ids = [] input_masks = [] segment_ids = [] for sentence in sentences: tokens = tokenizer.tokenize(sentence) tokens = ["[CLS]"] + tokens + ["[SEP]"] input_id = tokenizer.convert_tokens_to_ids(tokens) input_mask = [1] * len(input_id) segment_id = [0] * len(input_id) padding_length = max_seq_length - len(input_id) input_id += [0] * padding_length input_mask += [0] * padding_length segment_id += [0] * padding_length input_ids.append(input_id) input_masks.append(input_mask) segment_ids.append(segment_id) return np.array(input_ids), np.array(input_masks), np.array(segment_ids), np.array(labels) # 加载训练数据 train_sentences = ["Example sentence 1", "Example sentence 2", ...] train_labels = [0, 1, ...] train_input_ids, train_input_masks, train_segment_ids, train_labels = create_input_data(train_sentences, train_labels) # 构建模型 model = create_model() model.compile(optimizer=tf.keras.optimizers.Adam(lr=learning_rate), loss='binary_crossentropy', metrics=['accuracy']) # 开始微调 model.fit([train_input_ids, train_input_masks, train_segment_ids], train_labels, batch_size=train_batch_size, epochs=num_train_epochs)这段代码有什么问题吗?
05-24
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值