深層学習や機械学習の最適化計算などをやっていくと、微分係数を求めることがよくあると思います。
今回は、Pythonで数値計算的に微分可能な関数の任意の地点の微分係数を求める方法を紹介します。
関数の微分の定義
関数$f(x)$が微分可能である時、ある地点$x$の微分値は次にように定義される
\begin{equation} \frac{d f(x)}{dx} = \lim_{h \to \infin}\frac{f(x+h) - f(x)}{x-h} \end{equation}
高校の数学で登場した内容ですが、ある程度イメージは湧きますか?
微分係数の導出をPythonで実装
例題として、次の関数の微分値を求めてみます。
f(x) = 2x^2 + x + sin(x) + 1
$sin(x)$が入ってきて、中々関数の形状がイメージしにくいですね。これをPythonを持ちて可視化してみましょう。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-3, 3, 100)
def base_func(x):
return 2 * x ** 2 + x + np.sin(x) +1
fig, ax = plt.subplots(figsize=(10, 3), dpi=100)
y = base_func(x)
ax.set_xlim([-2, 2])
ax.set_ylim([0, 10])
ax.plot(x, y)

このような形状になることがわかります。$x^2$の項がかなり効いていて、$sinx$の周期的な成分はほとんど見えないような状況ですね。
続いて、この関数の微分係数を求めていきます。(1)の定義式通りに、微分を数値計算で求める関数を実装します。
def numerical_dif(f, x):
h = 10e-4
return (f(x + h) - f(x)) / h
この微分式を用いて、Pythonで可視化してみます。
1地点だけ求めても面白くないので、np.linspace(-2, 2, 50)で構成される点の数だけ微分値を求め、それを傾きとした直線を引いてみましょう。
次のコードを実行します。
y = base_func(x)
fig, ax = plt.subplots(figsize=(10, 3), dpi=100)
ax.plot(x, y, lw=0.9)
ax.set_xlim([-2, 2])
ax.set_ylim([0, 10])
for i in np.linspace(-2, 2, 50):
ax.scatter(i, base_func(i), s=5)
a = numerical_dif(base_func, i)
b = base_func(i) - i * a
values = a * x + b
ax.plot(x, values, lw=1.2, ls="-", alpha=0.5)

少し分かりにくいですが、直線上の任意の点の傾きを求めることができました。