韩国庆尚大学jinju的神经网络解决XOR问题

本文介绍了一个简单的ANN(人工神经网络)源码实现,包括网络创建、训练、测试等核心功能。该实现支持自定义网络结构,并提供了多种权重初始化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ANN源码如下,风格类似FANN:

// auralius manurung
// gyeongsang national university
// jinju, south korea
// june 2009

#include <string>
#include <math.h>
#include <stdlib.h>
#include <stdarg.h>
#include <iostream>
#include <fstream>

using namespace std;

#define MAX_NEURON_PER_LAYER	30

class CNeuralNetwork
{
public:
	enum{
		HARD_RANDOM,
		RANDOM,
		NGUYEN,
		INPUT_FIRST,
		OUTPUT_FIRST
	};
	CNeuralNetwork();
	~CNeuralNetwork();

  /**
	* Create the desired neural network.
	* Important: pay attention on the last paramater (...)
	*
	* @param input_num = number on input neuron
	* @param output_num = number of output neuron
	* @param hidden_layer_n um = number of hidden layer
	* @param ... = number of neurons on each hidden layer
	*/
	void ann_create_network(unsigned int input_num, unsigned int output_num, unsigned int hidden_layer_num, ...);

  /**
	* Set learning rate value.
	*
	* @param learning_rate = learning rate
	*/
	void ann_set_learning_rate(float learning_rate = 0);

   /**
	* Set momentum value.
	* Momentum value should be between 0 to 1.
	*
	* @param momentum = momentum value
	*/
	void ann_set_momentum(float momentum = 0);

  /**
	* Set leraning rate changing factor for adaptive learning.
	* It should be between 0 to 1.
	*
	* @param lr_factor = how rapid the learning rate should change
	*/
	void ann_set_lr_changing_factor(float lr_factor = 0);

  /**
	* Set slope value for logistic sigmoid activation function.
	*
	* @param slope_value = slope value of the sigmoid function
	*/
	void ann_set_slope_value(float slope_value = 1);

  /**
	* Set desired weight initializaton method.
	* Option: HARD_RANDOM, RANDOM, NGUYEN.
	* For HARD_RANDOM only, you must specify the range.
	*
	* @param method = desired method
	* @param range = range value, only for HARD_RANDOM
	*/
	void ann_set_weight_init_method(int method = NGUYEN , float range = 0);

  /**
	* Get last average error in one epoch after a training complete.
	*
	* @return  average error
	*/
    float ann_get_average_error();

  /**
	* Get number of epoch needed to complete training.
	*
	* @return  number of epoch
	*/
    int ann_get_epoch_num();

  /**
	* Train the neural network with train set from a text file and log the result to result.log.
	* The train-set file should contain input and desired output.
	*
	* @param file_name = file name for the train-set file
	* @return number of total epochs
	*/
	void ann_train_network_from_file(char *file_name, int max_epoch, float max_error, int parsing_direction);

  /**
	* Test the TRAINED neural network with test set from a text file and log the result to another file..
	* The test-set file should contain input and desired output.
	*
	* @param file_name = file name for the test-set file
	* @param log_file = the result will be logged here
	*/
	void ann_test_network_from_file(char *file_name, char *log_file, int parsing_direction);

  /**
	* Set inpur per neuron in input layer.
	* If your neural network has two inputs, the channel will be 0 and 1.
	*
	* @param input_channel = input channel
	* @param input = input value, the range: -1 to 1 (bipolar)
	*/
	void ann_set_input_per_channel(unsigned int input_channel, float input);

  /**
	* Simulate the neural network based on the current input.
	* After performing simulation, you can see the output by calling ann_get_output.
	*/
	void ann_simulate();

  /**
	* Get the otput after performing simulation.
	* If your neural network has two outputs, the channel will be 0 and 1.
	*
	* @param channel = output channel
	*/
	float ann_get_output(unsigned int channel);

