【问题标题】:tf.keras.Sequential binary classification model predicting [0.5, 0.5] or close totf.keras.Sequential 二元分类模型预测 [0.5, 0.5] 或接近
【发布时间】:2019-09-10 08:44:24
【问题描述】:

我目前正在尝试构建一个模型,根据主队、客队和比赛联赛,使用tf.keras.Sequential 模型,对给定足球比赛的结果是高于还是低于 2.5 球进行分类TensorFlow 2.0RC。

我遇到的问题是使用model.predict 方法时,我的softmax 结果收敛于[0.5,0.5]。奇怪的是,经过 1000 轮训练后,我的验证和测试准确率和损失分别约为 0.94 和 0.12,否则我会将其归结为过度拟合问题。我知道 1000 个 epoch 极有可能过度拟合,但是,我想了解为什么我的准确度会提高到大约 800 个 epochs。我的损失在大约 300 个 epochs 时趋于平缓。

我试图改变层数、每层中的单元数、激活函数、优化器和损失函数、时期数和学习率,但似乎只能增加损失。

无论如何,结果似乎仍然向[0.5,0.5] 收敛。

完整代码可以在https://github.com/AhmUgEk/tensorflow_football_predictions查看,但下面是显示模型组成的摘录。

# Create Keras Sequential model:
model = keras.Sequential()

model.add(feature_layer)  # Input processing layer.

model.add(Dense(units=32, activation='relu'))  # Hidden Layer 1.
model.add(Dropout(rate=0.4))
model.add(BatchNormalization())

model.add(Dense(units=32, activation='relu'))  # Hidden Layer 2.
model.add(Dropout(rate=0.4))
model.add(BatchNormalization())

model.add(Dense(units=2, activation='softmax'))  # Output layer.

# Compile the model:
model.compile(
    optimizer=keras.optimizers.Adam(learning_rate=0.0001),
    loss=keras.losses.MeanSquaredLogarithmicError(),
    metrics=['accuracy']
)

# Compile the model:
model.compile(
    optimizer=keras.optimizers.Adam(learning_rate=0.0001),
    loss=keras.losses.MeanSquaredLogarithmicError(),
    metrics=['accuracy']
)

# Fit the model to the training dataset and validate against the 
validation dataset between epochs:
model.fit(
    train_dataset,
    validation_data=val_dataset,
    epochs=1000,
    callbacks=[tensorboard_callback]
)

我希望收到[0.282, 0.718] 的结果,例如输入:

model.predict_classes([np.array(['E0'], dtype='object'),
    np.array(['Liverpool'], dtype='object'),
    np.array(['Newcastle'], dtype='object')])[0]

但根据上述,收到[0.5, 0.5] 的结果。

我在这里遗漏了什么明显的东西吗?

【问题讨论】:

  • 您的模型可能无法学习 2 个类别之间的不同特征,因此两者的置信度得分相同。您可以调整您的网络以查看结果是否有任何变化。如果您仍然无法解决问题,您可以分享您的模型代码和示例数据,我会尽力为您提供更多信息。
  • 嗨,Rishab。感谢cmets。如上所述,我一直在调整网络,但是,当结果实际上不确定时,我仍然无法理解model.evaluate 方法如何声称如此好的准确性和损失统计数据。另外,根据我的查询,我的完整代码可通过link 获得。
  • 我正在查看您的代码,因为我可以看到模型的训练损失在几个时期后已经停止下降。我仍在尝试调试问题,完成后将分享一些内容。
  • 感谢 Rishab,我们将不胜感激。
  • 你为什么使用 MeanSquaredLogarithmicError 作为损失?

标签: python tensorflow keras deep-learning tf.keras


【解决方案1】:

我对模型做了一些小的改动。现在,我没有得到准确的 [0.5, 0.5]。

结果:

[[0.61482537 0.3851746 ]
 [0.5121426  0.48785746]
 [0.48058605 0.51941395]
 [0.48913187 0.51086813]
 [0.45480043 0.5451996 ]
 [0.48933673 0.5106633 ]
 [0.43431875 0.5656812 ]
 [0.55314165 0.4468583 ]
 [0.5365097  0.4634903 ]
 [0.54371756 0.45628244]]

