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

Commit b0e7758

Browse files
committed
Merge branch 'master' into neural-translation
2 parents e52003b + a131b40 commit b0e7758

File tree

5 files changed

+185
-56
lines changed

5 files changed

+185
-56
lines changed

examples/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121

2222
## Text classification
2323

24-
* [Text Classification Using Recurrent Neural Networks on Words](text_classification.py) (See also [Simplified Version Using Built-in RNN Model](text_classification_builtin_rnn_model.py))
24+
* [Text Classification Using Recurrent Neural Networks on Words](text_classification.py)
25+
(See also [Simplified Version Using Built-in RNN Model](text_classification_builtin_rnn_model.py) with easy to use built-in parameters)
2526
* [Text Classification Using Convolutional Neural Networks on Words](text_classification_cnn.py)
2627
* [Text Classification Using Recurrent Neural Networks on Characters](text_classification_character_rnn.py)
2728
* [Text Classification Using Convolutional Neural Networks on Characters](text_classification_character_cnn.py)

examples/resnet.py

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
"""
1616
This example builds deep residual network for mnist data.
1717
Reference Paper: http://arxiv.org/pdf/1512.03385.pdf
18+
19+
Note that this is still a work-in-progress. Feel free to submit a PR
20+
to make this better.
1821
"""
1922

2023
import os
@@ -31,32 +34,30 @@
3134

3235

3336
def res_net(x, y, activation=tf.nn.relu):
34-
"""Builds a residual network.
37+
"""Builds a residual network. Note that if the input tensor is 2D, it must be
38+
square in order to be converted to a 4D tensor.
3539
3640
Borrowed structure from here: https://github.com/pkmital/tensorflow_tutorials/blob/master/10_residual_network.py
3741
3842
Args:
3943
x: Input of the network
4044
y: Output of the network
4145
activation: Activation function to apply after each convolution
42-
Raises:
43-
ValueError
44-
If a 2D tensor is not square, it cannot be converted to a
45-
4D tensor.
4646
"""
47-
LayerBlock = namedtuple(
48-
'LayerBlock', ['num_layers', 'num_filters', 'bottleneck_size'])
49-
blocks = [LayerBlock(3, 128, 32),
50-
LayerBlock(3, 256, 64),
51-
LayerBlock(3, 512, 128),
52-
LayerBlock(3, 1024, 256)]
53-
54-
# Input check
47+
48+
# Configurations for each bottleneck block
49+
BottleneckBlock = namedtuple(
50+
'BottleneckBlock', ['num_layers', 'num_filters', 'bottleneck_size'])
51+
blocks = [BottleneckBlock(3, 128, 32),
52+
BottleneckBlock(3, 256, 64),
53+
BottleneckBlock(3, 512, 128),
54+
BottleneckBlock(3, 1024, 256)]
55+
5556
input_shape = x.get_shape().as_list()
57+
58+
# Reshape the input into the right shape if it's 2D tensor
5659
if len(input_shape) == 2:
5760
ndim = int(sqrt(input_shape[1]))
58-
if ndim * ndim != input_shape[1]:
59-
raise ValueError('input_shape should be square')
6061
x = tf.reshape(x, [-1, ndim, ndim, 1])
6162

6263
# First convolution expands to 64 channels
@@ -74,11 +75,13 @@ def res_net(x, y, activation=tf.nn.relu):
7475
[1, 1], [1, 1, 1, 1],
7576
padding='VALID', bias=True)
7677

77-
# Create resnets for each residual block
78+
# Create each bottleneck building block for each layer
7879
for block_i, block in enumerate(blocks):
7980
for layer_i in range(block.num_layers):
8081

8182
name = 'block_%d/layer_%d' % (block_i, layer_i)
83+
84+
# 1x1 convolution responsible for reducing dimension
8285
with tf.variable_scope(name + '/conv_in'):
8386
conv = skflow.ops.conv2d(net, block.num_filters,
8487
[1, 1], [1, 1, 1, 1],
@@ -95,6 +98,7 @@ def res_net(x, y, activation=tf.nn.relu):
9598
batch_norm=True,
9699
bias=False)
97100

101+
# 1x1 convolution responsible for restoring dimension
98102
with tf.variable_scope(name + '/conv_out'):
99103
conv = skflow.ops.conv2d(conv, block.num_filters,
100104
[1, 1], [1, 1, 1, 1],
@@ -103,6 +107,8 @@ def res_net(x, y, activation=tf.nn.relu):
103107
batch_norm=True,
104108
bias=False)
105109

110+
# shortcut connections that turn the network into its counterpart
111+
# residual function (identity shortcut)
106112
net = conv + net
107113

108114
try:
@@ -116,16 +122,13 @@ def res_net(x, y, activation=tf.nn.relu):
116122
except IndexError:
117123
pass
118124

119-
125+
net_shape = net.get_shape().as_list()
120126
net = tf.nn.avg_pool(net,
121-
ksize=[1, net.get_shape().as_list()[1],
122-
net.get_shape().as_list()[2], 1],
127+
ksize=[1, net_shape[1], net_shape[2], 1],
123128
strides=[1, 1, 1, 1], padding='VALID')
124-
net = tf.reshape(
125-
net,
126-
[-1, net.get_shape().as_list()[1] *
127-
net.get_shape().as_list()[2] *
128-
net.get_shape().as_list()[3]])
129+
130+
net_shape = net.get_shape().as_list()
131+
net = tf.reshape(net, [-1, net_shape[1] * net_shape[2] * net_shape[3]])
129132

130133
return skflow.models.logistic_regression(net, y)
131134

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/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

0 commit comments

Comments
 (0)