Lost on the inputshape (Tensorflow.js LSTM model attempt) - javascript

I'm trying to play with my first LSTM model on Tensorflow.js, but I'm pretty much stuck on the shapes (I think)
Assuming the Input array:
X = [ [
0,
0.0013304822998336796,
0.0015680684248040588,
0.000617723924922986,
0.002708481824661435,
0.0035162746495605024,
-0.00009503444998804067,
-0.004941791399382223,
-0.0030886196246138198,
0.0010928961748635224
],
[
0,
0.00023727044084842497,
-0.0007118113225452749,
0.0013761685569213533,
0.0021828880558061314,
-0.0014236226450907719,
-0.006263939638399774,
-0.00441323019978157,
-0.00023727044084842497,
0.0033692402600484783
], ... ]
and output array:
Y = [
[ 0.0028556470420255664 ],
[ 0.006330620210385884 ],
[ -0.0029661016949151797 ],
...
]
Building the Tensors like:
const xs = tf.tensor2d(X, [X.length, X[0].length]);
const ys = tf.tensor2d(Y, [Y.length, 1]);
then the model and it's training like:
const model = tf.sequential();
model.add(tf.layers.lstm({units: 10, inputShape: [10] }));
model.add(tf.layers.dropout({rate: 0.25}));
model.add(tf.layers.dense({units: 1 }));
model.add(tf.layers.activation({ activation: 'linear' }));
model.compile({
optimizer: tf.train.adam(),
loss: 'meanAbsoluteError'
});
model.fit(xs, ys, {
batchSize: 4, epochs: 50, callbacks: {
onEpochEnd: async (epoch, log) => {
console.log("Epoch: ", epoch, " - ", log);
}
}
});
Keek getting the error "Error: Input 0 is incompatible with layer lstm_LSTM1: expected ndim=3, found ndim=2" ..... tryed changing the inputShape to something else, not giving error before the training, but giving a diferent error "Error when checking input: expected lstm_LSTM1_input to have 3 dimension(s). but got array with shape 168418,10" on train..... So I'm assuming I'm all wrong anyway with the shape somehow lol this is a model I tryed to migrate to .js from python, It is exactly what I need, but on the wrong language..... the original model in python is:
def build_lstm_model(input_data, output_size=1, neurons=20, activ_func='linear', dropout=0.25, loss='mae', optimizer='adam'):
model = Sequential()
model.add(LSTM(neurons, input_shape=( input_data.shape[1], input_data.shape[2])))
model.add(Dropout(dropout))
model.add(Dense(units=output_size))
model.add(Activation(activ_func))
model.compile(loss=loss, optimizer=optimizer)
and the training:
history = model.fit(X_train, y_train, epochs=50, batch_size=4)
What is exactly the "inputShape" on my situation? Are the tensors formed the wrong way? What am I missing?
Thank you, I was really looking forward to get this working, and understanding why it's not working. To get my hands dirty on Machine Learning.

The input shape of keras.layers.LSTM is (batch size, time step, features). As you can see, the RNN structure was made for time depend data, so if your data contains no time information, better not using it. On the other hand, if you do have a time information, then be sure your input shape is a 3d(batch size + time step and features = 1 + 2) input. If you don't set the batch size, keras will set it to None which serve as batch size=1, so never mind if you didn't set it up. In your case, you just use inputShape: [10] which is not the format for using keras.layers.LSTM. If you would like to try applying LSTM anyway, expand the dimension for your input, and don't forget the change the inputShape following with you change.

Related

Error when checking : expected dense_Dense_1_input to have 2 dimensions, but got array with shape [224, 224, 3]

