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

このディレクトリの構造であれば、通常クラス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)。

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

このようにして、元々
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に書かれている記述のうち、今回の話題と関係ある箇所も記載しています。

このとき、以下の流れで各__init__.pyが実行されます。
from torch import nnを実行すると、まず最初にtorch/__init__.pyが実行される。ここでは、torch/__init__.pyの中にnnについての記述がないので、普通にnnがimportされる(torch/__init__.pyは重要ではないので、図4に記載しなかった)。- 次に、nn/__init__.pyが実行される。このとき、
from .modules import Moduleが実行される(本当は上記は、from .modules import *だが、わかりやすいようにModuleとした)。 from .modules import Moduleが実行されることによって、今度はmodules/__init__.pyが実行される。- modules/__init__.pyには、
from .module import Moduleの記述があるため、今後はmodules.Moduleの形でクラスModuleを使えるようになる。 - その後、
from .modules import Moduleの処理に戻り、nn.Moduleの形で使えるようになる。
以上の処理を経て、nn.modules.module.Moduleをnn.Moduleの形で使えるようにしています。
まとめ
今回はPyTorchにおいてnn.Moduleの形で使える理由について記載しました。__init__.pyの使い方を工夫することで、ユーザからクラスを呼び出しやすい形にできることが学べました。