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.
Related
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.
<html>
<body id='body'>
<button onclick="StartData(event)"> Start</button>
<button onclick="getStopCordinates(event)">Stop</button>
<script>
let inputs = [];
let labels = [];
function Mouse(event) {
inputs.push({ x: event.clientX, y: event.clientY })
}
function StartData() {
document.getElementById('body').addEventListener("mouseover", Mouse())
}
function getStopCordinates(event) {
labels.push({ x: event.clientX, y: event.clientY })
document.getElementById('body').removeEventListener("mouseover", Mouse())
}
</script>
</body>
</html>
I am using above code to capture all the x y coordinates of the mouse in the body . When the user moves the pointer towards the stop button i am capturing all the x,y coordinates for this . and when user clicks stop i am capturing stop coordinates also . now i want to train the tensorflow js model from the captured points so that when user moves the mouse with same trajectory i can predict that he will click the stop button .
tensorflow code :
const model = tf.sequential();
// Add a single hidden layer
model.add(tf.layers.dense({inputShape: [2], units: 1, useBias: true}));
// Add an output layer
model.add(tf.layers.dense({units: 1, useBias: true}));
const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
trainModel(model,inputs,labels)
async function trainModel(model, inputs, labels) {
// Prepare the model for training.
model.compile({
optimizer: tf.train.adam(),
loss: tf.losses.meanSquaredError,
metrics: ['mse'],
});
const batchSize = 32;
const epochs = 50;
return await model.fit(inputs, labels, {
batchSize,
epochs,
shuffle: true,
callbacks: tfvis.show.fitCallbacks(
{ name: 'Training Performance' },
['loss', 'mse'],
{ height: 200, callbacks: ['onEpochEnd'] }
)
});
}
but this code gives error as the inputs and labels are not the same so how to correct this code for the above result ?
The inputs and labels should be an array of array and not an array of object. The inputs should rather be
[[1, 2], [4, 6], ...]
The same thing holds for the labels.
Since your are predicting 2 values, the last layer should have as number of units 2
const model = tf.sequential();
// Add a single hidden layer
model.add(tf.layers.dense({inputShape: [2], units: 1, useBias: true}));
// Add an output layer
model.add(tf.layers.dense({units: 1, useBias: true}));
The last thing - surely not the least - is to add activation in order to add non linearity to the model
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.
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 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],]