Error: Size(XX) must match the product of shape x,x,x,x - tensorflow

This is a newbie question, but any help will be appreciated.
I'm having a problem with a 3D tensor in TensorFlow.JS (node), with the following code:
const tf = require('#tensorflow/tfjs-node');
(async ()=>{
let list = [
{
xs: [
[
[ 0.7910133603149169, 0.7923634491520086, 0.79166712455722, 0.7928027625311359, 0.4426631841175303, 0.018719529693542337 ],
[ 0.7890709817505044, 0.7943561081665688, 0.7915865358198619, 0.7905450669351226, 0.4413258183256521, 0.04449784810703526 ],
[ 0.7940229392692819, 0.7924745639669473, 0.7881395357356101, 0.7880208892359736, 0.40902353356570315, 0.14643954229459097 ],
[ 0.801474878324385, 0.8003822349633881, 0.7969969705961001, 0.7939094034872144, 0.40227041242732126, 0.03893523221469505 ],
[ 0.8022503526561848, 0.8011600386679555, 0.7974621873981194, 0.8011488339557422, 0.43008361179994464, 0.11210020422004835 ],
],
[
[ 0.8034111510684465, 0.7985390234525179, 0.7949321830852709, 0.7943788081438548, 0.5739870761673189, 0.13358267460835263 ],
[ 0.805714476773561, 0.8072996569653942, 0.8040745782073486, 0.8035592212810225, 0.5899031300445114, 0.03229758335964042 ],
[ 0.8103322733081704, 0.8114317495511435, 0.8073606480159334, 0.8057140734135828, 0.5842202187553198, 0.01986941729798157 ],
[ 0.815132106874313, 0.8122641403791668, 0.8104353115275772, 0.8103395749739932, 0.5838313552472632, 0.03332674037143093 ],
[ 0.8118480102237944, 0.8166500561770489, 0.8128943005604122, 0.8147644523703373, 0.601619389872815, 0.04807286626501376 ],
]
],
ys: 1
}
];
const ds = tf.data.generator(async () => {
let index = 0;
return {
next: async () => {
if(index >= list.length) return { done : true };
let doc = list[index];
index++;
return {
value: {
xs : doc.xs,
ys : doc.ys
},
done: false
};
}
};
}).batch(1);
let model = tf.sequential();
model.add(tf.layers.dense({units: 60, activation: 'relu', inputShape: [2, 5, 6]}));
model.compile({
optimizer: tf.train.adam(),
loss: 'sparseCategoricalCrossentropy',
metrics: ['accuracy']
});
await model.fitDataset(ds, {epochs: 1});
return true;
})().then(console.log).catch(console.error);
This code generate the following error:
Error: Size(60) must match the product of shape 1,2,5,60
at Object.inferFromImplicitShape
I didn't understand why the layer is changing the last value of the inputShape from 6 to 60 (which is the expected output units for this layer).
Just to confirm, as far I know the units should be the product of: batchSize * x * y * z, in the example case: 1 * 2 * 5 * 6 = 60
Thank you!
Software specification:
tfjs-node: v1.2.11
Node JS: v11.2.0
OS: Ubuntu 18.04.2

Ok, the problem is that a fully connected layer (ts.layer.dense) expect a tensor1d as input, as described in this other question: Why do we flatten the data before we feed it into tensorflow?
So, to do the trick, the tensor must be re-shaped before the fully connected layer, as:
return {
value: {
xs : ts.reshape(doc.xs, [-1]),
ys : doc.ys
},
done: false
};
Where the -1 in ts.reshape(tensor, [-1]), means to the transformation function flatten the tensor.
For a visual demonstration, here a YouTube video: CNN Flatten Operation Visualized

Related

mxnet model convert to onnx success but ort.InferenceSession(model) failed

