Tensorflow.js inconsistent prediction, returns 0 or works as intended - tensorflow.js

I'm trying to do a simple Tensorflow.js linear model but I get inconsistent results. It will either return 0 for any input value entered, or it will work as intended (for example if I enter 11 for the input it returns close to 110).
When the page loads up it either works or it doesn't. I can get it to work if I refresh the page 3 or 4 times. Once it works it seems to keep working.
What am I doing wrong?
import {Component, OnInit} from '#angular/core';
import * as tf from '#tensorflow/tfjs';
#Component({
selector: 'app-linear-model',
templateUrl: './linear-model.component.html',
styleUrls: ['./linear-model.component.css']
})
export class LinearModelComponent implements OnInit {
title = 'Linear Model example';
linearModel: tf.Sequential;
prediction: any;
xData: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
yData: number[] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
constructor() {
}
ngOnInit() {
this.trainNewModel();
}
async trainNewModel() {
// this is based on the following tutorial:
// https://angularfirebase.com/lessons/tensorflow-js-quick-start/#Step-2-Install-Tensorflow-js
const learningRate = 0.01;
const optimizerVar = tf.train.sgd(learningRate);
// Define a model for linear regression.
this.linearModel = tf.sequential();
this.linearModel.add(tf.layers.dense({units: 1, inputShape: [1], activation: 'relu'}));
// Prepare the model for training: Specify the loss and the optimizer.
this.linearModel.compile({loss: 'meanSquaredError', optimizer: optimizerVar});
// Training data defined at top
const x = tf.tensor1d(this.xData);
const y = tf.tensor1d(this.yData);
// Train
await this.linearModel.fit(x, y, {epochs: 10});
console.log('model trained!');
}
predict(val) {
val = parseFloat(val);
const output = this.linearModel.predict(tf.tensor2d([val], [1, 1])) as any;
this.prediction = Array.from(output.dataSync())[0];
console.log(output.toString());
}
}

