расширить 1 тусклый вектор, используя ряд Тейлора log (1 + e ^ x) в python

Мне нужно нелинейно расширить значение каждого пикселя из 1 вектора тусклого пикселя с расширением ряда Тейлора конкретной нелинейной функции (e^x or log(x) or log(1+e^x)), но моя текущая реализация мне не подходит, по крайней мере, на основе концепций ряда Тейлора. Основная интуиция заключается в том, чтобы использовать массив пикселей в качестве входных нейронов для модели CNN, где каждый пиксель должен быть нелинейно расширен с помощью расширения ряда Тейлора нелинейной функции.

новое обновление 1:

Насколько я понимаю из ряда Тейлора, ряд Тейлора записывается для функции F переменной x с точки зрения значения функции F и ее производных для другого значения переменной x0. В моей задаче F — это функция нелинейного преобразования признаков (также известных как пиксели), x — это значение каждого пикселя, x0 — аппроксимация ряда Маклорена в точке 0.

новое обновление 2

если мы используем ряд Тейлора log(1+e^x) с порядком аппроксимации 2, каждое значение пикселя даст два новых пикселя, взяв первый и второй члены расширения ряда Тейлора.

графическая иллюстрация

Вот графическая иллюстрация приведенной выше формулировки:

введите здесь описание изображения

Где X — массив пикселей, p — порядок аппроксимации ряда Тейлора, а α — коэффициент разложения Тейлора.

Я хотел нелинейно расширить векторы пикселей с помощью расширения ряда Тейлора нелинейной функции, как показано на иллюстрации выше.

Моя текущая попытка

Это моя текущая попытка, которая не работает правильно для массивов пикселей. Я думал о том, как применить ту же идею к пиксельным массивам.

def taylor_func(x, approx_order=2):
    x_ = x[..., None] 
    x_ = tf.tile(x_, multiples=[1, 1, approx_order+ 1])  
    pows = tf.range(0, approx_order + 1, dtype=tf.float32) 
    x_p = tf.pow(x_, pows) 
    x_p_ = x_p[..., None]
    return x_p_

x = Input(shape=(4,4,3))
x_new = Lambda(lambda x: taylor_func(x, max_pow))(x)

моя новая обновленная попытка:

x_input= Input(shape=(32, 32,3))

def maclurin_exp(x, powers=2):
    out= 0
    for k in range(powers):
        out+= ((-1)**k) * (x ** (2*k)) / (math.factorial(2 * k))
    return res

x_input_new = Lambda(lambda x: maclurin_exp(x, max_pow))(x_input)

Эта попытка не дает того, что описывает приведенная выше математическая формулировка. Бьюсь об заклад, я что-то пропустил, делая расширение. Может ли кто-нибудь указать мне, как сделать это правильно? Любая лучшая идея?

цель

Я хотел взять пиксельный вектор и сделать его нелинейно распределенным или расширенным с помощью расширения ряда Тейлора определенной нелинейной функции. Есть ли способ сделать это? Есть предположения? Спасибо


person Jared    schedule 07.07.2020    source источник
comment
Привет, Джаред, не мог бы ты пояснить свою идею? Я не понимаю уравнение, которое вы написали. Вы пытаетесь заменить входное изображение размером N на M со значениями пикселей x[i] на составной массив размером pN на M с блоками элементов формы x[i]**k, с k=1...p и p в качестве степени усечения ряда Тейлора?   -  person Aramakus    schedule 10.07.2020
comment
Я думаю, это та часть, которую я точно не понимаю. Ряды Тейлора записываются для функции F переменной x через значение функции F и ее производных по другому значению переменной x0. Так что мне непонятно, что такое функция и что такое переменная, когда вы говорите expand pixel vector with Taylor series expansion. Представляет ли функция значение пикселя, а переменная — его координаты в двумерном массиве (дискретные значения)?   -  person Aramakus    schedule 11.07.2020
comment
Я не понимаю концепцию function is Taylor expansion of non-linear function. Рассмотрим простую усеченную степень 2 ряда Тейлора, как в исходном посте F(x) = F(x0) + F'(x0)*(x-x0) + 0.5*F''(x0)*(x-x0)**2 . Какие здесь F, x и x0? Если x — исходное изображение, то что такое x0?   -  person Aramakus    schedule 11.07.2020
comment
так же, как вы это делали - просто добавьте значения пикселей в степень 2 к исходному входу. Предубеждения будут эквивалентны x0, так что вы получите этот термин бесплатно. За исключением того, что я, вероятно, сделал бы что-то вроде x2 = tf.pow(x, 2), а затем x_tot = tf.concat([x, x2], axis = -2) и использовал бы это как ввод. Но я не думаю, что в этом есть какая-то польза, поскольку нелинейные преобразования в функции активации, как правило, дают вам возможности ваших входов.   -  person Aramakus    schedule 13.07.2020
comment
@Джаред, у меня к тебе вопрос. Похоже, вы хотите удвоить значение пикселя фотографии. Это правильно? Я спрашиваю, потому что я думаю, что вам нужно будет возвести его в квадрат, потому что вам нужно учитывать как ось X, так и ось Y.   -  person hrokr    schedule 14.07.2020
comment
У меня есть некоторые мысли. Первый - это log (0), а ln (0) асимптотичны до отрицательной бесконечности. Кроме того, я делаю расширение серии Тейлора, так как оно более гибкое. Но у меня должно быть кое-что для тебя сегодня вечером или завтра. И в приватном чате все в порядке.   -  person hrokr    schedule 14.07.2020
comment
Просто чтобы вы знали, я работаю над этим и стараюсь дать вам наиболее гибкий и полный ответ, который я могу дать, учитывая то, как я понимаю вопрос. Сначала я сосредоточусь на коде, поскольку это вопрос, который вы задали. Что касается сплайнинга, мне нужно увидеть, что это будет частью того, что вы делаете.   -  person hrokr    schedule 14.07.2020
comment
Я уже предположил, что из того, что вы написали ранее. Я предполагаю, что это то, что вы хотите использовать в качестве функции активации.   -  person hrokr    schedule 14.07.2020
comment
@hrokr спасибо. Какой-нибудь канонический ответ у вас может быть на это?   -  person Jared    schedule 14.07.2020
comment
Давайте продолжим обсуждение в чате.   -  person Jared    schedule 14.07.2020


