In order to implement this case in Java, we had to make some adjustments in the already written code. The NeuralNet
class is updated with a new method called getNetOutputValues()
, to give some output values given a training input dataset. This method performs almost the same operation as the forward method in the backpropagation phase, except for the fact that it returns a matrix containing the output dataset.
In addition, we had to add two components to the project (package edu.packt.neuralnet.util
): data and chart.
Charts can be drawn in Java by using the freely available package JFreeChart (http://www.jfree.org/jfreechart/). This package is attached with this chapter's source code. So, we designed a class called Chart
. It implements methods basically for plotting data series by making calls to natively implemented methods of the JFreeChart classes. The following table shows a list of methods contained in this class:
Class name: Chart | |
Attributes | |
public enum ChartPlotTypeENUM { FULL_DATA, COMPARISON; }
|
Enum to store chart types may be plotted |
Methods | |
public void plotXYData(Object[] vector, String chartTitle, String xAxisLabel, String yAxisLabel)
|
Method to plot XY chart based on a data vector |
Parameters: Vector with data to plot, chart title, x-axis label, and y-axis label | |
Returns: - | |
public void plotXYData(double[][] matrix, String chartTitle, String xAxisLabel, String yAxisLabel, ChartPlotTypeENUM chartPlotType)
|
Method to plot XY chart based on a data matrix |
Parameters: Matrix with data to plot, chart title, x-axis label, y-axis label, and plot type | |
Returns: - | |
private String selectComparisonSeriesName(int index)
|
Method to select comparison series name |
Parameters: Index | |
Returns: Series name | |
private String selectTemperatureSeriesName(int index)
|
Method to select temperature series name |
Parameters: Index | |
Returns: Series name | |
Class Implementation with Java: file Chart.java |
To work with data files, we have to implement a class called Data
. It currently performs reads from the so-called CSV format, which is suitable for data import and export. This class also performs preprocessing on the data by means of normalization.
Class name: Data | |
Attributes | |
private String path;
|
Variable to store the CSV file folder path |
private String fileName;
|
Attribute to store the CSV file name (with extension) |
public enum NormalizationTypesENUM { MAX_MIN, MAX_MIN_EQUALIZED; }
|
Enum to store normalization types may be used |
Constructors | |
public Data(String path, String fileName)
|
Constructor to set path and filename attributes |
public Data( )
|
Empty constructor to create an empty object |
Methods | |
Note: The getters and setters methods of this attribute were created too. | |
public double[][] rawData2Matrix(Data r) throws IOException
|
Method to read raw data (CSV file) and convert to a double Java matrix |
Parameters: Data object | |
Returns: Double matrix with raw data | |
private String defineAbsoluteFilePath(Data r) throws IOException
|
Method to define the absolute CSV file path |
Parameters: Data object | |
Returns: String with the absolute CSV file path | |
public double[][] normalize(double[][] rawMatrix, NormalizationTypesENUM normType)
|
Method to normalize a raw data matrix |
Parameters: Double raw data matrix, normalization type | |
Returns: Double matrix normalized | |
public double[][] denormalize(double[][] rawMatrix, double[][] matrixNorm, NormalizationTypesENUM normType)
|
Method to denormalize a raw data matrix |
Parameters: Double raw data matrix, double normalized matrix, normalization type | |
Returns: Double matrix denormalized | |
public double[][] joinArrays(ArrayList<double[][]> listOfArraysToJoin)
|
Method to join arrays (vectors) into a matrix |
Parameters: List of arrays | |
Returns: Double matrix | |
Class implementation with Java: file |
To forecast weather, we collected daily data from the Brazilian Institute of Meteorology (INMET). The data was measured from a Brazilian city located in the Amazon region.
From the eight variables available at the INMET website, five were selected for use in this project, where the average of the maximum and the minimum temperature became the mean temperature variable. The neural network was trained to forecast the average temperature. So, the structure of the neural network is as shown in the following figure:
We designed a class called Weather
exclusively for the weather case. It only has a static main method and is solely aimed at reading the weather data files, creating and training a neural network with this data, and plotting the error for validation. Let's take a glance at how the data files are read inside this class:
Data weatherDataInput = new Data( "data", "inmet_13_14_input.csv" ); Data weatherDataOutput = new Data( "data", "inmet_13_14_output.csv" ); //sets the normalisation type NormalizationTypesENUM NORMALIZATION_TYPE = Data.NormalizationTypesENUM.MAX_MIN_EQUALIZED; try { double[][] matrixInput = weatherDataInput.rawData2Matrix( weatherDataInput ); double[][] matrixOutput = weatherDataOutput.rawData2Matrix( weatherDataOutput ); //normalise the data double[][] matrixInputNorm = weatherDataInput.normalize( matrixInput, NORMALIZATION_TYPE ); double[][] matrixOutputNorm = weatherDataOutput.normalize( matrixOutput, NORMALIZATION_TYPE );
Then, the main method builds a neural network with four hidden neurons and sets the training dataset, as shown in the following code:
NeuralNet n1 = new NeuralNet(); n1 = n1.initNet(4, 1, 4, 1); n1.setTrainSet( matrixInputNorm ); n1.setRealMatrixOutputSet( matrixOutputNorm ); n1.setMaxEpochs( 1000 ); n1.setTargetError( 0.00001 ); n1.setLearningRate( 0.5 ); n1.setTrainType( TrainingTypesENUM.BACKPROPAGATION ); n1.setActivationFnc( ActivationFncENUM.SIGLOG ); n1.setActivationFncOutputLayer(ActivationFncENUM.LINEAR); NeuralNet n1Trained = new NeuralNet(); n1Trained = n1.trainNet( n1 ); System.out.println();
Here, the network is trained, and then, the charts of the error are plotted. The following lines show how the chart class is used:
Chart c1 = new Chart(); c1.plotXYData( n1.getListOfMSE().toArray(), "MSE Error", "Epochs", "MSE Value" ); //TRAINING: double[][] matrixOutputRNA = n1Trained.getNetOutputValues( n1Trained ); double[][] matrixOutputRNADenorm = new Data().denormalize( matrixOutput, matrixOutputRNA, NORMALIZATION_TYPE); ArrayList<double[][]> listOfArraysToJoin = new ArrayList<double[][]>(); listOfArraysToJoin.add( matrixOutput ); listOfArraysToJoin.add( matrixOutputRNADenorm ); double[][] matrixOutputsJoined = new Data().joinArrays( listOfArraysToJoin ); Chart c2 = new Chart(); c2.plotXYData( matrixOutputsJoined, "Real x Estimated - Training Data", "Weather Data", "Temperature (Celsius)", Chart.ChartPlotTypeENUM.COMPARISON );
In the following graph, it is possible to see the MSE training error plotted. The x-axis represents 1000 points (epochs of training), and the y-axis shows the variation of the MSE values. It is noticed that before the 100th epoch, the MSE value establishes.
Another graph is displayed next. It shows a comparison between the real (red line) and the estimated (blue line) average temperature. Dotted black lines symbolize the margins of error (-1.0 °C and +1.0 °C).