Простая RBF-сеть в Octave


Логотип Octave

Для математического пакета Octave на сегодняшний момент, насколько мне известно, из нейронных сетей реализован только многослойный персептрон (в виде этого модуля).

Так случилось, что мне понадобилась радиально-базисная (RBF) нейронная сеть. Встала задача аппроксимации функции одной переменной, а, судя по результатам этой работы, радиально-базисная сеть справляется с аппроксимацией лучше всех.

Аппроксимация  с помощью радиально-базисной сети наглядно показана тут - с помощью онлайн-апплета на Java (есть даже исходные коды). Где-то за день я написал подобную сеть для Octave. Делюсь своим решением - оно может послужить как прототипом, так и реально решить чьи-то задачи.

Адекватное описание алгоритма работы RBF-сети я взял с этой страницы (что немаловажно, оно - на русском языке).

Сеть я охарактеризовал следующими параметрами:

  • вектором R, содержащим радиусы функций нейронов скрытого слоя
  • вектором C, содержащим их центры
  • вектором W - с набором весов для каждого скрытого нейрона
  • и, собственно, целым числом hc - содержащем количество нейронов скрытого слоя.

Функция инициализации нейросети будет выглядеть следующим образом: 

function [rbf] = rbfnetinit (hidden_count, min_x, max_x) 
  rbf.hc = hidden_count;
  rbf.R = linspace(1, hidden_count, hidden_count);
  rbf.C = linspace(1, hidden_count, hidden_count);
  rbf.W = linspace(1, hidden_count, hidden_count);
  for i = 1:hidden_count
    rbf.R(i) = (max_x - min_x) / (hidden_count - 1);
    rbf.C(i) = min_x + (max_x - min_x) / (hidden_count - 1) * (i - 1);
    rbf.W(i) = 0;
  endfor
endfunction

Здесь сделано некоторое допущение относительно начального расположения радиусов и центров. Они задаются таким образом, чтобы равномерно "покрыть" площадь от максимального до минимального значения (именно так сделано в вышеописанном Java-приложении).

Выберем функцией нашей нейронной сети гауссиану:

function [res] = haussian (x, r, c)
  res = exp(-(((x-c)^2) / (r^2)));
endfunction

Тогда выходная функция нейронной сети будет описана так:

function [y] = rbfnetout (rbf, x)
  y = 0;
  for i = 1:rbf.hc
    y += haussian(x, rbf.R(i), rbf.C(i)) * rbf.W(i);
  endfor
endfunction 

А обучение нейронной сети будет осуществляться такой функцией:

function [W] = rbfnettrain (rbf, X, Y, sample_count)
  H = zeros(sample_count, rbf.hc);
  for j = 1:sample_count
    for i = 1:rbf.hc
      H(j, i) = haussian(X(j), rbf.R(i), rbf.C(i));
    endfor
  endfor
  H = pinv(H);
  W = H * Y;
endfunction

Здесь sample_count - это объём выборки; X - вектор входных значений, Y - вектор входных значений.

Результат аппроксимации функции одной переменной с помощью этой RBF-сети представлен на графике:

Результат аппроксимации с помощью RBF-сети

Для улучшения работы RBF-сети обычно нормализуют входные и, иногда, выходные данные.

Скачать полные исходные коды, включающие, кроме вышеописанного:

  • два вида нормализации
  • чтение данных из файла
  • отображение полученного результата на экран в виде графика

можно по этой ссылке.

29 ноября 2011 10:40 — Георгий Чурочкин