Апроксимуємо функцію за допомогою нейромережі
З метою освоєння бібліотек для роботи з нейронними мережами, вирішимо задачу апроксимації функції одного аргументу використовуючи алгоритми нейронних мереж для навчання і передбачення.
Вступ
Нехай задана функція f:[x0,x1]->R
Апроксимуємо задану функцію f формулою
P(x) = SUM W[i]*E(x,M[i])
де
- i = 1..n
- M[i] з R
- W[i] з R
- E(x,M) = { 0, при x<M; 1/2, при x=M; 1, при x>M
Очевидно, що при рівномірному розподілі значень M[i] на відрізку (x0,x1) знайдуться такі величини W[i], при яких формула P(x) буде найкращим чином апроксимировать функцію f(x). При цьому, для заданих значень M[i], визначених на відрізку (x0,x1) і упорядкованих за зростанням, можна описати послідовний алгоритм обчислення величин W[i] формули для P(x).
А ось і нейромережа
Перетворимо формулу P(x) = SUM W[i]*E(x,M[i]) до моделі нейромережі з одним вхідним нейроном, одним вихідним нейроном і n нейронами прихованого шару
P(x) = SUM W[i]*S(K[i]*x + B[i]) + C
де
- x-змінна — “вхідний” шар, що складається з одного нейрона
- {K, B} — параметри “прихованого” шару, що складається з n нейронів і функцією активації — сигмоїда
- {W, C} — параметри “вихідного” шару, що складається з одного нейрона, який обчислює зважену суму своїх входів.
- S — сигмоїда,
при цьому
- початкові параметри “прихованого” шару K[i]=1
- початкові параметри “прихованого” шару B[i] рівномірно розподілені на відрізку (-x1-x0)
Всі параметри нейромережі K, B, W і C визначимо навчанням нейромережі на зразках (x,y) значень функції f.
Сигмоїда
Сигмоїда — це гладка монотонна зростаюча нелінійна функція
- S(x) = 1 / (1 + exp(-x)).
Програма
Використовуємо для опису нашої нейромережі пакет Tensorflow
# вузол на який будемо подавати аргументи функції
x = tf.placeholder(tf.float32, [None, 1], name="x")
# вузол на який будемо подавати значення функції
y = tf.placeholder(tf.float32, [None, 1], name="y")
# прихований шар
nn = tf.layers.dense(x, hiddenSize,
activation=tf.nn.sigmoid,
kernel_initializer=tf.initializers.ones(),
bias_initializer=tf.initializers.random_uniform(minval=-x1, maxval=-x0),
name="hidden")
# вихідний шар
model = tf.layers.dense(nn, 1,
activation=None,
name="output")
# функція підрахунку помилки
cost = tf.losses.mean_squared_error(y, model)
train = tf.train.GradientDescentOptimizer(learn_rate).minimize(cost)
Навчання
init = tf.initializers.global_variables()
with tf.Session() as session:
session.run(init)
for _ in range(iterations):
train_dataset, train_values = generate_test_values()
session.run(train, feed_dict={
x: train_dataset,
y: train_values
})
Повний текст
import math
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
x0, x1 = 10, 20 # діапазон для аргументу функції
test_data_size = 2000 # кількість даних для ітерації навчання
iterations = 20000 # кількість ітерацій навчання
learn_rate = 0.01 # коефіцієнт перенавчання
hiddenSize = 10 # розмір прихованого шару
# функція генерації тестових величин
def generate_test_values():
train_x = []
train_y = []
for _ in range(test_data_size):
x = x0+(x1-x0)*np.random.rand()
y = math.sin(x) # досліджувана функція
train_x.append([x])
train_y.append([y])
return np.array(train_x), np.array(train_y)
# вузол на який будемо подавати аргументи функції
x = tf.placeholder(tf.float32, [None, 1], name="x")
# вузол на який будемо подавати значення функції
y = tf.placeholder(tf.float32, [None, 1], name="y")
# прихований шар
nn = tf.layers.dense(x, hiddenSize,
activation=tf.nn.sigmoid,
kernel_initializer=tf.initializers.ones(),
bias_initializer=tf.initializers.random_uniform(minval=-x1, maxval=-x0),
name="hidden")
# вихідний шар
model = tf.layers.dense(nn, 1,
activation=None,
name="output")
# функція підрахунку помилки
cost = tf.losses.mean_squared_error(y, model)
train = tf.train.GradientDescentOptimizer(learn_rate).minimize(cost)
init = tf.initializers.global_variables()
with tf.Session() as session:
session.run(init)
for _ in range(iterations):
train_dataset, train_values = generate_test_values()
session.run(train, feed_dict={
x: train_dataset,
y: train_values
})
if(_ % 1000 == 999):
print("cost = {}".format(session.run(cost, feed_dict={
x: train_dataset,
y: train_values
})))
train_dataset, train_values = generate_test_values()
train_values1 = session.run(model, feed_dict={
x: train_dataset,
})
plt.plot(train_dataset, train_values, "bo",
train_dataset, train_values1, "ro")
plt.show()
with tf.variable_scope("hidden", reuse=True):
w = tf.get_variable("kernel")
b = tf.get_variable("bias")
print("hidden:")
print("kernel=", w.eval())
print("bias = ", b.eval())
with tf.variable_scope("output", reuse=True):
w = tf.get_variable("kernel")
b = tf.get_variable("bias")
print("output:")
print("kernel=", w.eval())
print("bias = ", b.eval())
Ось що вийшло
- Синій колір — вихідна функція
- Червоний колір — апроксимація функції
Висновок консолі
cost = 0.15786637365818024
cost = 0.10963975638151169
cost = 0.08536215126514435
cost = 0.06145831197500229
cost = 0.04406769573688507
cost = 0.03488277271389961
cost = 0.026663536205887794
cost = 0.021445846185088158
cost = 0.016708852723240852
cost = 0.012960446067154408
cost = 0.010525770485401154
cost = 0.008495906367897987
cost = 0.0067353141494095325
cost = 0.0057082874700427055
cost = 0.004624188877642155
cost = 0.004093789495527744
cost = 0.0038146725855767727
cost = 0.018593043088912964
cost = 0.010414039716124535
cost = 0.004842184949666262
hidden:
kernel= [[1.1523403 1.181032 1.1671464 0.9644377 0.8377886 1.0919508
0.87283015 1.0875995 0.9677301 0.6194152 ]]
bias = [-14.812331 -12.219926 -12.067375 -14.872566 -10.633507 -14.014006
-13.379829 -20.508204 -14.923473 -19.354435]
output:
kernel= [[ 2.0069902 ]
[-1.0321712 ]
[-0.8878887 ]
[-2.0531905 ]
[ 1.4293027 ]
[ 2.1250408 ]
[-1.578137 ]
[ 4.141281 ]
[-2.1264815 ]
[-0.60681605]]
bias = [-0.2812019]
Вихідний код
https://github.com/dprotopopov/nnfunc