web-dev-qa-db-ja.com

n次元配列のnumpy二次導関数

N次元で最も低い勾配を見つけたい一連のシミュレーションデータがあります。データの間隔は各次元に沿って一定ですが、すべて同じではありません(簡単にするために変更することもできます)。

特に端に向かって、私はいくつかの数値の不正確さを抱えて生きることができます。スプラインを生成せず、その導関数を使用しないほうがいいと思います。そのままの値で十分です。

numpy.gradient()関数を使用すると、numpyを使用して1次導関数を計算できます。

_import numpy as np

data = np.random.Rand(30,50,40,20)
first_derivative = np.gradient(data)
# second_derivative = ??? <--- there be kudos (:
_

これはラプラス対ヘシアン行列に関するコメントです。これはもはや問題ではありませんが、将来の読者の理解を助けることを目的としています。

テストケースとして2D関数を使用して、しきい値を下回る「最も平坦な」領域を決定します。次の図は、最小値のsecond_derivative_abs = np.abs(laplace(data))と最小値の使用の結果の違いを示しています。

_second_derivative_abs = np.zeros(data.shape)
hess = hessian(data)
# based on the function description; would [-1] be more appropriate? 
for i in hess[0]: # calculate a norm
    for j in i[0]:
        second_derivative_abs += j*j
_

カラースケールは関数値、矢印は1次導関数(勾配)、赤い点はゼロに最も近い点、赤い線はしきい値を表します。

データのジェネレーター関数は_( 1-np.exp(-10*xi**2 - yi**2) )/100.0_で、xiは_np.meshgrid_で生成されました。

ラプラス:

laplace solution

ヘッセ行列:

hessian solution

16
Faultier

2次導関数は ヘッシアン行列 で与えられます。 Python ND配列の実装です。これは、np.gradient 2回出力を適切に保存し、

import numpy as np

def hessian(x):
    """
    Calculate the hessian matrix with finite differences
    Parameters:
       - x : ndarray
    Returns:
       an array of shape (x.dim, x.ndim) + x.shape
       where the array[i, j, ...] corresponds to the second derivative x_ij
    """
    x_grad = np.gradient(x) 
    hessian = np.empty((x.ndim, x.ndim) + x.shape, dtype=x.dtype) 
    for k, grad_k in enumerate(x_grad):
        # iterate over dimensions
        # apply gradient again to every component of the first derivative.
        tmp_grad = np.gradient(grad_k) 
        for l, grad_kl in enumerate(tmp_grad):
            hessian[k, l, :, :] = grad_kl
    return hessian

x = np.random.randn(100, 100, 100)
hessian(x)

2次導関数の大きさだけに関心がある場合は、 ラプラス演算子scipy.ndimage.filters.laplace 、これはヘッセ行列のトレース(対角要素の合計)です。

ヘッセ行列の最小要素を取ることは、あらゆる空間方向の最低勾配を推定するために使用できます。

22
rth

ヘッセ行列を勾配の勾配として見ることができます。ここで計算された最初の勾配の各成分に2回勾配を適用すると、ここで計算されたWikipediaです link ヘッセ行列を定義し、それが勾配の勾配、これが勾配を定義するpython実装、次にヘッセ行列です:

import numpy as np
#Gradient Function
def gradient_f(x, f):
  assert (x.shape[0] >= x.shape[1]), "the vector should be a column vector"
  x = x.astype(float)
  N = x.shape[0]
  gradient = []
  for i in range(N):
    eps = abs(x[i]) *  np.finfo(np.float32).eps 
    xx0 = 1. * x[i]
    f0 = f(x)
    x[i] = x[i] + eps
    f1 = f(x)
    gradient.append(np.asscalar(np.array([f1 - f0]))/eps)
    x[i] = xx0
  return np.array(gradient).reshape(x.shape)

#Hessian Matrix
def hessian (x, the_func):
  N = x.shape[0]
  hessian = np.zeros((N,N)) 
  Gd_0 = gradient_f( x, the_func)
  eps = np.linalg.norm(Gd_0) * np.finfo(np.float32).eps 
  for i in range(N):
    xx0 = 1.*x[i]
    x[i] = xx0 + eps
    Gd_1 =  gradient_f(x, the_func)
    hessian[:,i] = ((Gd_1 - Gd_0)/eps).reshape(x.shape[0])
    x[i] =xx0
  return hessian

テストとして、(x ^ 2 + y ^ 2)のヘッセ行列は 2 * I_2 ここで、I_2は次元2の単位行列です

3

スロープ、ヘシアン、ラプラシアンは関連していますが、3つの異なるものです。
2dで開始:2つの変数の関数(x、y)。丘の範囲の高さマップ、

  • 勾配別名勾配は、方向ベクトル、各ポイントの方向と長さ_x y_です。
    これは、デカルト座標では2つの数値_dx dy_、極座標では角度θと長さsqrt( dx^2 + dy^2 )で指定できます。丘の全範囲にわたって、 ベクトルフィールド を取得します。

  • ヘシアンは_x y_付近の曲率を記述します。放物面またはサドル、4つの数字:_dxx dxy dyx dyy_。

  • ラプラシアンは、各点で_dxx + dyy_の1つの数値_x y_です。丘の範囲にわたって、 スカラーフィールド を取得します。 ( Laplacian = 0 の関数または丘は特に滑らかです。)

勾配は線形近似とヘッセ行列の二次近似であり、点の近くの小さなステップhの場合xy

_f(xy + h)  ~  f(xy)
        +  slope . h    -- dot product, linear in both slope and h
        +  h' H h / 2   -- quadratic in h
_

ここで、xyslopeおよびhは2つの数値のベクトルであり、Hは4つの数値の行列_dxx dxy dyx dyy_です。

N-dも同様です。各点での勾配はN数値の方向ベクトル、ヘッシアンはN ^ 2数値、ラプラシアン1数値の行列です。

math.stackexchange でより良い答えが見つかるかもしれません。)

2
denis