I get the following error:
Error when checking : expected dense_Dense_1_input to have 2 dimensions, but got array with shape [224, 224, 3]
When I run the following code:
const modelJson = require("../offline_model/pose-model.json");
const modelWeights = require("../offline_model/weights.bin");
let imageTensor = images.next().value as tf.Tensor3D;
tf.loadLayersModel(bundleResourceIO(modelJson, modelWeights)).then(model => {
try {
imageTensor = tf.image.resizeBilinear(
imageTensor,
[224, 224],
false
);
const normalized = imageTensor.cast('float32').div(127.5).sub(1);
model.predict(normalized)
Maybe this code is not the most correct but I already tried every other code from stackoverflow and youtube videos and they all give some error. I think the problem is that in my model.json file (I trained the model with teachable machine) I find this value:
"name":"dense_Dense1", "batch_input_shape":[null,14739]
This is why it expects 2 dimensions and I have 3. I guess I am not sure how to change the 3 dimension tensor I have to fit the dimensions of the batch input shape.

How can I get this basic example working of TensorFlow.js training for a true / false output with tf.browser.fromPixels(image)?

I've Googled every version of the question I could think of, but for the life of me I cant find a single basic example of tensorflow.js training a tf.browser.fromPixels(image) to result in a yes or a no. All the examples out there I could find start with pre-trained nets.
I've built a database of 25x25 pixel images and have them all stored as canvases in a variable like:
let data = {
t: [canvas1, canvas2, canvas3, ... canvas3000 ....],
f: [canvas1, canvas2, ... and so on ...]
}
And I think it should be trivial to do something like:
data.t.forEach(canvas => {
const xs = tf.browser.fromPixels(canvas);
const ys = tf.tensor([1]); // output 1, since this canvas is from the `t` (true) dataset
model.fit(xs, ys, {
batchSize: 1,
epochs: 1000
});
});
data.f.forEach(canvas => {
const xs = tf.browser.fromPixels(canvas);
const ys = tf.tensor([0]); // output 0, since this canvas is from the `f` (false) dataset
model.fit(xs, ys, {
batchSize: 1,
epochs: 1000
});
});
model.predict(tf.browser.fromPixels(data.t[0])).print(); // -> [1]
model.predict(tf.browser.fromPixels(data.t[1])).print(); // -> [1]
model.predict(tf.browser.fromPixels(data.t[2])).print(); // -> [1]
model.predict(tf.browser.fromPixels(data.f[0])).print(); // -> [0]
model.predict(tf.browser.fromPixels(data.f[1])).print(); // -> [0]
model.predict(tf.browser.fromPixels(data.f[2])).print(); // -> [0]
But the specifics, like inputShape and various little details, being new to TF, make trying to accomplish this without being able to find a basic example pretty much a painful learning curve. What would a valid representation of this training func look like? Here's the code so far:
// Just imagine DataSet builds a large data set like described in my
// question and calls a callpack function with the data variable as
// its only argument, full of pre-categorized images. Since my database
// of images is locally stored, I cant really produce an example here
// that works fully, but this gets the idea across at least.
new DataSet(
data => {
const model = tf.sequential();
model.add(
// And yes, I realize I would want a convolutional layer,
// some max pooling, filtering, etc, but I'm trying to start simple
tf.layers.dense({
units: [1],
inputShape: [25, 25, 3],
dataFormat: "channelsLast",
activation: "tanh"
})
);
model.compile({optimizer: "sgd", loss: "binaryCrossentropy", lr: 0.1});
data.t.forEach(canvas => {
const xs = tf.browser.fromPixels(canvas);
const ys = tf.tensor([1]); // output 1, since this canvas is
// from the `t` (true) dataset
model.fit(xs, ys, {
batchSize: 1,
epochs: 1000
});
});
data.f.forEach(canvas => {
const xs = tf.browser.fromPixels(canvas);
const ys = tf.tensor([0]); // output 0, since this canvas is
// from the `f` (false) dataset
model.fit(xs, ys, {
batchSize: 1,
epochs: 1000
});
});
model.predict(tf.browser.fromPixels(data.t[0])).print(); // -> [1]
model.predict(tf.browser.fromPixels(data.t[1])).print(); // -> [1]
model.predict(tf.browser.fromPixels(data.t[2])).print(); // -> [1]
model.predict(tf.browser.fromPixels(data.f[0])).print(); // -> [0]
model.predict(tf.browser.fromPixels(data.f[1])).print(); // -> [0]
model.predict(tf.browser.fromPixels(data.f[2])).print(); // -> [0]
},
{canvas: true}
);
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#1.0.0/dist/tf.min.js"></script>
You have only one layer for your model. You need more layers than that.
There are lots of tutorial you can follow to build a classifier to distinguish between two or more class of images. Here is this tutorial on the official website of tensorflow using CNN.
Additionnaly, you can see how to use fully connected neural network using this snippet to build a classifier though the accuracy might not be as good as CNN models.

Tensorflow.js prediction seems to have an upper limit of 1?

I was playing around with some tensorflow code I got from a youtube tutorial that predicts data of flowers. Here is the script (the training data is assigned to variable "iris" and the testing data is assigned to variable "irisTesting":
const trainingData = tf.tensor2d(iris.map(item => [
item.sepal_length, item.petal_length, item.petal_width,
]));
const outputData = tf.tensor2d(iris.map(item => [
item.species === "setosa" ? 1 : 0,
item.species === "virginica" ? 1 : 0,
item.species === "versicolor" ? 1 : 0,
item.sepal_width
]));
const testingData = tf.tensor2d(irisTesting.map(item => [
item.sepal_length, item.petal_length, item.petal_width
]));
const model = tf.sequential();
model.add(tf.layers.dense({
inputShape: [3],
activation: "sigmoid",
units: 5,
}));
model.add(tf.layers.dense({
inputShape: [5],
activation: "sigmoid",
units: 4,
}));
model.add(tf.layers.dense({
activation: "sigmoid",
units: 4,
}));
model.compile({
loss: "meanSquaredError",
optimizer: tf.train.adam(.06),
});
const startTime = Date.now();
model.fit(trainingData, outputData, {epochs: 100})
.then((history) => {
//console.log(history);
console.log("Done training in " + (Date.now()-startTime) / 1000 + " seconds.");
model.predict(testingData).print();
});
When the console prints the predicted sepal_width, it seems to have an upper limit of 1. The training data has sepal_width values of well over 1, but here is the data that is logged:
Tensor
[[0.9561102, 0.0028415, 0.0708825, 0.9997129],
[0.0081552, 0.9410981, 0.0867947, 0.999761 ],
[0.0346453, 0.1170913, 0.8383155, 0.9999373]]
The last (fourth) column would be the predicted sepal_width value. The predicted values should be larger than 1 however it seems that something is preventing it from being larger than 1.
This is the original code:
https://gist.github.com/learncodeacademy/a96d80a29538c7625652493c2407b6be
You're using a sigmoid activation function in the final layer to predict the sepal_width. Sigmoid is continuous function bounded between 0 and 1. See Wikipedia for a more thorough explanation.
You should try to use a different activation function if you want to predict the sepal_width. For a list of available activation functions you can check Tensorflow's API page (this is for the Python version, but the it should be similar for the JavaScript version). You can try 'softplus', 'relu' or even 'linear', but I cannot say if any of these are suitable for your application. Try and experiment to see which is best.
The original code from here addresses a classification problem. It is not meaningful to add item.sepal_width in your outputData because it is not another class.
The activation function of your last layer is sigmoid.
The Sigmoid function looks like this:
source
And as you can see it is restricted in the range of 0 to 1. So if you want other output values you need to adjust your last activation function accordingly.

Simple linear regression with TensorFlowJS

I'm trying to get some linear regression for a project.
As I'm used to Javascript, I decided to try and use TensorFlowJS.
I'm following the tutorial from their website and have watched some videos explaining how it works, but I still can't understand why my algorithm doesn't return the result I expect.
Here is what I'm doing:
// Define a model for linear regression.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
// Prepare the model for training: Specify the loss and the optimizer.
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});
// Generate some synthetic data for training.
const xs = tf.tensor1d([1, 2, 3, 4]);
const ys = tf.tensor1d([1, 2, 3, 4]);
// Train the model using the data.
model.fit(xs, ys).then(() => {
// Use the model to do inference on a data point the model hasn't seen before:
// Open the browser devtools to see the output
const output = model.predict(tf.tensor2d([5], [1,1]));
console.log(Array.from(output.dataSync())[0]);
});
I'm trying here to have a linear graph, where the input should always be equal to the output.
I'm trying to predict what I would get with an input of 5, however it seems that the output is random.
Here it is on codepen so you can try: https://codepen.io/anon/pen/RJJNeO?editors=0011
Your model is making prediction after only one epoch (one cyle of training). As a result the loss is still big which leads to unaccurate prediction.
The weights of the model are initialized randomly. So with only one epoch, the prediction is very random. That's why, one needs to train for more than one epoch, or update weights after each batch (here you have only one batch also).
To have a look at the loss during training, you can change your fit method that way:
model.fit(xs, ys, {
callbacks: {
onEpochEnd: (epoch, log) => {
// display loss
console.log(epoch, log.loss);
}
}}).then(() => {
// make the prediction after one epoch
})
To get accurate prediction, you can increase the number of epochs
model.fit(xs, ys, {
epochs: 50,
callbacks: {
onEpochEnd: (epoch, log) => {
// display loss
console.log(epoch, log.loss);
}
}}).then(() => {
// make the prediction after one epoch
})
Here is a snippet which shows how increasing the number of epochs will help the model to perform well
// Define a model for linear regression.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
// Prepare the model for training: Specify the loss and the optimizer.
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});
// Generate some synthetic data for training.
const xs = tf.tensor1d([1, 2, 3, 4]);
const ys = tf.tensor1d([1, 2, 3, 4]);
// Train the model using the data.
model.fit(xs, ys, {
epochs: 50,
callbacks: {
onEpochEnd: (epoch, log) => {
console.log(epoch, log.loss);
}
}}).then(() => {
// Use the model to do inference on a data point the model hasn't seen before:
// Open the browser devtools to see the output
const output = model.predict(tf.tensor2d([6], [1,1]));
output.print();
});
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/tensorflow/0.12.4/tf.js"> </script>
</head>
<body>
</body>
</html>
Your training data needs to be one more dimension, than your model shape to reflect training batches. So x and y need to be at least 2D.

