LSTM: Figuring out the library? - machine-learning

I'm using the library https://github.com/cazala/synaptic
I am trying to predict the next value (value X) in the following series:
0 0 0 1 0 0 0 1 0 0 0 X
Which should be a 1.
Here is the code:
const options = {
peepholes: Layer.connectionType.ALL_TO_ALL,
hiddenToHidden: false,
outputToHidden: false,
outputToGates: false,
inputToOutput: true,
};
// 1 input, 3 hidden layers (4 nodes per layer), 1 output
const lstm = new Architect.LSTM(1, 4, 4, 4, 1, options);
const trainingArray = [
{
input: [0],
output: [0],
},
{
input: [0],
output: [0],
},
{
input: [0],
output: [1],
},
{
input: [1],
output: [0],
},
{
input: [0],
output: [0],
},
{
input: [0],
output: [0],
},
{
input: [0],
output: [1],
},
{
input: [1],
output: [0],
},
];
const trainingOptions = {
rate: 0.1,
iterations: 100000,
error: 0.05,
cost: null,
crossValidate: null,
};
let results = lstm.trainer.train(trainingArray, trainingOptions);
console.log(results);
array = [
0,
0,
0,
1,
0,
0,
0,
1,
0,
0,
0,
];
results = lstm.activate(array);
console.log(results);
The output in the console:
{ error: 0.049765018466871494, iterations: 673, time: 392 }
[ 0.05010961302724895 ]
I was expecting the result of the activation to be a value closer to 1 than 0 (much closer). I don't know if this is the library of my lack of knowledge with LSTM. Can someone point me in the correct direction?

I read through the source code and figured it out.
const synaptic = require('synaptic');
const Architect = synaptic.Architect;
const Layer = synaptic.Layer;
const lstmOptions = {
peepholes: Layer.connectionType.ALL_TO_ALL,
hiddenToHidden: false,
outputToHidden: false,
outputToGates: false,
inputToOutput: true,
};
const lstm = new Architect.LSTM(1, 4, 4, 4, 1, lstmOptions);
const trainSet = [
{ input: [0], output: [0.1] },
{ input: [1], output: [0.2] },
{ input: [0], output: [0.3] },
{ input: [1], output: [0.4] },
{ input: [0], output: [0.5] },
];
const trainOptions = {
rate: 0.2,
iterations: 10000,
error: 0.005,
cost: null,
crossValidate: null,
};
const trainResults = lstm.trainer.train(trainSet, trainOptions);
console.log(trainResults);
const testResults = [];
testResults[0] = lstm.activate([0]);
testResults[1] = lstm.activate([1]);
testResults[2] = lstm.activate([0]);
testResults[3] = lstm.activate([1]);
testResults[4] = lstm.activate([0]);
console.log(testResults);
Results in:
{ error: 0.004982436660844655, iterations: 2010, time: 384 }
[ [ 0.18288280009908592 ],
[ 0.2948083898027347 ],
[ 0.35061782593064206 ],
[ 0.3900799575806566 ],
[ 0.49454852760556606 ] ]
Which is accurate.

Related

WebGL: Converting JSON IFS 3D Model Data to Float32Arrays

