Using Lib FANN in R via Rcpp


Test Environment: OS: Windows XP, R: R 2.12.2(G:\Program Files\R\R-2.12.2\), Rcpp: 0.9.4, Rtools: 212 (G:\Rtools), FANN: 2.1.0
Lib FANN(Fast Artificial Neural Network Library) is a free open source neural network library written in C. In this tutorial I will show you how to use the Rcpp package to wrap FANN to R.

1. Download the FANN library: http://leenissen.dk/fann/wp/download/ (fann-2.1.0beta.zip)

2. Unzip the source code to some folder(“G:\libFANN\fann-2.1.0\“)

3. Make sure that you installed Rtools and setted the path for MinGW properly. You can check this post for that. The path for my MinGW(Rtools) is “G:\Rtools\MinGW

4. Install MSYS: Download and install MSYS 1.0.11 from http://www.mingw.org/wiki/MSYS. I installed MSYS into “G:\msys“. Make sure to tell msys where your installed MinGW(Rtools) is. This can be done in the post-install process of MSYS, or manually create a file named “fstab” in folder “G:\msys\1.0\etc“, with the following line:
G:/Rtools/MinGW /mingw #tell msys the path of MinGW

5. Run msys(there should be a shortcut on your desktop: “G:\msys\1.0\msys.bat -norxvt“), do the config for libFANN:
cd G:\libFANN\fann-2.1.0
./configure
Now you should find the Makefile created in “G:\libFANN\fann-2.1.0\src, let’s compile the source code of FANN:
cd src
make
After the compilation, you will find some files such as “fixedfann.o, floatfann.o, doublefann.o” created in the src folder.

6. Let’s first test the compiled lib: Copy the files “xor.data, xor_train.c, xor_test.c” from “examples” folder to “src” folder.
ar rc libFANNLib.a doublefann.o fixedfann.o floatfann.o
ranlib libFANNLib.a
gcc -o xor_train xor_train.c -Iinclude libFANNLib.a
gcc -o xor_test xor_test.c -Iinclude libFANNLib.a
Now will can find “xor_train.exe, xor_test.exe” in the “src” folder, click one after the other to run the test(to view the results, you should run them both from cmd).

7. It’s time to wrap FANN to R, we will write a simple package “RcppFANN” using Rcpp Module: go to R

library(Rcpp);
Rcpp.package.skeleton("RcppFANN");

find the created files in “C:\Documents and Settings\Administrator\My Documents\RcppFANN“(your working directory)

8. Go to the folder “C:\Documents and Settings\Administrator\My Documents\RcppFANN\src” and edit the two files “rcpp_hello_world.h, rcpp_hello_world.cpp“, we simply wrap the example code “xor_train.c, xor_test.c” into “rcpp_hello_world.cpp” using Rcpp Module:

//rcpp_hello_world.h
#ifndef _RcppFANN_RCPP_HELLO_WORLD_H
#define _RcppFANN_RCPP_HELLO_WORLD_H

#include

/*
 * note : RcppExport is an alias to `extern "C"` defined by Rcpp.
 *
 * It gives C calling convention to the rcpp_hello_world function so that
 * it can be called from .Call in R. Otherwise, the C++ compiler mangles the
 * name of the function and .Call can't find it.
 *
 * It is only useful to use RcppExport when the function is intended to be called
 * by .Call. See the thread http://thread.gmane.org/gmane.comp.lang.r.rcpp/649/focus=672
 * on Rcpp-devel for a misuse of RcppExport
 */

#endif

 

//rcpp_hello_world.cpp
#include "rcpp_hello_world.h"

using namespace Rcpp ;

#include

#include "fann.h"

int xor_test()
{
	fann_type *calc_out;
	unsigned int i;
	int ret = 0;

	struct fann *ann;
	struct fann_train_data *data;

	printf("Creating network.\n");

#ifdef FIXEDFANN
	ann = fann_create_from_file("xor_fixed.net");
#else
	ann = fann_create_from_file("xor_float.net");
#endif

	if(!ann)
	{
		printf("Error creating ann --- ABORTING.\n");
		return 0;
	}

	fann_print_connections(ann);
	fann_print_parameters(ann);

	printf("Testing network.\n");

#ifdef FIXEDFANN
	data = fann_read_train_from_file("xor_fixed.data");
#else
	data = fann_read_train_from_file("xor.data");
#endif

	for(i = 0; i < fann_length_train_data(data); i++) 	{ 		fann_reset_MSE(ann); 		calc_out = fann_test(ann, data->input[i], data->output[i]);
#ifdef FIXEDFANN
		printf("XOR test (%d, %d) -> %d, should be %d, difference=%f\n",
			   data->input[i][0], data->input[i][1], calc_out[0], data->output[i][0],
			   (float) fann_abs(calc_out[0] - data->output[i][0]) / fann_get_multiplier(ann));

		if((float) fann_abs(calc_out[0] - data->output[i][0]) / fann_get_multiplier(ann) > 0.2)
		{
			printf("Test failed\n");
			ret = -1;
		}
#else
		printf("XOR test (%f, %f) -> %f, should be %f, difference=%f\n",
			   data->input[i][0], data->input[i][1], calc_out[0], data->output[i][0],
			   (float) fann_abs(calc_out[0] - data->output[i][0]));
#endif
	}

	printf("Cleaning up.\n");
	fann_destroy_train(data);
	fann_destroy(ann);

	return ret;
}