Ask a Question
I success convert mxnet model to onnx but it failed when inference .The model 's shape is (1,1,100,100)
convert code
sym = 'single-symbol.json'
params = '/single-0090.params'
input_shape = (1, 1, 100, 100)
onnx_file = './model.onnx'
converted_model_path = onnx_mxnet.export_model(sym, params, [input_shape], np.float32, onnx_file,verbose=True)
model= onnx.load_model(converted_model_path)
checker.check_graph(model.graph)
checker.check_model(model)
output
INFO:root:Input shape of the model [(1, 1, 100, 100)]
INFO:root:Exported ONNX file ./model.onnx saved to disk
inference code
sess = ort.InferenceSession("./model.onnx")
output
onnxruntime.capi.onnxruntime_pybind11_state.RuntimeException:
[ONNXRuntimeError] : 6 : RUNTIME_EXCEPTION :
Exception during initialization:
/onnxruntime/core/providers/cpu/nn/pool_attributes.h:77
onnxruntime::PoolAttributes::PoolAttributes(const OpNodeProtoHelper<onnxruntime::ProtoHelperNodeContext> &,
const std::string &, int) pads[dim] < kernel_shape[dim] &&
pads[dim + kernel_shape.size()] < kernel_shape[dim] was false.
Pad should be smaller than kernel.
Question
mxnet pooling node json
{
"op": "Pooling",
"name": "pool1_fwd",
"attrs": {
"count_include_pad": "True",
"global_pool": "False",
"kernel": "(4, 4)",
"layout": "NCHW",
"pad": "(4, 4)",
"pool_type": "avg",
"pooling_convention": "valid",
"stride": "(4, 4)"
},
"inputs": [[46, 0, 0]]
}
I change the "pad": "(4, 4)" to "pad": "(3, 3)" smaller than "kernel": "(4, 4), then try convert again.
sess = ort.InferenceSession("./model.onnx")
output = sess.run(None, {"data": data.astype(np.float32)})
it worked,but the output value is not right.
how to fix it ?
BTW:convert the mxnet model to ncnn all is right(not change anything,pad=(4,4),kernel=(4,4))
Further information
python:3.8
onnx:1.10.2
mxnet:1.8.0
I fix it,recode model by pytorch and copy weights,use nn.ZeroPad2d(4) before avgpooling:
self.pad = nn.ZeroPad2d(4)
self.pool = nn.AvgPool2d(kernel_size=(4,4),stride=(4,4))
X = self.pool(self.pad(self.conv(X)))

Output probability of prediction in tensorflow.js

