Find out all the relevant ops for creating neural networks in tensorflow. Since some categories only exist in the tensorflow documentation, but not in the code, it has to be categorized manually or scraped from the documentation.

We assume that all the relevant operations reside in the tf.nn namespace. We parse the documentation to get the right categories and then run them to get the respective type of the operations. We try to pass as least argument as possible to all function and reuse arguments where possible


In [2]:
import tensorflow as tf
dir(tf.nn)


Out[2]:
['__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 '_allowed_symbols',
 '_ctc_ops',
 '_embedding_ops',
 '_nn_grad',
 '_nn_ops',
 '_sys',
 'all_candidate_sampler',
 'atrous_conv2d',
 'atrous_conv2d_transpose',
 'avg_pool',
 'avg_pool3d',
 'batch_norm_with_global_normalization',
 'batch_normalization',
 'bias_add',
 'bidirectional_dynamic_rnn',
 'compute_accidental_hits',
 'conv1d',
 'conv2d',
 'conv2d_backprop_filter',
 'conv2d_backprop_input',
 'conv2d_transpose',
 'conv3d',
 'conv3d_backprop_filter_v2',
 'conv3d_transpose',
 'convolution',
 'crelu',
 'ctc_beam_search_decoder',
 'ctc_greedy_decoder',
 'ctc_loss',
 'depthwise_conv2d',
 'depthwise_conv2d_native',
 'depthwise_conv2d_native_backprop_filter',
 'depthwise_conv2d_native_backprop_input',
 'dilation2d',
 'dropout',
 'dynamic_rnn',
 'elu',
 'embedding_lookup',
 'embedding_lookup_sparse',
 'erosion2d',
 'fixed_unigram_candidate_sampler',
 'fractional_avg_pool',
 'fractional_max_pool',
 'fused_batch_norm',
 'in_top_k',
 'l2_loss',
 'l2_normalize',
 'learned_unigram_candidate_sampler',
 'local_response_normalization',
 'log_poisson_loss',
 'log_softmax',
 'log_uniform_candidate_sampler',
 'lrn',
 'max_pool',
 'max_pool3d',
 'max_pool_with_argmax',
 'moments',
 'nce_loss',
 'normalize_moments',
 'pool',
 'quantized_avg_pool',
 'quantized_conv2d',
 'quantized_max_pool',
 'quantized_relu_x',
 'raw_rnn',
 'relu',
 'relu6',
 'relu_layer',
 'rnn_cell',
 'sampled_softmax_loss',
 'separable_conv2d',
 'sigmoid',
 'sigmoid_cross_entropy_with_logits',
 'softmax',
 'softmax_cross_entropy_with_logits',
 'softplus',
 'softsign',
 'sparse_softmax_cross_entropy_with_logits',
 'static_bidirectional_rnn',
 'static_rnn',
 'static_state_saving_rnn',
 'sufficient_statistics',
 'tanh',
 'top_k',
 'uniform_candidate_sampler',
 'weighted_cross_entropy_with_logits',
 'weighted_moments',
 'with_space_to_batch',
 'xw_plus_b',
 'zero_fraction']

Download the documentation in markdown and parse it.


In [2]:
!wget https://github.com/tensorflow/tensorflow/blob/master/tensorflow/docs_src/api_guides/python/nn.md


--2017-09-19 18:04:49--  https://github.com/tensorflow/tensorflow/blob/master/tensorflow/docs_src/api_guides/python/nn.md
Resolving github.com (github.com)... 192.30.253.113, 192.30.253.112
Connecting to github.com (github.com)|192.30.253.113|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘nn.md’

nn.md                   [  <=>               ]  95.32K   279KB/s    in 0.3s    

2017-09-19 18:04:50 (279 KB/s) - ‘nn.md’ saved [97605]


In [3]:
import re
import pprint
import tensorflow as tf
import inspect

# Define basic input output.
def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

x = tf.placeholder(tf.float32, shape=[None, 784])
W_conv1 = weight_variable([5, 5, 1, 32])
y_ = tf.placeholder(tf.float32, shape=[None, 10])
x_image = tf.reshape(x, [-1, 28, 28, 1])


# Regexes for finding headings and the function references.
section_header_regex = re.compile(r'##\s(.+)$')
function_reference_regex = re.compile(r'\*\s{3}@\{([\w\.]+?)\}')

