Keras ValueError: 维度必须相等,但对于 'node Equal 是 6 和 9

Posted

技术标签:

【中文标题】Keras ValueError: 维度必须相等,但对于 \'node Equal 是 6 和 9【英文标题】:Keras ValueError: Dimensions must be equal, but are 6 and 9 for 'node EqualKeras ValueError: 维度必须相等,但对于 'node Equal 是 6 和 9 【发布时间】:2020-07-18 23:57:35 【问题描述】:

这是错误

ValueError: Dimensions must be equal, but are 6 and 9 for 'node Equal = Equal[T=DT_FLOAT, incompatible_shape_error=true](IteratorGetNext:1, Cast_1)' with input shapes: [?,6], [?,9]

我正在尝试为一个简单的 Keras 网络提供一组 9 x 3 numpy 整数数组,其预期输出为 6 个类别的 softmax,目标是 6 个类别的一个热门分类。我正在使用填充来创建一致的 9,3 数组(我很想摆脱它,但这会产生大量其他错误)。现在,model.fit 接受输入和目标,但在运行时遇到此错误。我相信它试图将 9 x 3 输入数组的每一行与目标数组的每个内部元素相关联。这不是我想要建立的预期关联。我想获取整个 9 x 3 数组并将其与 6 个类别之一相关联。显然,我做错了什么,但我不知道它是什么。我四处寻找有类似问题的人,但找不到node Equal 部分的人。大多数其他具有相同 ValueError 的人都有不同的部分,这使得它看起来无关紧要,包括一些在 Kera 中直接出现的错误。

这里是一些重新创建错误的简单代码。

import tensorflow as tf
import numpy as np
from tensorflow import keras

model = keras.Sequential()
model.add(keras.layers.Dense(16, input_shape=(9, 3), activation='relu'))
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dense(16, activation='relu'))
model.add(keras.layers.Dense(6, activation='softmax'))
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

example_array = np.array([
                np.array([[ 5,  0,  1],
                [ 2,  0,  1],
                [ 4,  0,  1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1]]), 
                np.array([[ 4,  3,  0],
                [ 4,  2,  2],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1]]), 
                np.array([[ 3,  0,  2],
                [ 1,  1,  1],
                [ 3,  2,  0],
                [ 3,  0,  3],
                [ 1,  0,  2],
                [ 4,  1,  1],
                [ 1,  1,  1],
                [ 3,  1,  1],
                [-1, -1, -1]])])
example_target = np.array([[1, 0, 0, 0, 0, 0,],
                [0, 0, 0, 0, 1, 0,],
                [0, 0, 0, 0, 0, 1,]])

model.fit(example_array, example_target, epochs=1)

虽然这似乎会产生一个与原始 (IteratorGetNext:1, Cast_1) 位不同的 (Cast_2, Cast_3) 位略有不同的错误

ValueError: Dimensions must be equal, but are 6 and 9 for 'node Equal = Equal[T=DT_FLOAT, incompatible_shape_error=true](Cast_2, Cast_3)' with input shapes: [?,6], [?,9].

考虑到我从我的主代码的示例运行中获取了这个例子,这不应该发生,但如果你想与之交互,这里是我的主代码。

Network.py

import gym
import random
import numpy as np
import tensorflow as tf
from tensorflow import keras
from statistics import median, mean
from collections import Counter
import Mastermind

INITIAL_GAMES = 1000
#The number of avaliable colours
COLOURS = 6
GUESS_LENGTH = 4
#The number of guesses avaliable to the player
GUESSES = 10
env = Mastermind.MastermindEnv(GUESS_LENGTH, COLOURS, GUESSES)
colours = env.colours

def initial_games():
    # [OBS, MOVES]
    training_data = []
    # all scores:
    scores = []
    # just the scores that met our threshold:
    accepted_scores = []
    # iterate through however many games we want:
    for _ in range(INITIAL_GAMES):
        env.reset()
        score = 0
        # guesses and results specifically from this environment:
        game_memory = []
        # Each is given the number of guesses 
        # long plus one to garuentee no interrupts
        for t in range(GUESSES+1):
            # choose random guess
            guess = ""
            for _ in range(GUESS_LENGTH):
                guess += random.choice(colours)

            #Check guess
            observation, reward, done, info = env.step(guess)

            score += reward
            if done:
                #Memory is saved after game's completion
                game_memory = observation
                break

        # If our score is positive it means that the answer was
        # correctly guessed at which point we want to save the score
        # and the game memory
        if 10 > score > 0:
            accepted_scores.append(score)
            training_data.append(game_memory)

        # reset env to play again
        env.reset()
        # save overall scores
        scores.append(score)

    # just in case you wanted to reference later
    training_data_save = np.array(training_data)
    np.save('saved.npy',training_data_save)

    #some statistics stuff
    print('Average accepted score:',mean(accepted_scores))
    print('total games won:', len(accepted_scores))
    print(Counter(accepted_scores))

    return training_data

model = keras.Sequential()
model.add(keras.layers.Dense(16, input_shape=(9, 3), activation='relu'))
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dense(16, activation='relu'))
model.add(keras.layers.Dense(COLOURS, activation='softmax'))
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

