%% Train Network with Numeric Features
% This example shows how to create and train a simple neural network for deep learning feature data classification.
% If you have a data set of numeric features (for example a collection of numeric data without spatial or time dimensions), then you can train a deep learning network using a feature input layer. For an example showing how to train a network for image classification, see Create Simple Deep Learning Network for Classification.
% This example shows how to train a network to classify the gear tooth condition of a transmission system given a mixture of numeric sensor readings, statistics, and categorical labels.
%% Load Data
% Load the transmission casing dataset for training. The data set consists of 208 synthetic readings of a transmission system consisting of 18 numeric readings and three categorical labels:
% SigMean — Vibration signal mean
% SigMedian — Vibration signal median
% SigRMS — Vibration signal RMS
% SigVar — Vibration signal variance
% SigPeak — Vibration signal peak
% SigPeak2Peak — Vibration signal peak to peak
% SigSkewness — Vibration signal skewness
% SigKurtosis — Vibration signal kurtosis
% SigCrestFactor — Vibration signal crest factor
% SigMAD — Vibration signal MAD
% SigRangeCumSum — Vibration signal range cumulative sum
% SigCorrDimension — Vibration signal correlation dimension
% SigApproxEntropy — Vibration signal approximate entropy
% SigLyapExponent — Vibration signal Lyap exponent
% PeakFreq — Peak frequency.
% HighFreqPower — High frequency power
% EnvPower — Environment power
% PeakSpecKurtosis — Peak frequency of spectral kurtosis
% SensorCondition — Condition of sensor, specified as "Sensor Drift" or "No Sensor Drift"
% ShaftCondition — Condition of shaft, specified as "Shaft Wear" or "No Shaft Wear"
% GearToothCondition — Condition of gear teeth, specified as "Tooth Fault" or "No Tooth Fault"
% Read the transmission casing data from the CSV file "transmissionCasingData.csv".

filename = "transmissionCasingData.csv";
tbl = readtable(filename,'TextType','String');

% Convert the labels for prediction to categorical using the convertvars function.

labelName = "GearToothCondition";
tbl = convertvars(tbl,labelName,'categorical');

% View the first few rows of the table.

head(tbl)

% To train a network using categorical features, you must first convert the categorical features to numeric. First, convert the categorical predictors to categorical using the convertvars function by specifying a string array containing the names of all the categorical input variables. In this data set, there are two categorical features with names "SensorCondition" and "ShaftCondition".

categoricalInputNames = ["SensorCondition" "ShaftCondition"];
tbl = convertvars(tbl,categoricalInputNames,'categorical');

% Loop over the categorical input variables. For each variable:
% Convert the categorical values to one-hot encoded vectors using the onehotencode function.
% Add the one-hot vectors to the table using the addvars function. Specify to insert the vectors after the column containing the corresponding categorical data.
% Remove the corresponding column containing the categorical data.

for i = 1:numel(categoricalInputNames)
    name = categoricalInputNames(i);
    oh = onehotencode(tbl(:,name));
    tbl = addvars(tbl,oh,'After',name);
    tbl(:,name) = [];
end

% Split the vectors into separate columns using the splitvars function.

tbl = splitvars(tbl);

% View the first few rows of the table. Notice that the categorical predictors have been split into multiple columns with the categorical values as the variable names.

head(tbl)

% View the class names of the data set.

classNames = categories(tbl{:,labelName})

%
%% Split Data Set into Training and Validation Sets
% Partition the data set into training, validation, and test partitions. Set aside 15% of the data for validation, and 15% for testing.
% View the number of observations in the dataset.

numObservations = size(tbl,1)

% Determine the number of observations for each partition.

numObservationsTrain = floor(0.7*numObservations)
numObservationsValidation = floor(0.15*numObservations)
numObservationsTest = numObservations - numObservationsTrain - numObservationsValidation

% Create an array of random indices corresponding to the observations and partition it using the partition sizes.

idx = randperm(numObservations);
idxTrain = idx(1:numObservationsTrain);
idxValidation = idx(numObservationsTrain+1:numObservationsTrain+numObservationsValidation);
idxTest = idx(numObservationsTrain+numObservationsValidation+1:end);

% Partition the table of data into training, validation, and testing partitions using the indices.

tblTrain = tbl(idxTrain,:);
tblValidation = tbl(idxValidation,:);
tblTest = tbl(idxTest,:);

%
%% Define Network Architecture
% Define the network for classification.
% Define a network with a feature input layer and specify the number of features. Also, configure the input layer to normalize the data using Z-score normalization. Next, include a fully connected layer with output size 50 followed by a batch normalization layer and a ReLU layer. For classification, specify another fully connected layer with output size corresponding to the number of classes, followed by a softmax layer and a classification layer.

numFeatures = size(tbl,2) - 1;
numClasses = numel(classNames);
 
layers = [
    featureInputLayer(numFeatures,'Normalization', 'zscore')
    fullyConnectedLayer(50)
    batchNormalizationLayer
    reluLayer
    fullyConnectedLayer(numClasses)
    softmaxLayer
    classificationLayer];

%
%% Specify Training Options
% Specify the training options.
% Train the network using Adam.
% Train using mini-batches of size 16.
% Shuffle the data every epoch.
% Monitor the network accuracy during training by specifying validation data.
% Display the training progress in a plot and suppress the verbose command window output.
% The software trains the network on the training data and calculates the accuracy on the validation data at regular intervals during training. The validation data is not used to update the network weights.

miniBatchSize = 16;

options = trainingOptions('adam', ...
    'MiniBatchSize',miniBatchSize, ...
    'Shuffle','every-epoch', ...
    'ValidationData',tblValidation, ...
    'Plots','training-progress', ...
    'Verbose',false);

%
%% Train Network
% Train the network using the architecture defined by layers, the training data, and the training options. By default, trainNetwork uses a GPU if one is available, otherwise, it uses a CPU. Training on a GPU requires Parallel Computing Toolbox™ and a supported GPU device. For information on supported devices, see GPU Support by Release. You can also specify the execution environment by using the 'ExecutionEnvironment' name-value pair argument of trainingOptions.
% The training progress plot shows the mini-batch loss and accuracy and the validation loss and accuracy. For more information on the training progress plot, see Monitor Deep Learning Training Progress.

net = trainNetwork(tblTrain,labelName,layers,options);

%
%% Test Network
% Predict the labels of the test data using the trained network and calculate the accuracy. Specify the same mini-batch size used for training.

YPred = classify(net,tblTest(:,1:end-1),'MiniBatchSize',miniBatchSize);

% Calculate the classification accuracy. The accuracy is the proportion of the labels that the network predicts correctly.

YTest = tblTest{:,labelName};
accuracy = sum(YPred == YTest)/numel(YTest)

% View the results in a confusion matrix.

figure
confusionchart(YTest,YPred)

% Copyright 2020 The MathWorks, Inc.