def transform_heading(s: str):
    return s.lower().replace(' ', '_') + '_fns'

categories = {}
current_heading = ''
with open('nn.md', 'r') as doc_file:
    # Search for section headings.
    for line in doc_file:
        heading = section_header_regex.match(line)
        if heading is not None:
            current_heading = transform_heading(heading.group(1))
            categories[current_heading] = []
        elif current_heading:
            fn = function_reference_regex.match(line)
            if fn is not None:
                categories[current_heading].append(fn.group(1))
                


# Arguments passed to the tensorflow functions.
default_filter = W_conv1
defaults = {
    'features': [0.1, 0.1],
    'padding': 'SAME',
    'kernel_size': 3,
    'x': x_image,
    'keep_prob': 0.5,
    'value': x_image,
    'bias': [1] * 4,
    'input': x_image,
    'filter': default_filter,
    'strides': [1, 2, 2, 1],
    'stride': 2,
    'depthwise_filter': default_filter,
    'pointwise_filter': default_filter,
    'filters': [3, 3, 28, 2],
    'rate': 2,
    'output_shape': [3],
    'filter_sizes': [3, 3, 28, 2],
    'out_backprop': [1, 28, 28, 1],
    'input_sizes': [1, 3, 3, 3],
    'ksize': [1.0, 2.0, 2.0, 1.0],
    'pooling_ratio': [1.0, 1.44, 1.73, 1.0],
    'window_shape': [2, 2],
    'rates': [1, 2, 2, 1], # for morphological operations
    'kernel': default_filter,
    'dim': 0, # Normalization
    'axes': [0],
    'counts': 1,
    'mean_ss': 0.5,
    'variance_ss': 0.1,
    'shift': 1,
    'scale': 2.0,
    'offset': 0.0,
    'mean': 1.0,
    'variance': 0.1,
    'variance_epsilon': 0.01,
    't': [1.0],
    'targets': [1.0],
    'log_input': [1.0],
    'logits': [1.0],
    'pos_weight': 1.0,
    'cell': tf.contrib.rnn.BasicRNNCell(1), # rnn
    'inputs': x,
    'labels': y_,
    'predictions': y_,
    'k': 2.0,
    
}

# Ignore functions for which arguments that work cannot be found easily.
ignored_fns = {'convolution', 'atrous_conv2d', 'atrous_conv2d_transpose', 'conv2d_transpose', 
               'conv3d_transpose', 'conv1d', 'pool',
               'with_space_to_batch', 'lrn', 'normalize_moments', 'weighted_moments', 
               'batch_norm_with_global_normalization',
               'embedding_lookup', 'embedding_lookup_sparse',
               'bidirectional_dynamic_rnn', 'raw_rnn',
               'in_top_k'
              }
# Remove unimportant categories.
del categories['connectionist_temporal_classification_(ctc)_fns']
del categories['candidate_sampling_fns']

# Basic operations that are not of interest.
base_ops = {'Add', 'Reshape', 'Const', 'Mul', 'Sub', 'Neg', 'Exp', 'Maximum', 'Floor', 'Assign', 'Identity',
            'VariableV2', 'Sum', 'Squeeze'}

graph = tf.get_default_graph()

def transform_cat(cat_name):
    return cat.replace('_fns', '_types')

# Iterate over all function categories and find the type of the ops that are created by them.
category_types = {}
function_to_optype = {}
op_count = 0

for cat in categories.keys():
    current_cat_type = cat.replace('_fns', '_types')
    category_types[current_cat_type] = []
    current_cat_mapping = cat.replace('_fns', '_mapping')
    function_to_optype[current_cat_mapping] = []
    for fn_str in categories[cat]:
        if not fn_str.replace('tf.nn.', '') in ignored_fns:
            # Get the tensorflow function corresponding to the string.
            fn_obj = eval(fn_str)
            print(fn_obj)
            sig = inspect.signature(fn_obj)
            # Apply only those parameters that actually apply and don't have a default value.
            applicalbe_args = {k: v for k, v in defaults.items() 
                               if k in sig.parameters.keys() and sig.parameters[k].default == inspect._empty}
            binding = sig.bind(**applicalbe_args)
            binding.apply_defaults()
            try:
                # Call the function with the neccessary arguments.
                fn_obj(**binding.arguments)
                # Look at the type of the last op that was added to the operations, that is not a basic op.
                ops = graph.get_operations()
                num_new_ops = len(ops) - op_count
                for i, op in enumerate(reversed(ops)):
                    if op.type not in base_ops:
                        category_types[current_cat_type].append(op.type)
                        function_to_optype[current_cat_mapping].append((fn_obj.__name__, op.type))
                        break
                    else:
                        if num_new_ops <= i:
                            continue
                        else:
                            break
            # If the defined default values cause problems ignore the function.   
            except ValueError as e:
                print(e)

    