def initial_train_model():
    training_data = initial_games()
    for index in range(GUESS_LENGTH):
        training = []
        targets = []
        for observation in training_data:
            obs = []
            for i in range(len(observation)):
                if i == len(observation)-1:
                    targets.append(ord(observation[i][0][index])-97)
                else:
                    obs.append([ord(observation[i][0][index])-97,
                    ord(observation[i][1])-48,
                    ord(observation[i][2])-48])
                i += 1
            j = 10-len(observation)
            while j > 0:
                obs.append([-1, -1, -1])
                j -= 1
            training.append(np.array(obs))
        print(training)
        training = np.array(training)
        print(keras.utils.to_categorical(targets, num_classes=COLOURS))
        one_hot_targets = np.array(keras.utils.to_categorical(targets, num_classes=COLOURS))
        #print(one_hot_targets)
        model.fit(training, one_hot_targets, epochs=1)

initial_train_model()

Mastermind.py

import gym
from gym.utils import seeding
import numpy as np
import random

class MastermindEnv(gym.Env):
    """
    Description:
        A code guessing board game where a series of letters must be guessed 
        which gives small pieces of information to the player.

    Observation: 
        Type: List of Lists
        Guess   Blacks  Whites
        String  int     int

    Actions:
        Type: Discrete(colours^guess_length)
        String guess
        A string of length guess_length where each character can be any colour.

    Reward:
        Reward is 10 on game completion with 1 additional
        for each remaining guess.

    Starting State:
        An empty board with a target created

    Episode Termination:
        Remaining guesses reduced to 0
        guess == target
    Solved Requirements:
        100% winrate over 20 games
    """
    """
    metadata = 
        'render.modes': ['human', 'rgb_array'],
        'video.frames_per_second' : 50
    
    """
    def __init__(self, guess_length=4, colours=6, guesses=10):
        self.guess_length = guess_length
        self.total_guesses = guesses
        self.guesses = guesses
        self.colours = []
        for _ in range(colours):
            self.colours.append(chr(_ + 97))

        self.seed()
        self.state = []

    def seed(self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]

    def step(self, guess):
        done = False
        correct = False
        self.guesses -= 1
        if guess == self.target:
            done = True
            correct = True

        blacks = 0
        whites = 0
        accounted = []
        for i in range(len(guess)):
            if guess[i] == self.target[i]:
                blacks += 1
                accounted.append(i)
                continue
            for j in range(len(self.target)):
                if i != j and j not in accounted:
                    if guess[i] == self.target[j]:
                        whites += 1
                        accounted.append(j)
                        break  
        self.state.append([guess, blacks, whites])

        if self.guesses == 0:
            done = True

        if not done:
            reward = 0.0
        else:
            if correct:
                reward = float(self.guesses+1)
            else:
                reward = 0.0

        return np.array(self.state), reward, done, 

    def reset(self):
        self.state = []
        self.guesses = self.total_guesses
        # Creating a target
        target = ""
        for _ in range(self.guess_length):
            target += random.choice(self.colours)
        #print(target)
        self.target = target
        return np.array(self.state)

    def render(self, mode='human'):
        print(self.state[-1])

    def close(self):
        self.state = []
        self.guesses = self.total_guesses

主要是,如果可能,我希望每个 (9, 3) 数组与目标数组的单行相关联。

谢谢。

【问题讨论】:

【参考方案1】:

问题可能出在模型的定义中。您的输入数据有太多维度(4 个维度),无法直接适合 Dense 层(输入为 1 个维度,输出为 1 个维度)。您应该在第一个 Dense 层之前添加一个 Flatten 层。在您的情况下,您不再需要 Flatten 层,因为 Dense 层的输出与其输入具有相同的尺寸。

除此之外,您还应该将模型的 input_shape 定义为 input_shape=(9, 3, 3),因为您的模型由 3 个数组组成,每个数组大小为 9x3。

因此,您的示例代码应该是这样的:

import tensorflow as tf
import numpy as np
from tensorflow import keras

model = keras.Sequential()
model.add(tf.keras.layers.Flatten())
model.add(keras.layers.Dense(16, input_shape=(9, 3, 3), activation='relu'))
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dense(16, activation='relu'))
model.add(keras.layers.Dense(6, activation='softmax'))
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

example_array = np.array([
                np.array([[ 5,  0,  1],
                [ 2,  0,  1],
                [ 4,  0,  1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1]]), 
                np.array([[ 4,  3,  0],
                [ 4,  2,  2],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1],
                [-1, -1, -1]]), 
                np.array([[ 3,  0,  2],
                [ 1,  1,  1],
                [ 3,  2,  0],
                [ 3,  0,  3],
                [ 1,  0,  2],
                [ 4,  1,  1],
                [ 1,  1,  1],
                [ 3,  1,  1],
                [-1, -1, -1]])])
example_target = np.array([[1, 0, 0, 0, 0, 0,],
                [0, 0, 0, 0, 1, 0,],
                [0, 0, 0, 0, 0, 1,]])

model.fit(example_array, example_target, epochs=1)

Check this answer for a similar question.

【讨论】:

以上是关于Keras ValueError: 维度必须相等,但对于 'node Equal 是 6 和 9的主要内容,如果未能解决你的问题,请参考以下文章

Keras ValueError:尺寸必须相等,但对于 'node Equal 输入形状为 2 和 32:[?,2], [?,32,32]

ValueError:维度 (-1) 必须在 [0, 2) 范围内

Keras 嵌入层 - ValueError:检查输入时出错:预期有 2 个维度,但得到了 (39978, 20, 20)

ValueError:检查输入时出错:预期 keras_layer_input 有 4 个维度,但得到了形状为 (10, 1) 的数组

如何在 keras lambda 层中使用 tf.py_func 来包装 python 代码。 ValueError:应定义 Dense 输入的最后一个维度。没有找到

Python | Keras:ValueError:检查目标时出错:预期conv2d_3有4个维度,但得到了有形状的数组(1006,5)