import os
import tensorflow as tf
from ..model_unit import BaseModel
[docs]class DeepST(BaseModel):
"""Deep learning-based prediction model for Spatial-Temporal data (DeepST)
DeepST is composed of three components: 1) temporal dependent
instances: describing temporal closeness, period and seasonal
trend; 2) convolutional neural networks: capturing near and
far spatial dependencies; 3) early and late fusions: fusing
similar and different domains' data.
Reference: `DNN-Based Prediction Model for Spatial-Temporal Data (Junbo Zhang et al., 2016)
<https://www.microsoft.com/en-us/research/wp-content/uploads/2016/09/DeepST-SIGSPATIAL2016.pdf>`_.
Args:
closeness_len (int): The length of closeness data history. The former consecutive ``closeness_len`` time slots
of data will be used as closeness history.
period_len (int): The length of period data history. The data of exact same time slots in former consecutive
``period_len`` days will be used as period history.
trend_len (int): The length of trend data history. The data of exact same time slots in former consecutive
``trend_len`` weeks (every seven days) will be used as trend history.
width (int): The width of grid data.
height (int): The height of grid data.
externai_dim (int): Number of dimensions of external data.
kernel_size (int): Kernel size in Convolutional neural networks. Default: 3
num_conv_filters (int): the Number of filters in the convolution. Default: 64
lr (float): Learning rate. Default: 1e-5
code_version (str): Current version of this model code.
model_dir (str): The directory to store model files. Default:'model_dir'
gpu_device (str): To specify the GPU to use. Default: '0'
"""
def __init__(self,
closeness_len,
period_len,
trend_len,
width,
height,
external_dim,
kernel_size=3,
num_conv_filters=64,
lr=1e-5,
code_version='QuickStart-DeepST',
model_dir='model_dir',
gpu_device='0'):
super(DeepST, self).__init__(code_version=code_version, model_dir=model_dir, gpu_device=gpu_device)
self._width = width
self._height = height
self._closeness_len = closeness_len
self._period_len = period_len
self._trend_len = trend_len
self._external_dim = external_dim
self._lr = lr
self._kernel_size = kernel_size
self._num_conv_filters = num_conv_filters
self._graph = tf.Graph()
self._GPU_DEVICE = gpu_device
self._input = {}
self._output = {}
self._op = {}
self._variable_init = None
self._saver = None
self._model_dir = model_dir
# GPU Config
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = self._GPU_DEVICE
self._config = tf.ConfigProto()
self._config.gpu_options.allow_growth = True
self._session = tf.Session(graph=self._graph, config=self._config)
[docs] def build(self):
with self._graph.as_default():
c_conf = tf.placeholder(tf.float32, [None, self._height, self._width, self._closeness_len], name='c')
p_conf = tf.placeholder(tf.float32, [None, self._height, self._width, self._period_len], name='p')
t_conf = tf.placeholder(tf.float32, [None, self._height, self._width, self._trend_len], name='t')
target = tf.placeholder(tf.float32, [None, self._height, self._width, 1], name='target')
self._input['closeness_feature'] = c_conf.name
self._input['period_feature'] = p_conf.name
self._input['trend_feature'] = t_conf.name
self._input['target'] = target.name
# First convolution
h_c_1 = tf.layers.conv2d(inputs=c_conf, filters=self._num_conv_filters,
kernel_size=[self._kernel_size, self._kernel_size], padding='SAME', use_bias=True)
h_p_1 = tf.layers.conv2d(inputs=c_conf, filters=self._num_conv_filters,
kernel_size=[self._kernel_size, self._kernel_size], padding='SAME', use_bias=True)
h_t_1 = tf.layers.conv2d(inputs=c_conf, filters=self._num_conv_filters,
kernel_size=[self._kernel_size, self._kernel_size], padding='SAME', use_bias=True)
# First fusion
h_2 = tf.layers.conv2d(tf.concat([h_c_1, h_p_1, h_t_1], axis=-1),
filters=self._num_conv_filters, kernel_size=[self._kernel_size, self._kernel_size],
padding='SAME', use_bias=True)
# Stack more convolutions
middle_output = tf.layers.conv2d(h_2, filters=self._num_conv_filters,
kernel_size=[self._kernel_size, self._kernel_size],
padding='SAME', use_bias=True)
x = tf.layers.conv2d(middle_output, filters=self._num_conv_filters,
kernel_size=[self._kernel_size, self._kernel_size], padding='SAME', use_bias=True)
# external dims
if self._external_dim is not None and self._external_dim > 0:
external_input = tf.placeholder(tf.float32, [None, self._external_dim])
self._input['external_feature'] = external_input.name
external_dense = tf.layers.dense(inputs=external_input, units=10)
external_dense = tf.tile(tf.reshape(external_dense, [-1, 1, 1, 10]), [1, self._height, self._width, 1])
x = tf.concat([x, external_dense], axis=-1)
x = tf.layers.dense(x, units=1, name='prediction', activation=tf.nn.sigmoid)
loss = tf.sqrt(tf.reduce_mean(tf.square(x - target)), name='loss')
train_op = tf.train.AdamOptimizer(self._lr).minimize(loss)
self._output['prediction'] = x.name
self._output['loss'] = loss.name
self._op['train_op'] = train_op.name
self._variable_init = tf.global_variables_initializer()
self._saver = tf.train.Saver()
super(DeepST, self).build()
# Define your '_get_feed_dict function‘, map your input to the tf-model
def _get_feed_dict(self, closeness_feature=None, period_feature=None, trend_feature=None,
target=None, external_feature=None):
'''
The method to get feet dict for tensorflow model.
Users may modify this method according to the format of input.
Args:
closeness_feature (np.ndarray or ``None``): The closeness history data.
If type is np.ndarray, its shape is [time_slot_num, height, width, closeness_len].
period_feature (np.ndarray or ``None``): The period history data.
If type is np.ndarray, its shape is [time_slot_num, height, width, period_len].
trend_feature (np.ndarray or ``None``): The trend history data.
If type is np.ndarray, its shape is [time_slot_num, height, width, trend_len].
target (np.ndarray or ``None``): The target value data.
If type is np.ndarray, its shape is [time_slot_num, height, width, 1].
external_feature (np.ndarray or ``None``): The external feature data.
If type is np.ndaaray, its shape is [time_slot_num, feature_num].
'''
feed_dict = {}
if target is not None:
feed_dict['target'] = target
if self._external_dim is not None and self._external_dim > 0:
feed_dict['external_feature'] = external_feature
if self._closeness_len is not None and self._closeness_len > 0:
feed_dict['closeness_feature'] = closeness_feature
if self._period_len is not None and self._period_len > 0:
feed_dict['period_feature'] = period_feature
if self._trend_len is not None and self._trend_len > 0:
feed_dict['trend_feature'] = trend_feature
return feed_dict