python تحميل - كيف تحسب وظيفة sigmoid اللوجستية في بيثون؟




برنامج download (9)

هذه هي وظيفة السيجمائية اللوجستية:

وأنا أعلم العاشر. كيف يمكنني حساب F (x) في Python الآن؟

لنفترض أن x = 0.458.

F (س) =؟


Answers

يشمل Tensorflow أيضا وظيفة sigmoid : https://www.tensorflow.org/versions/r1.2/api_docs/python/tf/sigmoid

import tensorflow as tf

sess = tf.InteractiveSession()
x = 0.458
y = tf.sigmoid(x)

u = y.eval()
print(u)
# 0.6125396

طريقة أخرى عن طريق تحويل وظيفة tanh :

sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)

يتوفر أيضًا في scipy: http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.logistic.html

In [1]: from scipy.stats import logistic

In [2]: logistic.cdf(0.458)
Out[2]: 0.61253961344091512

وهو عبارة عن غلاف مكلف فقط (لأنه يسمح لك بقياس وترجمة الوظيفة اللوجيستية) لدالة scipy أخرى:

In [3]: from scipy.special import expit

In [4]: expit(0.458)
Out[4]: 0.61253961344091512

إذا كنت تشعر بالقلق إزاء مواصلة قراءة الأداء ، وإلا استخدام مجرد expit .

بعض القياس:

In [5]: def sigmoid(x):
  ....:     return 1 / (1 + math.exp(-x))
  ....: 

In [6]: %timeit -r 1 sigmoid(0.458)
1000000 loops, best of 1: 371 ns per loop


In [7]: %timeit -r 1 logistic.cdf(0.458)
10000 loops, best of 1: 72.2 µs per loop

In [8]: %timeit -r 1 expit(0.458)
100000 loops, best of 1: 2.98 µs per loop

كما هو متوقع logistic.cdf (أبطأ) من أبطأ من. لا يزال expit أبطأ من وظيفة sigmoid python sigmoid عندما يتم استدعاؤه بقيمة واحدة لأنه وظيفة عالمية مكتوبة في C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) ، وبالتالي يكون هناك اتصال تكاليف غير مباشرة. تعتبر هذه expit أكبر من سرعة عملية حساب expit عن طبيعتها المجمعة عند استدعائها بقيمة واحدة. ولكن يصبح لا يكاد يذكر عندما يتعلق الأمر المصفوفات الكبيرة:

In [9]: import numpy as np

In [10]: x = np.random.random(1000000)

In [11]: def sigmoid_array(x):                                        
   ....:    return 1 / (1 + np.exp(-x))
   ....: 

(ستلاحظ التغيير الضئيل من math.exp إلى np.exp (لا يدعم أول واحد المصفوفات ، ولكن أسرع بكثير إذا كان لديك قيمة واحدة للحساب))

In [12]: %timeit -r 1 -n 100 sigmoid_array(x)
100 loops, best of 1: 34.3 ms per loop

In [13]: %timeit -r 1 -n 100 expit(x)
100 loops, best of 1: 31 ms per loop

ولكن عندما تحتاج حقًا إلى الأداء ، فإن الممارسة الشائعة هي أن يكون لديك جدول مُسبَق مسبقًا لوظيفة sigmoid التي تعمل في ذاكرة الوصول العشوائي ، وتتاجر ببعض الدقة والذاكرة لبعض السرعة (على سبيل المثال: http://radimrehurek.com/2013/09/word2vec-in-python-part-two-optimizing/ )

لاحظ أيضًا أن تنفيذ expit ثابت عدديًا منذ الإصدار 0.14.0: https://github.com/scipy/scipy/issues/3385


طريق اخر

>>> def sigmoid(x):
...     return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)

أشعر بأن الكثيرين قد يكونون مهتمين بالمعلمات المجانية لتغيير شكل وظيفة السيني. ثانيًا بالنسبة للعديد من التطبيقات التي ترغب في استخدام وظيفة sigmoid لها نسخ متطابقة. ثالثًا ، قد ترغب في إجراء عملية تطبيع بسيطة على سبيل المثال قيم المخرجات تتراوح بين 0 و 1.