Your issue has to do with the random initialization of the kernel of the dense layer.
Given the value of the weights and the bias, it might happen that the learning rate causes the loss not to decrease. One can keep track of the loss value and if that happens to lower the learning rate.
Another way to solve the issue would be to set an initializer matrix for the dense layers.
this.linearModel.add(tf.layers.dense({units: 1, inputShape: [1], activation: 'relu', kernelInitializer:'ones'}
live code here

Related

My react native tensorflow model gives the same prediction every result

I have trained a keras model with 6 classes for CNN Image Recognition. Then, I converted it to tensorflowjs using this command:
tensorflowjs_converter --quantization_bytes 1 --input_format=keras {saved_model_path} {target_path}
which then gives me 2 files (model.json, group1-shard1of1.bin). After adding it to my react native project and test the prediction function, it always returns the same result. I am converting my image to tensor base on this github thread:
const processImagePrediction = async (base64Image: any) => {
const fileUri = base64Image.uri;
const imgB64 = await FileSystem.readAsStringAsync(fileUri, {
encoding: FileSystem.EncodingType.Base64,
});
const imgBuffer = tf.util.encodeString(imgB64, 'base64').buffer;
const raw = new Uint8Array(imgBuffer);
let imageTensor = decodeJpeg(raw);
const scalar = tf.scalar(255);
imageTensor = tf.image.resizeNearestNeighbor(imageTensor, [224, 224]);
const tensorScaled = imageTensor.div(scalar);
//Reshaping my tensor base on my model size (224, 224)
const img = tf.reshape(tensorScaled, [1, 224, 224, 3]);
console.log("IMG: ", img);
const results = model.predict(img);
let pred = results.dataSync();
console.log("PREDICTION: ", pred);
}
I was expecting to have a different result but no matter what image I capture it always returns this result:
LOG IMG: {"dataId": {"id": 23}, "dtype": "float32", "id": 38, "isDisposedInternal": false, "kept": false, "rankType": "4", "scopeId": 6, "shape": [1, 224, 224, 3], "size": 150528, "strides": [150528, 672, 3]} LOG PREDICTION: [-7.7249579429626465, 4.73449182510376, 2.609705924987793, 20.0458927154541, -7.944214344024658, -18.101320266723633]
The numbers somehow change slightly but it retains the highest prediction (which is class number 4).
P.S. I'm new to image recognition so any tips would be appreciated.

Typescript Convert Enum to Constant Class

How do I convert an Enum to a Constant Class like this, in Typescript? Currently using React Typescript, with functional components .
This question is slightly different: TypeScript enum to object array
export enum ProductStatus {
Draft = 1,
Review = 2,
Approved = 3,
Rejected = 4,
Billed = 5,
Collected = 6,
Unpayable = 7,
WorkInProgress = 8,
ReadyToReview = 9,
NeedsRevision = 10,
Failed = 11,
}
export const ProductStatus = {
Draft: 1,
Review: 2,
Approved: 3,
Rejected: 4,
Billed: 5,
Collected: 6,
Unpayable: 7,
WorkInProgress: 8,
ReadyToReview: 9,
NeedsRevision: 10,
Failed: 11,
};
loop throught the keys and use ethe reduce function
const newConst = React.useMemo(() => {
return Object.keys(ProductStatus).reduce((acc, key) => {
if (isNaN(Number(key))) {
acc[key] = ProductStatus[key];
}
return acc;
}, {});
}, []);
console.log(newConst );
https://stackblitz.com/edit/react-ts-ivfxqw?file=App.tsx
We can use Object.values to get the values from the enum and convert them to an object using reduce.
const ProductStatusObject = Object.values(ProductStatus)
.filter((v): v is keyof typeof ProductStatus => typeof v !== "number")
.reduce((p, c) => {
p[c] = ProductStatus[c]
return p
}, {} as Record<keyof typeof ProductStatus, number>)
ProductStatusObject
// ^? Record<"Draft" | "Review" | "Approved" | ..., number>
As you may know, enums contain a mapping in both directions. We need to filter out the values which are not of type string to only get the keys of the enum. The filter callback also needs a type predicate to indicate to TypeScript that the resulting array only contains values of type keyof typeof ProductStatus.
The reduce method takes the elements of the array and assigns them as keys to an object using the corresponding enum value. I typed the object as Record<keyof typeof ProductStatus, number> to get a useful return type.
console.log(ProductStatusObject)
/*
{
"Draft": 1,
"Review": 2,
"Approved": 3,
"Rejected": 4,
"Billed": 5,
"Collected": 6,
"Unpayable": 7,
"WorkInProgress": 8,
"ReadyToReview": 9,
"NeedsRevision": 10,
"Failed": 11
}
*/
Playground

nested object, array combination

So I have a dilemma.
I have the next code
const loc = [
{ location_key: [32, 22, 11], autoassign: 1 },
{ location_key: [41, 42], autoassign: 1 }
];
const bulkConfigs = [
{
dataValues: {
config_key: 100,
}
},
{
dataValues: {
config_key: 200,
}
}
];
I need to create an object looking like this:
config_key: here get the config key from from bulkConfigs,
location_key: here get the location_key,
autoassign: 1
Also I need this object created
config_key: config_key,
location_key: '',
autoassign: 1,
as many times as they are locations for each config_key, what I mean is in this example from config_key: 200 we will have 2 objects like this one and for config_key: 100 we will have 3 objects like this. I suppose this can be done with reduce ... also bulkConfigs and loc can have more then just 2 objects, but the number will be always the same, like if they are 3 bulkConfigs there will be also 3 loc, but location_key might be different, one can have 7 location_key, other 4, and the last one just 1.
So in other words, the arrys are always the same length and they are always in the same order so they have the same index. Only the location_key can change, and I need the object created as many times as location_key exist.
I have tried a few things, but I don't know when it comes to this stuff .... I just can't do, that's what happens when you start with react and not java script :)
Ok so I managed to do this using lodash, here is my solution, I know it's nested like hell and probably this could be done way easier, but for a newbie is good enough. Feel free to come with more elegant solutions.
If you have a similar problem, here is the solution.
A code sandbox so you can play with:
https://codesandbox.io/s/epic-field-bdwyi?file=/src/index.js
import _ from "lodash";
const locs = [{ location_key: [32, 22, 11] }, { location_key: [41, 42] }];
const bulkConfigs = [
{
dataValues: {
config_key: 100
}
},
{
dataValues: {
config_key: 200
}
}
];
// map over the array of bulckConfigs and get indexes
const mergedArrays = _.map(bulkConfigs, (bulkConfig, i) => {
// create the object that we need
const objectNeed = {
// flatMap over the locs array to get flat values from objects in it
location_key: _.flatMap(locs, ({ location_key }, index) => {
// match the indexs of both arrays
if (index === i) {
// return the location_key values for each config
return location_key;
} else {
// compact to remove the undefinded values returned
return _.compact();
}
}),
config_key: bulkConfig.dataValues.config_key,
autoassign: 1
};
return objectNeed;
});
// now we just need to crate the same object as many locations and use flatMap to flatten the objects
const allObjects = _.flatMap(mergedArrays, mergedArray => {
const yy = _.map(mergedArray.location_key, location => {
const zz = {
location_key: location,
config_key: mergedArray.config_key,
autoassign: 1
};
return zz;
});
return yy;
});
console.log(allObjects);
And the more elegant version of it :)
const getConfigs = (locEl, index) => {
return _.map(locEl.location_key, (locationKey) => {
return {
location_key: locationKey,
config_key: bulkConfigs[index].dataValues.config_key,
autoassign: 1,
};
});
};
const configLocations = _.chain(locs)
.map(getConfigs)
.flatten()
.value();
console.log(configLocations);

ngOnChanges only triggered on last iteration

I have the following structure:
Data-Handling Component
|
|-- Grid Component
|-- Chart Component
That is Data-Handling Component is the parent of two sibling components: Grid and Chart.
I have an array of numbers which is shared between the three components via #Input() / #Output properties.
When in the Grid component I update a single value of the array, an #Output() property sends the information to the parent Data-Handling component, which in turn, sends the information to the Chart component through one of his #Input() properties.
As such (I've re-written and skipped some of the code, so some syntactic errors might be present):
grid.component.html:
[Not Relevant?]
grid.component.ts:
#Input() gridValues: any[] = [] // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#Output() valueChanged: EventEmitter<any> = new EventEmitter<any>()
updateAllValuesToThree(): void {
for (var i = 0; i < this.gridValues.length; i++) {
this.updateValue(i, 3)
}
}
updateValue(index: number, value: number): void {
let updatedValue: any = {}
updatedValue.index = index
updatedValue.value = value
this.gridValues[index] = value
this.valueChanged.emit(updatedValue)
}
dataHandling.component.html:
<grid (valueChanged)="onValueUpdate($event)"
[gridValues]="dataArray">
</grid>
<chart [chartData]="dataArray"
[individualValueChanged]="individualValueChanged">
</chart>
dataHandling.component.ts:
dataArray: number[] = [] // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
individualValueChanged: any = {}
onValueUpdate(event: any): void {
this.dataArray[event.currentValue.index] = event.currentValue.value
this.individualValueChanged = event.currentValue
}
chart.component.ts:
#Input chartData: number[] = [] // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#Input individualValueChanged: any = {}
ngOnChanges(changes: SimpleChanges): void {
if (changes.individualValueChanged && changes.individualValueChanged.currentValue) {
let changeInfo: any = changes.individualValueChanged.currentValue
this.chartData[changeInfo.index] = changeInfo.value
}
}
chart.component.html:
[Not Relevant?]
Well. If I update a SINGLE value from the Grid to the Chart, everything's OK.
However, when I call the EventEmitter inside the for loop for every element of the gridValues array, only the last element of the array is modified in the chart component's chartData array.
So:
in the Grid component I'd have: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
in the Data-Handling component I'd have: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
in the Chart component I'd have: [1, 2, 3, 4, 5, 6, 7, 8, 9, 3]
Every event fires correctly into the Data-Handling component from the Grid, but only the last update event goes into the Chart component, thus triggering the ngOnChanges().
Is this working as intended? Am I missing something?
This is expected behavior. #Input updates are done during change detection. #Output are processed outside of change detection.
When you trigger an event here:
for (var i = 0; i < this.gridValues.length; i++) {
this.updateValue(i, 3)
}
The following method in data handling component is triggered:
onValueUpdate(event: any): void {
this.dataArray[event.currentValue.index] = event.currentValue.value
this.individualValueChanged = event.currentValue
}
So this method is triggered as many times as you trigger this.updateValue(i, 3). The last value of event.currentValue will be set for this.individualValueChanged.
Only once all events are processed Angular goes through the change detection stage and updates the input individualValueChanged binding which contains the last value.
For more information on change detection read Everything you need to know about change detection in Angular. Also read Two Phases of Angular Applications

Redux - How to add entry to array in reducer

I stuck with this bit and I can't progress - I guess solution is simple but I can't figure out. I'm trying to add entry in reducer so data in in would look something this:
state = {
entryId: {
entryName: ["something", "something2", "something3" /* and so on... */]
}
};
So far this is the closest I get, but, instead of adding new unique entry, it is replacing the one that is stored already. Also I need to be able to add this item to empty state where entryId, entryName doesn't exist yet to avoid error:
switch(type) {
case ADD_ENTRY:
return {
...state,
[entryId]: {
...state[entryId],
[entryName]: {
[uniqueEntry]: true
}
}
};
}
Any idea what I'm doing wrong?
If you're trying to add an element to the end of the entryName array you should be doing:
return {
...state,
[entryId]: {
...state[entryId],
[entryName]: [
...state[entryId][entryName],
uniqueEntry
]
}
};
ES6 spread with arrays works like this:
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const eight = 8;
const newArray = ['stuff', ...array1, 'things', ...array2, ...[7, eight], 9];
console.log(newArray); // ["stuff", 1, 2, 3, "things", 4, 5, 6, 7, 8, 9]
Check out this gist which has an example of something very similar to what you're doing.
I found this set of examples extremely helpful as well. A lot of great stuff in here:
https://github.com/sebmarkbage/ecmascript-rest-spread
Update:
If entryName is initialized to undefined like you say in your comment, you could do this:
return {
...state,
[entryId]: {
...state[entryId],
[entryName]: [
...state[entryId][entryName] || [],
uniqueEntry
]
}
};
I think this is a pretty great example of how painful it can be working with React/redux using a heavily nested data structure. FWIW, it's been recommended to me many times to flatten your state as much as possible.

Resources