diff --git a/NEWS b/NEWS index 2f8d920f4a6..70242d9f5ff 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ -2015-01-18 Soeren Sonnenburg +2015-01-26 Soeren Sonnenburg - * SHOGUN Release version 3.2.1 (libshogun 16.1, data 0.8, parameter 1) + * SHOGUN Release version 4.0.0 (libshogun 17.0, data 0.9, parameter 1) * This release features the work of our 8 GSoC 2014 students [student; mentors]: - OpenCV Integration and Computer Vision Applications [Abhijeet Kislay; Kevin Hughes] - Large-Scale Multi-Label Classification [Abinash Panda; Thoralf Klein] diff --git a/src/interfaces/modular/IO.i b/src/interfaces/modular/IO.i index d1961287982..63b4bf59564 100644 --- a/src/interfaces/modular/IO.i +++ b/src/interfaces/modular/IO.i @@ -26,6 +26,7 @@ %rename(SerializableHdf5File) CSerializableHdf5File; %rename(SerializableJsonFile) CSerializableJsonFile; %rename(SerializableXmlFile) CSerializableXmlFile; +%rename(NeuralNetworkFileReader) CNeuralNetworkFileReader; %rename(SimpleFile) CSimpleFile; %rename(MemoryMappedFile) CMemoryMappedFile; %rename(VwParser) CVwParser; @@ -131,6 +132,7 @@ namespace shogun %include %include %include +%include %include %include diff --git a/src/interfaces/modular/IO_includes.i b/src/interfaces/modular/IO_includes.i index 72a19d54ccb..608fa495b21 100644 --- a/src/interfaces/modular/IO_includes.i +++ b/src/interfaces/modular/IO_includes.i @@ -20,6 +20,7 @@ #include #include #include +#include #include #include %} diff --git a/src/interfaces/octave_static/OctaveInterface.cpp b/src/interfaces/octave_static/OctaveInterface.cpp index 33937d5614e..bbd49c10d8a 100644 --- a/src/interfaces/octave_static/OctaveInterface.cpp +++ b/src/interfaces/octave_static/OctaveInterface.cpp @@ -633,8 +633,8 @@ void COctaveInterface::clear_octave_globals() void COctaveInterface::run_octave_init() { - char* name=strdup("octave"); - char* opts=strdup("-q"); + char* name=get_strdup("octave"); + char* opts=get_strdup("-q"); char* argv[2]={name, opts}; octave_main(2,argv,1); free(opts); diff --git a/src/interfaces/r_static/RInterface.cpp b/src/interfaces/r_static/RInterface.cpp index bc476e39cd4..00df9fdb5be 100644 --- a/src/interfaces/r_static/RInterface.cpp +++ b/src/interfaces/r_static/RInterface.cpp @@ -18,6 +18,7 @@ extern "C" { #include #include #include +#include #ifdef HAVE_PYTHON #include "../python_static/PythonInterface.h" @@ -552,8 +553,8 @@ void CRInterface::run_r_init() #ifdef R_HOME_ENV setenv("R_HOME", R_HOME_ENV, 0); #endif - char* name=strdup("R"); - char* opts=strdup("-q"); + char* name=get_strdup("R"); + char* opts=get_strdup("-q"); char* argv[2]={name, opts}; Rf_initEmbeddedR(2, argv); free(opts); diff --git a/src/shogun/io/File.cpp b/src/shogun/io/File.cpp index 58ce9cecfde..0b86a622cdd 100644 --- a/src/shogun/io/File.cpp +++ b/src/shogun/io/File.cpp @@ -185,12 +185,12 @@ CFile::~CFile() void CFile::set_variable_name(const char* name) { SG_FREE(variable_name); - variable_name=strdup(name); + variable_name=get_strdup(name); } char* CFile::get_variable_name() { - return strdup(variable_name); + return get_strdup(variable_name); } #define SPARSE_VECTOR_GETTER(type) \ diff --git a/src/shogun/io/NeuralNetworkFileReader.cpp b/src/shogun/io/NeuralNetworkFileReader.cpp new file mode 100644 index 00000000000..84265f49dbc --- /dev/null +++ b/src/shogun/io/NeuralNetworkFileReader.cpp @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2014, Shogun Toolbox Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Written (W) 2014 Khaled Nasr + */ + +#include +#ifdef HAVE_JSON + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace shogun; + +CNeuralNetwork* CNeuralNetworkFileReader::read_file(const char* file_path) +{ + json_object* json_network = json_object_from_file(file_path); + + if (is_error(json_network)) + { + SG_ERROR("Error while opening file: %s!\n", file_path); + return NULL; + } + + CNeuralNetwork* network = parse_network(json_network); + + json_object_put(json_network); + + return network; +} + +CNeuralNetwork* CNeuralNetworkFileReader::read_string(const char* str) +{ + json_object* json_network = json_tokener_parse(str); + + if (is_error(json_network)) + { + SG_ERROR("Error while parsing the given string\n"); + return NULL; + } + + CNeuralNetwork* network = parse_network(json_network); + + json_object_put(json_network); + + return network; +} + +CNeuralNetwork* CNeuralNetworkFileReader::parse_network(json_object* json_network) +{ + CNeuralNetwork* network = new CNeuralNetwork; + + // find the layers + json_object_iter iter; + json_object* json_layers = NULL; + json_object_object_foreachC(json_network, iter) + { + if (string_equal(iter.key, "layers")) + json_layers = iter.val; + } + + if (json_layers) + network->set_layers(parse_layers(iter.val)); + else + SG_ERROR("No layers found in file\n"); + + // set the connections + json_object_iter layers_iter; + json_object_object_foreachC(json_layers, layers_iter) + { + json_object_iter layer_iter; + json_object_object_foreachC(layers_iter.val, layer_iter) + { + if (string_equal(layer_iter.key, "inputs")) + { + int32_t len = json_object_array_length(layer_iter.val); + + for (int32_t i=0; iconnect(from, to); + } + } + } + } + + // set the training parameters + float sigma = 0.01; + json_object_object_foreachC(json_network, iter) + { + if (string_equal(iter.key, "sigma")) + sigma = json_object_get_double(iter.val); + else if (string_equal(iter.key, "optimization_method")) + { + const char* method = json_object_get_string(iter.val); + if (string_equal(method, "NNOM_LBFGS")) + network->optimization_method = NNOM_LBFGS; + else if (string_equal(method, "NNOM_GRADIENT_DESCENT")) + network->optimization_method = NNOM_GRADIENT_DESCENT; + else + SG_ERROR("Invalid optimization method (%s)\n", method); + } + else if (string_equal(iter.key, "l2_coefficient")) + network->l2_coefficient = json_object_get_double(iter.val); + else if (string_equal(iter.key, "l1_coefficient")) + network->l1_coefficient = json_object_get_double(iter.val); + else if (string_equal(iter.key, "dropout_hidden")) + network->dropout_hidden = json_object_get_double(iter.val); + else if (string_equal(iter.key, "dropout_input")) + network->dropout_input = json_object_get_double(iter.val); + else if (string_equal(iter.key, "max_norm")) + network->max_norm = json_object_get_double(iter.val); + else if (string_equal(iter.key, "epsilon")) + network->epsilon = json_object_get_double(iter.val); + else if (string_equal(iter.key, "max_num_epochs")) + network->max_num_epochs = json_object_get_int(iter.val); + else if (string_equal(iter.key, "gd_mini_batch_size")) + network->gd_mini_batch_size = json_object_get_int(iter.val); + else if (string_equal(iter.key, "gd_learning_rate")) + network->gd_learning_rate = json_object_get_double(iter.val); + else if (string_equal(iter.key, "gd_learning_rate_decay")) + network->gd_learning_rate_decay = json_object_get_double(iter.val); + else if (string_equal(iter.key, "gd_momentum")) + network->gd_momentum = json_object_get_double(iter.val); + else if (string_equal(iter.key, "gd_error_damping_coeff")) + network->gd_error_damping_coeff = json_object_get_double(iter.val); + + else if (!string_equal(iter.key, "layers")) + SG_ERROR("Invalid parameter (%s)\n", iter.key); + } + + network->initialize(sigma); + + return network; +} + +CDynamicObjectArray* CNeuralNetworkFileReader::parse_layers( + json_object* json_layers) +{ + CDynamicObjectArray* layers = new CDynamicObjectArray(); + + json_object_iter iter; + json_object_object_foreachC(json_layers, iter) + { + layers->append_element(parse_layer(iter.val)); + } + + return layers; +} + +CNeuralLayer* CNeuralNetworkFileReader::parse_layer(json_object* json_layer) +{ + json_object_iter iter; + + CNeuralLayer* layer = NULL; + const char* type = NULL; + + // find the layer type and create a appropriate instance + json_object_object_foreachC(json_layer, iter) + { + if (string_equal(iter.key, "type")) + { + type = json_object_get_string(iter.val); + + if (string_equal(type, "NeuralInputLayer")) + layer = new CNeuralInputLayer(); + else if (string_equal(type, "NeuralLinearLayer")) + layer = new CNeuralLinearLayer(); + else if (string_equal(type, "NeuralLogisticLayer")) + layer = new CNeuralLogisticLayer(); + else if (string_equal(type, "NeuralSoftmaxLayer")) + layer = new CNeuralSoftmaxLayer(); + else if (string_equal(type, "NeuralRectifiedLinearLayer")) + layer = new CNeuralRectifiedLinearLayer(); + else + SG_ERROR("Unknown layer type: %s", type); + } + } + + // fill in the fields + json_object_object_foreachC(json_layer, iter) + { + if(string_equal(iter.key, "num_neurons")) + { + layer->set_num_neurons(json_object_get_int(iter.val)); + } + else if(string_equal(type,"NeuralInputLayer") && + string_equal(iter.key, "start_index")) + { + ((CNeuralInputLayer*)layer)->set_start_index( + json_object_get_int(iter.val)); + } + } + + return layer; +} + +int32_t CNeuralNetworkFileReader::find_layer_index(json_object* json_layers, + const char* layer_key) +{ + int32_t index = 0; + + json_object_iter iter; + json_object_object_foreachC(json_layers, iter) + { + if (string_equal(iter.key, layer_key)) + return index; + else + index++; + } + + return -1; +} + +bool CNeuralNetworkFileReader::string_equal(const char* str1, const char* str2) +{ + return (strcmp(str1, str2) == 0); +} + +#endif diff --git a/src/shogun/io/NeuralNetworkFileReader.h b/src/shogun/io/NeuralNetworkFileReader.h new file mode 100644 index 00000000000..330dec04921 --- /dev/null +++ b/src/shogun/io/NeuralNetworkFileReader.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2014, Shogun Toolbox Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Written (W) 2014 Khaled Nasr + */ + +#ifndef __NEURALNETWORKFILEREADER_H__ +#define __NEURALNETWORKFILEREADER_H__ + +#include + +#ifdef HAVE_JSON + +#include + +#include +#include + +namespace shogun +{ +class CNeuralNetwork; +class CNeuralLayer; +class CDynamicObjectArray; + +/** @brief Creates a CNeuralNetwork from a JSON file + * + * The class creates and initializes a CNeuralNetwork using a JSON file. The + * file can be used to specify the structure of the network (types of layers, + * connections between layers, ..) and the training parameters. + * + * The file must contain a JSON object with the name "layers". This describes + * the layers of the network. Each layer must have the following: + * - a "type" field that contains the name of the class to be created, without + * the C, i.e "NeuralLogisticLayer" for CNeuralLogisticLayer. + * - a "num_neurons" field that contains the number of neurons + * - For CNeuralInputLayer, a "start_index" field could be added to specify + * the start index + * - For non-input layers, an "inputs" field must be specified, which is an + * array of strings (names of other layer) that specify which layers are + * connected to this layer as input. + * + * The training parameters can also be specified (see example below). For a + * list of all possible parameters, see the public variable of CNeuralNetwork. + * + * A field named "sigma" could be added to specify the standard deviation of + * the gaussian used to initialize the parameters. + * + * The following example shows how to create a network with two input layers, + * one logistic hidden layer, one rectified-linear hidden layer and a softmax + * output layer. The logistic layer takes input from the first input layer. + * The rectified-linear layer takes input from the second input layer and the + * logistic layer. The softmax layer takes input from the logistic layer and the + * rectified-linear layer. The network uses dropout and is trained with gradient + * descent. + * + * \code{.json} + { + "sigma": 0.01, + + "l2_coefficient": 0.001, + + "optimization_method": "NNOM_GRADIENT_DESCENT", + + "dropout_hidden": 0.5, + + "dropout_input": 0.2, + + "layers": + { + "input1": + { + "type": "NeuralInputLayer", + "num_neurons": 6, + "start_index": 0 + }, + "input2": + { + "type": "NeuralInputLayer", + "num_neurons": 10, + "start_index": 6 + }, + "logistic": + { + "type": "NeuralLogisticLayer", + "num_neurons": 32, + "inputs": ["input1"] + }, + "rectified": + { + "type": "NeuralRectifiedLinearLayer", + "num_neurons": 8, + "inputs": ["logistic", "input2"] + }, + "softmax": + { + "type": "NeuralSoftmaxLayer", + "num_neurons": 4, + "inputs": ["logistic", "rectified"] + } + } + } + * \endcode + * + */ +class CNeuralNetworkFileReader : public CSGObject +{ +public: + /** default constructor */ + CNeuralNetworkFileReader() { } + + virtual ~CNeuralNetworkFileReader() { } + + /** Reads a given JSON file + * + * @param file_path path to the JSON file describing the network + * + * @return newly created and initialized neural network according to the + * contents of the file + */ + virtual CNeuralNetwork* read_file(const char* file_path); + + /** Reads a given JSON string + * + * @param str string containing JSON code describing the network + * + * @return newly created and initialized neural network according to the + * contents of the string + */ + virtual CNeuralNetwork* read_string(const char* str); + + virtual const char* get_name() const { return "NeuralNetworkFileReader";} + +protected: + /** Parses a JSON object into a CNeuralNetwork */ + virtual CNeuralNetwork* parse_network(json_object* json_network); + + /** Parses a JSON object into a CDynamicObjectArray of CNeuralLayer objects + */ + virtual CDynamicObjectArray* parse_layers(json_object* json_layers); + + /** Parses a JSON object into a CNeuralLayer */ + virtual CNeuralLayer* parse_layer(json_object* json_layer); + +private: + /** Attempts to find a layer with the given key in the given array of + * layers. Return the index of the layer if found, -1 otherwise + */ + int32_t find_layer_index(json_object* json_layers, const char* layer_key); + + /** Returns true if the two given strings match completely, false otherwise + */ + bool string_equal(const char* str1, const char* str2); +}; + +} +#endif /* HAVE_JSON */ +#endif /* __NEURALNETWORKFILEREADER_H__ */ diff --git a/src/shogun/neuralnets/NeuralLayer.h b/src/shogun/neuralnets/NeuralLayer.h index 8503b70f0e6..ad832d7707b 100644 --- a/src/shogun/neuralnets/NeuralLayer.h +++ b/src/shogun/neuralnets/NeuralLayer.h @@ -264,6 +264,16 @@ class CNeuralLayer : public CSGObject */ virtual int32_t get_height() { return m_height; } + /** Gets the number of neurons in the layer + * + * @param num_neurons number of neurons in the layer + */ + virtual void set_num_neurons(int32_t num_neurons) + { + m_num_neurons = num_neurons; + set_batch_size(m_batch_size); + } + /** Gets the number of parameters used in this layer * * @return number of parameters used in this layer @@ -296,6 +306,12 @@ class CNeuralLayer : public CSGObject return m_local_gradients; } + /** Gets the indices of the layers that are connected to this layer as input + * + * @return layer's input indices + */ + virtual SGVector get_input_indices() { return m_input_indices; } + virtual const char* get_name() const { return "NeuralLayer"; } private: diff --git a/src/shogun/neuralnets/NeuralNetwork.h b/src/shogun/neuralnets/NeuralNetwork.h index 593b8714374..fe3c49ee639 100644 --- a/src/shogun/neuralnets/NeuralNetwork.h +++ b/src/shogun/neuralnets/NeuralNetwork.h @@ -77,6 +77,9 @@ enum ENNOptimizationMethod * using save_serializable() (loaded using load_serializable()) * - Apply the network using apply() * + * The network can also be initialized from a JSON file using + * CNeuralNetworkFileReader. + * * Supported feature types: CDenseFeatures * Supported label types: * - CBinaryLabels diff --git a/tests/unit/io/NeuralNetworkFileReader_unittest.cc b/tests/unit/io/NeuralNetworkFileReader_unittest.cc new file mode 100644 index 00000000000..058357ce983 --- /dev/null +++ b/tests/unit/io/NeuralNetworkFileReader_unittest.cc @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2014, Shogun Toolbox Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Written (W) 2014 Khaled Nasr + */ + +#include + +#ifdef HAVE_JSON + +#include +#include +#include +#include +#include + +#include + +using namespace shogun; + +TEST(NeuralNetworkFileReader, read) +{ + const char* net_string = + "{" + " \"sigma\": 0.01," + " \"optimization_method\": \"NNOM_GRADIENT_DESCENT\"," + " \"l2_coefficient\": 0.001," + " \"l1_coefficient\": 0.003," + " \"dropout_hidden\": 0.5," + " \"dropout_input\": 0.2," + " \"max_norm\": 15," + " \"epsilon\": 1e-8," + " \"max_num_epochs\": 1000," + " \"gd_mini_batch_size\": 100," + " \"gd_learning_rate\": 1.0," + " \"gd_learning_rate_decay\": 0.995," + " \"gd_momentum\": 0.95," + " \"gd_error_damping_coeff\": 0.9," + + " \"layers\":" + " {" + " \"input1\":" + " {" + " \"type\": \"NeuralInputLayer\"," + " \"num_neurons\": 6," + " \"start_index\": 0" + " }," + " \"input2\":" + " {" + " \"type\": \"NeuralInputLayer\"," + " \"num_neurons\": 10," + " \"start_index\": 6" + " }," + " \"logistic1\":" + " {" + " \"type\": \"NeuralLogisticLayer\"," + " \"num_neurons\": 32," + " \"inputs\": [\"input1\", \"input2\"]" + " }," + " \"linear1\":" + " {" + " \"type\": \"NeuralLinearLayer\"," + " \"num_neurons\": 8," + " \"inputs\": [\"logistic1\"]" + " }," + " \"rectified1\":" + " {" + " \"type\": \"NeuralRectifiedLinearLayer\"," + " \"num_neurons\": 8," + " \"inputs\": [\"logistic1\", \"input2\"]" + " }," + " \"softmax\":" + " {" + " \"type\": \"NeuralSoftmaxLayer\"," + " \"num_neurons\": 4," + " \"inputs\": [\"linear1\", \"rectified1\"]" + " }" + " }" + "}"; + + CNeuralNetworkFileReader reader; + CNeuralNetwork* net = reader.read_string(net_string); + + EXPECT_EQ(NNOM_GRADIENT_DESCENT, net->optimization_method); + EXPECT_EQ(0.001, net->l2_coefficient); + EXPECT_EQ(0.003, net->l1_coefficient); + EXPECT_EQ(0.5, net->dropout_hidden); + EXPECT_EQ(0.2, net->dropout_input); + EXPECT_EQ(15, net->max_norm); + EXPECT_EQ(1e-8, net->epsilon); + EXPECT_EQ(1000, net->max_num_epochs); + EXPECT_EQ(100, net->gd_mini_batch_size); + EXPECT_EQ(1.0, net->gd_learning_rate); + EXPECT_EQ(0.995, net->gd_learning_rate_decay); + EXPECT_EQ(0.95, net->gd_momentum); + EXPECT_EQ(0.9, net->gd_error_damping_coeff); + + CDynamicObjectArray* layers = net->get_layers(); + + CNeuralLayer* input1 = (CNeuralLayer*)layers->element(0); + EXPECT_EQ(0, strcmp(input1->get_name(), "NeuralInputLayer")); + EXPECT_EQ(6, input1->get_num_neurons()); + EXPECT_EQ(0, ((CNeuralInputLayer*)input1)->get_start_index()); + SG_UNREF(input1); + + CNeuralLayer* input2 = (CNeuralLayer*)layers->element(1); + EXPECT_EQ(0, strcmp(input1->get_name(), "NeuralInputLayer")); + EXPECT_EQ(10, input2->get_num_neurons()); + EXPECT_EQ(6, ((CNeuralInputLayer*)input2)->get_start_index()); + SG_UNREF(input2); + + CNeuralLayer* logistic1 = (CNeuralLayer*)layers->element(2); + EXPECT_EQ(0, strcmp(logistic1->get_name(), "NeuralLogisticLayer")); + EXPECT_EQ(32, logistic1->get_num_neurons()); + EXPECT_EQ(2, logistic1->get_input_indices().vlen); + EXPECT_EQ(0, logistic1->get_input_indices()[0]); + EXPECT_EQ(1, logistic1->get_input_indices()[1]); + SG_UNREF(logistic1); + + CNeuralLayer* linear1 = (CNeuralLayer*)layers->element(3); + EXPECT_EQ(0, strcmp(linear1->get_name(), "NeuralLinearLayer")); + EXPECT_EQ(8, linear1->get_num_neurons()); + EXPECT_EQ(1, linear1->get_input_indices().vlen); + EXPECT_EQ(2, linear1->get_input_indices()[0]); + SG_UNREF(linear1); + + CNeuralLayer* rectified1 = (CNeuralLayer*)layers->element(4); + EXPECT_EQ(0, strcmp(rectified1->get_name(), "NeuralRectifiedLinearLayer")); + EXPECT_EQ(8, rectified1->get_num_neurons()); + EXPECT_EQ(2, rectified1->get_input_indices().vlen); + EXPECT_EQ(1, rectified1->get_input_indices()[0]); + EXPECT_EQ(2, rectified1->get_input_indices()[1]); + SG_UNREF(rectified1); + + CNeuralLayer* softmax = (CNeuralLayer*)layers->element(5); + EXPECT_EQ(0, strcmp(softmax->get_name(), "NeuralSoftmaxLayer")); + EXPECT_EQ(4, softmax->get_num_neurons()); + EXPECT_EQ(2, softmax->get_input_indices().vlen); + EXPECT_EQ(3, softmax->get_input_indices()[0]); + EXPECT_EQ(4, softmax->get_input_indices()[1]); + SG_UNREF(softmax); + + SG_UNREF(layers); + SG_UNREF(net); +} + +#endif