aboutsummaryrefslogtreecommitdiff
path: root/model/memory_network_mlp.py
blob: cb8de2a330815b3b84bb45f86218e2cfb053ce3a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from theano import tensor

from fuel.transformers import Batch, MultiProcessing, Merge
from fuel.streams import DataStream
from fuel.schemes import ConstantScheme, ShuffledExampleScheme, SequentialExampleScheme
from blocks.bricks import application, MLP, Rectifier, Initializable, Softmax

import data
from data import transformers
from data.cut import TaxiTimeCutScheme
from data.hdf5 import TaxiDataset, TaxiStream
import error
from model import ContextEmbedder

from memory_network import StreamSimple as Stream
from memory_network import MemoryNetworkBase


class Model(MemoryNetworkBase):
    def __init__(self, **kwargs):
        super(Model, self).__init__(**kwargs)

        self.prefix_encoder = MLP(activations=[Rectifier() for _ in config.prefix_encoder.dim_hidden]
                                              + [config.representation_activation()],
                                  dims=[config.prefix_encoder.dim_input]
                                       + config.prefix_encoder.dim_hidden
                                       + [config.representation_size],
                                  name='prefix_encoder')

        self.candidate_encoder = MLP(
                    activations=[Rectifier() for _ in config.candidate_encoder.dim_hidden]
                                + [config.representation_activation()],
                    dims=[config.candidate_encoder.dim_input]
                         + config.candidate_encoder.dim_hidden
                         + [config.representation_size],
                    name='candidate_encoder')
        self.softmax = Softmax()

        self.prefix_extremities = {'%s_k_%s' % (side, ['latitude', 'longitude'][axis]): axis 
                                   for side in ['first', 'last'] for axis in [0, 1]}
        self.candidate_extremities = {'candidate_%s_k_%s' % (side, axname): axis
                                      for side in ['first', 'last']
                                      for axis, axname in enumerate(['latitude', 'longitude'])}

        self.inputs = self.context_embedder.inputs \
                      + ['candidate_%s'%k for k in self.context_embedder.inputs] \
                      + self.prefix_extremities.keys() + self.candidate_extremities.keys()
        self.children = [ self.context_embedder,
                          self.prefix_encoder,
                          self.candidate_encoder,
                          self.softmax ]

    def _push_initialization_config(self):
        for (mlp, config) in [[self.prefix_encoder, self.config.prefix_encoder],
                              [self.candidate_encoder, self.config.candidate_encoder]]:
            mlp.weights_init = config.weights_init
            mlp.biases_init = config.biases_init

    @application(outputs=['destination'])
    def predict(self, **kwargs):
        prefix_embeddings = tuple(self.context_embedder.apply(
                                **{k: kwargs[k] for k in self.context_embedder.inputs }))
        prefix_extremities = tuple((kwargs[k] - data.train_gps_mean[v]) / data.train_gps_std[v]
                                   for k, v in self.prefix_extremities.items())
        prefix_inputs = tensor.concatenate(prefix_extremities + prefix_embeddings, axis=1)
        prefix_representation = self.prefix_encoder.apply(prefix_inputs)
        if self.config.normalize_representation:
            prefix_representation = prefix_representation \
                    / tensor.sqrt((prefix_representation ** 2).sum(axis=1, keepdims=True))

        candidate_embeddings = tuple(self.context_embedder.apply(**{k: kwargs['candidate_%s'%k]
                                     for k in self.context_embedder.inputs }))
        candidate_extremities = tuple((kwargs[k] - data.train_gps_mean[v]) / data.train_gps_std[v]
                                      for k, v in self.candidate_extremities.items())
        candidate_inputs = tensor.concatenate(candidate_extremities + candidate_embeddings, axis=1)
        candidate_representation = self.candidate_encoder.apply(candidate_inputs)
        if self.config.normalize_representation:
            candidate_representation = candidate_representation \
                    / tensor.sqrt((candidate_representation ** 2).sum(axis=1, keepdims=True))

        similarity_score = tensor.dot(prefix_representation, candidate_representation.T)
        similarity = self.softmax.apply(similarity_score)

        candidate_destination = tensor.concatenate(
                (tensor.shape_padright(kwargs['candidate_last_k_latitude'][:,-1]),
                 tensor.shape_padright(kwargs['candidate_last_k_longitude'][:,-1])),
                axis=1)

        return tensor.dot(similarity, candidate_destination)

    @predict.property('inputs')
    def predict_inputs(self):
        return self.inputs

    @application(outputs=['cost'])
    def cost(self, **kwargs):
        y_hat = self.predict(**kwargs)
        y = tensor.concatenate((kwargs['destination_latitude'][:, None],
                                kwargs['destination_longitude'][:, None]), axis=1)

        return error.erdist(y_hat, y).mean()

    @cost.property('inputs')
    def cost_inputs(self):
        return self.inputs + ['destination_latitude', 'destination_longitude']