实施:

import datetime
import os
import numpy as np
import pandas as pd
import tensorflow as tf

from gpu_limiter import limit_gpu
from pipe_functions import csv_to_df, dataframe_to_dataset
from sklearn.model_selection import train_test_split
from tensorflow import keras
from tensorflow.keras.layers import BatchNormalization, Dense, DenseFeatures, Dropout, Input
from tensorflow.keras.callbacks import TensorBoard, ModelCheckpoint
import tensorflow.keras.backend as K
from tensorflow.data import Dataset


# Test GPU availability and instantiate memory growth limitation if True:
if tf.test.is_gpu_available():
    print('GPU Available\n')
    limit_gpu()
else:
    print('Running on CPU')

df = csv_to_df("./csv_files")

# Format & organise imported data, making the "Date" column the new index:
df['Date'] = pd.to_datetime(df['Date'])
df = df[['Date', 'Div', 'HomeTeam', 'AwayTeam', 'FTHG', 'FTAG']].dropna().set_index('Date').sort_index()
df['Over_2.5'] = (df['FTHG'] + df['FTAG'] > 2.5).astype(int)
df = df.drop(['FTHG', 'FTAG'], axis=1)


# Split data into training, validation and testing data:
# Note: random_state variable set to ensure reproducibility.
train, test = train_test_split(df, test_size=0.05, random_state=42)
train, val = train_test_split(train, test_size=0.05, random_state=42)

# print(df['Over_2.5'].value_counts())  # Check that data is balanced.


# Create datasets from train, val & test dataframes:
target_col = 'Over_2.5'
batch_size = 32

def df_to_dataset(features: np.ndarray, labels: np.ndarray, shuffle=True, batch_size=8) -> Dataset:
    ds = Dataset.from_tensor_slices(({"feature": features}, {"target": labels}))
    if shuffle:
        ds = ds.shuffle(buffer_size=len(features))
    ds = ds.batch(batch_size)
    return ds

def get_feature_transform() -> DenseFeatures:
    # Format features into feature columns to ensure data is in the correct format for feeding into the model:
    feature_cols = []
    for column in filter(lambda x: x != target_col, df.columns):
        feature_cols.append(tf.feature_column.embedding_column(tf.feature_column.categorical_column_with_vocabulary_list(
            key=column, vocabulary_list=df[column].unique()), dimension=5))
    return DenseFeatures(feature_cols)

# Transforms all features into dense tensors.
feature_transform = get_feature_transform()
train_features = feature_transform(dict(train)).numpy()
val_features = feature_transform(dict(val)).numpy()
test_features = feature_transform(dict(test)).numpy()

train_dataset = df_to_dataset(train_features, train[target_col].values, shuffle=True, batch_size=batch_size)
val_dataset = df_to_dataset(val_features, val[target_col].values, shuffle=True, batch_size=batch_size)  # Shuffle not required to validation data.
test_dataset = df_to_dataset(test_features, test[target_col].values, shuffle=True, batch_size=batch_size)  # Shuffle not required to test data.

# Create Keras Functional API:
# Create a feature layer from the feature columns, to be placed at the input layer of the model:

def build_model(input_shape: tuple) -> keras.Model:

    input_layer = keras.Input(shape=input_shape, name='feature')

    model = Dense(units=1028, activation='relu', kernel_initializer='normal', name='dense0')(input_layer)  # Hidden Layer 1.
    model = BatchNormalization(name='bc0')(model)

    model = Dense(units=1028, activation='relu', kernel_initializer='normal', name='dense1')(model)  # Hidden Layer 2.
    model = Dropout(rate=0.1)(model)
    model = BatchNormalization(name='bc1')(model)

    model = Dense(units=100, activation='relu', kernel_initializer='normal', name='dense2')(model)  # Hidden Layer 3.
    model = Dropout(rate=0.25)(model)
    model = BatchNormalization(name='bc2')(model)

    model = Dense(units=50, activation='relu', kernel_initializer='normal', name='dense3')(model)  # Hidden Layer 4.
    model = Dropout(rate=0.4)(model)
    model = BatchNormalization(name='bc3')(model)

    output_layer = Dense(units=2, activation='softmax', kernel_initializer='normal', name='target')(model)  # Output layer.

    model = keras.Model(inputs=input_layer, outputs=output_layer, name='better-than-chance')

    # Compile the model:
    model.compile(
        optimizer=keras.optimizers.Adam(learning_rate=0.001),
        loss='mse',
        metrics=['accuracy']
    )
    return model

