Lo que he hecho : Tengo un conjunto de datos completo de 898 etiquetas con un total de ~55 000 imágenes. Por razones de velocidad, tomé 10 de esas etiquetas y unas 600 imágenes para probar el código a continuación. Intenté cambiar el tamaño del lote, modificando la función de datos, pero fue en vano.
Problema : Error: Batch size mismatch: output dense_Dense1 has 10; expected 500 based on input conv2d_Conv2D1_input.
Objetivo : cambie la salida final de dense_Dense1 para tener 500, o cambie la entrada esperada de conv2d_Conv2D1_input a solo 10.
Código completo:
var tf = require('@tensorflow/tfjs'); var tfnode = require('@tensorflow/tfjs-node'); var fs = require(`fs`) const numberOfClasses = 10; const imageWidth = 500; const imageHeight = 800; const imageChannels = 3; const batchSize = 3; const epochsValue = 5; const createImage = async (fileName) => { const imageBuffer = await fs.readFileSync(fileName); const image = await tfnode.node.decodeImage(imageBuffer); return image; } const labelArray = indice => Array.from({length: numberOfClasses}, (_, k) => k === indice ? 1 : 0) async function* data() { for (i = 1; i < numberOfClasses+1; i++) { for (x = 10; x < 40; x++) { const feature = await createImage(`./images/${i}/${i}-${x}.png`) ; const label = tf.tensor1d(labelArray(i)) yield {xs: feature, ys: label}; } } } function onBatchEnd(batch, logs) { console.log('Accuracy', logs.acc); } const main = async () => { const model = tf.sequential(); model.add(tf.layers.conv2d({ inputShape: [imageWidth, imageHeight, imageChannels], filters: 8, kernelSize: 5, padding: 'same', activation: 'relu' })); model.add(tf.layers.maxPooling2d({ poolSize: 2, strides: 2 })); model.add(tf.layers.conv2d({ filters: 16, kernelSize: 5, padding: 'same', activation: 'relu' })); model.add(tf.layers.maxPooling2d({ poolSize: 3, strides: 3 })); model.add(tf.layers.flatten()); model.add(tf.layers.dense({ units: numberOfClasses, activation: 'softmax' })); model.compile({ optimizer: 'sgd', loss: 'categoricalCrossentropy', metrics: ['accuracy'] }); model.summary() const ds = tf.data.generator(data); model.fitDataset(ds, { epochs: 5, batchSize: 10, callbacks: {onBatchEnd} }).then(info => { console.log('Final accuracy', info.history.acc); }); } main()El error se explica por sí mismo.
Error: discrepancia en el tamaño del lote: la salida dense_Dense1 tiene 10; esperado 500 basado en la entrada conv2d_Conv2D1_input.
Hay un desajuste de forma entre lo que espera el modelo y lo que tiene el conjunto de datos. dense_Dense1 es la última capa y 10 el número de clases ( model.summary() es útil para conocer el nombre de las capas)
500 es el número de lotes, al menos eso es lo que obtiene el modelo con fitDataset() . Aquí está la confusión. 500 es el tamaño del primer eje de la feature . La feature es un tensor 3d con el primer eje (ancho de la imagen) siendo 500. Si el tensor 3d se usa directamente para la predicción, el modelo considera que el ancho de la imagen es el número de lotes y las características son tensores 2d. Por lo tanto, la característica debería ser más bien un tensor 4d.
Sin embargo, para ir más allá, el modelo no está prediciendo en una sola imagen a la vez. Dado que más tarde hay un batch(10) . Después de cada iteración de los data* , las características se apilan y, después de 10 iteraciones, se utilizan para las predicciones. Es útil porque se pueden usar otros operadores para reorganizar el lote y así sucesivamente.
Aquí está la solución:
yield {xs: feature.expandDims(), ys: label.expandDims()};O incluso mejor, puede agrupar el número de muestras antes de ajustarlo al modelo de esta manera
const ds = tf.data.generator(data).batch(1);Miré el código fuente de javascript de tensorflow y encontré el siguiente fragmento del archivo https://github.com/tensorflow/tfjs/blob/550e2c7ced057309533f44f76e692fe28aa7a802/tfjs-layers/src/engine/training_dataset.ts en la línea 202, donde verá el siguiente fragmento.
for (let yIndex = 0; yIndex < flattenedYs.length; yIndex++) { tfc.util.assert( flattenedYs[yIndex].shape[0] === batchSize, () => `Batch size mismatch: output ` + `${model.outputNames[yIndex]} has ${ flattenedYs[yIndex].shape[0]}; ` + `expected ${batchSize} based on input ${model.inputNames[0]}.`); }este es el único lugar en todo el código base que genera este error que coincide exactamente con su error. Aunque no soy un experto en aprendizaje profundo, puedo decir que el problema probablemente esté en la dimensión y de sus datos.
ese fragmento proviene de una función llamada standardizeDataIteratorOutput , cuyo forloop interno está tratando de validar la dimensión y de su conjunto de datos flattenedYs[yIndex].shape[0] === batchSize así que, en pocas palabras, supongo, su tamaño de lote se establece en 10, que no coincide con el tamaño de entrada Y. probablemente necesite reorganizar los datos de la imagen para que coincidan.