Source code for theanet.layer.convpool

import numpy as np
import math
import theano as th
import theano.tensor as tt
import theano.tensor.nnet.conv as nnconv
from theano.tensor.signal import downsample
from .layer import Layer, activation_by_name

from .weights import init_wb

float_x = th.config.floatX
# ############################## ConvPool Layer ################################


[docs]class ConvLayer(Layer): def __init__(self, inpt, wts, rand_gen, batch_sz, num_prev_maps, in_sz, num_maps, filter_sz, stride, mode='valid', actvn='relu50', reg=()): """ :param inpt: :param wts: :param rand_gen: :param batch_sz: :param num_prev_maps: :param in_sz: :param num_maps: :param filter_sz: :param stride: :param mode: "valid", "full", "same" :param actvn: :param reg: :raise NotImplementedError: TODO: Add support for rectangular input """ assert (wts is not None or rand_gen is not None) assert mode in ("valid", "full", "same") image_shape = (batch_sz, num_prev_maps, in_sz, in_sz) filter_shape = (num_maps, num_prev_maps, filter_sz, filter_sz) # Assign Weights fan_in = num_prev_maps * filter_sz * filter_sz fan_out = num_maps * filter_sz * filter_sz self.W, self.b = init_wb(wts, rand_gen, filter_shape, (filter_shape[0], ), fan_in, fan_out, actvn, 'Conv') # Add Conv2D Operation to the graph border_mode = "valid" if mode == "valid" else "full" conv_out = nnconv.conv2d(inpt, self.W, image_shape, filter_shape, subsample=(stride, stride), border_mode=border_mode) if mode == 'same': assert stride == 1, "For Same mode stride should be 1" shift = (filter_sz - 1) // 2 conv_out = conv_out[:, :, shift:in_sz + shift, shift:in_sz + shift] self.out_sz = in_sz elif mode == "full": self.out_sz = in_sz + filter_sz + 1 elif mode == "valid": self.out_sz = in_sz - filter_sz + 1 # TODO: Remove stride support OR make more robust self.out_sz //= stride self.output = activation_by_name(actvn)(conv_out + self.b.dimshuffle('x', 0, 'x', 'x')) # Store Parameters self.params = [self.W, self.b] self.inpt = inpt self.num_maps = num_maps self.mode = mode self.n_out = num_maps * self.out_sz ** 2 self.reg = {"L1": 0, "L2": 0, "momentum": .95, "rate": 1, "maxnorm": 0,} self.reg.update(reg) self.args = (batch_sz, num_prev_maps, in_sz, num_maps, filter_sz, stride, mode, actvn, reg) self.representation = ( "Conv Maps:{:2d} Filter:{} Stride:{} Mode:{} Output:{:2d} " "Act:{}\n\t L1:{L1} L2:{L2} Momentum:{momentum} Rate:{rate} Max Norm:{maxnorm}" "".format(num_maps, filter_sz, stride, mode, self.out_sz, actvn, **self.reg))
[docs] def TestVersion(self, inpt): return ConvLayer(inpt, (self.W, self.b), None, *self.args)
[docs]class PoolLayer(Layer): def __init__(self, inpt, num_maps, in_sz, pool_sz, ignore_border=False): """ Pool Layer to follow Convolutional Layer :param inpt: :param pool_sz: :param ignore_border: When True, (5,5) input with ds=(2,2) will generate a (2,2) output. (3,3) otherwise. """ self.output = downsample.max_pool_2d(inpt, (pool_sz, pool_sz), ignore_border=ignore_border) if ignore_border: self.out_sz = in_sz//pool_sz else: self.out_sz = math.ceil(in_sz/pool_sz) self.params = [] self.inpt = inpt self.num_maps = num_maps self.ignore_border = ignore_border self.args = (num_maps, in_sz, pool_sz, ignore_border) self.n_out = num_maps * self.out_sz ** 2 self.representation = ( "Pool Maps:{:2d} Pool_sz:{} Border:{} Output:{:2d}" "".format(num_maps, pool_sz, "Ignore" if ignore_border else "Keep", self.out_sz))
[docs] def TestVersion(self, inpt): return PoolLayer(inpt, *self.args)
[docs]class MeanLayer(Layer): def __init__(self, inpt, num_maps, in_sz): self.output = tt.mean(inpt, axis=(2,3)) self.params = [] self.inpt = inpt self.num_maps = num_maps self.in_sz = in_sz self.out_sz = 1 self.n_out = num_maps self.representation = ( "Mean Maps:{:2d} Output:{:2d}" "".format(num_maps, self.out_sz))
[docs] def TestVersion(self, inpt): return MeanLayer(inpt, self.num_maps, self.in_sz)