Repository: dmlc/dgl
Pull request: [Feature] Automatically determine the backend of dgl.nn
## Description

Fixes #1292 .

`import dgl` no longer imports `dgl.nn` automatically.

Problem statement:
AttributeError: module 'dgl.nn' has no attribute 'pytorch'
## 🐛 Bug

When I try to use some of the predefined modules of dgl by the following code, I encounter an error: AttributeError: module 'dgl.nn' has no attribute 'pytorch'.

Similar problems also happen to other backends, including TensorFlow and MXNet.

## To Reproduce

Steps to reproduce the behavior:

```python
import dgl.nn
# or import dgl
c = dgl.nn.pytorch.conv.GraphConv(10,2)
```

## Expected behavior

The code should generate a GraphConv layer without any error.

## Environment

 - DGL Version (e.g., 1.0): 0.4.2
 - Backend Library & Version (e.g., PyTorch 0.4.1, MXNet/Gluon 1.3): Pytorch 1.4.0
 - OS (e.g., Linux): Irrelelevent 
 - How you installed DGL (`conda`, `pip`, source): conda
 - Build command you used (if compiling from source):
 - Python version: 3.7
 - CUDA/cuDNN version (if applicable): Irrelelevent 
 - GPU models and configuration (e.g. V100): Irrelelevent 
 - Any other relevant information:

## Additional context

I read the source code and **found the reason and solution** to this problem.

### Reason:

The `__init__.py` file of `dgl/nn` is empty. Therefore, if i import dgl or dgl.nn, python cannot automatically find files of its sub-directories.

I verified it by the following code:
```python
import dgl.nn.python
c = dgl.nn.pytorch.conv.GraphConv(10,2)
```
It works fine.

### Solution:

Add 3 lines of code like `from . import pytorch` into file `dgl/nn/__init__.py` for PyTorch and the other 2 backends.
It is better to automatically detect the backend library and import the correct sub-directory.

Hints from issue discussion:
> Add 3 lines of code like `from . import pytorch` into file `dgl/nn/__init__.py` for PyTorch and the other 2 backends.
> It is better to automatically detect the backend library and import the correct sub-directory.

I would prefer the latter solution.  The former solution would require all backends to be installed.

Commit message: rename load_backend to private

Patch to review:
diff --git a/python/dgl/__init__.py b/python/dgl/__init__.py
index a2df8416b893..890a80552399 100644
--- a/python/dgl/__init__.py
+++ b/python/dgl/__init__.py
@@ -8,7 +8,6 @@
 from .backend import load_backend
 
 from . import function
-from . import nn
 from . import contrib
 from . import container
 from . import random
diff --git a/python/dgl/nn/__init__.py b/python/dgl/nn/__init__.py
index 242106dd407b..d0201b4ec98e 100644
--- a/python/dgl/nn/__init__.py
+++ b/python/dgl/nn/__init__.py
@@ -1 +1,12 @@
 """Package for neural network common components."""
+import os
+import importlib
+import sys
+
+def _load_backend(mod_name):
+    mod = importlib.import_module('.%s' % mod_name, __name__)
+    thismod = sys.modules[__name__]
+    for api, obj in mod.__dict__.items():
+        setattr(thismod, api, obj)
+
+_load_backend(os.environ.get('DGLBACKEND', 'pytorch').lower())


Code review comments:
diff_hunk: @@ -1 +1,12 @@
 """Package for neural network common components."""
+import os
+import importlib
+import sys
+
+def _load_backend(mod_name):
+    mod = importlib.import_module('.%s' % mod_name, __name__)
+    thismod = sys.modules[__name__]
+    for api, obj in mod.__dict__.items():
+        setattr(thismod, api, obj)
+
+_load_backend(os.environ.get('DGLBACKEND', 'pytorch').lower())
path: python/dgl/nn/__init__.py
text: @user1:
using `dgl.backend.backend_name` instead