Ответы (2)


Это действительно интересный вопрос, но я пока не могу сказать, что я в нем разобрался. Итак, хотя у меня есть некоторые мысли, я могу упустить суть того, что вы хотите сделать.

Похоже, вы хотите разработать свою собственную функцию активации вместо использования чего-то RELU или softmax. Вреда точно нет. И вы дали трех кандидатов: e^x, log(x), and log(1+e^x).

введите здесь описание изображения

Обратите внимание, что log(x) асимптотически приближается к отрицательной бесконечности x --> 0. Таким образом, log(x) верен. Если это было предназначено для проверки ответов, которые вы получили, или что-то было записано, когда вы засыпали, не беспокойтесь. Но если это не так, вам следует потратить некоторое время и убедиться, что вы понимаете основы того, что вы делаете, потому что последствия могут быть весьма серьезными.

Вы указали, что искали канонический ответ, и здесь вы получаете два к одному. Вы получаете как канонический ответ, так и высокопроизводительный код.

Учитывая, что вы вряд ли сможете писать более быстрый и оптимизированный код, чем ребята из SciPy, Numpy или Pandas. Или ПиПи. Или Cython, если уж на то пошло. Вещи у них стандартные. Так что не пытайтесь конкурировать с ними, написав свою собственную, менее производительную (и, возможно, с ошибками) версию, которую вам придется поддерживать с течением времени. Вместо этого максимизируйте время разработки и выполнения, используя их.

Давайте взглянем на реализацию e^x в SciPy и дадим вам код для работы. Я знаю, что на данном этапе вам не нужен график, но они красивы и могут помочь вам понять, как Тейлор (или Маклорен, он же Эйлер-Маклорен) будет работать при изменении порядка аппроксимации. Так уж получилось, что SciPy имеет встроенную аппроксимацию Тейлора.

import scipy
import numpy as np
import matplotlib.pyplot as plt

from scipy.interpolate import approximate_taylor_polynomial

x = np.linspace(-10.0, 10.0, num=100)

plt.plot(x, np.exp(x), label="e^x", color = 'black')

for degree in np.arange(1, 4, step=1):

    e_to_the_x_taylor = approximate_taylor_polynomial(np.exp, 0, degree, 1, order=degree + 2)

    plt.plot(x, e_to_the_x_taylor(x), label=f"degree={degree}")

plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.0, shadow=True)

plt.tight_layout()
plt.axis([-10, 10, -10, 10])
plt.show()

Это производит это:

введите здесь описание изображения

Но скажем, если вы хорошо разбираетесь в «математике», так сказать, и готовы использовать что-то немного более медленное, если оно более «математическое», поскольку оно хорошо обрабатывает символическую запись. Для этого позвольте мне предложить SymPy.

Имея это в виду, вот немного кода SymPy с графиком, потому что он выглядит хорошо И потому что нам нужно вернуться и снова попасть в другую точку.

from sympy import series, Symbol, log, E
from sympy.functions import exp
from sympy.plotting import plot
import matplotlib.pyplot as plt
%matplotlib inline

plt.rcParams['figure.figsize'] = 13,10
plt.rcParams['lines.linewidth'] = 2

x = Symbol('x')

