Апроксимуємо функцію за допомогою нейромережі

З метою освоєння бібліотек для роботи з нейронними мережами, вирішимо задачу апроксимації функції одного аргументу використовуючи алгоритми нейронних мереж для навчання і передбачення.

Вступ

 

Нехай задана функція 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]

 

Читайте також  Не попадіться в пастку використовуючи Oracle JDK 11

Вихідний код

 

https://github.com/dprotopopov/nnfunc

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *