Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit a131b40

Browse files
committed
Merge branch 'resnet'
2 parents edc98e6 + 6ebacbc commit a131b40

File tree

5 files changed

+143
-26
lines changed

5 files changed

+143
-26
lines changed

skflow/estimators/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ def predict(self, X, axis=1, batch_size=-1):
264264
265265
Args:
266266
X: array-like matrix, [n_samples, n_features...] or iterator.
267-
axis: Which axis to argmax for classification.
267+
axis: Which axis to argmax for classification.
268268
By default axis 1 (next after batch) is used.
269269
Use 2 for sequence predictions.
270270
batch_size: If test set is too big, use batch size to split

skflow/estimators/rnn.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class TensorFlowRNNClassifier(TensorFlowEstimator, ClassifierMixin):
3535
input_op_fn: Function that will transform the input tensor, such as
3636
creating word embeddings, byte list, etc. This takes
3737
an argument X for input and returns transformed X.
38-
bidirection: Whether this is a bidirectional rnn.
38+
bidirectional: boolean, Whether this is a bidirectional rnn.
3939
sequence_length: If sequence_length is provided, dynamic calculation is performed.
4040
This saves computational time when unrolling past max sequence length.
4141
initial_state: An initial state for the RNN. This must be a tensor of appropriate type
@@ -71,7 +71,7 @@ def exp_decay(global_step):
7171

