Исследование поведения предложенного функционала. Часть II.

Пора перейти к более реалистичным тестам. Логичным шагом будет начать работать с операторами, а не с их имитацией. Предполагаются следующие цели:

  1. Показать, что значение предлагаемой меры неивариантности будет равно нулю, на операторе второй производной и наборе и парных синусов и косинусов аргумента $kx$, для некоторых $k \in [1 \dots M-1]$
  2. Показать, что значение меры инвариантности относительно оператора второй производной будет ненулевым, если посчитать его на наборе парных синусов и косинусов аргумента $kx$, для некоторых $k \in [1 \dots M]$ с некоторой дополнительной функцией $\alpha \cdot f(x)$, вторая производная которой явно не может быть аппроксимированна тригонометрическими функциями с аргументами $kx$ для того же набора $k$, и самой $\alpha \cdot f(x)$. Примером такой функции может служить та же сигмоида, что и в части I. Её вторая производная локальна(значит не должна воспроизвестись синусами и косинусами) и не воспроизводится самой сигмоидой. Оказывается, что результат зависит от $\alpha$.
  3. Исследовать поведение функционала в зависимости от $\alpha$ и сделать выводы.

In [103]:
import numpy as np
import tensorflow as tf
from matplotlib import pylab as plt
%matplotlib inline

m = 4500 
k_max = 6
M = k_max*2-2
a = -10
b = 10

x_grid = np.linspace(a, b, m, endpoint=True)
sess = tf.Session()
x = tf.placeholder(tf.double)
k_vec = [i for i in range(1, k_max)]
trial_func = []
for i in range(len(k_vec)):
    trial_func.append(tf.sin(k_vec[i]*x))
    trial_func.append(tf.cos(k_vec[i]*x))
    
alpha = tf.Variable(50, dtype=tf.double)
sess.run(tf.global_variables_initializer(), {x:x_grid})
alpha_loc = tf.placeholder(tf.double)
ass_alpha = tf.assign(alpha, alpha_loc)

trial_func.append(alpha*tf.sigmoid(x))

deriatives = [tf.gradients(trial_func[i], x)[0] for i in range(M+1)]
images = ([tf.gradients(trial_func[i], x)[0] for i in range(M+1)])

print(np.array(sess.run(images, {x:x_grid})).shape)

def get_noninv_index_tensor(trial_func, images, x):
    A = tf.transpose(trial_func)
    A_T = trial_func
    y_0 = tf.reduce_sum(input_tensor=images, axis=0)
    y = tf.expand_dims(y_0, -1)
    omega = tf.matmul(tf.matmul(tf.matrix_inverse(tf.matmul(A_T, A)), A_T), y)
    regression_fit = tf.matmul(tf.transpose(trial_func), omega)
    noninvariance_index = (1 / m) * tf.reduce_sum(tf.square(y - regression_fit))
    return regression_fit, noninvariance_index

regression_fit_sig, noninv_sig = get_noninv_index_tensor(trial_func, images, x)
regression_fit_nosig, noninv_nosig = get_noninv_index_tensor(trial_func[:M], images[:M], x)


print('1) Calculated measure of noninvariance: ', sess.run(noninv_nosig, {x:x_grid}))
print('2) Calculated measure of noninvariance: ', sess.run(noninv_sig, {x:x_grid}))


(11, 4500)
1) Calculated measure of noninvariance:  5.299143668641333e-29
2) Calculated measure of noninvariance:  16.197830514441446

In [104]:
def plot_all(x_in,title):
    fig = plt.figure(figsize=(16,8))
    func_set_matrix = sess.run(trial_func, {x:x_in})
    images_matrix = sess.run(images, {x:x_in})
    regression_fit = sess.run(regression_fit_sig, {x:x_in})
    plt.title(title, fontsize = 16)
    plt.grid(True)
    for i in range(np.array(trial_func).shape[0]):
        plt.plot(x_in, func_set_matrix[i])
    plt.plot(x_in, np.sum(images_matrix, axis=0), 'g--')
    plt.plot(x_in, regression_fit, 'r--')

In [105]:
noninv_list = []
noninv_list_nosig = []
i_list = []
local_alpha = 1e-5
x_grid_obs = np.linspace(a-50, b+50, 10000, endpoint=True)
for i in range(50):
    sess.run(ass_alpha, {alpha_loc:local_alpha})
    noninv_list.append(sess.run(noninv_sig, {x:x_grid}))
    noninv_list_nosig.append(sess.run(noninv_nosig, {x:x_grid}))
    i_list.append(local_alpha)
    if i==45:
        title = r'$\alpha$'+'='+ str(local_alpha)
        plot_all(x_grid_obs, title)
    
    if i==14:
        title = r'$\alpha$'+'='+ str(local_alpha)
        plot_all(x_grid_obs, title)
    if i==5:
        title = r'$\alpha$'+'='+ str(local_alpha)
        plot_all(x_grid_obs, title)
    if i==0:
        title = r'$\alpha$'+'='+ str(local_alpha)
        plot_all(x_grid_obs, title)
    local_alpha += 5



In [106]:
fig = plt.figure(figsize=(20,10))
plt.grid(True)
plt.title('Noninvariance index', fontsize=26)
plt.xlabel(r'$\alpha$', fontsize=20)
plt.ylabel('J', fontsize=20)
plt.plot(i_list, noninv_list, 'rx--')
plt.plot(i_list, noninv_list_nosig, 'gx--')


Out[106]:
[<matplotlib.lines.Line2D at 0x7f9adafabe10>]

Результат.

Как и ожидалось, в случае использования инвариантного базиса, мера неивариантности $\approx 0$, а в случае неинвариантного $\neq 0$. Это даёт основания считать предложенную меру пригодной для использования с операторами, а не только с синтетическими наборами функций.

Однако, удалось показать относительно ожидаемый, но неприятный эффект: значение функционала зависит от линейных коэффициентов перед базисными функциями. Это легко понять, вспомнив, как формируется функция, к которой производится аппроксимация. Если в наборе функций есть функция с номером $l$: $f_l(x) = \alpha \cdot g_l(x)$, при этом аппроксимация происходит к функции $y(x)$ : $$y(x)= \sum_i \beta_i \cdot f_i(x)$$ при этом $\forall i: \beta_i=1$. Можно переопределить $y(x)$: $$y(x)=\sum_{i\neq l} f_i(x) + \alpha \cdot g(x)$$ Таким образом, малый $\alpha$ фактически выводит функцию $g_l(x)$ "из игры".

В данном случае, при малом $\alpha$, сигмоида, которая "портит" инвариантность набора, сходит на нет и ситуация вырождается в набор без сигмоиды. При увеличении $\alpha$, $y(x)$ "растягивается" в сторону неивариантной части, увеличивая значение функционала.

Этот эффект может оказаться достаточно проблематичным явлением при использовании этого функционала для решения уравнений. По крайней мере, о нем не стоит забывать. Именно в этом месте появляется существенная разница между такой численной оценкой неинвариантности и тем, что бы мы хотели ожидать с точки зрения алгебры. Хотя, с точки зрения алгебры мне незнакомы ситуации, когда ставилась бы задачи количественно оценивать инвариантность наборов векторов/функций относительно оператора.