  /**
	* Avoid memory leakage.
	* Delete all previous dynamically created variables.
	*
	* @param channel = output channel
	*/
	void ann_clear();

private:
	float rand_float_range(float a, float b);
	float sigmoid(float f_net);
	float sigmoid_derivative(float result);
	void initialize_weights();
	void calculate_outputs();
	void calculate_weights();
	void calculate_errors();
	float get_mse_error();
	void parse_data(string data_seq, int parsing_direction = INPUT_FIRST);
	float get_norm_of_weight(int layer_num, int neuron_num);
    void generate_report();

	int	m_layer_num;
	int	*m_neuron_num;	            // this holds information of number of neurons on each layer

	float			m_learning_rate;
	float           m_lr_factor;                // learning rate changing factor, for adaptive learning

	float			m_momentum;

	float           m_slope;

	float			m_init_val;					// weight init value
	int				m_method;					// method for weight initialization

	float			m_average_error;			// average error in 1 epoch

	float			*m_current_input;
	float			*m_desired_output;

	float			***m_weight;

	float			**m_node_output;
	float			**m_node_output_prev;

	float			**m_error;
	float			**m_error_prev;

    int             m_epoch;

};

#include "stdafx.h"
#include "Neural Network.h"

CNeuralNetwork::CNeuralNetwork()
{
}

CNeuralNetwork::~CNeuralNetwork()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PRIVATE MEMBERS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

float CNeuralNetwork::rand_float_range(float a, float b)
{
	return ((b-a)*((float)rand()/RAND_MAX))+a;
}

float CNeuralNetwork::sigmoid(float f_net)
{
	return (float) ((2/(1+exp(-1*m_slope*f_net)))-1);
}

float CNeuralNetwork::sigmoid_derivative(float result)
{
	return (float) 0.5*(1-pow(result,2));
}

float CNeuralNetwork::get_norm_of_weight(int layer_num, int neuron_num)
{
	float ret = 0;
	for(int k=0;k<m_neuron_num[layer_num-1];k++){
        ret = ret + pow(m_weight[layer_num][neuron_num][k],2);
	}
	return ret;
}

void CNeuralNetwork::initialize_weights()
{
	// METHOD 1
	if (m_method == HARD_RANDOM){
		for(int i=1;i<m_layer_num;i++)
			for(int j=0;j<m_neuron_num[i];j++)
				for(int k=0;k<m_neuron_num[i-1];k++)
					m_weight[i][j][k]=rand_float_range(-m_init_val, m_init_val);
	}

	// METHOD 2
	else if (m_method == RANDOM){
		float range = sqrt(m_learning_rate / m_neuron_num[0]);

		for(int i=1;i<m_layer_num;i++)
			for(int j=0;j<m_neuron_num[i];j++)
				for(int k=0;k<m_neuron_num[i-1];k++)
					m_weight[i][j][k]=rand_float_range(-range, range);
	}

	// METHOD 3
	else if (m_method == NGUYEN){
		for(int i=1;i<m_layer_num;i++)
			for(int j=0;j<m_neuron_num[i];j++)
				for(int k=0;k<m_neuron_num[i-1];k++)
					m_weight[i][j][k]=rand_float_range(-1, 1);

		for(int i=1;i<m_layer_num;i++){
			float beta = 0.7 * pow((float) m_neuron_num[i], (float) 1/m_neuron_num[0]);
			for(int j=0;j<m_neuron_num[i];j++)
				for(int k=0;k<m_neuron_num[i-1];k++)
					m_weight[i][j][k]=beta * m_weight[i][j][k] / get_norm_of_weight(i,j);
		}
	}
}

// MEAN SQUARED ERROR
float CNeuralNetwork::get_mse_error()
{
	float result = 0.0F;
	int number_of_output_nodes = m_neuron_num[m_layer_num - 1];
	for( int i = 0; i < number_of_output_nodes; i++)
		result = result + pow((m_desired_output[i] - m_node_output[m_layer_num - 1][i]), 2);
	return result / 2;
}

