Skip to content

Commit

Permalink
Cleanup code
Browse files Browse the repository at this point in the history
  • Loading branch information
Dobiasd committed Oct 30, 2019
1 parent 1b0a824 commit 828f254
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 97 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,8 @@ script:
- cd ..
# run stateful tests
- cd test/stateful_test
- echo "compiling stateful recurrent tests"
- $CXX -I../../include -std=c++14 -O3 stateful_recurrent_tests.cpp -o stateful_recurrent_tests_cpp
- mkdir models
- echo "running stateful recurrent tests"
- python3 stateful_recurrent_tests.py
- cd ../..
# release possibly new version to conan
Expand Down
6 changes: 3 additions & 3 deletions test/stateful_test/readme.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
## Stand-Alone Stateful RNN Tests
# Stand-Alone Stateful RNN Tests

This is a set of tests that is not part of the frugally-deep unit tests. These test the functionality of the stateful property for RNNs (e.g., LSTMs, GRUs, and bidirectional variants). This requires multiple calls to `model.stateful_predict()` to test and that is why it is not covered by the standard unit tests which only verify test vectors for a single call to `model.predict()` or `model.stateful_predict()`.

To execute this test, just run the following commands:

```bash
mkdir models
g++ -I../../include -std=c++14 -O3 stateful_recurrent_tests.cpp -o stateful_recurrent_tests_cppts
g++ -I../../include -std=c++14 -O3 stateful_recurrent_tests.cpp -o stateful_recurrent_tests_cpp
python3 stateful_recurrent_tests.py
```

This does the following:

1. Runs a series of RNN models in Keras and stores the models and some test vectors in the `models` subdirectory.
2. Runs the `../../keras_export/convert_model.py ` script to convert all of the generated Keras models. The resulting json files also are written to the `models` subdirectory.
3. Compiles and runs `stateful_recurrent_tests.cpp` which loads each of the json model files and generates test vectors using frugrally-deep that correspond to those in step 1.
3. Compiles and runs `stateful_recurrent_tests.cpp` which loads each of the json model files and generates test vectors using frugrally-deep that correspond to those in step 1.
4. Compares the test vectors from Keras and frugally-deep to report PASS/FAIL on the tests.

The main Python script also creates the models directory as needed and clears it at the start of its execution.
188 changes: 96 additions & 92 deletions test/stateful_test/stateful_recurrent_tests.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import h5py
import keras
import numpy as np
from keras.layers import Input, Dense, GRU, LSTM, Bidirectional
import tensorflow as tf

tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
import os
import sys
import errno
import shutil

tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)

__author__ = "Keith Chugg"
__copyright__ = "Copyright 2019, Keith Chugg"
Expand All @@ -26,7 +24,7 @@ def get_trained_model(x_train, y_train, layer_name, n_recurrent_units, bidi):
REC_LAYER = LSTM
else:
REC_LAYER = GRU
###### Define/Build/Train Training Model
# Define/Build/Train Training Model
training_in_shape = x_train.shape[1:]
training_in = Input(shape=training_in_shape)
if bidi:
Expand All @@ -45,7 +43,7 @@ def get_trained_model(x_train, y_train, layer_name, n_recurrent_units, bidi):

