#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Create a neural network model file."""
import logging
import os
import tarfile
import random
import yaml
import h5py
import numpy
import theano
# nntoolkit modules
from nntoolkit import utils
[docs]def get_parser():
"""Return the parser object for this script."""
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
parser = ArgumentParser(description=__doc__,
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument("-t", "--type",
choices=["mlp"],
default="mlp",
dest="type",
help="which type of neural network do you want to "
"create?",
metavar="TYPE")
parser.add_argument("-a", "--architecture",
dest="architecture",
help="""architecture of the network""",
default="160:500:369")
parser.add_argument("-f", "--file",
dest="model_file",
help="write model file to MODEL_FILE",
metavar="MODEL_FILE")
return parser
[docs]def xaviar10_weight_init(neurons_a, neurons_b):
"""Initialize the weights between a layer with ``neurons_a`` neurons
and a layer with ``neurons_b`` neurons.
:returns: A neurons_a × neurons_b matrix.
"""
fan_in = neurons_a
fan_out = neurons_b - 2
init_weight = 4.0*numpy.sqrt(6.0/(fan_in+fan_out))
W = [numpy.random.uniform(low=-init_weight,
high=init_weight,
size=neurons_a)
for _ in range(neurons_b)]
return W
[docs]def is_valid_model_file(model_file_path):
"""Check if ``model_file_path`` is a valid model file."""
if os.path.isfile(model_file_path):
logging.error("'%s' already exists.", model_file_path)
return False
if not model_file_path.endswith(".tar"):
logging.error("'%s' does not end with '.tar'.", model_file_path)
return False
return True
[docs]def create_hdf5s_for_layer(i, layer):
"""Create one HDF5 file for the weight matrix W and one for the bias vector
b.
"""
Wfile = h5py.File('W%i.hdf5' % i, 'w')
Wfile.create_dataset(Wfile.id.name, data=layer['W'])
Wfile.close()
bfile = h5py.File('b%i.hdf5' % i, 'w')
bfile.create_dataset(bfile.id.name, data=layer['b'])
bfile.close()
[docs]def create_layers(neurons):
"""Create the layers of the neural network.
:param neurons: A list of integers which indicates how many neurons are in
which layer
:returns: a list of dictionaries with random variables for the weight
matrix W and the bias vector b
"""
layers_binary = []
for neurons_b, neurons_a in zip(neurons, neurons[1:]):
W = xaviar10_weight_init(neurons_a, neurons_b)
b = [random.random() for _ in range(neurons_a)]
# TODO: parse architecture string to allow arbitrary activation
# functions
layers_binary.append({'W': numpy.array(W, dtype=theano.config.floatX),
'b': numpy.array(b, dtype=theano.config.floatX),
'activation': 'Sigmoid'})
layers_binary[-1]['activation'] = 'Softmax'
return layers_binary
[docs]def main(nn_type, architecture, model_file):
"""Create a neural network file of ``nn_type`` with ``architecture``.
Store it in ``model_file``.
:param nn_type: A string, e.g. 'mlp'
:param model_file: A path which should end with .tar. The created model
will be written there.
"""
if not is_valid_model_file(model_file):
return
logging.info("Create %s with a %s architecture...", nn_type, architecture)
filenames = ["model.yml"] # "input_semantics.csv", "output_semantics.csv"
if nn_type == 'mlp':
# Create layers by looking at 'architecture'
layers = []
# TODO: the activation function could be here!
neurons = list(map(int, architecture.split(':')))
layers_binary = create_layers(neurons)
utils.create_boilerplate_semantics_files(neurons)
filenames.append("input_semantics.csv")
filenames.append("output_semantics.csv")
# Write layers
for i, layer in enumerate(layers_binary):
create_hdf5s_for_layer(i, layer)
layers.append({'W': {'size': list(layer['W'].shape),
'filename': 'W%i.hdf5' % i},
'b': {'size': list(layer['b'].shape),
'filename': 'b%i.hdf5' % i},
'activation': layer['activation']})
filenames.append('W%i.hdf5' % i)
filenames.append('b%i.hdf5' % i)
model = {'type': 'mlp', 'layers': layers}
with open('model.yml', 'w') as f:
yaml.dump(model, f, default_flow_style=False)
# Create tar file
with tarfile.open(model_file, "w:") as tar:
for name in filenames:
tar.add(name)
# Remove temporary files which are now in tar file
for filename in filenames:
os.remove(filename)
if __name__ == '__main__':
args = get_parser().parse_args()
main(args.type, args.architecture, args.model_file)