pprint.pprint(category_types)
pprint.pprint(function_to_optype)


<function relu at 0x7f78381f68c8>
<function relu6 at 0x7f782e457048>
<function crelu at 0x7f782e43ef28>
<function elu at 0x7f783824d730>
<function softplus at 0x7f78381f6f28>
<function softsign at 0x7f783825a0d0>
<function dropout at 0x7f782e3d3c80>
<function bias_add at 0x7f782e43ee18>
Dimensions must be equal, but are 1 and 4 for 'BiasAdd' (op: 'BiasAdd') with input shapes: [?,28,28,1], [4].
<function sigmoid at 0x7f782e996048>
<function tanh at 0x7f782e996158>
<function conv2d at 0x7f7838239f28>
<function depthwise_conv2d at 0x7f782e36e268>
<function depthwise_conv2d_native at 0x7f783824d400>
<function separable_conv2d at 0x7f782e36e2f0>
Dimensions 5 and 1 are not compatible
<function conv3d at 0x7f783824d158>
Attr 'strides' of 'Conv3D' Op passed list of length 4 less than minimum 5.
<function conv2d_backprop_filter at 0x7f783824d048>
<function conv2d_backprop_input at 0x7f783824d0d0>
<function conv3d_backprop_filter_v2 at 0x7f783824d268>
Attr 'strides' of 'Conv3DBackpropFilterV2' Op passed list of length 4 less than minimum 5.
<function depthwise_conv2d_native_backprop_filter at 0x7f783824d488>
<function depthwise_conv2d_native_backprop_input at 0x7f783824d510>
<function avg_pool at 0x7f782e457488>
<function max_pool at 0x7f782e457510>
<function max_pool_with_argmax at 0x7f7838260400>
<function avg_pool3d at 0x7f78382396a8>
Attr 'ksize' of 'AvgPool3D' Op passed list of length 4 less than minimum 5.
<function max_pool3d at 0x7f783824ef28>
Attr 'ksize' of 'MaxPool3D' Op passed list of length 4 less than minimum 5.
<function fractional_avg_pool at 0x7f783824d8c8>
<function fractional_max_pool at 0x7f783824dd90>
<function dilation2d at 0x7f783824d598>
Shape must be rank 3 but is rank 4 for 'Dilation2D' (op: 'Dilation2D') with input shapes: [?,28,28,1], [5,5,1,32].
<function erosion2d at 0x7f782e3d3ea0>
Shape must be rank 3 but is rank 4 for 'erosion2d' (op: 'Dilation2D') with input shapes: [?,28,28,1], [5,5,1,32].
<function l2_normalize at 0x7f782e36e158>
<function lrn at 0x7f783824ed08>
<function sufficient_statistics at 0x7f782e36e378>
<function moments at 0x7f782e36e488>
<function fused_batch_norm at 0x7f782e36e620>
Shape must be rank 1 but is rank 0 for 'FusedBatchNorm' (op: 'FusedBatchNorm') with input shapes: [?,28,28,1], [], [], [0], [0].
<function batch_normalization at 0x7f782e36e598>
<function l2_loss at 0x7f783824ec80>
<function log_poisson_loss at 0x7f782e3e3b70>
<function sigmoid_cross_entropy_with_logits at 0x7f782e378f28>
Both labels and logits must be provided.
<function softmax at 0x7f782e4571e0>
<function log_softmax at 0x7f782e457268>
<function softmax_cross_entropy_with_logits at 0x7f782e457378>
Both labels and logits must be provided.
<function sparse_softmax_cross_entropy_with_logits at 0x7f782e457400>
Both labels and logits must be provided.
<function weighted_cross_entropy_with_logits at 0x7f782e36e048>
<function dynamic_rnn at 0x7f782e347488>
If there is no initial_state, you must give a dtype.
<function top_k at 0x7f782e3d3d08>
{'activation_functions_types': ['Relu',
                                'Relu6',
                                'Relu',
                                'Elu',
                                'Softplus',
                                'Softsign',
                                'Sigmoid',
                                'Tanh'],
 'classification_types': [],
 'convolution_types': ['Conv2D',
                       'DepthwiseConv2dNative',
                       'DepthwiseConv2dNative',
                       'Conv2DBackpropFilter',
                       'Conv2DBackpropInput',
                       'DepthwiseConv2dNativeBackpropFilter',
                       'DepthwiseConv2dNativeBackpropInput'],
 'embeddings_types': [],
 'evaluation_types': ['TopKV2'],
 'losses_types': ['L2Loss'],
 'morphological_filtering_types': [],
 'normalization_types': ['LRN'],
 'pooling_types': ['AvgPool',
                   'MaxPool',
                   'MaxPoolWithArgmax',
                   'FractionalAvgPool',
                   'FractionalMaxPool'],
 'recurrent_neural_networks_types': []}
{'activation_functions_mapping': [('relu', 'Relu'),
                                  ('relu6', 'Relu6'),
                                  ('crelu', 'Relu'),
                                  ('elu', 'Elu'),
                                  ('softplus', 'Softplus'),
                                  ('softsign', 'Softsign'),
                                  ('sigmoid', 'Sigmoid'),
                                  ('tanh', 'Tanh')],
 'classification_mapping': [],
 'convolution_mapping': [('conv2d', 'Conv2D'),
                         ('depthwise_conv2d', 'DepthwiseConv2dNative'),
                         ('depthwise_conv2d_native', 'DepthwiseConv2dNative'),
                         ('conv2d_backprop_filter', 'Conv2DBackpropFilter'),
                         ('conv2d_backprop_input', 'Conv2DBackpropInput'),
                         ('depthwise_conv2d_native_backprop_filter',
                          'DepthwiseConv2dNativeBackpropFilter'),
                         ('depthwise_conv2d_native_backprop_input',
                          'DepthwiseConv2dNativeBackpropInput')],
 'embeddings_mapping': [],
 'evaluation_mapping': [('top_k', 'TopKV2')],
 'losses_mapping': [('l2_loss', 'L2Loss')],
 'morphological_filtering_mapping': [],
 'normalization_mapping': [('lrn', 'LRN')],
 'pooling_mapping': [('avg_pool', 'AvgPool'),
                     ('max_pool', 'MaxPool'),
                     ('max_pool_with_argmax', 'MaxPoolWithArgmax'),
                     ('fractional_avg_pool', 'FractionalAvgPool'),
                     ('fractional_max_pool', 'FractionalMaxPool')],
 'recurrent_neural_networks_mapping': []}

