代码拉取完成,页面将自动刷新
/**
******************************************************************************
* @file rbfNeuralNetwork.c
* @author 古么宁
* @brief rbf 神经网络实现
* 文件参考了网络上不少博文:https://blog.csdn.net/liuy9803/article/details/81510296
* <注:此文件用到变长数组,要C99以上或GNUC版本编译器支持>
******************************************************************************
*
* COPYRIGHT(c) 2018 GoodMorning
*
******************************************************************************
*/
/* Includes ---------------------------------------------------*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "rbfNeuralNetwork.h"
/* Private types ------------------------------------------------------------*/
/* Private macro ------------------------------------------------------------*/
/* Private variables ------------------------------------------------------------*/
/* Global variables ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static double sample_err(rbfnn_t * rbfnn ,void * sample_in , void * sample_out , uint32_t size , void * errsglbuf);
static int rbfnn_param_init(rbfnn_t * rbfnn, void * sample_in , void * sample_out , uint32_t size);
static void rbfnn_param_update(rbfnn_t * rbfnn,
double eta,
void * sample_in,
void * sample_out ,
uint32_t size,
void * smperrsgl);
/* Gorgeous Split-line -----------------------------------------------*/
/*
* @brief sample_err
* 计算样品点和对应的网络输出的误差
*
* @param rbfnn : 所指神经网络
* @param samplein : 输入样点群,形如 samplein[size][netin];
* 一个样点共有 netin 个输入
* @param sampleout : 输出样点群,形如 sampleout[size][netout];
* 一个样点共有 netout 个输出
* @param size : size 样点总个数
* @param errsglbuf : 储存个体样点误差的内存
*/
static double sample_err(rbfnn_t * rbfnn ,void * sample_in , void * sample_out , uint32_t size , void * errsglbuf)
{
double errsum = 0;
double (*errsgl)[rbfnn->out] = errsglbuf;
double (*samplein)[rbfnn->in] = sample_in;
double (*sampleout)[rbfnn->out] = sample_out;
double result[rbfnn->out];
for (uint32_t smp = 0; smp < size; ++smp) //实际的样本容量
{
rbfnn_calculate(rbfnn , &samplein[smp][0], &result[0]);
for (uint32_t out = 0 ; out < rbfnn->out ; ++ out)
{
double ersgl = sampleout[smp][out] - result[out];//个体误差
errsgl[smp][out] = ersgl;
errsum += ersgl * ersgl;//整体误差
}
}
return errsum / 2;
}
/*
* @brief rbfnn_param_init
* 用样品初始化神经网络参数
*
* @param rbfnn : 所指神经网络
* @param samplein : 输入样点群,形如 samplein[size][netin];
* 一个样点共有 netin 个输入
* @param sampleout : 输出样点群,形如 sampleout[size][netout];
* 一个样点共有 netout 个输出
* @param size : size 样点总个数
*/
static int rbfnn_param_init(rbfnn_t * rbfnn, void * sample_in , void * sample_out , uint32_t size)
{
int index = 0;
int sampled;
int sampling ;
double dDx = 0;
int aindex[rbfnn->nrnn];
double * nDi = rbfnn->Di ;
double (* nCi)[rbfnn->in] = rbfnn->Ci ;
double (* nWi)[rbfnn->out] = rbfnn->Wi ;
double (*samplein)[rbfnn->in] = sample_in;
double min_in[rbfnn->in] ;
double max_in[rbfnn->in] ;
if ( rbfnn->nrnn > size)
{
printf("too few samples\r\n");
return 1;
}
//随机选取 NeuronNum 个不重复样点,把样点的索引记于 aindex[] ;
for ( sampling = 0; sampling < rbfnn->nrnn; )
{
index = rand() % size;
//判断有没有相同的点,初始化时不能有相同的核心
for (sampled = 0; sampled < sampling; sampled++)
{
if (index == aindex[sampled])
break;
}
if (sampled == sampling) //不重样,记录这个点。
aindex[sampling++] = index;
}
for (uint32_t nrnn = 0; nrnn < rbfnn->nrnn; nrnn++)
{
index = aindex[nrnn]; //取出保存的索引号
for (uint32_t i = 0 ; i < rbfnn->in ; ++i )
nCi[nrnn][i] = samplein[index][i]; //把这些样点作为神经元的初始核心向量,后期修正
for (uint32_t i = 0 ; i < rbfnn->out ; ++i ) //初始化神经元的输出权重随机在[-1,1],后期修正
nWi[nrnn][i] = rand() * 2.0 / RAND_MAX - 1;
}
//初始化神经元的基宽,后期修正
//获取样点的各个输入维度的范围
for (uint32_t i = 0; i < rbfnn->in ; ++i)
{
min_in[i] = samplein[0][i];
max_in[i] = samplein[0][i];
}
for (uint32_t smp = 1; smp < size ; ++smp)
{
for (uint32_t i = 0; i < rbfnn->in ; ++i)
{
double value = samplein[smp][i];
if (min_in[i] > value)
min_in[i] = value;
else
if (max_in[i] < value)
max_in[i] = value;
}
}
dDx = 1;
// 如有两个输入时,得到输入面积为 S = (Ymax-Ymin)*(Xmax-Xmin)
// 把面积分为 rbfnn->nrnn 份,每份基宽为 sqrt(S/rbfnn->nrnn)
for (uint32_t i = 0; i < rbfnn->in ; ++i)
{
double width = (max_in[i] - min_in[i]);
dDx *= width;
}
dDx = sqrt(dDx/rbfnn->nrnn);
for (uint32_t nrnn = 0; nrnn < rbfnn->nrnn; nrnn++)
nDi[nrnn] = dDx ; //初始化神经元的基宽,后期修正
return 0;
}
/*
* @brief rbfnn_param_update
* 用网络输出的误差更新神经网络参数
*
* @param rbfnn : 所指神经网络
* @param eta : 所指神经网络学习速率
* @param samplein : 输入样点群,形如 samplein[size][netin];
* 一个样点共有 netin 个输入
* @param sampleout : 输出样点群,形如 sampleout[size][netout];
* 一个样点共有 netout 个输出
* @param size : size 样点总个数
* @param errsglbuf : 储存个体样点误差的内存
*/
static void rbfnn_param_update(rbfnn_t * rbfnn,
double eta,
void * sample_in,
void * sample_out ,
uint32_t size,
void * smperrsgl)
{
double ejGxui;
double neuronDi_2 ;
double sumdDi;
double sumdWi;
double sumdCi[rbfnn->in] ;
double * nDi = rbfnn->Di ;
double (* nCi)[rbfnn->in] = rbfnn->Ci ;
double (* nWi)[rbfnn->out] = rbfnn->Wi ;
double (*samplein)[rbfnn->in] = sample_in;
double (*errsgl) [rbfnn->out] = smperrsgl;
double x_c[rbfnn->in];
for (uint32_t out = 0 ; out < rbfnn->out ; ++out)
{
for (uint32_t nrnn = 0; nrnn < rbfnn->nrnn ; ++nrnn)
{
for (uint32_t in = 0 ; in < rbfnn->in ;++in)
sumdCi[in] = 0;
sumdDi = 0;
sumdWi = 0;
neuronDi_2 = nDi[nrnn] * nDi[nrnn]; //当前神经元基宽的平方
for (uint32_t smp = 0; smp < size; smp++)
{
double x_ci_2 = 0; //离神经元中心的距离的平方
for (uint32_t i = 0; i < rbfnn->in ; ++i)
{
x_c[i] = samplein[smp][i] - nCi[nrnn][i];
x_ci_2 += (x_c[i] * x_c[i]); //离神经元中心的距离的平方
}
// ej * G(|| x-ci ||) = ej * exp(-(x-ci)2/(2Di2))
ejGxui = errsgl[smp][out] * exp(-1.0 * x_ci_2 / (2 * neuronDi_2));
//Σ(ej * G(|| x-ci ||)( x-ci ) )
for (uint32_t in = 0 ; in < rbfnn->in ;++in)
sumdCi[in] += ejGxui * x_c[in];
sumdDi += ejGxui * x_ci_2;//Σ (ej * G(|| x-ci ||)|| x-ci ||2 )
sumdWi += ejGxui; //Σ (ej * G(|| x-ci ||)
}
// Ci += ΔCi = η (Wij / d2) * Σ(ej * G(|| x-ci ||)( x-ci ) ) = η (Wij / d2) × sumdCi
for (uint32_t in = 0 ; in < rbfnn->in ;++in)
nCi[nrnn][in] += (eta * nWi[nrnn][out] / neuronDi_2 * sumdCi[in]);
// Di += ΔDi = η (Wij / d3) * Σ(ej * G(|| x-ci ||)|| x-ci ||2)
nDi[nrnn] += (eta * nWi[nrnn][out] / (neuronDi_2 * nDi[nrnn]) * sumdDi);
// η Σ (ej * G(|| x-ci ||)
nWi[nrnn][out] += (eta * sumdWi);
}
}
}
/*
* @brief rbfnn_init
* 初始化神经网络内存
*
* @param rbfnn : 所指神经网络
*/
void rbfnn_init(rbfnn_t * rbfnn)
{
double * buf = rbfnn->Ci;
buf += rbfnn->in * rbfnn->nrnn ;
rbfnn->Di = buf;
buf += rbfnn->nrnn;
rbfnn->Wi = buf;
}
/*
* @brief rbfnn_train
* 用样品训练神经网络
*
* @param rbfnn : 所指神经网络
* @param traincfg : 训练参数
* @param samplein : 某个样点的输入,形如 samplein[size][netin];
* 一个样点共有 netin 个输入
* @param sampleout : 某个样点的输出,形如 sampleout[size][netout];
* 一个样点共有 netout 个输出
* @param size : size 样点总个数
*/
void rbfnn_train(rbfnn_t * rbfnn,rbfnntr_t * traincfg , void * sample_in , void * sample_out , uint32_t size)
{
uint32_t count = 0;
uint32_t trtime = 0;
double smperrsum = 0;
void * smperrsgl ;
if (NULL == rbfnn->Wi) //判断空间是否有初始化
{
printf("Uninitialized rbf Neural Network\r\n");
return ;
}
//申请内存储存样点误差,用于训练网络
smperrsgl = malloc(rbfnn->out * size * sizeof(double));
if (NULL == smperrsgl)
{
printf("not enough memory to train rbf Neural Network\r\n");
return ;
}
// 根据样点初始化网络参数
if (rbfnn_param_init(rbfnn,sample_in,sample_out,size))
return ;
printf("rbf Neural Network training...\r\n");
// 计算网络输出和样点输出的误差,得到个体误差和总体误差
smperrsum = sample_err(rbfnn,sample_in,sample_out,size,smperrsgl);
do
{
//用个体误差修正网络参数
rbfnn_param_update(rbfnn,traincfg->eta,sample_in,sample_out,size,smperrsgl);
//再次计算网络输出和样点输出的误差
smperrsum = sample_err(rbfnn,sample_in,sample_out,size,smperrsgl);
if (++count > 999)
{
count = 0;
//printf("error sum:%10.3lf\r", smperrsum);fflush(stdout);//刷新缓冲区
printf("%d train ,error sum :%f\r\n",trtime,smperrsum);
}
}
while (++trtime < traincfg->maxt && smperrsum > traincfg->limit);
printf("trained %d times,error sum:%lf\r\n", trtime, smperrsum);
//释放样点误差内存
free(smperrsgl);
}
/*
* @brief rbfnn_calculate
* 神经网络预测
*
* @param rbfnn : 所指神经网络
* @param netin : 输入,维度要和 rbfnn 相同
* @param netout : 输出,维度要和 rbfnn 相同
*/
void rbfnn_calculate(rbfnn_t * rbfnn , double * netin ,double *netout )
{
double (* nCi)[rbfnn->in] = rbfnn->Ci ;
double (* nWi)[rbfnn->out] = rbfnn->Wi ;
double * nDi = rbfnn->Di ;
for (uint32_t i = 0 ; i < rbfnn->out ; ++i)
netout[i] = 0;
for (uint32_t nrnn = 0; nrnn < rbfnn->nrnn; ++nrnn)
{
double x_ci_2 = 0;
for (uint32_t i = 0; i < rbfnn->in ; ++i)
{
double dff = netin[i] - nCi[nrnn][i];
x_ci_2 += (dff * dff);
}
double neuron_out = exp(-1.0 * x_ci_2 / (2 * nDi[nrnn] * nDi[nrnn]));
for (uint32_t i = 0 ; i < rbfnn->out ; ++i)
netout[i] += nWi[nrnn][i] * neuron_out;
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。