////

int FANN_API test_callback(struct fann *ann, struct fann_train_data *train,
	unsigned int max_epochs, unsigned int epochs_between_reports,
	float desired_error, unsigned int epochs)
{
	printf("Epochs     %8d. MSE: %.5f. Desired-MSE: %.5f\n", epochs, fann_get_MSE(ann), desired_error);
	return 0;
}

int xor_train()
{
	fann_type *calc_out;
	const unsigned int num_input = 2;
	const unsigned int num_output = 1;
	const unsigned int num_layers = 3;
	const unsigned int num_neurons_hidden = 3;
	const float desired_error = (const float) 0;
	const unsigned int max_epochs = 1000;
	const unsigned int epochs_between_reports = 10;
	struct fann *ann;
	struct fann_train_data *data;

	unsigned int i = 0;
	unsigned int decimal_point;

	printf("Creating network.\n");
	ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_output);

	data = fann_read_train_from_file("xor.data");

	fann_set_activation_steepness_hidden(ann, 1);
	fann_set_activation_steepness_output(ann, 1);

	fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
	fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);

	fann_set_train_stop_function(ann, FANN_STOPFUNC_BIT);
	fann_set_bit_fail_limit(ann, 0.01f);

	fann_init_weights(ann, data);

	printf("Training network.\n");
	fann_train_on_data(ann, data, max_epochs, epochs_between_reports, desired_error);

	printf("Testing network. %f\n", fann_test_data(ann, data));

	for(i = 0; i < fann_length_train_data(data); i++) 	{ 		calc_out = fann_run(ann, data->input[i]);
		printf("XOR test (%f,%f) -> %f, should be %f, difference=%f\n",
			   data->input[i][0], data->input[i][1], calc_out[0], data->output[i][0],
			   fann_abs(calc_out[0] - data->output[i][0]));
	}

	printf("Saving network.\n");

	fann_save(ann, "xor_float.net");

	decimal_point = fann_save_to_fixed(ann, "xor_fixed.net");
	fann_save_train_to_fixed(data, "xor_fixed.data", decimal_point);

	printf("Cleaning up.\n");
	fann_destroy_train(data);
	fann_destroy(ann);

	return 0;
}

////

RCPP_MODULE(mod){
 function("xor_test", &xor_test);
 function("xor_train", &xor_train);
}

9. Edit the “Makevars.win” to:
## Use the R_HOME indirection to support installations of multiple R version
PKG_LIBS = $(shell “${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe” -e “Rcpp:::LdFlags()”) G:/libFANN/fann-2.1.0/src/libFANNLib.a
PKG_CPPFLAGS = -I”G:\libFANN\fann-2.1.0\src\include”

10. Now we can compile and install our test package:
Windows Start -> run -> cmd -> cd C:\Documents and Settings\Administrator\My Documents
C:\Documents and Settings\Administrator\My Documents>
“G:\Program Files\R\R-2.12.2\bin\i386\Rcmd” check RcppFANN
“G:\Program Files\R\R-2.12.2\bin\i386\Rcmd” INSTALL RcppFANN

11. Finally, let test our package:
copy the data files “xor.data“(located in “G:\libFANN\fann-2.1.0\examples“) to folder “C:\Documents and Settings\Administrator\My Documents\“(or your working directory).
In R:

library("Rcpp");
library("RcppFANN");
mod mod$xor_train();

Result:

[1] 0

If everything goes well, you can find three files “xor_fixed.data, xor_fixed.net, xor_float.net“(the trained network) created in “C:\Documents and Settings\Administrator\My Documents\“.

mod$xor_test();

Result:

[1] 0

Well, FANN is successfully running in R, but we can’t see anything useful in R because the results of the original test function are printed using the C “printf” function. To make the lib really useful, you can write some further wrapper functions to retrieve those results and supply data to FANN in R.

Source code of the test package “RcppFANN”: https://bzstat.googlecode.com/svn/trunk/blogpost/RcppFANN

Links:
http://dirk.eddelbuettel.com/code/rcpp.html
http://dirk.eddelbuettel.com/code/rcpp/Rcpp-package.pdf
http://dirk.eddelbuettel.com/code/rcpp/Rcpp-modules.pdf
http://stat.ethz.ch/R-manual/R-devel/doc/manual/R-admin.html
http://sourceforge.net/projects/rfann/
http://cran.r-project.org/web/packages/RSNNS/

Advertisements
This entry was posted in programming, r. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s