In [7]:
category_types_without_suffix = {}
for cat_type in category_types.keys():
    category_types_without_suffix[cat_type.replace('_types', '')] = category_types[cat_type]
pprint.pprint(category_types_without_suffix)


{'activation_functions': ['Relu',
                          'Relu6',
                          'Relu',
                          'Elu',
                          'Softplus',
                          'Softsign',
                          'Sigmoid',
                          'Tanh'],
 'classification': [],
 'convolution': ['Conv2D',
                 'DepthwiseConv2dNative',
                 'DepthwiseConv2dNative',
                 'Conv2DBackpropFilter',
                 'Conv2DBackpropInput',
                 'DepthwiseConv2dNativeBackpropFilter',
                 'DepthwiseConv2dNativeBackpropInput'],
 'embeddings': [],
 'evaluation': ['TopKV2'],
 'losses': ['L2Loss'],
 'morphological_filtering': [],
 'normalization': ['LRN'],
 'pooling': ['AvgPool',
             'MaxPool',
             'MaxPoolWithArgmax',
             'FractionalAvgPool',
             'FractionalMaxPool'],
 'recurrent_neural_networks': []}

This should be more or less are complete list of the relevant operation types. Now we can define a layer as a sequence of operation types.

  • A Conv2D layer is a convolution operation, followed by addition (for the bias) and an activation function.
  • A Pooling layer is simply a pooling operation.
  • A Dense layer is matrix multiplication (MatMul) followed by addition and an activation function.