单层前馈神经网络(SLFN)以其良好的学习能力在许多领域得到了广泛的应用,然而传统的学习算法,如BP等固有的一些缺点,成为制约其发展的主要瓶颈,前馈神经网络大多采用梯度下降法,该方法存在以下几个方面的缺点和不足:
1、训练速度慢。由于梯度下降法需要多次迭代,从而达到修正权值和阈值的目的,因此训练过程耗时较长;
2、容易陷入局部极小值,无法到达全局最小;
3、学习率yita的选择敏感,学习率对神经网络的性能影响较大,必须选择合适的才能达到较为理想的效果,太小则算法的收敛速度很慢,训练过程耗时较长,太大,则训练过程可能不稳定。
本文将介绍一种新的SLFN的算法,极限学习机,该算法将随机产生输入层和隐含层间的连接权值和隐含层神经元的阈值,且在训练过程中无需调整,只需要设置隐含层的神经元的个数,便可以获得唯一最优解,与传统的训练方法相比,该方法具有学习速率快、泛化性能好等优点。
典型的单隐层前馈神经网络如上图所示,输入层与隐含层,隐含层与输出层之间是全连接的。输入层的神经元的个数是根据样本的而特征数的多少来确定的,输出层的神经元的个数是根据样本的种类数来确定的
设隐含层神经元的阈值 b为:
当隐层神经元的个数和样本数相同时(10)式有唯一的解,也就是说零误差的逼近训练样本。通常的学习算法中,W和b需要不断进行调整,但研究结果告诉我们,他们事实上是不需要进行不断调整的,甚至可以随意指定。调整他们不仅费时,而且并没有太多的好处。(此处有疑虑,可能是断章取义,这个结论有可能是基于某个前提下的)。
总结一下:ELM与BP都是基于前馈神经网络的架构之下的,他们的不同之处在于学习的方法不同,BP是通过梯度下降法,利用反向传播的方式进行的学习,需要不断地进行迭代来更新权重和阈值,而ELM则是通过增加隐层节点的个数来达到学习的目的,隐层节点的个数一般是根据样本的个数来确定的,巧妙地将隐含层的个数与样本的个数进行了联系。其实在许多前向神经网络中,默认的最大的隐层节点的个数就是样本数,(如RBF)。它不需要进行迭代,所以速度就比BP要快很多。ELM的精华之处就在于那两条他所依赖的定理,这些定理决定了他的学习方式。输入层和隐含层之间的权重w和隐含层节点的阈值b是通过随机初始化得到的,而且不需要进行调整。一般隐层节点的个数与样本的个数相同(在样本数比较少的情况下)。
ELM的matlab代码可以直接在网上下到,而且原理也很简单,ELMtrain的过程就是为了计算隐含层与输出层之间的权重,是根据标签矩阵T利用公式11得到的,ELMpredict则是利用隐含层与输出层之间的权重来计算输出T,当然也会将ELMtrain中的随机初始化的输入节点和隐层节点之间的权值和隐层节点的阈值照搬过来,不会再进行随机初始化(否则隐层与输出层之间的权值不就白计算了嘛,因为他们就是根据ELMtrain中随机初始化的那些值计算得到的呀)所以整个极限学习机还是很简单的。
极限学习机是一种学习方式,深度学习也可以和极限学习机相结合,例如ELM-AE
极限学习机与径向基神经网络的思想如出一辙,通过增加隐层神经元的个数可以实现将线性不可分的样本映射到高层的线性可分的空间,然后再通过隐层与输出层之间进行线性划分,完成分类功能,不过径向基的激活函数是用的径向基函数,相当于svm中的核函数(径向基核函数)
在看完了径向基神经网络之后,发现极限学习机必是受了RBF的思想影响。因为RBF也是隐层结点个数尽量多,而且严格径向基网络就是要求隐层结点个数与输入样本个数相等,并且隐层神经元与输出层神经元之间也是线性加权得到的最终的输出,隐层与输出层之间的权值,RBF是通过解线性方程得到的,极限学习机也是通过隐层输出的广义逆矩阵进行线性方程的求解得到的。
定理一是对应的RBF中的 正则化的RN(通用逼近器),即隐层结点个数=输入样本个数,定理二是对应的RBF中的 广义网络GN(模式分类器),隐层节点<输入样本数,个人感觉极限学习机是融合了RBF和BP两种算法的学习思想,输入层与隐层之间是BP,隐层与输出层之间是RBF,当然隐层节点的个数也是惯用了RBF的两种形式,即RN和GN
function [time, Et]=ANFISELMELM(adaptive_mode) adaptive_mode = 'none'; tic; clc; clearvars -except adaptive_mode; close all; % load dataset data = csvread('iris.csv'); input_data = data(:, 1:end-1); output_data = data(:, end); % Parameter initialization [center,U] = fcm(input_data, 3, [2 100 1e-6]); %center = center cluster, U = membership level [total_examples, total_features] = size(input_data); class = 3; % [Changeable] epoch = 0; epochmax = 400; % [Changeable] %Et = zeros(epochmax, 1); [Yy, Ii] = max(U); % Yy = max value between both membership function, Ii = the class corresponding to the max value % Population initialization pop_size = 10; population = zeros(pop_size, 3, class, total_features); % parameter: population size * 6 * total classes * total features velocity = zeros(pop_size, 3, class, total_features); % velocity matrix of an iteration c1 = 1.2; c2 = 1.2; original_c1 = c1; original_c2 = c2; r1 = 0.4; r2 = 0.6; max_c1c2 = 2; % adaptive c1 c2 % adaptive_mode = 'none'; % class(adaptive_mode) iteration_tolerance = 50; iteration_counter = 0; change_tolerance = 10; is_first_on = 1; is_trapped = 0; %out_success = 0; for particle=1:pop_size a = zeros(class, total_features); b = repmat(2, class, total_features); c = zeros(class, total_features); for k =1:class for i = 1:total_features % looping for all features % premise parameter: a aTemp = (max(input_data(:, i))-min(input_data(:, i)))/(2*sum(Ii' == k)-2); aLower = aTemp*0.5; aUpper = aTemp*1.5; a(k, i) = (aUpper-aLower).*rand()+aLower; %premise parameter: c dcc = (2.1-1.9).*rand()+1.9; cLower = center(k,total_features)-dcc/2; cUpper = center(k,total_features)+dcc/2; c(k,i) = (cUpper-cLower).*rand()+cLower; end end population(particle, 1, :, :) = a; population(particle, 2, :, :) = b; population(particle, 3, :, :) = c; end %inisialisasi pBest pBest_fitness = repmat(100, pop_size, 1); pBest_position = zeros(pop_size, 3, class, total_features); % calculate fitness function for i=1:pop_size particle_position = squeeze(population(i, :, :, :)); e = get_fitness(particle_position, class, input_data, output_data); if e < pBest_fitness(i) pBest_fitness(i) = e; pBest_position(i, :, :, :) = particle_position; end end % find gBest [gBest_fitness, idx] = min(pBest_fitness); gBest_position = squeeze(pBest_position(idx, :, :, :)); % ITERATION while epoch < epochmax epoch = epoch + 1; % calculate velocity and update particle % vi(t + 1) = wvi(t) + c1r1(pbi(t) - pi(t)) + c2r2(pg(t) - pi(t)) % pi(t + 1) = pi(t) + vi(t + 1) r1 = rand(); r2 = rand(); for i=1:pop_size velocity(i, :, :, :) = squeeze(velocity(i, :, :, :)) + ((c1 * r1) .* (squeeze(pBest_position(i, :, :, :)) - squeeze(population(i, :, :, :)))) + ((c2 * r2) .* (gBest_position(:, :, :) - squeeze(population(i, :, :, :)))); population(i, :, :, :) = population(i, :, :, :) + velocity(i ,:, :, :); end % Draw the SSE plot plot(1:epoch, Et); title(['Epoch ' int2str(epoch) ' -> MSE = ' num2str(Et(epoch))]); grid pause(0.001); end %[out output out-output] % ---------------------------------------------------------------- time = toc; end