void CNeuralNetwork::parse_data(string data_seq, int parsing_direction)
{
	//if seq == INPUT_FIRST --> string format: INPUT OUTPUT
	//if seq == OUTPUT_FIRST --> string format: OUTPUT INPUT

	size_t found = 0;
	size_t comma = 0;
	size_t start = 0;
	int i = 0;

	size_t length = data_seq.length();

	while(found < length ){
		//clean up white spaces
		while(data_seq.at(found) == ' ' || data_seq.at(found) == ',')
			found++;

		start = found;
		found = data_seq.find(' ', found + 1);
		comma = data_seq.find(',', start + 1);
		if (found > comma)
			found = comma;

		char buff[64];
		data_seq.copy(buff, found - start, start);

		if (parsing_direction == INPUT_FIRST){
			if (i < m_neuron_num[0])
				m_current_input[i] = atof(buff);
			else
				m_desired_output[i - m_neuron_num[0]] = atof(buff);
		}
		else{
			if (i < m_neuron_num[m_layer_num - 1])
				m_desired_output[i] = atof(buff);
			else
				m_current_input[i - m_neuron_num[m_layer_num - 1]] = atof(buff);
		}

		i++;
	}
}

void CNeuralNetwork::calculate_outputs()
{
	float f_net;
    int number_of_weights;
    for(int i=0;i<m_layer_num;i++)
        for(int j=0;j<m_neuron_num[i];j++)
        {
			m_node_output_prev[i][j] = m_node_output[i][j]; // store previous values
            f_net = 0.0F;
            if(i == 0)
				number_of_weights = 1;
            else
				number_of_weights = m_neuron_num[i-1];

            for(int k=0;k<number_of_weights;k++)
                if(i == 0)
                    f_net=m_current_input[j];
                else
                    f_net=f_net+m_node_output[i-1][k]*m_weight[i][j][k];
			if (i == 0)
				m_node_output[i][j] = f_net;	// for input layer we are using unity function
			else
				m_node_output[i][j]=sigmoid(f_net);
        }
}

void CNeuralNetwork::calculate_weights()
{
	for(int i=1;i<m_layer_num;i++){
		for(int j=0;j<m_neuron_num[i];j++){
            for(int k=0;k<m_neuron_num[i-1];k++)
            {
				float delta = m_learning_rate * m_error[i][j] * m_node_output[i-1][k];
				float delta_prev = m_learning_rate * m_error_prev[i][j] * m_node_output_prev[i-1][k];
				m_weight[i][j][k] = (float) m_weight[i][j][k] + delta + m_momentum * delta_prev;
            }
		}
	}
}

void CNeuralNetwork::calculate_errors()
{
    float sum = 0.0F;
	int number_of_output_nodes = m_neuron_num[m_layer_num - 1];

	for( int i = 0; i< number_of_output_nodes; i++){
		m_error_prev[m_layer_num - 1][i] = m_error[m_layer_num - 1][i]; // store previous values
        m_error[m_layer_num - 1][i] = (float) ((m_desired_output[i] - m_node_output[m_layer_num-1][i]) * sigmoid_derivative(m_node_output[m_layer_num-1][i]));
	}

	for(int i = m_layer_num-2; i>=0; i--){
        for( int j=0;j<m_neuron_num[i];j++)
        {
            sum = 0.0F;
            for( int k = 0; k < m_neuron_num[i+1]; k++)
                sum = sum + m_error[i+1][k] * m_weight[i+1][k][j];
			m_error_prev[i][j] = m_error[i][j]; // store previous values
            m_error[i][j] = (float) (sigmoid_derivative(m_node_output[i][j]) * sum);
        }
	}
}


