【问题标题】:Binary classification with softmax activation always outputs 1使用 softmax 激活的二元分类总是输出 1
【发布时间】:2021-01-06 16:50:37
【问题描述】:

很抱歉问题的质量,但是这里是初学者,我只是在用泰坦尼克号数据集试试运气,但它总是预测乘客已经死亡。我尝试在下面解释代码:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns


import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import losses
from tensorflow.keras.layers.experimental import preprocessing

import os

加载数据集

dataset_dir = os.path.join(os.getcwd(), 'titanic')
train_url = os.path.join(dataset_dir, 'train.csv')
test_url = os.path.join(dataset_dir, 'test.csv')


raw_train_dataset = pd.read_csv(train_url)
raw_test_dataset = pd.read_csv(test_url)


train = raw_train_dataset.copy()
test = raw_test_dataset.copy()

删除一些列,我可能在这里错了

train = train.drop(['Cabin','Name','Ticket'], 1)
test = test.drop(['Cabin','Name','Ticket'], 1)

热向量

train = pd.get_dummies(train, prefix='', prefix_sep='')
test = pd.get_dummies(test, prefix='', prefix_sep='')

训练标签

train_predict = train.pop('Survived')

用平均值填充空年龄

train['Age'].fillna((train['Age'].mean()), inplace=True)
test['Age'].fillna((train['Age'].mean()), inplace=True)

删除空列

test = test.dropna()
train = train.dropna()

创建归一化层

normalizer = preprocessing.Normalization()
normalizer.adapt(np.array(train))

创建 dnn,我错了吗

model = keras.Sequential([
      normalizer,
      layers.Dense(64, activation='relu'),
      layers.Dropout(0.2),
      layers.Dense(1)
  ])



model.compile(loss=losses.BinaryCrossentropy(from_logits=True),
              optimizer='adam',
              metrics=tf.metrics.BinaryAccuracy(threshold=0.0))


history = model.fit(
    train, train_predict,
    validation_split=0.2,
     epochs=30)

这在每种情况下都显示为 1,但我在训练时仍然获得 85% 的准确率,我不需要完全解决问题(我想自己尝试),而只是我卡住的部分

result = tf.nn.softmax(model(train))
print(result)

【问题讨论】:

    标签: python tensorflow machine-learning keras deep-learning


    【解决方案1】:

    tf.nn.softmax 将始终返回sum=1 的数组。由于您的输出是 1 个值(您的最终/输出层上有一个单元),因此 softmax 操作会将这个值转换为 1。

    for value in [.2, .999, .0001, 100., -100.]:
        print(tf.nn.softmax([value]))
    
    tf.Tensor([1.], shape=(1,), dtype=float32)
    tf.Tensor([1.], shape=(1,), dtype=float32)
    tf.Tensor([1.], shape=(1,), dtype=float32)
    tf.Tensor([1.], shape=(1,), dtype=float32)
    tf.Tensor([1.], shape=(1,), dtype=float32)
    

    你要找的是tf.nn.sigmoid:

    for value in [.2, .999, .0001, 100., -100.]:
        print(tf.nn.sigmoid([value]))
    
    tf.Tensor([0.549834], shape=(1,), dtype=float32)
    tf.Tensor([0.7308619], shape=(1,), dtype=float32)
    tf.Tensor([0.500025], shape=(1,), dtype=float32)
    tf.Tensor([1.], shape=(1,), dtype=float32)
    tf.Tensor([0.], shape=(1,), dtype=float32)
    

    losses.BinaryCrossentropy(from_logits=True) 就像 sigmoid 交叉熵。

    如果要将值四舍五入以获得 0 或 1,请使用 tf.round

    tf.round(tf.nn.sigmoid([.1]))
    

    【讨论】:

    • 谢谢 nicolas,但它给了我 0 到 1 之间的十进制值,我只需要预测 0 或 1
    • 再问一个问题,为什么tf.round(tf.nn.sigmoid([.1])) 不包含在模型中而是在模型之外
    • 如果您愿意,您可以这样做。在最后一层添加activation='sigmoid',损失函数from_logits=False
    • 当我这样做时它失败了,我得到二进制精度 35%
    • 不,它没有。
    猜你喜欢
    • 2018-02-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    • 2016-12-08
    • 2018-08-14
    • 2020-02-25
    • 1970-01-01
    相关资源
    最近更新 更多