Материал: Лабораторная работа 5

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

"""

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