def get_test_model(n_recurrent_units, sequence_length, feature_dim, layer_name, stateful, initialize_states, weights,
bidi):
features_in = Input(batch_shape=(1, sequence_length, feature_dim)) ## stateful ==> needs batch_shape specified
features_in = Input(batch_shape=(1, sequence_length, feature_dim)) # stateful ==> needs batch_shape specified
if layer_name == 'LSTM':
REC_LAYER = LSTM
else:
Expand Down Expand Up @@ -82,10 +80,9 @@ def get_test_model(n_recurrent_units, sequence_length, feature_dim, layer_name,
state_h_in = Input(batch_shape=(1, n_recurrent_units))
state_c_in = Input(batch_shape=(1, n_recurrent_units))
if layer_name == 'LSTM':
recurrent_out = REC_LAYER(n_recurrent_units, return_sequences=True, stateful=stateful)(features_in,
initial_state=[
state_h_in,
state_c_in])
recurrent_out = REC_LAYER(n_recurrent_units,
return_sequences=True,
stateful=stateful)(features_in, initial_state=[state_h_in, state_c_in])
pred = Dense(1)(recurrent_out)
test_model = keras.Model(inputs=[features_in, state_h_in, state_c_in], outputs=pred)
else:
Expand Down Expand Up @@ -132,7 +129,7 @@ def eval_test_model(baseline_out, test_model, x_in, layer_name, bidi, stateful,
# msg += f'{layer_name}; Sequence {s}; stateful {stateful}; Initialzied state: {states_initialized}; State Reset: {state_reset}\n'
if VERBOSE:
print(msg)
pred_in = x_in[s].reshape(x_inf[1:].shape)
pred_in = x_in[s].reshape(x_in[1:].shape)
if not states_initialized: # no initial state
pred_seq = test_model.predict(pred_in)
else:
Expand Down Expand Up @@ -162,85 +159,92 @@ def eval_test_model(baseline_out, test_model, x_in, layer_name, bidi, stateful,
return results


print("Starting stateful recurrent tests", flush=True)

##### generate toy data
train_seq_length = 4
feature_dim = 1
num_seqs = 8

x_train = np.random.normal(0, 1, num_seqs * train_seq_length * feature_dim)
x_train = x_train.reshape(num_seqs, train_seq_length, feature_dim)
y_train = np.random.normal(0, 1, num_seqs * train_seq_length)
y_train = y_train.reshape(num_seqs, train_seq_length, 1)

n_recurrent_units = 2
all_results = np.zeros(0, dtype=np.float32)

# hand-generate the input data to make it easy to input into C++ code by hand.
# this hard-codes the train_seq_length, feature_dim vars for this purpose
x_inf = np.asarray([2.1, -1.2, 3.14, 1.2, 1, 3, -2, 10], dtype=np.float32) # simple
x_inf = x_inf.reshape((2, train_seq_length, 1))

initial_states = np.asarray([1.1, -2.1, 2.7, 3.1, -2.5, 3.0, -2.0, -10.0], dtype=np.float32)
initial_states = initial_states.reshape((4, 1, 2))

model_file_names = []

for bidi in [False, True]:
for layer_name in ['GRU', 'LSTM']:
### train with no initial state, no statefulness
training_model, trained_weights = get_trained_model(x_train, y_train, layer_name, n_recurrent_units, bidi)
y_inf = training_model.predict(x_inf)
for stateful in [False, True]:
for initialize_states in [False, True]:
### evaluate the model
test_model, model_fname = get_test_model(n_recurrent_units, train_seq_length, feature_dim, layer_name,
stateful, initialize_states, trained_weights, bidi)
result = eval_test_model(y_inf, test_model, x_inf, layer_name, bidi, stateful, initialize_states,
initial_states)
all_results = np.append(all_results, result)
model_file_names.append(model_fname)

if VERBOSE:
print('\n\n')
print(all_results)
print(model_file_names)

all_results.tofile('models/python_results.npy')

for h5_fname in model_file_names:
json_fname = h5_fname.replace('.h5', '.json')
cmd = 'python3 ../../keras_export/convert_model.py ' + h5_fname + ' ' + json_fname
os.system(cmd)

os.system('./stateful_recurrent_tests_cpp')

frugally_deep_results = np.fromfile('models/fd_results.bin', dtype=np.float32)

num_test_models = len(model_file_names)
test_sequences_per_model = 4
frugally_deep_results = frugally_deep_results.reshape((num_test_models, test_sequences_per_model * train_seq_length))
all_results = all_results.reshape((num_test_models, test_sequences_per_model * train_seq_length))
all_results = all_results.astype(np.float32)

all_tests_passed = True
for i, model_fname in enumerate(model_file_names):
test_name = os.path.basename(model_fname)
test_name = test_name.split('.h5')[0]
print('Test ', i + 1, ' ', test_name, ': ')
diff = np.abs(all_results[i] - frugally_deep_results[i])
max_delta = np.max(diff)
def main():
print("Starting stateful recurrent tests")

# generate toy data
train_seq_length = 4
feature_dim = 1
num_seqs = 8

x_train = np.random.normal(0, 1, num_seqs * train_seq_length * feature_dim)
x_train = x_train.reshape(num_seqs, train_seq_length, feature_dim)
y_train = np.random.normal(0, 1, num_seqs * train_seq_length)
y_train = y_train.reshape(num_seqs, train_seq_length, 1)

n_recurrent_units = 2
all_results = np.zeros(0, dtype=np.float32)

# hand-generate the input data to make it easy to input into C++ code by hand.
# this hard-codes the train_seq_length, feature_dim vars for this purpose
x_inf = np.asarray([2.1, -1.2, 3.14, 1.2, 1, 3, -2, 10], dtype=np.float32) # simple
x_inf = x_inf.reshape((2, train_seq_length, 1))

initial_states = np.asarray([1.1, -2.1, 2.7, 3.1, -2.5, 3.0, -2.0, -10.0], dtype=np.float32)
initial_states = initial_states.reshape((4, 1, 2))

model_file_names = []

for bidi in [False, True]:
for layer_name in ['GRU', 'LSTM']:
# train with no initial state, no statefulness
training_model, trained_weights = get_trained_model(x_train, y_train, layer_name, n_recurrent_units, bidi)
y_inf = training_model.predict(x_inf)
for stateful in [False, True]:
for initialize_states in [False, True]:
# evaluate the model
test_model, model_fname = get_test_model(n_recurrent_units, train_seq_length, feature_dim,
layer_name,
stateful, initialize_states, trained_weights, bidi)
result = eval_test_model(y_inf, test_model, x_inf, layer_name, bidi, stateful, initialize_states,
initial_states)
all_results = np.append(all_results, result)
model_file_names.append(model_fname)

if VERBOSE:
print('Max delta: ', "{:4.3e}".format(max_delta))
if max_delta < TEST_EPSILON:
print('PASSED')
else:
print('********* FAILED !!!!!!!!!!!!\n\n')
print('Keras: ', all_results[i], '\n')
print('Frugally-deep: ', frugally_deep_results[i], '\n')
all_tests_passed = False

if not all_tests_passed:
sys.exit(errno.EIO)
print('\n\nPassed all stateful tests')
print('\n\n')
print(all_results)
print(model_file_names)

all_results.tofile('models/python_results.npy')

for h5_fname in model_file_names:
json_fname = h5_fname.replace('.h5', '.json')
cmd = 'python3 ../../keras_export/convert_model.py ' + h5_fname + ' ' + json_fname
os.system(cmd)

os.system('./stateful_recurrent_tests_cpp')

frugally_deep_results = np.fromfile('models/fd_results.bin', dtype=np.float32)

num_test_models = len(model_file_names)
test_sequences_per_model = 4
frugally_deep_results = frugally_deep_results.reshape(
(num_test_models, test_sequences_per_model * train_seq_length))
all_results = all_results.reshape((num_test_models, test_sequences_per_model * train_seq_length))
all_results = all_results.astype(np.float32)

all_tests_passed = True
for i, model_fname in enumerate(model_file_names):
test_name = os.path.basename(model_fname)
test_name = test_name.split('.h5')[0]
print('Test ', i + 1, ' ', test_name, ': ')
diff = np.abs(all_results[i] - frugally_deep_results[i])
max_delta = np.max(diff)
if VERBOSE:
print('Max delta: ', "{:4.3e}".format(max_delta))
if max_delta < TEST_EPSILON:
print('PASSED')
else:
print('********* FAILED !!!!!!!!!!!!\n\n')
print('Keras: ', all_results[i], '\n')
print('Frugally-deep: ', frugally_deep_results[i], '\n')
all_tests_passed = False

if not all_tests_passed:
sys.exit(errno.EIO)
print('\n\nPassed all stateful tests')


if __name__ == "__main__":
main()
Binary file added test/stateful_test/stateful_recurrent_tests_cpp
Binary file not shown.

0 comments on commit 828f254

Please sign in to comment.