7272
def __init__(self, rnn_size, n_classes, cell_type='gru', num_layers=1,
7373
input_op_fn=null_input_op_fn,
74-
initial_state=None, bidirection=False,
74+
initial_state=None, bidirectional=False,
7575
sequence_length=None, tf_master="", batch_size=32,
7676
steps=50, optimizer="SGD", learning_rate=0.1,
7777
tf_random_seed=42, continue_training=False,
@@ -80,7 +80,7 @@ def __init__(self, rnn_size, n_classes, cell_type='gru', num_layers=1,
8080
self.rnn_size = rnn_size
8181
self.cell_type = cell_type
8282
self.input_op_fn = input_op_fn
83-
self.bidirection = bidirection
83+
self.bidirectional = bidirectional
8484
self.num_layers = num_layers
8585
self.sequence_length = sequence_length
8686
self.initial_state = initial_state
@@ -97,7 +97,7 @@ def __init__(self, rnn_size, n_classes, cell_type='gru', num_layers=1,
9797
def _model_fn(self, X, y):
9898
return models.get_rnn_model(self.rnn_size, self.cell_type,
9999
self.num_layers,
100-
self.input_op_fn, self.bidirection,
100+
self.input_op_fn, self.bidirectional,
101101
models.logistic_regression,
102102
self.sequence_length,
103103
self.initial_state)(X, y)
@@ -123,7 +123,7 @@ class TensorFlowRNNRegressor(TensorFlowEstimator, RegressorMixin):
123123
input_op_fn: Function that will transform the input tensor, such as
124124
creating word embeddings, byte list, etc. This takes
125125
an argument X for input and returns transformed X.
126-
bidirection: Whether this is a bidirectional rnn.
126+
bidirectional: boolean, Whether this is a bidirectional rnn.
127127
sequence_length: If sequence_length is provided, dynamic calculation is performed.
128128
This saves computational time when unrolling past max sequence length.
129129
initial_state: An initial state for the RNN. This must be a tensor of appropriate type
@@ -152,7 +152,7 @@ def exp_decay(global_step):
152152

153153
def __init__(self, rnn_size, cell_type='gru', num_layers=1,
154154
input_op_fn=null_input_op_fn, initial_state=None,
155-
bidirection=False, sequence_length=None,
155+
bidirectional=False, sequence_length=None,
156156
n_classes=0, tf_master="", batch_size=32,
157157
steps=50, optimizer="SGD", learning_rate=0.1,
158158
tf_random_seed=42, continue_training=False,
@@ -161,7 +161,7 @@ def __init__(self, rnn_size, cell_type='gru', num_layers=1,
161161
self.rnn_size = rnn_size
162162
self.cell_type = cell_type
163163
self.input_op_fn = input_op_fn
164-
self.bidirection = bidirection
164+
self.bidirectional = bidirectional
165165
self.num_layers = num_layers
166166
self.sequence_length = sequence_length
167167
self.initial_state = initial_state
@@ -178,7 +178,7 @@ def __init__(self, rnn_size, cell_type='gru', num_layers=1,
178178
def _model_fn(self, X, y):
179179
return models.get_rnn_model(self.rnn_size, self.cell_type,
180180
self.num_layers,
181-
self.input_op_fn, self.bidirection,
181+
self.input_op_fn, self.bidirectional,
182182
models.linear_regression,
183183
self.sequence_length,
184184
self.initial_state)(X, y)

skflow/io/data_feeder.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
from __future__ import division, print_function, absolute_import
1818

1919
import itertools
20+
import math
21+
2022
import six
2123
from six.moves import xrange # pylint: disable=redefined-builtin
22-
import math
2324

2425
import numpy as np
2526
from sklearn.utils import check_array

skflow/models.py

Lines changed: 111 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from __future__ import division, print_function, absolute_import
1717

1818
import tensorflow as tf
19-
from tensorflow.models.rnn import rnn, rnn_cell
2019

2120
from skflow.ops import mean_squared_error_regressor, softmax_classifier, dnn
2221

@@ -93,9 +92,102 @@ def dnn_estimator(X, y):
9392
return target_predictor_fn(layers, y)
9493
return dnn_estimator
9594

95+
## This will be in Tensorflow 0.7.
96+
## TODO(ilblackdragon): Clean this up when it's released
97+
98+
99+
def _reverse_seq(input_seq, lengths):
100+
"""Reverse a list of Tensors up to specified lengths.
101+
Args:
102+
input_seq: Sequence of seq_len tensors of dimension (batch_size, depth)
103+
lengths: A tensor of dimension batch_size, containing lengths for each
104+
sequence in the batch. If "None" is specified, simply reverses
105+
the list.
106+
Returns:
107+
time-reversed sequence
108+
"""
109+
if lengths is None:
110+
return list(reversed(input_seq))
111+
112+
for input_ in input_seq:
113+
input_.set_shape(input_.get_shape().with_rank(2))
114+
115+
# Join into (time, batch_size, depth)
116+
s_joined = tf.pack(input_seq)
117+
118+
# Reverse along dimension 0
119+
s_reversed = tf.reverse_sequence(s_joined, lengths, 0, 1)
120+
# Split again into list
121+
result = tf.unpack(s_reversed)
122+
return result
123+
124+
125+
def bidirectional_rnn(cell_fw, cell_bw, inputs,
126+
initial_state_fw=None, initial_state_bw=None,
127+
dtype=None, sequence_length=None, scope=None):
128+
"""Creates a bidirectional recurrent neural network.
129+
Similar to the unidirectional case above (rnn) but takes input and builds
130+
independent forward and backward RNNs with the final forward and backward
131+
outputs depth-concatenated, such that the output will have the format
132+
[time][batch][cell_fw.output_size + cell_bw.output_size]. The input_size of
133+
forward and backward cell must match. The initial state for both directions
134+
is zero by default (but can be set optionally) and no intermediate states are
135+
ever returned -- the network is fully unrolled for the given (passed in)
136+
length(s) of the sequence(s) or completely unrolled if length(s) is not given.
137+
Args:
138+
cell_fw: An instance of RNNCell, to be used for forward direction.
139+
cell_bw: An instance of RNNCell, to be used for backward direction.
140+
inputs: A length T list of inputs, each a tensor of shape
141+
[batch_size, cell.input_size].
142+
initial_state_fw: (optional) An initial state for the forward RNN.
143+
This must be a tensor of appropriate type and shape
144+
[batch_size x cell.state_size].
145+
initial_state_bw: (optional) Same as for initial_state_fw.
146+
dtype: (optional) The data type for the initial state. Required if either
147+
of the initial states are not provided.
148+
sequence_length: (optional) An int64 vector (tensor) of size [batch_size],
149+
containing the actual lengths for each of the sequences.
150+
scope: VariableScope for the created subgraph; defaults to "BiRNN"
151+
Returns:
152+
A set of output `Tensors` where:
153+
outputs is a length T list of outputs (one for each input), which
154+
are depth-concatenated forward and backward outputs
155+
Raises:
156+
TypeError: If "cell_fw" or "cell_bw" is not an instance of RNNCell.
157+
ValueError: If inputs is None or an empty list.
158+
"""
159+
160+
if not isinstance(cell_fw, tf.nn.rnn_cell.RNNCell):
161+
raise TypeError("cell_fw must be an instance of RNNCell")
162+
if not isinstance(cell_bw, tf.nn.rnn_cell.RNNCell):
163+
raise TypeError("cell_bw must be an instance of RNNCell")
164+
if not isinstance(inputs, list):
165+
raise TypeError("inputs must be a list")
166+
if not inputs:
167+
raise ValueError("inputs must not be empty")
168+
169+
name = scope or "BiRNN"
170+
# Forward direction
171+
with tf.variable_scope(name + "_FW"):
172+
output_fw, _ = tf.nn.rnn(cell_fw, inputs, initial_state_fw, dtype,
173+
sequence_length)
174+
175+
# Backward direction
176+
with tf.variable_scope(name + "_BW"):
177+
tmp, _ = tf.nn.rnn(cell_bw, _reverse_seq(inputs, sequence_length),
178+
initial_state_bw, dtype, sequence_length)
179+
output_bw = _reverse_seq(tmp, sequence_length)
180+
# Concat each of the forward/backward outputs
181+
outputs = [tf.concat(1, [fw, bw])
182+
for fw, bw in zip(output_fw, output_bw)]
183+
184+
return outputs
185+
186+
# End of Tensorflow 0.7
187+
96188

97189
def get_rnn_model(rnn_size, cell_type, num_layers, input_op_fn,
98-
bidirection, target_predictor_fn,
190+
bidirectional, target_predictor_fn,
99191
sequence_length, initial_state):
100192
"""Returns a function that creates a RNN TensorFlow subgraph with given
101193
params.
@@ -107,13 +199,14 @@ def get_rnn_model(rnn_size, cell_type, num_layers, input_op_fn,
107199
input_op_fn: Function that will transform the input tensor, such as
108200
creating word embeddings, byte list, etc. This takes
109201
an argument X for input and returns transformed X.
110-
bidirection: Whether this is a bidirectional rnn.
202+
bidirectional: boolean, Whether this is a bidirectional rnn.
111203
target_predictor_fn: Function that will predict target from input
112204
features. This can be logistic regression,
113205
linear regression or any other model,
114206
that takes X, y and returns predictions and loss tensors.
115207
sequence_length: If sequence_length is provided, dynamic calculation is performed.
116208
This saves computational time when unrolling past max sequence length.
209+
Required for bidirectional RNNs.
117210
initial_state: An initial state for the RNN. This must be a tensor of appropriate type
118211
and shape [batch_size x cell.state_size].
119212
@@ -124,26 +217,28 @@ def rnn_estimator(X, y):
124217
"""RNN estimator with target predictor function on top."""
125218
X = input_op_fn(X)
126219
if cell_type == 'rnn':
127-
cell_fn = rnn_cell.BasicRNNCell
220+
cell_fn = tf.nn.rnn_cell.BasicRNNCell
128221
elif cell_type == 'gru':
129-
cell_fn = rnn_cell.GRUCell
222+
cell_fn = tf.nn.rnn_cell.GRUCell
130223
elif cell_type == 'lstm':
131-
cell_fn = rnn_cell.BasicLSTMCell
224+
cell_fn = tf.nn.rnn_cell.BasicLSTMCell
132225
else:
133226
raise ValueError("cell_type {} is not supported. ".format(cell_type))
134-
if bidirection:
227+
if bidirectional:
135228
# forward direction cell
136-
rnn_fw_cell = rnn_cell.MultiRNNCell([cell_fn(rnn_size)] * num_layers)
229+
rnn_fw_cell = tf.nn.rnn_cell.MultiRNNCell([cell_fn(rnn_size)] * num_layers)
137230
# backward direction cell
138-
rnn_bw_cell = rnn_cell.MultiRNNCell([cell_fn(rnn_size)] * num_layers)
231+
rnn_bw_cell = tf.nn.rnn_cell.MultiRNNCell([cell_fn(rnn_size)] * num_layers)
139232
# pylint: disable=unexpected-keyword-arg, no-value-for-parameter
140-
encoding = rnn.bidirectional_rnn(rnn_fw_cell, rnn_bw_cell,
141-
sequence_length=sequence_length,
142-
initial_state=initial_state)
233+
encoding = bidirectional_rnn(rnn_fw_cell, rnn_bw_cell, X,
234+
dtype=tf.float32,
235+
sequence_length=sequence_length,
236+
initial_state_fw=initial_state,
237+
initial_state_bw=initial_state)
143238
else:
144-
cell = rnn_cell.MultiRNNCell([cell_fn(rnn_size)] * num_layers)
145-
_, encoding = rnn.rnn(cell, X, dtype=tf.float32,
146-
sequence_length=sequence_length,
147-
initial_state=initial_state)
239+
cell = tf.nn.rnn_cell.MultiRNNCell([cell_fn(rnn_size)] * num_layers)
240+
_, encoding = tf.nn.rnn(cell, X, dtype=tf.float32,
241+
sequence_length=sequence_length,
242+
initial_state=initial_state)
148243
return target_predictor_fn(encoding[-1], y)
149244
return rnn_estimator

skflow/tests/test_nonlinear.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,27 @@ def input_fn(X):
9999
regressor.weights_
100100
regressor.bias_
101101
predictions = regressor.predict(test_data)
102+
103+
def testBidirectionalRNN(self):
104+
random.seed(42)
105+
import numpy as np
106+
data = np.array(list([[2, 1, 2, 2, 3],
107+
[2, 2, 3, 4, 5],
108+
[3, 3, 1, 2, 1],
109+
[2, 4, 5, 4, 1]]), dtype=np.float32)
110+
labels = np.array(list([1, 0, 1, 0]), dtype=np.float32)
111+
def input_fn(X):
112+
return tf.split(1, 5, X)
113+
114+
# Classification
115+
classifier = skflow.TensorFlowRNNClassifier(
116+
rnn_size=2, cell_type='lstm', n_classes=2, input_op_fn=input_fn,
117+
bidirectional=True)
118+
classifier.fit(data, labels)
119+
predictions = classifier.predict(np.array(list([[1, 3, 3, 2, 1],
120+
[2, 3, 4, 5, 6]])))
121+
self.assertAllClose(predictions, np.array([1, 0]))
122+
102123

103124
if __name__ == "__main__":
104125
tf.test.main()

0 commit comments

Comments
 (0)