【问题标题】:Why can the reshape function in keras not change the number of dimensions为什么keras中的reshape函数不能改变维数
【发布时间】:2019-12-09 18:19:17
【问题描述】:

我正在尝试使用 Keras 制作的神经网络制作国际象棋引擎。我想输出基于训练游戏的可能策略的预测,我使用 73x8x8 输出来做到这一点(棋盘上的每个位置乘以 73 个不同的可能移动,8 个方向 * 7 个方格用于“皇后移动”,8骑士移动,3 个升级(任何其他升级都是皇后升级)乘以 3 个方向)。 然而,我网络中的最后一层是 Dense 层,它输出一维 4672 长的输出。我正在尝试通过 Reshape 层将其重塑为更易于使用的东西。

但是,它给了我这个错误:ValueError: Error when checks target: expected reshape_1 to have 4 dimensions, but got array with shape (2, 1)

我看过这个问题:Error when checking target: expected dense_1 to have 3 dimensions, but got array with shape (118, 1),但答案似乎不适用于密集层,因为它们没有“返回序列”输入。

这是我的代码:

from keras.models import Model, Input
from keras.layers import Conv2D, Dense, Flatten, Reshape
from keras.optimizers import SGD
import numpy
from copy import deepcopy


class NeuralNetwork:
    def __init__(self):
        self.network = Model()
        self.create_network()

    def create_network(self):
        input = Input((13, 8, 8))
        output = Conv2D(256, (3, 3), padding='same')(input)
        policy_head_output = Conv2D(2, (1, 1))(output)
        policy_head_output = Flatten()(policy_head_output)
        policy_head_output = Dense(4672, name='policy_output')(policy_head_output)
        policy_head_output = Reshape((73, 8, 8), input_shape=(4672,))(policy_head_output)
        value_head_output = Conv2D(1, (1, 1))(output)
        value_head_output = Dense(256)(value_head_output)
        value_head_output = Flatten()(value_head_output)
        value_head_output = Dense(1, name="value_output")(value_head_output)
        self.network = Model(outputs=[value_head_output, policy_head_output], inputs=input)

    def train_network(self, input_training_data, labels):
        sgd = SGD(0.2, 0.9)
        self.network.compile(sgd, 'categorical_crossentropy', metrics=['accuracy'])
        self.network.fit(input_training_data, [labels[0], labels[1]])
        self.network.save("Neural Net 1")


def make_training_data():
    training_data = []
    labels = []
    for i in range(6):
        training_data.append(make_image())
        labels.append(make_label_image())
    return training_data, labels


def make_image():
    data = []
    for i in range(13):
        blank_board = []
        for j in range(8):
            a = []
            for k in range(8):
                a.append(0)
            blank_board.append(a)
        data.append(blank_board)
    return data


def make_label_image():
    policy_logits = []
    blank_board = []
    for i in range(8):
        a = []
        for j in range(8):
            a.append(0)
        blank_board.append(a)

    for i in range(73):
        policy_logits.append(deepcopy(blank_board))
    return [policy_logits, [0]]


def main():
    input_training_data, output_training_data = make_training_data()
    neural_net = NeuralNetwork()
    input_training_data = numpy.array(input_training_data)
    output_training_data = numpy.array(output_training_data)
    neural_net.train_network(input_training_data, output_training_data)


main()

谁能解释一下:

  1. 发生了什么

  2. 我能做些什么来修复它

【问题讨论】:

  • 嗯,你的 NN 的输出有形状 (None, 73, 8, 8),但是你想用 (output_training_data) 训练的输出有形状 (None, 1),其中 None 是在这种情况下为 6(训练示例的数量)。网络应该预测哪个实际目标?您可以使用 output = Dense(1, name='final_output')(output) 而不是 Reshaping,但我不确定这是否适合给定的任务。
  • 另一件事:您至少需要一个维度为 2 的输出才能使用交叉熵。可能首先使用“mse”损失进行原型设计,因为这适用于许多情况,然后再优化损失函数。
  • 道歉@Max,我似乎设法错误地生成了我的测试代码,因此它给出了正确的错误,但原因是错误的。我现在用给出正确错误的代码替换了它。
  • 也许可以尝试使用一维矩阵 (4672,1) 而不是行向量 (4672,)

标签: python tensorflow keras reshape


【解决方案1】:

你的方法有一些问题。

1。您的输出/目标数据

因此,您正在创建一个包含两个元素(板、标签)的列表对象。董事会是73x8x8,其中标签是0/1。这会产生不一致的尺寸。当你将这个参差不齐的结构转换为一个 numpy 数组时,就会发生这种情况。

a = [[0,1,2,3],[0]]
arr = np.array(a)
print(arr)
# => [list([0, 1, 2, 3]) list([0])]

然后数据切片索引发生了一个非常奇怪的转折,我不会去那里。因此,首先要分离出您的数据,以便 make_training_data 中返回的每个元素都具有一致的尺寸。所以这里我们分别返回了 input_image、output_board_image 和 output_labels。

def make_training_data():
    training_data = []
    labels = []
    board_output = []
    for i in range(6):
        training_data.append(make_image())
        board, lbl = make_label_image()
        labels.append(lbl)
        board_output.append(board)
    return training_data, board_output, labels

main() 中,它变成了,

input_training_data, output_training_board, output_training_labels = make_training_data()
input_training_data = np.array(input_training_data)
output_training_board = np.array(output_training_board)
output_training_labels = np.array(output_training_labels)

错误

所以你得到了错误

ValueError: 检查目标时出错:预期 reshape_1 有 4 个维度,但得到的数组形状为 (2, 1)

嗯,很简单,您在执行model.fit() 时以错误的顺序给出了输出。换句话说,你的模型说,

outputs=[value_head_output, policy_head_output]

你的make_labels() 说,

[policy_logits, [0]]

反之亦然。您糟糕的模型正试图将标签重塑为该 4 维结构。这就是它抱怨的原因。应该是这样的,

neural_net.train_network(input_training_data, [output_training_labels, output_training_board])

即使你只纠正了这个(没有 make_training_data()),你也可能无法让它工作,因为你的 numpy 结构(第一部分)中的所有这些不一致。

损失函数

这是关于你的损失函数的。您有一个带有单个输出的Dense 层,并且您正在使用categorical_crossentropy,它用于“分类”输出。你应该在这里使用binary_crossentropy,因为你只有一个索引。

此外,如果您希望多个输出的多个损失,请执行以下操作。

self.network.compile(sgd, ['binary_crossentropy', 'mean_squared_error'], metrics=['accuracy'])

这只是一个例子。如果你愿意,你也可以对两个输入有相同的损失。

【讨论】:

    猜你喜欢
    • 2017-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 2013-10-29
    • 2019-01-18
    相关资源
    最近更新 更多