void CNeuralNetwork::generate_report()
{
    ofstream log ("result.log");

    log << "number of layers : " <<  m_layer_num << endl;
    for (int i = 0; i < m_layer_num; i++)
        log << "neuron numbers in layer " << i << ": " << m_neuron_num[i] << endl;

    log << endl << "number of epoch needed: " << m_epoch << endl;
    log << "final average mse: " << m_average_error << endl << endl;

    log << "weights value: " << endl;
    log << "==============" << endl;

    for(int i=1;i<m_layer_num;i++){
        log << endl << "layer: "  << i << endl;
        for(int j=0;j<m_neuron_num[i];j++){
			for(int k=0;k<m_neuron_num[i-1];k++){
                log << "w" << k << j << ": " << m_weight[i][j][k] << endl;
			}
        }
    }

    log.close();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PUBLIC MEMBERS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CNeuralNetwork::ann_create_network(unsigned int input_num, unsigned int output_num, unsigned int hidden_layer_num, ...)
{
	m_layer_num = hidden_layer_num + 2; // preserve extra spaces for input and output layers

	m_current_input  = new float[input_num];
	m_desired_output = new float[output_num];
	m_neuron_num	 = new int[m_layer_num];

	// Get number of neuron for each hidden layer
	va_list neuron_num;
	va_start(neuron_num, hidden_layer_num);
	for (unsigned int i = 0; i < hidden_layer_num; i++)
		m_neuron_num[i+1] = va_arg(neuron_num, unsigned int);
	va_end(neuron_num);

	// For input and output layer
	m_neuron_num[0] = input_num;
	m_neuron_num[m_layer_num - 1] = output_num;

	/////////////////////////////////////////////////////////
	// --- CREATE ALL DYNAMIC MULTIDIMENSIONAL ARRAY HERE ---

	// m_weight is 3-D array
	// m_weight[layer][number of neuron on previous layer][number of neuron on current layer]
	m_weight = new float**[m_layer_num];
	if (m_weight != NULL){
		for (int i = 1; i < m_layer_num; i++){
			*(m_weight+i) = new float*[m_neuron_num[i]];
			for (int j = 0; j < m_neuron_num[i]; j++)
				*(*(m_weight+i)+j) = new float[m_neuron_num[i-1]];
		}
	}

	// 2-D array
	// m_array_name[layer][number of neuron on current layer]
	m_node_output				= new float*[m_layer_num];
	m_node_output_prev			= new float*[m_layer_num];
	m_error						= new float*[m_layer_num];
	m_error_prev				= new float*[m_layer_num];

	for (int i = 0; i < m_layer_num; i++){
		*(m_node_output+i) = new float[m_neuron_num[i]];
		*(m_node_output_prev+i) = new float[m_neuron_num[i]];
		*(m_error+i) = new float[m_neuron_num[i]];
		*(m_error_prev+i) = new float[m_neuron_num[i]];
	}

	// --- END ---
	//////////////

	// Initialize m_error_prev and m_node_output variables
	for(int i=0;i<m_layer_num;i++)
		for(int j=0;j<m_neuron_num[i];j++){
			m_node_output[i][j] = 0.0F;
			m_error[i][j] = 0.0F;
			m_node_output_prev[i][j] = 0.0F;
			m_error_prev[i][j] = 0.0F;
		}

	// Initialize weights
	initialize_weights();
}

//SET

void CNeuralNetwork::ann_set_learning_rate(float learning_rate)
{
	m_learning_rate = learning_rate;
}

void CNeuralNetwork::ann_set_momentum(float momentum)
{
	m_momentum = momentum;
}

void CNeuralNetwork::ann_set_weight_init_method(int method, float range)
{
	m_method = method;
	m_init_val = range;
}

void CNeuralNetwork::ann_set_slope_value(float slope_value)
{
    m_slope = slope_value;
}

void CNeuralNetwork::ann_set_lr_changing_factor(float lr_factor)
{
    m_lr_factor = lr_factor;
}

void CNeuralNetwork::ann_set_input_per_channel(unsigned int input_channel, float input)
{
	m_current_input[input_channel] = input;
}

// GET

float CNeuralNetwork::ann_get_average_error()
{
    return m_average_error;
}

float CNeuralNetwork::ann_get_output(unsigned int channel)
{
	return m_node_output[m_layer_num-1][channel];
}

int CNeuralNetwork::ann_get_epoch_num()
{
    return m_epoch;
}

// TRAIN, TEST, SIMULATE AND CLEAR

void CNeuralNetwork::ann_train_network_from_file(char *file_name, int max_epoch, float max_error, int parsing_direction)
{
    string line;
	ifstream file (file_name);
	m_average_error = 0.0F;

	if (file.is_open()){
		for (m_epoch = 0; m_epoch < max_epoch; m_epoch++){
			int training_data_num = 0;
			float error = 0.0F;
			while (! file.eof() ){
				getline(file, line);
				if (line.empty())
					break;
				parse_data(line, parsing_direction);

				calculate_outputs();
				calculate_errors();
				calculate_weights();

				error = error + get_mse_error();
				training_data_num ++;
			}
			file.clear(); // clear buffer
			file.seekg(0, ios::beg); // go to begining of file

			float error_prev = m_average_error;
			m_average_error = error/training_data_num; // average of mse in one epoch

			if (m_average_error <= max_error)
				break;

			m_learning_rate = m_learning_rate*(m_lr_factor*m_average_error*error_prev + 1);
		}
	}
	file.close();
	generate_report();
}

void CNeuralNetwork::ann_test_network_from_file(char *file_name, char *log_file, int parsing_direction)
{
	string line;
	ifstream file (file_name);
	ofstream log (log_file);

	if (file.is_open()){
		while (! file.eof() ){
			getline(file, line);
			parse_data(line, parsing_direction);
			if (line.empty())
                break;

			calculate_outputs();
			calculate_errors();

			log << "expected output: ";
			for(int i = 0; i< m_neuron_num[m_layer_num-1]; i++){
                log << m_desired_output[i] << " ";
			}
            log << " calculated output: ";
            for(int i = 0; i< m_neuron_num[m_layer_num-1]; i++){
                log << ann_get_output(i) << " ";
			}
			log << " mse error : " <<  get_mse_error() << endl;
		}
	}
	file.close();
	log.close();
}

void CNeuralNetwork::ann_simulate()
{
	calculate_outputs();
}

void CNeuralNetwork::ann_clear()
{
	for (int i = 1; i < m_layer_num; i++){
		for (int j = 0; j < m_neuron_num[i]; j++)
			delete [] m_weight[i][j];
		delete [] m_weight[i];
	}
	delete [] m_weight;

	for (int i = 0; i < m_layer_num; i++){
		delete [] m_node_output[i];
		delete [] m_node_output_prev[i];
		delete [] m_error[i];
		delete [] m_error_prev[i];
	}
	delete [] m_node_output;
	delete [] m_node_output_prev;
	delete [] m_error;
	delete [] m_error_prev;

	delete [] m_current_input;
	delete [] m_desired_output;
	delete []m_neuron_num;

}

// Neural Network.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Neural Network.h"


int main(int argc, char* argv[])
{
	CNeuralNetwork nn;
	nn.ann_set_learning_rate(0.5);
	nn.ann_set_momentum(0);
	nn.ann_set_lr_changing_factor(0);
	nn.ann_set_slope_value(1);
	nn.ann_set_weight_init_method(nn.RANDOM);
	if( argc<=1 )
	{
		nn.ann_create_network(2,1,1,3);
		nn.ann_train_network_from_file("input.txt", 10000, 0.01, nn.OUTPUT_FIRST);
	}
	else
	{
		nn.ann_create_network(22,1,4,30,30,30,30);
		nn.ann_train_network_from_file("SPECT.train", 10000, 0.001, 1);
	}	
	printf("number of epoch: %i with final error: %f\n", nn.ann_get_epoch_num(), nn.ann_get_average_error());

	nn.ann_set_input_per_channel(0, 1.0F);
	nn.ann_set_input_per_channel(1, 1.0F);
	nn.ann_simulate();
	printf("1 XOR 1 is %f\n", nn.ann_get_output(0));

	nn.ann_set_input_per_channel(0, 0.0F);
	nn.ann_set_input_per_channel(1, 0.0F);
	nn.ann_simulate();
	printf("0 XOR 0 is %f\n", nn.ann_get_output(0));

	nn.ann_set_input_per_channel(0, 1.0F);
	nn.ann_set_input_per_channel(1, 0.0F);
	nn.ann_simulate();
	printf("1 XOR 0 is %f\n", nn.ann_get_output(0));

	nn.ann_set_input_per_channel(0, 0.0F);
	nn.ann_set_input_per_channel(1, 1.0F);
	nn.ann_simulate();
	printf("0 XOR 1 is %f\n", nn.ann_get_output(0));

	nn.ann_test_network_from_file("input.txt", "log.txt", nn.OUTPUT_FIRST);

	nn.ann_clear();
}

运行结果:



采用ANN的OCR字符识别系统:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值