このページは、nAGライブラリのJupyterノートブックExampleの日本語翻訳版です。オリジナルのノートブックはインタラクティブに操作することができます。
単純な非線形最小二乗フィッティングの例
この例では、重み付き非線形最小二乗法を用いてデータをモデルにフィッティングする方法を示します。
handle_solve_bxnl
(e04gg
)は、nAG最適化モデリングスイートの境界制約付き非線形最小二乗信頼領域ソルバー(BXNL)で、小規模から中規模の問題を対象としています。以下の問題を解きます:
ここで、
通常、キャリブレーションやデータフィッティングの文脈では、残差は
以下の例は、e04gg
を使用する方法を示しています。ターゲットシートをスキャンし、トラック直径(図1の赤いくさび)をヒストグラムに記録し、混合正規分布と対数正規分布モデルを実験ヒストグラムにフィッティングします(図2参照)。
図1: エッチングされた
e04gg
は、以下の6パラメータモデルをフィッティングするために使用されます:
import numpy as np
import math
import matplotlib.pyplot as plt
from naginterfaces.base import utils
from naginterfaces.library import opt
# 問題データ
# 観測数
= 64
nres # 観測値
= range(1, nres+1)
diameter = [
density 0.0722713864, 0.0575221239, 0.0604719764, 0.0405604720, 0.0317109145,
0.0309734513, 0.0258112094, 0.0228613569, 0.0213864307, 0.0213864307,
0.0147492625, 0.0213864307, 0.0243362832, 0.0169616519, 0.0095870206,
0.0147492625, 0.0140117994, 0.0132743363, 0.0147492625, 0.0140117994,
0.0140117994, 0.0132743363, 0.0117994100, 0.0132743363, 0.0110619469,
0.0103244838, 0.0117994100, 0.0117994100, 0.0147492625, 0.0110619469,
0.0132743363, 0.0206489676, 0.0169616519, 0.0169616519, 0.0280235988,
0.0221238938, 0.0235988201, 0.0221238938, 0.0206489676, 0.0228613569,
0.0184365782, 0.0176991150, 0.0132743363, 0.0132743363, 0.0088495575,
0.0095870206, 0.0073746313, 0.0110619469, 0.0036873156, 0.0051622419,
0.0058997050, 0.0014749263, 0.0022123894, 0.0029498525, 0.0014749263,
0.0007374631, 0.0014749263, 0.0014749263, 0.0007374631, 0.0000000000,
0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000
]
# コールバック関数に渡されるデータ構造を定義する
= {'d': diameter, 'y': density} data
# PADCエッチトラック直径カウント(密度)のヒストグラムをプロットする
= np.arange(1, 10*nres+9)/10.0
dh = plt.figure()
fig = fig.add_subplot(111)
ax 'PADC etch track diameter histogram', fontsize=16)
ax.set_title('Diameter (nm)')
ax.set_xlabel('Density')
ax.set_ylabel(=1, xmax=65)
ax.set_xlim(xmin'y'], color='lightsteelblue')
ax.bar(diameter, data[
ax.grid() plt.show()

図2:
α粒子のエッチングトラック直径のヒストグラム。棒グラフの高さは、集約モデル
# 正規分布と対数正規分布を定義する
def lognormal(d, a, b, Al):
return Al/(d*b*np.sqrt(2*math.pi))*np.exp(-((np.log(d)-a)**2)/(2*b**2))
def gaussian(d, mu, sigma, Ag):
return Ag*np.exp(-0.5*((d-mu)/sigma)**2)/(sigma*np.sqrt(2*math.pi))
この問題を解決する観点から、最小化する関数は、モデル diameter
,
density
)を使用した残差の合計です。 パラメータベクトルは
# 最小二乗関数を正規分布と対数正規分布の混合として定義する
# 関数。また、その一次導関数を追加する
def lsqfun(x, nres, inform, data):
"""
Objective function callback passed to the least squares solver.
x = (a, b, Al, mu, sigma, Ag)
"""
= np.zeros(nres)
rx = data['d']
d = data['y']
y = x[0]
a = x[1]
b = x[2]
Al = x[3]
mu = x[4]
sigma = x[5]
Ag for i in range(nres):
= lognormal(d[i], a, b, Al) + gaussian(d[i], mu, sigma, Ag) - y[i]
rx[i] return rx, inform
def lsqgrd(x, nres, rdx, inform, data):
"""
Computes the Jacobian of the least square residuals.
x = (a, b, Al, mu, sigma, Ag)
"""
= len(x)
n = data['d']
d = x[0]
a = x[1]
b = x[2]
Al = x[3]
mu = x[4]
sigma = x[5]
Ag for i in range(nres):
# 対数正規分布の導関数
= lognormal(d[i], a, b, Al)
l # dl/da
*n+0] = (np.log(d[i])-a)/(b**2) * l
rdx[i# dl/db
*n+1] = ((np.log(d[i])-a)**2 - b**2)/b**3 * l
rdx[i# dL/dAl
*n+2] = lognormal(d[i], a, b, 1.0)
rdx[i# ガウス導関数
= gaussian(d[i], mu, sigma, Ag)
g # dμ/dμ
*n+3] = (d[i] - mu) / sigma**2 * g
rdx[i# dg/dsigma
*n+4] = ((d[i] - mu)**2 - sigma**2)/sigma**3 * g
rdx[i# dg/dAg
*n+5] = gaussian(d[i], mu, sigma, 1.0)
rdx[ireturn inform
# パラメータベクトル: x = (a, b, Al, mu, sigma, Ag)
= 6 nvar
# モデルハンドルを初期化する
= opt.handle_init(nvar)
handle
# 密な非線形最小二乗目的関数を定義する
opt.handle_set_nlnls(handle, nres)
# 各残差に重みを追加
= np.ones(nres)
weights 55:63] = 5.0
weights[/= weights.sum()
weights
# 測定値(重み)の信頼性を定義する
'rw', rarr=weights) opt.handle_set_get_real(handle,
HandleSetGetRealReturnData(lrarr=64, rarr=None)
# パラメータ空間を制限する (0 <= x)
100.0*np.ones(nvar)) opt.handle_set_simplebounds(handle, np.zeros(nvar),
# ソルバーの出力を制御するためのオプションパラメータを設定する
for option in [
'Print Options = NO',
'Print Level = 1',
'Print Solution = X',
'Bxnl Iteration Limit = 100',
'Bxnl Use weights = YES',
# 3次正則化項を追加(過学習を回避)
'Bxnl Reg Order = 3',
'Bxnl Glob Method = REG',
]:
opt.handle_opt_set(handle, option)
# 省略された反復出力のために明示的なI/Oマネージャーを使用する:
= utils.FileObjManager(locus_in_output=False) iom
# 初期推定値(開始点)を定義する
= np.array([1.63, 0.88, 1.0, 30, 1.52, 0.24], dtype=float) x
ソルバーを呼び出す
# ソルバーを呼び出す
= opt.handle_solve_bxnl(handle, lsqfun, lsqgrd, x, nres, data=data, io_manager=iom) slv
E04GG、境界制約付き問題に対する非線形最小二乗法 状態: 収束、最適解が見つかりました 目的関数の値 4.44211E-08 射影勾配のノルム 1.18757E-09 スケーリングされた射影勾配のノルム 3.98428E-06 ステップのノルム 1.66812E-01
プライマル変数: idx 下限 値 上限 1 0.00000E+00 2.02043E+00 1.00000E+02 2 0.00000E+00 1.39726E+00 1.00000E+02 3 0.00000E+00 6.93255E-01 1.00000E+02 4 0.00000E+00 3.65929E+01 1.00000E+02 5 0.00000E+00 7.01808E+00 1.00000E+02 6 0.00000E+00 3.36877E-01 1.00000E+02
最適解
# 最適なパラメータ値
# Al * log-Normal(a, b):
= slv.x[0]
aopt = slv.x[1]
bopt = slv.x[2]
Alopt
# Ag * ガウス関数(mu, sigma):
= slv.x[3]
muopt = slv.x[4]
sigmaopt = slv.x[5] Agopt
そして目的関数の値は
print(slv.rinfo[0])
4.4421102582032486e-08
次の図3のプロットは、ヒストグラムに対する混合分布のフィッティングを示しています:
= lognormal(dh, aopt, bopt, Alopt)
lopt = gaussian(dh, muopt, sigmaopt, Agopt)
gopt = lopt + gopt
w = plt.figure()
fig = fig.add_subplot(111)
ax 'PADC etch track diameter histogram and fit', fontsize=16)
ax.set_title('Diameter (nm)')
ax.set_xlabel('Density')
ax.set_ylabel(=1, xmax=65)
ax.set_xlim(xmin'y'], color='lightsteelblue')
ax.bar(diameter, data['-', linewidth=3, color='tab:green')
ax.plot(dh, w,
ax.grid()'Aggregated', 'Measured track diameter density'])
ax.legend([ plt.show()

図3: 集計されたフィットを含むヒストグラム。
以下の図4は、展開されたフィットを示しています。赤色は対数正規分布、青色は正規分布を表しています:
= plt.figure()
fig = fig.add_subplot(111)
ax 'PADC etch track diameter histogram unfolding', fontsize=16)
ax.set_title('Diameter (nm)')
ax.set_xlabel('Density')
ax.set_ylabel(=1, xmax=65)
ax.set_xlim(xmin'y'], color='lightsteelblue')
ax.bar(diameter, data['-', linewidth=4, color='tab:red')
ax.plot(dh, lopt, '-', linewidth=4, color='tab:blue')
ax.plot(dh, gopt, '-', linewidth=3, color='tab:green')
ax.plot(dh, w,
ax.grid()= 'Unfolded Normal($\\mu=%1.2f$, $\\sigma=%1.2f, A=%1.2f$)' % (muopt, sigmaopt, Agopt)
glab = 'Unfolded log-Normal($a=%1.2f$, $b=%1.2f, A=%1.2f$)' % (aopt, bopt, Alopt)
llab 'Aggregated', 'Measured track diameter density'])
ax.legend([llab, glab, plt.show()

図4: フィッティングに使用された集約モデル(緑色の曲線)と展開されたモデル(青色と赤色の曲線)。 最適なパラメータ値は凡例に記載されています。
最後に、クリーンアップしてハンドルを破棄します
# ハンドルを破棄する:
opt.handle_free(handle)