def taylor(function, x0, n):
    """ Defines Taylor approximation of a given function
    function -- is our function which we want to approximate
    x0 -- point where to approximate
    n -- order of approximation
    """    
    return function.series(x,x0,n).removeO()

# I get eyestain; feel free to get rid of this
plt.rcParams['figure.figsize'] = 10, 8
plt.rcParams['lines.linewidth'] = 1

c = log(1 + pow(E, x))

plt = plot(c, taylor(c,0,1), taylor(c,0,2), taylor(c,0,3), taylor(c,0,4), (x,-5,5),legend=True, show=False)

plt[0].line_color = 'black'
plt[1].line_color = 'red'
plt[2].line_color = 'orange'
plt[3].line_color = 'green'
plt[4].line_color = 'blue'
plt.title = 'Taylor Series Expansion for log(1 +e^x)'
plt.show()

введите здесь описание изображения

Я думаю, что любой из этих вариантов приведет вас туда, куда вам нужно.

Хорошо, теперь о другом. Вы четко заявили после небольшого пересмотра, что log(1 +e^x) был вашим первым выбором. Но остальные не проходят тест на обнюхивание. e^x сильно колеблется при изменении степени полинома. Из-за непрозрачности алгоритмов и того, как мало людей могут концептуально понять эти вещи, специалисты по данным могут напортачить до такой степени, которую люди даже не могут себе представить. Поэтому убедитесь, что вы очень хорошо разбираетесь в теории.

И последнее, рассмотрите возможность рассмотрения CDF дистрибутива Эрланга как функции активации (при условии, что я прав, и вы хотите использовать свою собственную функцию активации в качестве области исследования). Я не думаю, что кто-то смотрел на это, но это кажется многообещающим. Я думаю, вы могли бы выделить каждый канал RGB как один из двух параметров, а другой — физическую координату.

person hrokr    schedule 14.07.2020

Вы можете использовать tf.tile и tf.math.pow для создания элементов расширения серии. Затем вы можете использовать tf.math.cumsum для вычисления частичных сумм s_i. В конце концов вы можете умножить на веса w_i и вычислить окончательную сумму.

Вот пример кода:

import math
import tensorflow as tf

x = tf.keras.Input(shape=(32, 32, 3))  # 3-channel RGB.

# The following is determined by your series expansion and its order.
# For example: log(1 + exp(x)) to 3rd order.
# https://www.wolframalpha.com/input/?i=taylor+series+log%281+%2B+e%5Ex%29
order = 3
alpha = tf.constant([1/2, 1/8, -1/192])  # Series coefficients.
power = tf.constant([1.0, 2.0, 4.0])
offset = math.log(2)

# These are the weights of the network; using a constant for simplicity here.
# The shape must coincide with the above order of series expansion.
w_i = tf.constant([1.0, 1.0, 1.0])

elements = offset + alpha * tf.math.pow(
    tf.tile(x[..., None], [1, 1, 1, 1, order]),
    power
)
s_i = tf.math.cumsum(elements, axis=-1)
y = tf.math.reduce_sum(w_i * s_i, axis=-1)
person a_guest    schedule 15.07.2020
comment
@Jared Это тензор elements, который представляет элементы расширения ряда. Он имеет форму (?, 32, 32, 3, order), где order — порядок расширения ряда. Таким образом, первый член равен elements[..., 0], а второй член — elements[..., 1] и так далее. - person a_guest; 16.07.2020
comment
@Jared Что такое delta1 и delta2? Где это определено? - person a_guest; 16.07.2020
comment
это показано выше графика в моем посте. delta1 — первые члены разложения Тейлора, delta2 — сумма первого и второго членов разложения. Я хотел бы delta1 и delta2 как два недавно расширенных нейрона, которые будут независимо переданы сверточному фильтру. Можно ли расширить вашу мысль, если это возможно? Большое спасибо! - person Jared; 16.07.2020
comment
@Jared Конечно, это будет s_i в приведенном выше коде. Это кумулятивная сумма по оси всех элементов ряда, поэтому s_i[..., 0] — это только первый член, s_i[..., 1] — сумма первого и второго членов и так далее. - person a_guest; 16.07.2020
comment
Давайте продолжим это обсуждение в чате. - person Jared; 16.07.2020
comment
почему эта строка: elements = offset + alpha * tf.math.pow(tf.tile(x[:, None, ...], [1, order, 1, 1, 1]), power[:, None, None, None]) жестко закодирована для порядка 3? что, если мы расширим его только двумя членами расширения? какой общий код будет? Спасибо за канонический ответ!!! - person Jared; 17.07.2020
comment
@Jared Это не жестко закодировано для определенного заказа, оно работает для любого заказа. Размер последнего измерения определяет порядок. - person a_guest; 17.07.2020