15

スカラー変数xの場合、Python で数値的に安定したシグモイド関数を書き留める方法を知っています。

def sigmoid(x):
    if x >= 0:
        return 1. / ( 1. + np.exp(-x) )
    else:
        return exp(x) / ( 1. + np.exp(x) )

スカラーのリストについては、たとえば 、事前z = [x_1, x_2, x_3, ...]にそれぞれの符号がわからない場合x_i、上記の定義を一般化して試すことができます。

def sigmoid(z):
    result = []
    for x in z:
        if x >= 0:
            result.append(1. / ( 1. + np.exp(-x) ) )
        else:
            result.append( exp(x) / ( 1. + np.exp(x) ) )
    return result

これはうまくいくようです。ただし、これはおそらく最もpythonicな方法ではないと思います。「清潔さ」の定義をどのように改善すればよいですか? たとえば、内包表記を使用して関数定義を短縮する方法はありますか?

SOで同様の質問が見つからないため、これが尋ねられた場合は申し訳ありません。お時間をいただき、ありがとうございました。

4

6 に答える 6

1

受け入れられた答えは正しいですが、このコメントで指摘されているように、両方の分岐を計算するため、問題があります。

むしろ、 を使用したい場合がありますnp.piecewise()。これははるかに高速で意味があり (区分関数を定義するためのものでnp.whereはありません)、両方のブランチに入ることによって引き起こされる誤解を招く警告がありません。

基準

ソースコード

import numpy as np
import time

N: int = int(1e+4)

np.random.seed(0)

x: np.ndarray = np.random.random((N, N))
x *= 1e+3

start: float = time.time()
y1 = np.where(x > 0, 1 / (1 + np.exp(-x)), np.exp(x) / (1 + np.exp(x)))
end: float = time.time()
print()
print(end - start)

start: float = time.time()
y2 = np.piecewise(x, [x > 0], [lambda i: 1 / (1 + np.exp(-i)), lambda i: np.exp(i) / (1 + np.exp(i))])
end: float = time.time()
print(end - start)

assert (np.array_equal(y1, y2))

結果

np.piecewise()静かで 2 倍高速です。

test.py:12: RuntimeWarning: overflow encountered in exp
  y1 = np.where(x > 0, 1 / (1 + np.exp(-x)), np.exp(x) / (1 + np.exp(x)))
test.py:12: RuntimeWarning: invalid value encountered in true_divide
  y1 = np.where(x > 0, 1 / (1 + np.exp(-x)), np.exp(x) / (1 + np.exp(x)))

6.32736349105835
3.138420343399048
于 2020-07-12T10:54:29.197 に答える