繁体   English   中英

在 python 中使用 log(1+e^x) 的泰勒级数扩展 1 个暗向量

[英]expand 1 dim vector by using taylor series of log(1+e^x) in python

我需要使用特定非线性 function ( e^x or log(x) or log(1+e^x) )的泰勒级数扩展从 1 个暗淡像素向量中对每个像素值进行非线性扩展,但我目前的实现至少基于泰勒级数概念,对我来说是不正确的。 背后的基本直觉是将像素阵列作为 CNN model 的输入神经元,其中每个像素都应该通过非线性 function 的泰勒级数展开进行非线性展开。

新更新1

根据我对泰勒级数的理解,泰勒级数是为变量x的 function F的值编写的 function F ,它是变量x0的另一个值的导数。 在我的问题中, F是特征(又名像素)的非线性变换的 function, x是每个像素值, x0是麦克劳林级数近似为 0。

新的更新 2

如果我们使用近似阶数为 2 的log(1+e^x)泰勒级数,则每个像素值将通过采用泰勒级数的第一个和第二个展开项产生两个新像素。

图解

这是上述公式的图形说明:

在此处输入图像描述

其中X是像素阵列, p是泰勒级数的近似阶, α是泰勒展开系数。

我想用非线性 function 的泰勒级数扩展来非线性扩展像素向量,如上图所示。

我目前的尝试

这是我目前的尝试,它不适用于像素 arrays。 我在考虑如何使相同的想法适用于像素 arrays。

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)

这种尝试不会产生上述数学公式所描述的内容。 我敢打赌我在扩展时错过了一些东西。 谁能指出我如何纠正这个问题? 有更好的主意吗?

目标

我想采用像素向量并通过某些非线性 function 的泰勒级数展开来进行非线性分布或展开。 有没有办法做到这一点? 有什么想法吗? 谢谢

这是一个非常有趣的问题,但我还不能说我对此很清楚。 所以,虽然我有一些想法,但我可能会错过你想要做的事情的主旨。

似乎您想开发自己的激活 function 而不是使用 RELU 或 softmax。 那里当然没有坏处。 你给了三个候选人: e^x, log(x), and log(1+e^x)

在此处输入图像描述

注意 log(x) 渐近地接近负无穷 x --> 0。所以,log(x) 是正确的。 如果这是为了检查你得到的答案,或者是在你入睡时记下的东西,不用担心。 但如果不是,您应该花一些时间并确保您了解您所做的事情的基础,因为后果可能非常严重。

您表示您正在寻找一个规范的答案,并且您在这里得到一个二合一的答案。 你会得到一个规范的答案和高性能的代码。

考虑到您不可能比 SciPy、Numpy 或 Pandas 的人编写更快、更精简的代码。 或者,PyPy。 或者 Cython。 他们的东西是标准的。 因此,不要试图通过编写自己的、性能较差(并且可能存在错误)的版本来与它们竞争,然后随着时间的推移您将不得不对其进行维护。 相反,通过使用它们来最大化您的开发和运行时间。

让我们看一下 SciPy 中的实现e^x并为您提供一些可以使用的代码。 我知道您在这个阶段不需要图表,但它们很漂亮,可以帮助您了解 Taylor(或 Maclaurin,又名 Euler-Maclaurin)将如何随着近似顺序的变化而工作。 碰巧 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()

这产生了这个:

在此处输入图像描述

但是,假设您对“数学”很好,可以这么说,并且愿意 go 如果它更“数学”,那么它会稍微慢一些,因为它可以很好地处理符号表示法。 为此,让我推荐 SymPy。

考虑到这一点,这里有一些带有图形的 SymPy 代码,因为它看起来不错,而且因为我们需要返回 go 并再次触及另一个点。

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()

在此处输入图像描述

我认为任何一个选项都会让你到达你需要 go 的地方。

好的,现在谈谈另一点。 经过一番修改后,您明确表示 log(1 +e^x) 是您的首选。 但其他人没有通过嗅探测试。 e^x 随着多项式次数的变化而剧烈波动。 由于算法的不透明性以及很少有人能够从概念上理解这些东西,数据科学家可以把事情搞砸到人们甚至无法想象的程度。 因此,请确保您对此理论非常扎实。

最后一件事,考虑查看 Erlang Distribution 的 CDF 作为激活 function (假设我是对的,并且您希望将自己的激活 ZC1C425268E68385D1AB5074C17A 的研究区域推出)。 我认为没有人看过它,但它看起来很有希望。 我认为您可以将 RGB 的每个通道分解为两个参数之一,另一个是物理坐标。

您可以使用tf.tiletf.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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM