* This custom layer is similar to the 'relu' non-linear Activation `Layer`, but * it keeps both the negative and positive signal. The input is centered at the * mean value, and then the negative activations and positive activations are * separated into different channels, meaning that there are
| 32 | * https://github.com/tensorflow/tfjs/issues/254 |
| 33 | */ |
| 34 | class Antirectifier extends tf.layers.Layer { |
| 35 | constructor() { |
| 36 | super({}); |
| 37 | // TODO(bileschi): Can we point to documentation on masking here? |
| 38 | this.supportsMasking = true; |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * This layer only works on 4D Tensors [batch, height, width, channels], |
| 43 | * and produces output with twice as many channels. |
| 44 | * |
| 45 | * layer.computeOutputShapes must be overridden in the case that the output |
| 46 | * shape is not the same as the input shape. |
| 47 | * @param {*} inputShapes |
| 48 | */ |
| 49 | computeOutputShape(inputShape) { |
| 50 | return [inputShape[0], inputShape[1], inputShape[2], 2 * inputShape[3]] |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * Centers the input and applies the following function to every element of |
| 55 | * the input. |
| 56 | * |
| 57 | * x => [max(x, 0), max(-x, 0)] |
| 58 | * |
| 59 | * The theory being that there may be signal in the both negative and positive |
| 60 | * portions of the input. Note that this will double the number of channels. |
| 61 | * @param inputs Tensor to be treated. |
| 62 | * @param kwargs Only used as a pass through to call hooks. Unused in this |
| 63 | * example code. |
| 64 | */ |
| 65 | call(inputs, kwargs) { |
| 66 | let input = inputs; |
| 67 | if (Array.isArray(input)) { |
| 68 | input = input[0]; |
| 69 | } |
| 70 | this.invokeCallHook(inputs, kwargs); |
| 71 | const origShape = input.shape; |
| 72 | const flatShape = |
| 73 | [origShape[0], origShape[1] * origShape[2] * origShape[3]]; |
| 74 | const flattened = input.reshape(flatShape); |
| 75 | const centered = tf.sub(flattened, flattened.mean(1).expandDims(1)); |
| 76 | const pos = centered.relu().reshape(origShape); |
| 77 | const neg = centered.neg().relu().reshape(origShape); |
| 78 | return tf.concat([pos, neg], 3); |
| 79 | } |
| 80 | |
| 81 | /** |
| 82 | * If a custom layer class is to support serialization, it must implement |
| 83 | * the `className` static getter. |
| 84 | */ |
| 85 | static get className() { |
| 86 | return 'Antirectifier'; |
| 87 | } |
| 88 | } |
| 89 | tf.serialization.registerClass(Antirectifier); // Needed for serialization. |
| 90 | |
| 91 | export function antirectifier() { |
nothing calls this directly
no outgoing calls
no test coverage detected