第一章「ディープラーニングのためのPythonのツボ」
numpy.arrayの注意点
numpy.array は「コピー」ではなく「参照渡し」になる点に注意が必要です。
import numpy as np
# xを定義
x = np.array([5,7,9])
# yにxを代入(コピーではなく参照)
y = x
y[0] = 100
print(x) # [100, 7, 9] ← xも書き換わってしまう!
コピーを作りたい場合は .copy() を明示的に使います。
x = np.array([5,7,9])
y = x.copy()
y[0] = 100
print(x) # [5, 7, 9] ← xは変わらない
PyTorchとnumpyのやりとり
書籍では以下のように紹介されています。
import torch
x1 = torch.ones(5)
x2 = x1.data.numpy()
これは「コピー」ではなく参照渡しで、x2 を変更すると x1 にも影響します。
コピーが欲しい場合は .copy() を使います。
x1 = torch.ones(5)
x2 = x1.data.numpy().copy()
💡 補足(ChatGPT推奨)
-
.dataは現在では 非推奨 - 理由は、autograd(自動微分)の管理から外れてしまい、予期せぬバグを生む可能性があるため
代わりに、以下のように .detach() を使うのが安全です。
x1 = torch.ones(5)
x2 = x1.detach().numpy()
クラスのインスタンスを関数として利用する
__call__ メソッドを定義すると、クラスのインスタンスを「関数」として呼び出せます。
class H:
def __call__(self, x):
return 2*x**2 + 2
import numpy as np
x = np.arange(-2, 2.1, 0.25)
h = H()
y = h(x)
この場合、h(x) は H().__call__(x) を呼び出しており、インスタンスを関数のように使えます。
💡 活用例
- 損失関数や活性化関数をクラスとして定義したいとき
- 内部にパラメータを持つ「関数オブジェクト」を渡したいとき
class MyReLU:
def __call__(self, x):
return np.maximum(0, x)
relu = MyReLU()
print(relu([-1, 0, 2])) # [0, 0, 2]
まとめ
-
numpyは参照渡しが多いので.copy()を意識する - PyTorchとの変換は 本では
.data.numpy()が紹介されているが、実務では.detach().numpy()が推奨 -
__call__を使うとインスタンスを関数のように扱え、便利なデザインが可能
参考文献
- 赤石雅典 「最短コースでわかる PyTorch & 深層学習プログラミング」