Using tensorflow.js to predict movie desirability based on genre

using the default basic example of tensorflow.js website I'm trying to change it so by giving it an array that specifies movie genres it can predict if I will like the movie or not:
// Define a model for linear regression.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
// Prepare the model for training: Specify the loss and the optimizer.
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});
// Generate some synthetic data for training.
//[action, adventure, romance]
const xs = tf.tensor1d([1,1,0]);
//target data should be rating from 1 to 5
const ys = tf.tensor1d([3]);
// Train the model using the data.
model.fit(xs, ys).then(() => {
// Use the model to do inference on a data point the model hasn't seen before:
// Open the browser devtools to see the output
model.predict(tf.tensor2d([1,0,0])).print();
});
however, regarding the const ys = tf.tensor1d([3]); it throws an error telling me that Input Tensors should have the same number of samples as target Tensors. Found 3 input sample(s) and 1 target sample(s), but I want a prediction from an array[3] to a number from 1 to 5 and I don't know how to achieve this using this sample
The number of samples should match the number of targets, otherwise model can not learn. I updated your example, added another sample, and another target, and corrected the shapes.
// Define a model for linear regression.
const model = tf.sequential();
model.add(tf.layers.dense({ units: 1, inputDim: 3 }));
// Prepare the model for training: Specify the loss and the optimizer.
model.compile({ loss: 'meanSquaredError', optimizer: 'sgd' });
// Generate some synthetic data for training.
//[action, adventure, romance]
const xs = tf.tensor2d([[1, 1, 0], [1, 0, 1]]);
//target data should be rating from 1 to 5
const ys = tf.tensor2d([[3], [2]]);
// Train the model using the data.
model.fit(xs, ys).then(() => {
// Use the model to do inference on a data point the model hasn't seen before:
// Open the browser devtools to see the output
model.predict(tf.tensor2d([[1, 0, 0]])).print();
});
this compiles and produces the following result:
Tensor
[[1.6977279],]

Categories