Repository: pytorch/vision

Issue:
Excessively long initialization time for Inception3
Creating an instance of the `Inception3` class via `torchvision.models.inception_v3(pretrained=False)` or `torchvision.models.Inception3()` takes several minutes to complete.

It appears that all of the time is being spent here [here](https://github.com/pytorch/vision/blob/28b7f8ae219ede3cef93100251bfff75a9a53644/torchvision/models/inception.py#L111).

I believe this may be related to some change in scipy perhaps as I do not think this model used to take so long to instantiate.


Discussion:
I confirmed that rolling scipy from `1.4.1` back to `1.3.1` causes the issue to go away.

So this is not strictly a torchvision bug but it does mean that `Inception3` becomes somewhat unusable for people who install the current scipy version from pip.
@os-gabe one alternative, given that we don't really train inception from scratch, would be to remove the custom initialization based on scipy.

That would be a breaking change though.
Here is the scipy issue for reference https://github.com/scipy/scipy/issues/11299
@fmassa what if the `Inception3` constructor took in an keyword argument to skip the random initialization? If the flag defaulted to `False` wouldn't this maintain backwards compatibility? This seems like a fairly nice solution in general since the random initialization is not needed when we just plan to load weights anyway.
Yeah, we could do something similar to what we do in VGG https://github.com/pytorch/vision/blob/e130c6cca88160b6bf7fea9b8bc251601a1a75c5/torchvision/models/vgg.py#L26
with `init_weights`. Can you send a PR for inception?

Resolving patch:
diff --git a/torchvision/models/inception.py b/torchvision/models/inception.py
--- a/torchvision/models/inception.py
+++ b/torchvision/models/inception.py
@@ -65,7 +65,7 @@ def inception_v3(pretrained=False, progress=True, **kwargs):
 class Inception3(nn.Module):
 
     def __init__(self, num_classes=1000, aux_logits=True, transform_input=False,
-                 inception_blocks=None):
+                 inception_blocks=None, init_weights=True):
         super(Inception3, self).__init__()
         if inception_blocks is None:
             inception_blocks = [
@@ -102,19 +102,19 @@ def __init__(self, num_classes=1000, aux_logits=True, transform_input=False,
         self.Mixed_7b = inception_e(1280)
         self.Mixed_7c = inception_e(2048)
         self.fc = nn.Linear(2048, num_classes)
-
-        for m in self.modules():
-            if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear):
-                import scipy.stats as stats
-                stddev = m.stddev if hasattr(m, 'stddev') else 0.1
-                X = stats.truncnorm(-2, 2, scale=stddev)
-                values = torch.as_tensor(X.rvs(m.weight.numel()), dtype=m.weight.dtype)
-                values = values.view(m.weight.size())
-                with torch.no_grad():
-                    m.weight.copy_(values)
-            elif isinstance(m, nn.BatchNorm2d):
-                nn.init.constant_(m.weight, 1)
-                nn.init.constant_(m.bias, 0)
+        if init_weights:
+            for m in self.modules():
+                if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear):
+                    import scipy.stats as stats
+                    stddev = m.stddev if hasattr(m, 'stddev') else 0.1
+                    X = stats.truncnorm(-2, 2, scale=stddev)
+                    values = torch.as_tensor(X.rvs(m.weight.numel()), dtype=m.weight.dtype)
+                    values = values.view(m.weight.size())
+                    with torch.no_grad():
+                        m.weight.copy_(values)
+                elif isinstance(m, nn.BatchNorm2d):
+                    nn.init.constant_(m.weight, 1)
+                    nn.init.constant_(m.bias, 0)
 
     def _transform_input(self, x):
         if self.transform_input:


Test patch: