初心者データサイエンティストの備忘録

調べたことは全部ここに書いて自分の辞書を作る

【PyTorch】nn.Moduleの形で使える理由

はじめに

 PyTorchのチュートリアルの「0. PyTorch入門 [4]モデル構築」を勉強しています。この中で、クラスnn.Moduleを継承する箇所があります。このnn.Moduleについて、ソースコードを読んだところ、奇妙なことに気付きました。ディレクトリの構成が図1のようになっているのです。

図1:nn配下のディレクトリ構造

 このディレクトリの構造であれば、通常クラスModuleをimportするには下記のようにしなければできないはずです。

from torch.nn.modules import module

# Moduleを使うときは下記のようにして使う
module.Module

 ところが、チュートリアルでは下記のようにimportしています。

from torch import nn

# Moduleを使うときは下記のようにして使う
nn.Module

 なぜ、nn直下にクラスModuleが存在しないのに、nn.Moduleとしてクラスを使えるのでしょうか?このことが気になり、調査してみました。

結論

 nn.Moduleの形で使える理由を知るには、__init__.pyについて理解する必要があります。__init__.pyはimportする際に実行されるファイルです(図2)。

図2:__init__.pyの実行.jpg

 この__init__.pyについて、図3のような使い方をすることができます。

図3:__init__.pyの使い方

 このようにして、元々

from my_package.sub_package.module import Module

とすべき箇所を、

from my_package.sub_package import Module

と記述できるようになります。これを繰り返していくことで、冒頭で疑問に感じた

from torch.nn.modules import module

from torch import nn

というシンプルな形で実行できるようになるのです。

nn.Moduleの場合どうなっているか?

 図4はnn配下のディレクトリを__init__.pyを含めて記載したものです。__init__.pyに書かれている記述のうち、今回の話題と関係ある箇所も記載しています。

図4:__init__.pyを含めたnn配下のディレクトリ構造

 このとき、以下の流れで各__init__.pyが実行されます。

  1. from torch import nnを実行すると、まず最初にtorch/__init__.pyが実行される。ここでは、torch/__init__.pyの中にnnについての記述がないので、普通にnnがimportされる(torch/__init__.pyは重要ではないので、図4に記載しなかった)。
  2. 次に、nn/__init__.pyが実行される。このとき、from .modules import Moduleが実行される(本当は上記は、from .modules import *だが、わかりやすいようにModuleとした)。
  3. from .modules import Moduleが実行されることによって、今度はmodules/__init__.pyが実行される。
  4. modules/__init__.pyには、from .module import Moduleの記述があるため、今後はmodules.Moduleの形でクラスModuleを使えるようになる。
  5. その後、from .modules import Moduleの処理に戻り、nn.Moduleの形で使えるようになる。

 以上の処理を経て、nn.modules.module.Moduleをnn.Moduleの形で使えるようにしています。

まとめ

 今回はPyTorchにおいてnn.Moduleの形で使える理由について記載しました。__init__.pyの使い方を工夫することで、ユーザからクラスを呼び出しやすい形にできることが学べました。

参考文献