|
10 | 10 | from . import files |
11 | 11 | from . import cost |
12 | 12 | from . import iterate |
| 13 | +from . import ops |
13 | 14 | import numpy as np |
14 | 15 | from six.moves import xrange |
15 | 16 | import random |
@@ -2788,6 +2789,81 @@ def __init__( |
2788 | 2789 | self.all_drop = dict(layer.all_drop) |
2789 | 2790 | self.all_layers.extend( [self.outputs] ) |
2790 | 2791 |
|
| 2792 | +## TimeDistributedLayer |
| 2793 | +class TimeDistributedLayer(Layer): |
| 2794 | + """ |
| 2795 | + The :class:`TimeDistributedLayer` class that applies a function to every timestep of the input tensor. |
| 2796 | + For example, if using :class:`DenseLayer` as the ``layer_class``, inputs [batch_size , length, dim] |
| 2797 | + outputs [batch_size , length, new_dim]. |
| 2798 | +
|
| 2799 | + Parameters |
| 2800 | + ---------- |
| 2801 | + layer : a :class:`Layer` instance |
| 2802 | + The `Layer` class feeding into this layer, [batch_size , length, dim] |
| 2803 | + layer_class : a :class:`Layer` class |
| 2804 | + args : dictionary |
| 2805 | + The arguments for the ``layer_class``. |
| 2806 | + name : a string or None |
| 2807 | + An optional name to attach to this layer. |
| 2808 | +
|
| 2809 | + Examples |
| 2810 | + -------- |
| 2811 | + >>> batch_size = 32 |
| 2812 | + >>> timestep = 20 |
| 2813 | + >>> input_dim = 100 |
| 2814 | + >>> x = tf.placeholder(dtype=tf.float32, shape=[batch_size, timestep, input_dim], name="encode_seqs") |
| 2815 | + >>> net = InputLayer(x, name='input') |
| 2816 | + >>> net = TimeDistributedLayer(net, layer_class=DenseLayer, args={'n_units':50, 'name':'dense'}, name='time_dense') |
| 2817 | + ... [TL] InputLayer input: (32, 20, 100) |
| 2818 | + ... [TL] TimeDistributedLayer time_dense: layer_class:DenseLayer |
| 2819 | + >>> print(net.outputs._shape) |
| 2820 | + ... (32, 20, 50) |
| 2821 | + >>> net.print_params(False) |
| 2822 | + ... param 0: (100, 50) time_dense/dense/W:0 |
| 2823 | + ... param 1: (50,) time_dense/dense/b:0 |
| 2824 | + ... num of params: 5050 |
| 2825 | + """ |
| 2826 | + def __init__( |
| 2827 | + self, |
| 2828 | + layer = None, |
| 2829 | + layer_class = None, |
| 2830 | + args = {}, |
| 2831 | + name ='time_distributed', |
| 2832 | + ): |
| 2833 | + Layer.__init__(self, name=name) |
| 2834 | + self.inputs = layer.outputs |
| 2835 | + print(" [TL] TimeDistributedLayer %s: layer_class:%s args:%s" % |
| 2836 | + (self.name, layer_class.__name__, args)) |
| 2837 | + |
| 2838 | + if not args: args = dict() |
| 2839 | + assert isinstance(args, dict), "'args' must be a dict." |
| 2840 | + |
| 2841 | + if not isinstance(self.inputs, tf.Tensor): |
| 2842 | + self.inputs = tf.transpose(tf.stack(self.inputs), [1, 0, 2]) |
| 2843 | + |
| 2844 | + input_shape = self.inputs.get_shape() |
| 2845 | + |
| 2846 | + timestep = input_shape[1] |
| 2847 | + x = tf.unstack(self.inputs, axis=1) |
| 2848 | + |
| 2849 | + with ops.suppress_stdout(): |
| 2850 | + for i in range(0, timestep): |
| 2851 | + with tf.variable_scope(name, reuse=(False if i==0 else True)) as vs: |
| 2852 | + set_name_reuse((False if i==0 else True)) |
| 2853 | + net = layer_class(InputLayer(x[i], name=args['name']+str(i)), **args) |
| 2854 | + x[i] = net.outputs |
| 2855 | + variables = tf.get_collection(TF_GRAPHKEYS_VARIABLES, scope=vs.name) |
| 2856 | + |
| 2857 | + self.outputs = tf.stack(x, axis=1, name=name) |
| 2858 | + |
| 2859 | + self.all_layers = list(layer.all_layers) |
| 2860 | + self.all_params = list(layer.all_params) |
| 2861 | + self.all_drop = dict(layer.all_drop) |
| 2862 | + self.all_layers.extend( [self.outputs] ) |
| 2863 | + self.all_params.extend( variables ) |
| 2864 | + |
| 2865 | + |
| 2866 | + |
2791 | 2867 | ## Recurrent layer |
2792 | 2868 | class RNNLayer(Layer): |
2793 | 2869 | """ |
|
0 commit comments