# # Create a TensorBoard log file (time appended) directory for every run of the model:
# directory = ".\\logs\\" + str(datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
# os.mkdir(directory)

# # Create a TensorBoard callback to log a record of model performance for every 1 epoch:
# tensorboard_callback = TensorBoard(log_dir=directory, histogram_freq=1, write_graph=True, write_images=True)

# Run "tensorboard --logdir .\logs" in anaconda prompt to review & compare logged results.
# Note: Make sure that the correct environment is activated before running.

model = build_model((train_features.shape[1],))
model.summary()

# checkpoint = ModelCheckpoint('model-{epoch:03d}.h5', verbose=1, monitor='val_loss',save_best_only=True, mode='auto')  

# Fit the model to the training dataset and validate against the validation dataset between epochs:
model.fit(
    train_dataset,
    validation_data=val_dataset,
    epochs=10)
    # callbacks=[checkpoint]

# Saves and reloads model.
# model.save("./model.h5")
# model_from_saved = keras.models.load_model("./model.h5")

# Evaluate model accuracy against test dataset:
# scores, accuracy = model.evaluate(train_dataset)
# print('Accuracy:', accuracy)

##############
## OPTIONAL ##
##############

# DUBUGGING
# inp = model.input                                           # input placeholder
# outputs = [layer.output for layer in model.layers]          # all layer outputs
# functors = [K.function([inp], [out]) for out in outputs]    # evaluation functions

# # Testing
# layer_outs = [func([test_features]) for func in functors]
# print(layer_outs)


# # # Form a prediction based on inputs:
prediction = model.predict({"feature": test_features[:10]})
print(prediction)
  1. 您可以做的一件事是尝试一些集成学习方法,例如 RandomForestXGBoost 并比较结果。

  2. 您应该尝试将其他关键绩效指标 (KPI) 添加到 您的数据,然后尝试拟合模型。

【讨论】:

  • 感谢您与我一起探索模型。几个问题。首先,我注意到您已将模型构造设为函数。是否这样以后可以禁用模型并针对保存的版本进行预测? (我计划在下一次迭代中实现保存/加载功能,但希望模型首先启动并运行)。我还注意到您将“MSE”保留为损失函数,尽管如上所述,这更倾向于回归问题?最后,对于具有 3 个特征的模型来说,1028 张量似乎不高吗?感谢您的努力
  • MSE 通常用于回归问题,MSE 的问题是随着时间的推移梯度会变小,这通常不是在交叉熵损失的情况下。你不需要密集层中的 1024 个神经元。我只是在玩模型。该模型的实现也是基于 Keras 功能 API 而不是顺序 API。
  • 感谢您的回复。我有机会查看您的模型版本,但是,在 20 个 epoch 之后,我仍然向[0.5, 0.5] 收敛,无论我是使用函数式 API 还是顺序式,我的损失在 CategoricalCrossentropy 上停留在大约 0.7 MSE 约为 0.25。对于在最初的几个 epoch 之后可能导致损失停止改善的原因,您还有其他想法吗?我将探索添加功能是否有助于减少损失,因为我认为这可能是数据的限制。再次感谢您的所有帮助。
  • 在我回答的最后,我告诉你要处理你的数据。做一些特征工程师并尝试做一些探索性数据分析。您可以使用 Pandas Profiling 进行快速概览。该模型从数据中学习,所以如果你没有输入好的数据,无论你应用多么好的正则化和优化技巧,你都不会得到想要的性能。
猜你喜欢
  • 1970-01-01
  • 2021-03-18
  • 1970-01-01
  • 1970-01-01
  • 2012-01-29
  • 2011-09-02
  • 2021-04-17
  • 2020-07-31
  • 1970-01-01
相关资源
最近更新 更多