محاولة:

def normalized_sigmoid_fkt(a, b, x):
   '''
   Returns array of a horizontal mirrored normalized sigmoid function
   output between 0 and 1
   Function parameters a = center; b = width
   '''
   s= 1/(1+np.exp(b*(x-a)))
   return 1*(s-min(s))/(max(s)-min(s)) # normalize function to 0-1

ولرسم ومقارنة:

def draw_function_on_2x2_grid(x): 
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
    plt.subplots_adjust(wspace=.5)
    plt.subplots_adjust(hspace=.5)

    ax1.plot(x, normalized_sigmoid_fkt( .5, 18, x))
    ax1.set_title('1')

    ax2.plot(x, normalized_sigmoid_fkt(0.518, 10.549, x))
    ax2.set_title('2')

    ax3.plot(x, normalized_sigmoid_fkt( .7, 11, x))
    ax3.set_title('3')

    ax4.plot(x, normalized_sigmoid_fkt( .2, 14, x))
    ax4.set_title('4')
    plt.suptitle('Different normalized (sigmoid) function',size=10 )

    return fig

أخيرا:

x = np.linspace(0,1,100)
Travel_function = draw_function_on_2x2_grid(x)


إليك كيفية تنفيذ السيني اللوجستي بطريقة مستقرة عدديًا (كما هو موضح here ):

def sigmoid(x):
    "Numerically-stable sigmoid function."
    if x >= 0:
        z = exp(-x)
        return 1 / (1 + z)
    else:
        z = exp(x)
        return z / (1 + z)

أو ربما هذا هو أكثر دقة:

import numpy as np

def sigmoid(x):  
    return math.exp(-np.logaddexp(0, -x))

داخليا ، فإنه ينفذ نفس الحالة المذكورة أعلاه ، ولكن بعد ذلك يستخدم log1p .

بشكل عام ، السيني اللوجيستي متعدد الحدود هو:

def nat_to_exp(q):
    max_q = max(0.0, np.max(q))
    rebased_q = q - max_q
    return np.exp(rebased_q - np.logaddexp(-max_q, np.logaddexp.reduce(rebased_q)))

(ومع ذلك ، يمكن أن يكون logaddexp.reduce أكثر دقة.)


نسخة مستقرة عدديًا من وظيفة السيني اللوجستي.

    def sigmoid(x):
        pos_mask = (x >= 0)
        neg_mask = (x < 0)
        z = np.zeros_like(x,dtype=float)
        z[pos_mask] = np.exp(-x[pos_mask])
        z[neg_mask] = np.exp(x[neg_mask])
        top = np.ones_like(x,dtype=float)
        top[neg_mask] = z[neg_mask]
        return top / (1 + z)

إجابة جيدة منunwind. ومع ذلك لا يمكن التعامل مع الرقم السالب الشديد (رمي OverflowError).

تحسيناتي:

def sigmoid(x):
    try:
        res = 1 / (1 + math.exp(-x))
    except OverflowError:
        res = 0.0
    return res

هل يمكن جعل اثنين الديكور منفصلة أن تفعل ما تريد كما هو موضح أدناه مباشرة. لاحظ استخدام *args, **kwargsإعلان wrapped()الدالة الذي يدعم الوظيفة المزودة بخصائص متعددة (وهي ليست ضرورية فعلاً say()للوظيفة المثالية ، ولكنها متضمنة للعمومية).

لأسباب مماثلة ، functools.wrapsيتم استخدام الديكور لتغيير السمات الفوقية للوظيفة الملفوفة لتكون تلك الموجودة في الزينة. هذا يجعل رسائل الخطأ ووثائق الوظائف المدمجة ( func.__doc__) هي تلك الخاصة بالوظيفة المزخرفة بدلاً من wrapped()s.

from functools import wraps

def makebold(fn):
    @wraps(fn)
    def wrapped(*args, **kwargs):
        return "<b>" + fn(*args, **kwargs) + "</b>"
    return wrapped