I have a model.json generated from tensorflow via tensorflow.js coverter
In the original implementation of model in tensorflow in python, it is built like this:
model = models.Sequential([
base_model,
layers.Dropout(0.2),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes)
])
In tensorflow, the probability can be generated by score = tf.nn.softmax(predictions[0]), according to the tutorial on official website.
How do I get this probability in tensorflow.js?
I have copied the codes template as below:
$("#predict-button").click(async function () {
if (!modelLoaded) { alert("The model must be loaded first"); return; }
if (!imageLoaded) { alert("Please select an image first"); return; }
let image = $('#selected-image').get(0);
// Pre-process the image
console.log( "Loading image..." );
let tensor = tf.browser.fromPixels(image, 3)
.resizeNearestNeighbor([224, 224]) // change the image size
.expandDims()
.toFloat()
// RGB -> BGR
let predictions = await model.predict(tensor).data();
console.log(predictions);
let top5 = Array.from(predictions)
.map(function (p, i) { // this is Array.map
return {
probability: p,
className: TARGET_CLASSES[i] // we are selecting the value from the obj
};
}).sort(function (a, b) {
return b.probability - a.probability;
}).slice(0, 2);
console.log(top5);
$("#prediction-list").empty();
top5.forEach(function (p) {
$("#prediction-list").append(`<li>${p.className}: ${p.probability.toFixed(6)}</li>`);
});
How should I modify the above code?
The output is just the same as the value of variable 'predictions':
Float32Array(5)
0: -2.5525975227355957
1: 7.398464679718018
2: -3.252196788787842
3: 4.710395812988281
4: -4.636396408081055
buffer: (...)
byteLength: (...)
byteOffset: (...)
length: (...)
Symbol(Symbol.toStringTag): (...)
__proto__: TypedArray
0: {probability: 7.398464679718018, className: "Sunflower"}
1: {probability: 4.710395812988281, className: "Rose"}
length: 2
__proto__: Array(0)
Please help!!!
Thanks!
In order to extract the probabilities from the logits of the model using a softmax function you can do the following:
This is the array of logits that are also the predictions you get from the model
const logits = [-2.5525975227355957, 7.398464679718018, -3.252196788787842, 4.710395812988281, -4.636396408081055]
You can call tf.softmax() on the array of values
const probabilities = tf.softmax(logits)
Result:
[0.0000446, 0.9362511, 0.0000222, 0.0636765, 0.0000056]
Then if you wanted to get the index with the highest probability you can make use of tf.argMax():
const results = tf.argMax(probabilities).dataSync()[0]
Result:
1
Edit
I am not too familiar with jQuery so this might not be correct. But here is how I would get the probabilities of the outputs in descending order:
let probabilities = tf.softmax(predictions).dataSync();
$("#prediction-list").empty();
probabilities.forEach(function(p, i) {
$("#prediction-list").append(
`<li>${TARGET_CLASSES[i]}: ${p.toFixed(6)}</li>`
);
});

How to reshape 3D tensor in Tensorflow.js to 4D tensor?

I am using a custom model that takes as input [null, 224,224,3]
But I am getting the error below when I try to make predictions on the model.
Total size of new array must be unchanged.
Tensor being passed in:
Tensor
dtype: int32
rank: 3
shape: [224,224,3]
values:
[[[124, 130, 132],
[137, 148, 147],
[123, 134, 127],
...,
[0 , 0 , 0 ],
[0 , 0 , 0 ],
[0 , 0 , 0 ]],
const getPrediction = async tensor => {
if (!tensor) {
console.log("Tensor not found!");
return;
}
const reshapeLayers = tf.layers.reshape({
targetShape: [1, 224, 224, 3]
});
reshapeLayers.apply(tensor);
const model = await loadedModel;
const prediction = model.predict(reshapeLayers, 1);
console.log(`Predictions: ${JSON.stringify(prediction)}`);
if (!prediction || prediction.length === 0) {
return;
}
// Only take the predictions with a probability of 30% and greater
if (prediction[0].probability > 0.3) {
//Stop looping
cancelAnimationFrame(requestAnimationFrameId);
setPredictionFound(true);
setModelPrediction(prediction[0].className);
tensor.dispose();
}
};
You are passing to model.predict a layer instead of a tensor. It should rather be
model.predict(tensor.reshape([1,224,224,3]))

TFJS predict vs Python predict

I trained my model using Keras in Python and I converted my model to a tfjs model to use it in my webapp. I also wrote a small prediction script in python to validate my model on unseen data. In python it works perfectly, but when I'm trying to predict in my webapp it goes wrong.
This is the code I use in Python to create tensors and predict based on these created tensors:
input_dict = {name: tf.convert_to_tensor([value]) for name, value in sample_v.items()}
predictions = model.predict(input_dict)
classes = predictions.argmax(axis=-1)
In TFJS however it seems I can't pass a dict (or object) to the predict function, but if I write code to convert it to a tensor array (like I found on some places online), it still doesn't seem to work.
Object.keys(input).forEach((k) => {
input[k] = tensor1d([input[k]]);
});
console.log(Object.values(input));
const prediction = await model.executeAsync(Object.values(input));
console.log(prediction);
If I do the above, I get the following error: The shape of dict['key_1'] provided in model.execute(dict) must be [-1,1], but was [1]
If I then convert it to this code:
const input = { ...track.audioFeatures };
Object.keys(input).forEach((k) => {
input[k] = tensor2d([input[k]], [1, 1]);
});
console.log(Object.values(input));
I get the error that some dtypes have to be int32 but are float32. No problem, I can set the dtype manually:
const input = { ...track.audioFeatures };
Object.keys(input).forEach((k) => {
if (k === 'int_key') {
input[k] = tensor2d([input[k]], [1, 1], 'int32');
} else {
input[k] = tensor2d([input[k]], [1, 1]);
}
});
console.log(Object.values(input));
I still get the same error, but if I print it, I can see the datatype is set to int32.
I'm really confused as to why this is and why I can't just do like python and just put a dict (or object) in TFJS, and how to fix the issues I'm having.
Edit 1: Complete Prediction Snippet
const model = await loadModel();
const input = { ...track.audioFeatures };
Object.keys(input).forEach((k) => {
if (k === 'time_signature') {
input[k] = tensor2d([parseInt(input[k], 10)], [1, 1], 'int32');
} else {
input[k] = tensor2d([input[k]], [1, 1]);
}
});
console.log(Object.values(input));
const prediction = model.predict(Object.values(input));
console.log(prediction);
Edit 2: added full errormessage

tensorflow.js loss goes to infinity

I am trying to make a simple project to find coefficients of an equation using a tensorflow.js model. however, when ran, the loss approaches infinity and becomes NaN withing 4 or so iterations. I don't know why this is happening. Here is my code:
let xs = [];
let ys = [];
let aReal = Math.random();
let bReal = Math.random();
let cReal = Math.random();
let dReal = Math.random();
for (let i = -100; i < 100; i+=1) {
xs.push(i);
ys.push((aReal*Math.pow(i, 3) + bReal*Math.pow(i, 2) + cReal*i + dReal) + Math.random()*10-1);
}
const a = tf.variable(tf.scalar(Math.random()));
const b = tf.variable(tf.scalar(Math.random()));
const c = tf.variable(tf.scalar(Math.random()));
const d = tf.variable(tf.scalar(Math.random()));
function predict(x) {
return tf.tidy(() => {
return a.mul(x.pow(tf.scalar(3, 'int32')))
.add(b.mul(x.square()))
.add(c.mul(x))
.add(d);
});
}
function loss(predictions, labels) {
const meanSquareError = predictions.sub(labels).square().mean();
print(meanSquareError.dataSync());
return meanSquareError;
}
function train(xS, yS, numIterations) {
const learningRate = 0.1;
const optimizer = tf.train.sgd(learningRate);
console.log(xS.dataSync(), yS.dataSync());
for (let iter = 0; iter < numIterations; iter++) {
optimizer.minimize(() => {
const predYs = predict(xS);
return loss(predYs, yS);
});
}
}
train(tf.tensor(xs), tf.tensor(ys), 100);
let yPred = predict(tf.tensor(xs)).dataSync();
console.log(yPred);
let trace1 = {
x: xs,
y: ys,
mode: 'markers',
type: 'scatter'
};
let trace2 = {
x: xs,
y: yPred,
mode: 'lines',
};
console.log(aReal, bReal, cReal, dReal);
console.log(a.dataSync(), b.dataSync(), c.dataSync(), d.dataSync());
let graphData = [trace1, trace2];
Plotly.newPlot('graph', graphData);
Plotly is just a js library I'm using to plot the data.
Try lowering your learning rate. Once it's stable you can tweak it back up to speed training. If it's too high you'll get instability and NaNs
const learningRate = 0.0001;
You should try to normalize your input data for the prediction to work correctly. Otherwise the optimization becomes numerically unstable.
ys = [...];
// compute mean and stdev for ys!
normalized = (ys-ysmean)/(ysstd);
train(xs, normalized);
normed_pred = predict(xs);
pred = ysstd*normed_pred+ysmean;
In the tests I ran, your code works perfect on linear models y=ax+b; therefore my conclusion.
The loss depends on the values you start with, so if they are too big the loss may jump to the infinite and the prediction will return NaN. Try normalizing them so that they scale between 1 and -1. For instance when you train on MNIST, you divide all the values by 255, meaning that some white pixel [255, 255, 255] will become [1., 1., 1.].