142 lines
4.9 KiB
Python
142 lines
4.9 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
"""Layer definitions.
|
||
|
|
||
|
This module defines classes which encapsulate a single layer.
|
||
|
|
||
|
These layers map input activations to output activation with the `fprop`
|
||
|
method and map gradients with repsect to outputs to gradients with respect to
|
||
|
their inputs with the `bprop` method.
|
||
|
|
||
|
Some layers will have learnable parameters and so will additionally define
|
||
|
methods for getting and setting parameter and calculating gradients with
|
||
|
respect to the layer parameters.
|
||
|
"""
|
||
|
|
||
|
import numpy as np
|
||
|
import mlp.initialisers as init
|
||
|
|
||
|
|
||
|
class Layer(object):
|
||
|
"""Abstract class defining the interface for a layer."""
|
||
|
|
||
|
def fprop(self, inputs):
|
||
|
"""Forward propagates activations through the layer transformation.
|
||
|
|
||
|
Args:
|
||
|
inputs: Array of layer inputs of shape (batch_size, input_dim).
|
||
|
|
||
|
Returns:
|
||
|
outputs: Array of layer outputs of shape (batch_size, output_dim).
|
||
|
"""
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
def bprop(self, inputs, outputs, grads_wrt_outputs):
|
||
|
"""Back propagates gradients through a layer.
|
||
|
|
||
|
Given gradients with respect to the outputs of the layer calculates the
|
||
|
gradients with respect to the layer inputs.
|
||
|
|
||
|
Args:
|
||
|
inputs: Array of layer inputs of shape (batch_size, input_dim).
|
||
|
outputs: Array of layer outputs calculated in forward pass of
|
||
|
shape (batch_size, output_dim).
|
||
|
grads_wrt_outputs: Array of gradients with respect to the layer
|
||
|
outputs of shape (batch_size, output_dim).
|
||
|
|
||
|
Returns:
|
||
|
Array of gradients with respect to the layer inputs of shape
|
||
|
(batch_size, input_dim).
|
||
|
"""
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
|
||
|
class LayerWithParameters(Layer):
|
||
|
"""Abstract class defining the interface for a layer with parameters."""
|
||
|
|
||
|
def grads_wrt_params(self, inputs, grads_wrt_outputs):
|
||
|
"""Calculates gradients with respect to layer parameters.
|
||
|
|
||
|
Args:
|
||
|
inputs: Array of inputs to layer of shape (batch_size, input_dim).
|
||
|
grads_wrt_to_outputs: Array of gradients with respect to the layer
|
||
|
outputs of shape (batch_size, output_dim).
|
||
|
|
||
|
Returns:
|
||
|
List of arrays of gradients with respect to the layer parameters
|
||
|
with parameter gradients appearing in same order in tuple as
|
||
|
returned from `get_params` method.
|
||
|
"""
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
@property
|
||
|
def params(self):
|
||
|
"""Returns a list of parameters of layer.
|
||
|
|
||
|
Returns:
|
||
|
List of current parameter values.
|
||
|
"""
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
|
||
|
class AffineLayer(LayerWithParameters):
|
||
|
"""Layer implementing an affine tranformation of its inputs.
|
||
|
|
||
|
This layer is parameterised by a weight matrix and bias vector.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, input_dim, output_dim,
|
||
|
weights_initialiser=init.UniformInit(-0.1, 0.1),
|
||
|
biases_initialiser=init.ConstantInit(0.),
|
||
|
weights_cost=None, biases_cost=None):
|
||
|
"""Initialises a parameterised affine layer.
|
||
|
|
||
|
Args:
|
||
|
input_dim (int): Dimension of inputs to the layer.
|
||
|
output_dim (int): Dimension of the layer outputs.
|
||
|
weights_initialiser: Initialiser for the weight parameters.
|
||
|
biases_initialiser: Initialiser for the bias parameters.
|
||
|
"""
|
||
|
self.input_dim = input_dim
|
||
|
self.output_dim = output_dim
|
||
|
self.weights = weights_initialiser((self.output_dim, self.input_dim))
|
||
|
self.biases = biases_initialiser(self.output_dim)
|
||
|
|
||
|
def fprop(self, inputs):
|
||
|
"""Forward propagates activations through the layer transformation.
|
||
|
|
||
|
For inputs `x`, outputs `y`, weights `W` and biases `b` the layer
|
||
|
corresponds to `y = W.dot(x) + b`.
|
||
|
|
||
|
Args:
|
||
|
inputs: Array of layer inputs of shape (batch_size, input_dim).
|
||
|
|
||
|
Returns:
|
||
|
outputs: Array of layer outputs of shape (batch_size, output_dim).
|
||
|
"""
|
||
|
#TODO write your code here
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
def grads_wrt_params(self, inputs, grads_wrt_outputs):
|
||
|
"""Calculates gradients with respect to layer parameters.
|
||
|
|
||
|
Args:
|
||
|
inputs: array of inputs to layer of shape (batch_size, input_dim)
|
||
|
grads_wrt_to_outputs: array of gradients with respect to the layer
|
||
|
outputs of shape (batch_size, output_dim)
|
||
|
|
||
|
Returns:
|
||
|
list of arrays of gradients with respect to the layer parameters
|
||
|
`[grads_wrt_weights, grads_wrt_biases]`.
|
||
|
"""
|
||
|
#TODO write your code here
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
@property
|
||
|
def params(self):
|
||
|
"""A list of layer parameter values: `[weights, biases]`."""
|
||
|
return [self.weights, self.biases]
|
||
|
|
||
|
def __repr__(self):
|
||
|
return 'AffineLayer(input_dim={0}, output_dim={1})'.format(
|
||
|
self.input_dim, self.output_dim)
|