新形状和旧形状必须具有相同数量的元素

Posted

技术标签:

【中文标题】新形状和旧形状必须具有相同数量的元素【英文标题】:new shape and old shape must have the same number of elements 【发布时间】:2019-03-14 17:29:27 【问题描述】:

出于学习目的,我使用的是 Tensorflow.js,在尝试使用带有批处理数据集(10 x 10)的 fit 方法来学习批处理训练过程时遇到错误。

我有几张 600x600x3 的图像要分类(2 个输出,1 或 0)

这是我的训练循环:

  const batches = await loadDataset()

  for (let i = 0; i < batches.length; i++) 
    const batch = batches[i]
    const xs = batch.xs.reshape([batch.size, 600, 600, 3])
    const ys = tf.oneHot(batch.ys, 2)

    console.log(
      xs: xs.shape,
      ys: ys.shape,
    )
    //  xs: [ 10, 600, 600, 3 ], ys: [ 10, 2 ] 

    const history = await model.fit(
      xs, ys,
      
        batchSize: batch.size,
        epochs: 1
      ) // <----- The code throws here

    const loss = history.history.loss[0]
    const accuracy = history.history.acc[0]

    console.log( loss, accuracy )
  

这是我定义数据集的方式

const chunks = chunk(examples, BATCH_SIZE)

const batches = chunks.map(
  batch => 
    const ys = tf.tensor1d(batch.map(e => e.y), 'int32')
    const xs = batch
      .map(e => imageToInput(e.x, 3))
      .reduce((p, c) => p ? p.concat(c) : c)
    return  size: batch.length, xs , ys 
  
)

这是模型:

const model = tf.sequential()
model.add(tf.layers.conv2d(
  inputShape: [600, 600, 3],
  kernelSize: 60,
  filters: 50,
  strides: 20,
  activation: 'relu',
  kernelInitializer: 'VarianceScaling'
))
model.add(tf.layers.maxPooling2d(
  poolSize: [20, 20],
  strides: [20, 20]
))
model.add(tf.layers.conv2d(
  kernelSize: 5,
  filters: 100,
  strides: 20,
  activation: 'relu',
  kernelInitializer: 'VarianceScaling'
))

model.add(tf.layers.maxPooling2d(
  poolSize: [20, 20],
  strides: [20, 20]
))
model.add(tf.layers.flatten())
model.add(tf.layers.dense(
  units: 2,
  kernelInitializer: 'VarianceScaling',
  activation: 'softmax'
))

我在 for 循环的第一次迭代中收到来自 .fit 的错误,如下所示:

Error: new shape and old shape must have the same number of elements.
    at Object.assert (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/util.js:36:15)
    at reshape_ (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/ops/array_ops.js:271:10)
    at Object.reshape (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/ops/operation.js:23:29)
    at Tensor.reshape (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/tensor.js:273:26)
    at Object.derB [as $b] (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/ops/binary_ops.js:32:24)
    at _loop_1 (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/tape.js:90:47)
    at Object.backpropagateGradients (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/tape.js:108:9)
    at /Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/engine.js:334:20
    at /Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/engine.js:91:22
    at Engine.scopedRun (/Users/person/nn/node_modules/@tensorflow/tfjs-core/dist/engine.js:101:23)

我不知道从中理解什么,也没有找到关于该特定错误的文档或帮助,有什么想法吗?

【问题讨论】:

【参考方案1】:

模型的问题在于convolutionmaxPooling 一起应用的方式

第一层是用 [20, 20] 的步幅和 50 个过滤器对 kernelSize 60 进行卷积。 该层的输出将具有近似形状[600 / 20, 600 / 20, 50] = [30, 30, 50]

最大池化以[20, 20] 的步幅应用。这一层的输出也会有近似的形状[30 / 20, 30 / 20, 50] =[1, 1, 50 ]

从这一步开始,模型无法再执行 kernelSize 为 5 的卷积。因为内核形状 [5, 5] 大于输入形状 [1, 1] 导致抛出错误。该模型可以执行的唯一卷​​积是大小为 1 的内核的卷积。显然,该卷积将输出输入而无需任何转换。

同样的规则适用于最后一个maxPooling,其poolingSize不能不同于1,否则会抛出错误。

这是一个sn-p:

const model = tf.sequential()
model.add(tf.layers.conv2d(
  inputShape: [600, 600, 3],
  kernelSize: 60,
  filters: 50,
  strides: 20,
  activation: 'relu',
  kernelInitializer: 'VarianceScaling'
))
model.add(tf.layers.maxPooling2d(
  poolSize: [20, 20],
  strides: [20, 20]
))
model.add(tf.layers.conv2d(
  kernelSize: 1,
  filters: 100,
  strides: 20,
  activation: 'relu',
  kernelInitializer: 'VarianceScaling'
))

model.add(tf.layers.maxPooling2d(
  poolSize: 1,
  strides: [20, 20]
))
model.add(tf.layers.flatten())
model.add(tf.layers.dense(
  units: 2,
  kernelInitializer: 'VarianceScaling',
  activation: 'softmax'
))

model.compile(optimizer: 'sgd', loss: 'meanSquaredError');
model.fit(tf.ones([10, 600, 600, 3]), tf.ones([10, 2]), batchSize: 4);

model.predict(tf.ones([1, 600, 600, 3])).print()
<html>
  <head>
    <!-- Load TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.13.0"> </script>
  </head>

  <body>
  </body>
</html>

【讨论】:

以上是关于新形状和旧形状必须具有相同数量的元素的主要内容,如果未能解决你的问题,请参考以下文章

Logits 和 Labels 必须具有相同的形状:Tensorflow

如何修复 Logits 和 Labels 必须具有相同的形状?

ValueError:x 和 y 必须具有相同的第一维,但具有形状

ValueError:x 和 y 必须具有相同的第一维,但具有形状 (6,) 和 (8,) [重复]

Variational AutoEncoder- Keras-logits 和标签必须具有相同的形状?

TensorFlow ValueError:logits 和标签必须具有相同的形状 ((25, 1) vs (1, 1))