Мне очень нравится ваша идея иметь "двунаправленный softmax".Извините, но через некоторое время я смог доказать, что такое softmax невозможно в общем случае (если интересно, я могу добавить упрощенное описание, почему).
Но есть и другие способырешить это без «двунаправленного софтмакса» и без нарушения ваших ограничений.Я предлагаю вам использовать полную игру для 40 игроков с 10 функциями в качестве входных данных и ранжировать каждого из 40 игроков в качестве выходных данных.Вместо того, чтобы классифицировать каждого игрока на 4 класса, я предлагаю вам дать каждому игроку очки (например, -1 для не лучших трех, 0 для третьего лучшего игрока, 1 для второго лучшего игрока и 2 для лучшего игрока).По прогнозу, вы можете просто выбрать игрока с наибольшим счетом в качестве лучшего игрока, второго по величине в качестве второго лучшего, третьего по величине в качестве третьего лучшего, а остальные не в лучших трех.Таким образом, вы не нарушаете свое ограничение, согласно которому каждый игрок должен получить «класс» и только одного игрока за первое, второе и третье место.
см. Ниже минимальный рабочий пример:
# import packages
import numpy as np
from tensorflow.keras.layers import Dense, Input, Flatten#, Reshape
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
# generate data
games, m = 50, 40
X = np.zeros((games, m, 11))
Y = np.zeros((games, m))
for i in range(games):
X[i, :, 0] = i
X[i, :, 1:] = np.random.rand(m, 10)
y_indexes = np.arange(m)
np.random.shuffle(y_indexes)
# score players
Y[i,y_indexes[0]] = 2 # best
Y[i,y_indexes[1]] = 1 # second best
Y[i,y_indexes[2]] = 0 # third best
Y[i,y_indexes[3:]] = -1 # not best
# run model
inputs = Input(shape=(m,10)) # -1 as we dont use fist column (game number)
inputs_flatten = Flatten()(inputs)
x = Dense(1024, activation='relu')(inputs_flatten)
x = Dense(512, activation='relu')(x)
x = Dense(256, activation='relu')(x)
outputs = Dense(m, activation=None)(x)
model = Model(inputs = inputs, outputs = outputs)
adam = Adam(lr=0.001)
model.compile(optimizer=adam, loss='mse', metrics=['accuracy'])
hist = model.fit(X[:,:,1:], Y, epochs=20, batch_size=10)
# predict third, second and best players for the first game
# the print number, is the player number
Y_pred = model.predict(X[0:1,:,1:])
print(np.argsort(Y_pred.reshape(-1))[-3:])
#[7 29 19]
# True best players fist game
print(np.argsort(Y[0,:].reshape(-1))[-3:])
#[7 29 19]
обратите внимание, что эта архитектура модели глубже и имеет больше узлов, чем рекомендуется для такого небольшого набора данных (только 50 событий, по одному на каждую игру).