"""
import neurolab as nl import numpy as np
from matplotlib import pyplot
from neurolab import trans, train as trainf, error as errorf
def isprime(n):
"""
Тестировать число на простоту (оптимизация 6k±1) :param n: int
:return: bool
"""
if n < 4: return n > 1
if n % 2 == 0 or n % 3 == 0: return False for i in range(5, int(n ** 0.5 + 1), 6): if n % i == 0 or n % (i + 2) == 0:
return False return True
def error(s):
"""
Вывод ошибки в поток stderr
:param s: str
"""
from sys import stderr stderr.write(s) exit(-1)
def newff(minmax, size, transf=None, trainf=None, errorf=None):
"""
Создать многослойный персептрон
Аналог стандартной функции neurolab.net.newff с возможностью задания функции
обучения и функции ошибки
:param minmax: list of list, диапазон входных значений
:param size: list of int, количество нейронов для каждого слоя
:param transf: list of neurolab.trans.*, список активационных функций для каждого
слоя
:param trainf: neurolab.train.*, функция обучения :param errorf: neurolab.error.*, функция ошибки
:return: neurolab.core.Net
"""
from neurolab import trans, layer, train, error, init from neurolab.core import Net
net_ci = len(minmax) net_co = size[-1]
if transf is None:
transf = [trans.TanSig()] * len(size) assert len(transf) == len(size)
layers = []
for i, nn in enumerate(size):
layer_ci = size[i - 1] if i > 0 else net_ci l = layer.Perceptron(layer_ci, nn, transf[i]) l.initf = init.initnw
layers.append(l)
connect = [[i - 1] for i in range(len(layers) + 1)]
net = Net(minmax, net_co, layers, connect, trainf or train.train_bfgs, errorf or error.SSE())
return net
#=== Исходные данные ===
#Число точек
n = 100
#Число лагов (5 - по заданию) b = 5
#Генерация вектора X
X = np.linspace(0.001, 10, n)
11
# Генерация вектора Y на основе вектора X
Y = np.cos(X - 0.5) * np.abs(X) + np.random.rand(X.size) * 0.2 # "Шуманизация"
#Обучающая выборка k = n * 3 // 4
Xt = X[0:k] Yt = Y[0:k]
#Проверочная выборка Xv = X[k:n]
Yv = Y[k:n] vs = Xv.size
#Глубина прогноза
m = k - b
#Горизонт прогноза (по умолчанию 1) g = 1
#Минимальные и максимальные значения координат min_x = min(X)
max_x = max(X) min_y = min(Y) max_y = max(Y)
#=== Прогнозирование временного ряда ===
#Построение обучающих "подвыборок" km = k - m
if m <= g:
error('Горизонт прогноза слишком большой.') elif g != 1 and isprime(km):
error('Измените значение глубины прогноза (либо горизонта прогноза в 1).') elif km % g != 0:
error('Горизонт прогноза указан неверно.\n({} mod g) должно быть равно
0.'.format(km)) q = km // g + 1
Yq = np.zeros((q, m)) for i in range(0, q):
Yq[i, :] = Yt[g * i:m + g * i]
#Настройка минимальных и максимальных значений
mmx = np.zeros((Yq.shape[1], 2)) mmx[:, 0] = min_y - min_y mmx[:, 1] = max_y + max_y
#Создание нейронной сети обратного распространения с прямой связью
#2 скрытых слоя
#Передаточные функции: гиперболический тангенс и линейная функция
net = newff(mmx, [100, 1], [nl.trans.TanSig(), nl.trans.PureLin()], trainf.train_cg, errorf.MSE())
#Максимальное число эпох epochs = 10000
#Цель (внимание: возможно переобучение) goal = 0.00001
#Обучение сети
print('> Обучение сети началось')
Yq1 = Yq[0:q - 1, :]
Yq2 = Yq[1:q, -1]
train_mse = net.train(Yq1, Yq2.reshape(Yq2.size, 1), epochs=epochs, goal=goal)[-1] print('> Обучение сети закончилось')
# Моделирование работы сети
print('> Моделирование работы сети началось') Yp = Yq[q - 1, :]
Yr = np.zeros(vs) forecast_mse = 0.0 for i in range(0, vs):
Yr[i] = net.sim([Yp])[0][0]
Yp = np.concatenate((Yp[1:Yp.shape[0]], np.array([Yr[i]]))) forecast_mse += (Yr[i] - Yv[i]) ** 2
forecast_mse /= vs
print('> Моделирование работы сети закончилось')
# Построение графика
pyplot.plot(Xt, Yt, 'b*') # Построение обучающей выборки pyplot.plot(Xv, Yv, 'gs') # Построение проверочной выборки pyplot.plot(Xv, Yr, 'rx') # Построение прогноза
tx = (max_x - min_x) / 20 ty = (max_y - min_y) / 20
pyplot.text(min_x + tx, min_y + ty, "Train MSE: {:.8}".format(train_mse)) pyplot.text(min_x + tx, min_y + ty * 2, "Forecast MSE: {:.8}".format(forecast_mse)) pyplot.xlim([min_x, max_x]) # Установка границы по X
12
pyplot.ylim([min_y, max_y]) # Установка границы по Y pyplot.xlabel('X') # Метка оси X
pyplot.ylabel('Y') # Метка оси Y pyplot.grid(True) # Сетка pyplot.show()
Ключевыми параметрами являются:
1.Число точек n ;
2.Число лагов b ;
3.Цель обучения goal .
Именно они определяют, какой результат будет на выходе.
Для всех трех промежутков нахождения решения получим следующие результаты (рис. 17, 18, 19).
Рисунок 17 — 100 точек, 5 лагов, (0 ,10 ] , цель 1e-5
Рисунок 18 — 100 точек, 5 лагов, (0 ,20 ] , цель 1e-5
13
Рисунок 19 — 100 точек, 5 лагов, (0 ,30 ] , цель 1e-5
В данных случаях ошибка больше, чем при использовании MATLAB. Это связано с тем, что в MATLAB используется алгоритм Левенберга — Марквардта (Levenberg–Marquardt algorithm, «LM»), а в Neurolab — алгоритм нелинейного сопряженного градиента (nonlinear conjugate gradient method, «CG») в качестве функции оптимизации. Первый работает дольше второго, но выдает более точный результат. Поэтому число лагов, равное 5, для CG не подходит.
Увеличим число лагов b=50 .
Для всех трех промежутков нахождения решения получим следующие результаты (рис. 20, 21, 22).
Рисунок 20 — 100 точек, 50 лагов, (0 ,10 ] , цель 1e-5
14
Рисунок 21 — 100 точек, 50 лагов, (0 ,20 ] , цель 1e-5
Рисунок 22 — 100 точек, 50 лагов, (0 ,30 ] , цель 1e-5
Ошибка значительно снизилась. Кроме того, для третьего промежутка при использовании CG (Neurolab) (рис. 22) ошибка получилась меньше, чем при использовании LM (MATLAB) (рис. 16).
Теперь сравним работу CG и LM на 300 точках и 150 лагах (рис. 23, 24,
25).
15