I have a project I'm working on that involves rendering 3D models in WebGL, GitHub here. In pulling together several different resources, I've found two different formats for the model data: one with JSON entries like so:
var houseIFS =
{
"vertices": [
[ 2, -1, 2 ],
[ 2, -1, -2 ],
[ 2, 1, -2 ],
[ 2, 1, 2 ],
[ 1.5, 1.5, 0 ],
[ -1.5, 1.5, 0 ],
[ -2, -1, 2 ],
[ -2, 1, 2 ],
[ -2, 1, -2 ],
[ -2, -1, -2 ]
],
"faces": [
[ 0, 1, 2, 3 ],
[ 3, 2, 4 ],
[ 7, 3, 4, 5 ],
[ 2, 8, 5, 4 ],
[ 5, 8, 7 ],
[ 0, 3, 7, 6 ],
[ 0, 6, 9, 1 ],
[ 2, 1, 9, 8 ],
[ 6, 7, 8, 9 ]
],
"normals": [
[ 1, 0, 0 ],
[ 0.7071, 0.7071, 0 ],
[ 0, 0.9701, 0.2425 ],
[ 0, 0.9701, -0.2425 ],
[ -0.7071, 0.7071, 0 ],
[ 0, 0, 1 ],
[ 0, -1, 0 ],
[ 0, 0, -1 ],
[ -1, 0, 0 ]
],
"faceColors": [
[ 1, .8, .8 ],
[ .7, .7, 1 ],
[ 0, 0, 1 ],
[ 0, 0, .7 ],
[ .7, .7, 1 ],
[ 1, 0, 0 ],
[ .4, .4, .4 ],
[ 1, 0, 0 ],
[ 1, .8, .8 ],
]
};
and another with more primitive return types:
/** The return value of each function is an object, model, with properties:
*
* model.vertexPositions -- the vertex coordinates;
* model.vertexNormals -- the normal vectors;
* model.vertexTextureCoords -- the texture coordinates;
* model.indices -- the face indices.
*
* The first three properties are of type Float32Array, while
* model.indices is of type Uint16Array.
*/
I tried to create a method to convert the data from the "modern" version to the "primitive":
function convertPoly(model) {
return {
vertexPositions: new Float32Array(model.vertices),
vertexNormals: new Float32Array(model.normals),
vertexTextureCoords: new Float32Array(model.faces),
indices: new Uint16Array(model.faces)
}
}
but I don't think this is correct, and I don't see anything rendered after trying to render it. How can I compute indices from the vertices or faces? I guess I don't really understand what the indices really represent or how they work (is it triangle vertices of the faces?).

Could not feed my convolution1d with csv data

I need a help for my following problem.
I'm trying to feed my csv data to my first layer which is convolution1d but it shows
Input 0 is incompatible with layer conv1d_Conv1D1: expected ndim=3, found ndim=2
Here is my code
//move the tfjs_binding.node file in build-tmp-napi-v7/Release folder to build-tmp-napi-v7 folder will solve the problem.
const dfd = require("danfojs-node");
const tf = require("#tensorflow/tfjs-node");
var petData;
const TIME_STEPS = (24 * 60) / 60;
console.log("start");
var model = tf.sequential();
model.add(
tf.layers.conv1d({
filters: 3,
kernelSize: 3,
inputShape:[1]
})
);
// model.add(tf.layers.dropout({ rate: 0.2 }));
// model.add(
// tf.layers.conv1d({
// filters: 16,
// kernelSize: 7,
// padding: "same",
// strides: 2,
// activation: "relu",
// })
// );
// model.add(
// tf.layers.conv1d({
// filters: 16,
// kernelSize: 7,
// padding: "same",
// strides: 2,
// activation: "relu",
// })
// );
// model.add(tf.layers.dropout({ rate: 0.2 }));
// model.add(
// tf.layers.conv1d({
// filters: 32,
// kernelSize: 7,
// padding: "same",
// strides: 2,
// activation: "relu",
// })
// );
// model.add(
// tf.layers.conv1d({
// filters: 1,
// kernelSize: 7,
// padding: "same",
// })
// );
model.compile({
optimizer: tf.train.adam((learningRate = 0.001)),
loss: tf.losses.meanSquaredError,
});
model.summary();
console.log("model created.");
dfd
.read_csv("./petTempData.csv", (chunk = 10000))
.then((df) => {
let encoder = new dfd.LabelEncoder();
let cols = ["Date", "Time"];
cols.forEach((col) => {
encoder.fit(df[col]);
enc_val = encoder.transform(df[col]);
df.addColumn({ column: col, value: enc_val });
});
petData = df.iloc({ columns: [`1`] });
yData = df["Temperature"];
// let scaler = new dfd.MinMaxScaler();
// scaler.fit(petData);
// petData = scaler.transform(petData);
// petData = petData.tensor.expandDims(-1);
// const data = petData.tensor.reshape([24, 2, 1]);
console.log(petData.shape);
model.fit(petData.tensor, yData.tensor, {
epochs: 10,
batchSize: 4,
// validationSplit: 0.01,
callbacks: tf.callbacks.earlyStopping({
monitor: "loss",
patience: "5",
mode: "min",
}),
});
})
.catch((err) => {
console.log(err);
});
And here is my csv raw file
Date,Time,Temperature
31-12-2020,01:30,36.6
31-12-2020,02:30,36.7
31-12-2020,03:30,36.6
31-12-2020,04:30,36.5
31-12-2020,05:30,36.8
31-12-2020,06:30,36.6
31-12-2020,07:30,36.6
31-12-2020,08:30,36.5
31-12-2020,09:30,36.6
31-12-2020,10:30,36.7
31-12-2020,11:30,36.6
31-12-2020,12:30,36.7
31-12-2020,13:30,36.7
31-12-2020,14:30,36.8
31-12-2020,15:30,36.9
31-12-2020,16:30,36.6
31-12-2020,17:30,36.7
31-12-2020,18:30,36.8
31-12-2020,19:30,36.7
31-12-2020,20:30,36.6
31-12-2020,21:30,36.6
31-12-2020,22:30,36.5
31-12-2020,23:30,36.5
,,
I've tried to reshape my input, and expandDims but none of them work.
Any solution is much appreciated!
The conv1d layer expects an inputShape of dim 2, therefore, the inputShape needs to be [a, b](with a, b positive integers).
model = tf.sequential();
model.add(
tf.layers.conv1d({
filters: 3,
kernelSize: 1,
inputShape:[1, 3]
})
);
model.predict(tf.ones([1, 1, 3])).print()

