簡體   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