def makeitalic(fn):
    @wraps(fn)
    def wrapped(*args, **kwargs):
        return "<i>" + fn(*args, **kwargs) + "</i>"
    return wrapped

@makebold
@makeitalic
def say():
    return 'Hello'

print(say())  # -> <b><i>Hello</i></b>

التحسينات

كما ترى ، هناك الكثير من الشفرات المكررة في هذين المصممين. بالنظر إلى هذا التشابه ، سيكون من الأفضل لك بدلاً من ذلك أن تصنع نوعًا عامًا كان في الواقع مصنعًا للديكور - وبعبارة أخرى ، مصممًا يزيّن الديكورات الأخرى. بهذه الطريقة سيكون هناك تكرار أقل للكود - ويسمح بمتابعة مبدأ DRY .

def html_deco(tag):
    def decorator(fn):
        @wraps(fn)
        def wrapped(*args, **kwargs):
            return '<%s>' % tag + fn(*args, **kwargs) + '</%s>' % tag
        return wrapped
    return decorator

@html_deco('b')
@html_deco('i')
def greet(whom=''):
    return 'Hello' + (' ' + whom) if whom else ''

print(greet('world'))  # -> <b><i>Hello world</i></b>

لجعل الشفرة أكثر قابلية للقراءة ، يمكنك تعيين اسم وصفي أكثر للديكور الذي تولده المصنع:

makebold = html_deco('b')
makeitalic = html_deco('i')

@makebold
@makeitalic
def greet(whom=''):
    return 'Hello' + (' ' + whom) if whom else ''

print(greet('world'))  # -> <b><i>Hello world</i></b>

أو حتى الجمع بينهما مثل هذا:

makebolditalic = lambda fn: makebold(makeitalic(fn))

@makebolditalic
def greet(whom=''):
    return 'Hello' + (' ' + whom) if whom else ''

print(greet('world'))  # -> <b><i>Hello world</i></b>

نجاعة

في حين أن الأمثلة المذكورة أعلاه تعمل بكاملها ، فإن الشفرة التي تم إنشاؤها تنطوي على قدر كبير من النفقات العامة في شكل مكالمات دالة غريبة عندما يتم تطبيق ديكور متعدد في وقت واحد. هذا قد لا يهم ، اعتمادا على الاستخدام الدقيق (الذي قد يكون I / O- ملزمة ، على سبيل المثال).

إذا كانت سرعة الوظيفة المزخرفة مهمة ، فيمكن الحفاظ على الحمل العلوي لمكالمة واحدة إضافية عن طريق كتابة وظيفة مصنع ديكور مختلفة بعض الشيء والتي تنفذ إضافة كل العلامات في وقت واحد ، حتى تتمكن من توليد كود يتجنب المكالمات الدالة الإضافية التي تكبدتها باستخدام ديكورات منفصلة لكل علامة.

وهذا يتطلب المزيد من التعليمات البرمجية في الديكور نفسه ، ولكن هذا لا يعمل إلا عندما يتم تطبيقه على التعريفات الوظيفية ، وليس لاحقًا عندما يتم استدعاؤها. ينطبق هذا أيضًا عند إنشاء أسماء أكثر قابلية للقراءة باستخدام lambdaوظائف كما هو موضح مسبقًا. عينة:

def multi_html_deco(*tags):
    start_tags, end_tags = [], []
    for tag in tags:
        start_tags.append('<%s>' % tag)
        end_tags.append('</%s>' % tag)
    start_tags = ''.join(start_tags)
    end_tags = ''.join(reversed(end_tags))

    def decorator(fn):
        @wraps(fn)
        def wrapped(*args, **kwargs):
            return start_tags + fn(*args, **kwargs) + end_tags
        return wrapped
    return decorator

makebolditalic = multi_html_deco('b', 'i')

@makebolditalic
def greet(whom=''):
    return 'Hello' + (' ' + whom) if whom else ''

print(greet('world'))  # -> <b><i>Hello world</i></b>




python