Show Series and colorAxis both in Legend

Is it possible to have both colorAxis and series in the legend? http://jsfiddle.net/6k17dojn/ i see i can only show one at a time when I toggle this setting
colorAxis: {
showInLegend: true,
}
Currently to show a basic legend with colorAxis, you need to add some code to Highcharts core. This plugin below allows you to add colorAxis to a legend if showInLegend property is set to false:
(function(H) {
H.addEvent(H.Legend, 'afterGetAllItems', function(e) {
var colorAxisItems = [],
colorAxis = this.chart.colorAxis[0],
i;
if (colorAxis && colorAxis.options) {
if (colorAxis.options.dataClasses) {
colorAxisItems = colorAxis.getDataClassLegendSymbols();
} else {
colorAxisItems.push(colorAxis);
}
}
i = colorAxisItems.length;
while (i--) {
e.allItems.unshift(colorAxisItems[i]);
}
});
}(Highcharts))
Live demo: http://jsfiddle.net/BlackLabel/hs1zeruy/
API Reference: https://api.highcharts.com/highcharts/colorAxis.showInLegend
Docs: https://www.highcharts.com/docs/extending-highcharts
It's possible, but not with the data you currently work with. A heatmap's data is a set of coordinates, but here, your two series overlap.
Your raw data is :
[
[0,0,0.2, 0.4],
[0,1,0.1, 0.5],
[0,2,0.4, 0.9],
[0,3,0.7, 0.1],
[0,4,0.3, 0.6]
]
From there, you're mapping two series: 2018, and 2019 via the seriesMapping: [{x: 0, y: 1, value: 2}, {x: 0, y: 1, value: 3}] option.
You thus end up with the following two series:
2018 2019 2019 should be
[ [ [
[0, 0, 0.2], [0, 0, 0.4], [1, 0, 0.4],
[0, 1, 0.1], [0, 1, 0.5], [1, 1, 0.5],
[0, 2, 0.4], [0, 2, 0.9], [1, 2, 0.9],
[0, 3, 0.7], [0, 3, 0.1], [1, 3, 0.1],
[0, 4, 0.3] [0, 4, 0.6] [1, 4, 0.6]
] ] ]
Notice that in both cases, the coordinates are the same, but for 2019, the x value should be 1. Since you have 0 as x coordinate for both series, they overlap.
To fix you issue, you need to change your data (or pre-process it, whatever is easier). For example:
var data = '[[0,0,0.2, 0.4],[0,1,0.1, 0.5],[0,2,0.4, 0.9],[0,3,0.7, 0.1],[0,4,0.3, 0.6]]';
var rows = JSON.parse(data);
rows = $.map(rows, function(arr){
return [[
arr[0], arr[1], arr[2], // 2018
arr[0] + 1, arr[1], arr[3], // 2019
]];
});
// and the seriesMapping changes to
data: {
rows: rows,
firstRowAsNames: false,
seriesMapping: [{x: 0, y: 1, value: 2}, {x: 3, y: 4, value: 5}]
},
You can see it in action here: http://jsfiddle.net/Metoule/qgd2ca6p/6/

How to visualize a set of identical flows?

