Я пытаюсь создать учебный проект для популярной португальской карточной игры. У меня работает среда. Код может выполняться самостоятельно, за n раундов, используя случайные выборки.
Для быстрого объяснения игра похожа на Hearts. В нем 4 игрока в 2 командах. У каждого игрока по 10 карт, играя по возможности, пока не осталось карт. Каждый трюк зарабатывает очки, после 10 трюков команда с более чем 60 очками выигрывает раунд.
Во-первых, у меня были некоторые сомнения относительно того, как «кодировать» карты / колоду. Я передаю модели карты на столе, карты на руках и уже играли в карты. Я однозначно закодировал колоду, 4 масти, 10 цифр / цифр. Я также должен включить козырь (взят с начала раунда). Таким образом, в качестве примера 1 карта выглядит следующим образом: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], где первые четыре числа соответствуют масти, ипоследняя является козырной (булевой), а остальная - какая карта (2, 3, 4, 5, 6, j, q, k, 7, a). Я передаю колоду для каждой руки, стола, сыгранной, так что 40 * 3, 15 фишек для каждой (1800 фишек при сглаживании). Возможно, это не лучший подход, если кто-то мог бы посоветовать это было бы здорово.
С этими данными я устанавливаю 1 игрока в качестве агента ИИ. Когда наступает очередь ИИ, состояние - это карты в руке, карты на столе, игральные карты. Для следующего состояния я прохожу трюк с данными того же типа. Награда от этого трюка является совокупной величиной (максимум 120 баллов). Когда я запускаю код, потеря выводит значение вначале, как в первый раз, затем отображает NaN. Так что прогнозы выходят также как NaN (у меня есть 10 выходов, по 1 на каждую карту в руке. Также есть некоторые сомнения по этому поводу, потому что они начинаются с 10 карт, но по ходу игры и разыгрывания карт это число переходит кноль.)
Вот код для обучения:
async expReplay() {
console.debug('Training...')
const minibatch = await this.memory.concat().sort(() => .5 - Math.random()).slice(0, this.batchSize)
for (let i = 0; i < minibatch.length - 1; i++) {
let [state, action, reward, next_state, done] = minibatch[i]
state = await tf.concat(state).flatten().reshape([1, this.stateSize])
next_state = await tf.concat(next_state).flatten().reshape([1, this.stateSize])
let target = reward
if (!done) {
let predictNext = await this.model.predict(next_state)
target = reward + this.gamma * predictNext.argMax().dataSync()[0]
}
let target_f = await this.model.predict(state).dataSync()
target_f[action] = target
target_f = await tf.tensor2d(target_f, [1, this.actionSize])
await this.model.fit(state, target_f, {
epochs: 1,
verbose: 1,
callbacks: {
onEpochEnd: (epoch, logs) => {
process.stdout.write(`${logs.loss} ${logs.acc} \r`)
}
}
})
await state.dispose()
await next_state.dispose()
await target_f.dispose()
}
if (this.epsilon > this.epsilonMin) {
this.epsilon *= this.epsilonDecay
}
return 'Training... stop!'
}
Этот цикл, который я использовал ранее, на DQN также для трейдера Биткойн, я экспериментировал, и он работал нормально,Так что я предполагаю, что мои данные где-то не так. Я зарегистрировал состояние и next_state для проверки на NaN, но не обнаружил ...
Если вам нужна дополнительная информация, пожалуйста, спросите!