const lodashDefaults = require('lodash').defaults;
const Layer = require('../layer');
const Weights = require('../../weights');
/*
@node Dense
@description Dense implements the operation: `output = activation(dot(input, kernel) + bias)`` where activation is the element-wise activation function passed as the activation argument, kernel is a weights matrix created by the layer, and bias is a bias vector created by the layer (only applicable if `use_bias` is True).
@property units
@type number
@required true
@step 0
@min 1
@description Positive integer, dimensionality of the output space.
@property activation
@type text
@description Activation function to use (see activations). If you don't specify anything, no activation is applied (ie. "linear" activation: a(x) = x)
*/
/**
* Regular fully-connected layer.
* @extends mentality.keras.layers.Layer
* @memberof mentality.keras.layers
*/
class Dense extends Layer {
/**
* Constructor
* @param {Object} args Properties of conv layer.
* @param {Layer | undefined} input Input layer.
* @return {Conv}
*/
constructor(args = {}, input) {
super(args, input);
this.parameters = {
units: args.units,
};
this.weightConfig = new Weights(args);
this.parameters.units = args.units;
this.setInput(input);
}
/**
* Compute shape of output tensor.
*
* @return {number[]} Output tensor's shape.
*/
computeOutputShape() {
const inputShape = this.input.computeOutputShape();
if (inputShape.length > 2) throw new Error(`Invalid shape. Expected shape length 2. Got ${inputShape.length}.`);
const outputShape = Array.from(inputShape);
outputShape[outputShape.length - 1] = this.parameters.units;
return outputShape;
}
/**
* Build layer.
* @param {Writer} writer Writer object used to build.
* @param {Object} opts Options.
*/
build(writer, opts = {}) {
const requiredParams = [
`units=${this.parameters.units}`,
];
const weightParams = this.weightConfig.toParams(opts);
const params = requiredParams.concat(weightParams).join(',\n');
const lines = `${this.getName()} = mentality.keras.layers.Dense(${params})(${this.input.getName()})`;
writer.emitFunctionCall(lines);
writer.emitNewline();
}
/**
* Export layer as JSON.
* @param {Object} opts Options.
* @return {Object} Layer properties as JSON.
*/
toJson(opts = {}) {
return lodashDefaults({
units: this.parameters.units,
}, this.weightConfig.getConfig(opts), super.toJson(opts));
}
/**
* Get neurons in this layer.
* @return {Number} Number of neurons.
*/
countNeurons() {
return this.parameters.units;
}
/**
* Get connections in this layer.
* @return {Number} Number of neurons.
*/
countWeights() {
return this.input.computeOutputShape()[1] * this.parameters.units;
}
}
module.exports = Dense;