I have data which can be interpreted as from a to b to c:
[
["hello", "world", "10"],
["hello", "world", "10"],
["hello", "wazaa", "10"],
["bonjour", "wazaa", "30"],
]
The same flow can be repeated (first two examples) and any combination is possible.
A chart which could be used to show these flows is parallel-coordinates: there is always the same number of columns and each flow can be tracked (as opposed to sankey which aggregates each input column).
The problem I have with parallel-coordinates is that multiple identical entries will stack (I guess) and the fact there are duplicates will not appear.
Is there a way to change the width of the line to indicate that several identical data lines were used? Or to provide a count of the identical entries which would be reflected in the width (or, worst case, color)?
You can preprocess your data and set higher lineWidth value for series with repeating data:
var series = [{
data: [0, 0, 10]
},
{
data: [0, 0, 10]
},
{
data: [0, 0, 10]
},
{
data: [0, 0, 10]
},
{
data: [0, 1, 10]
},
{
data: [1, 1, 30]
}
],
j = series.length - 1,
dataLength = series[0].data.length,
i;
for (; j > 0; j--) {
i = 0;
for (; i < dataLength; i++) {
if (series[j].data[i] === series[j - 1].data[i]) {
if (i === dataLength - 1) {
series[j - 1].lineWidth = series[j].lineWidth ?
series[j].lineWidth + 1 : 2
series.splice(j, 1);
}
} else {
i = dataLength;
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/4pth15yf/
API: https://api.highcharts.com/highcharts/series.line.lineWidth

Highcharts: Stacked bar chart display categories data, not series

I have two JS associative arrays that look like this:
var distroDates = [
{
name: 'exDate',
data: [
'06/25/2013',
'12/17/2012',
'06/20/2012',
'12/19/2011',
'06/21/2011',
'12/20/2010',
'06/21/2010',
'12/21/2009',
'06/22/2009',
'12/22/2008',
'06/23/2008',
'12/24/2007',
'12/21/2006',
'12/23/2005',
'12/23/2004',
'12/22/2003',
'12/23/2002'
]
},
{
name: 'Record Date',
data: [
'06/27/2013',
'12/19/2012',
'06/22/2012',
'12/21/2011',
'06/23/2011',
'12/22/2010',
'06/23/2010',
'12/23/2009',
'06/24/2009',
'12/24/2008',
'06/25/2008',
'12/27/2007',
'12/26/2006',
'12/28/2005',
'12/28/2004',
'12/24/2003',
'12/26/2002'
]
},
{
name: 'Payable Date',
data: [
'07/02/2013',
'12/24/2012',
'06/27/2012',
'12/29/2011',
'06/27/2011',
'12/30/2010',
'06/25/2010',
'12/31/2009',
'06/26/2009',
'12/31/2008',
'06/27/2008',
'01/04/2008',
'12/28/2006',
'12/30/2005',
'12/30/2004',
'01/02/2004',
'01/02/2003'
]
}
]
var distroData = [
{
name: 'Income',
data: [
0.3908,
0.4948,
0.2311,
0.3342,
0.245,
0.2213,
0.19,
0.1404,
0.2014,
0.2266,
0.2131,
0.2328,
0.1288,
0.0044,
0.6248,
0,
0
]
},
{
name: 'S.T. Capital Gains',
data: [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
{
name: 'L.T. Capital Gains',
data: [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
{
name: 'Return on Capital',
data: [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0.0202,
0,
0,
0
]
}
]
The distroData array is used for the series. The distroDates is used for the categories. I want the categories to display in the tooltip (rather than the usual series data) and I want the tooltip to update with the category values as I hover over each bar along the x-axis.
The following code accomplished this using Highcharts v2.1.4/Highstock v1.2.5 (both are loaded):
tooltip: {
formatter: function() {
var s = '<table class="tooltip distro"><tbody>';
var chart = this.points[0].series.chart; //get the chart object
var categories = chart.xAxis[0].categories; //get the categories array
var index = 0;
var distroDataPoint;
while(this.x !== categories[index]){index++;} //compute the index of corr y value in each data arrays
$.each(distroDates, function(i, categories) { //loop through categories array
s += '<tr><td>'+ categories.name +':</td><td>' + categories.data[index] + '</td></tr>'; //use index to peg categories and distro data to series
distroDataPoint = '<tr><td>Distribution:</td><td>$' + distroData[0].data[index] + '</td></tr>';
});
s += distroDataPoint + '</tbody></table>'
return s;
},
shared: true
},
However, when I upgraded to Highstock 1.3.4 (which includes Highcharts) the while statement locked my browser (FF and Chrome). The browser gave the familiar "Script is non-responsive" alert I assume because it was caught in an expensive loop.
Any ideas how I can rewrite or substitute the while so that performance is acceptable?
Why don't you just use shared tooltip? Just set tooltip.shared = true and everything will work fine. See example how to format shared tooltip here.

Resources