We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Fully connected layer before mean and covariance modules
I am trying to do a non-linear transformation of input before forwarding it through mean and covariance modules. Before master branch was merged to priors (commit 1f5491e3edcac6497d3370c8aaef9a9362048a3e), I can add a fully connected layer before passing the input through mean and covariance modules to learn a non-linear representation. For example, the following script worked fine. 

```
import math
import torch
import gpytorch
from matplotlib import pyplot as plt

from torch import optim
from gpytorch.kernels import RBFKernel
from gpytorch.means import ConstantMean
from gpytorch.likelihoods import GaussianLikelihood
from gpytorch.random_variables import GaussianRandomVariable

train_x = torch.linspace(0, 1, 11)
train_y = torch.sin(train_x.data * (2 * math.pi)) + torch.randn(train_x.size()) * 0.2

class ExactGPModel(gpytorch.models.ExactGP):
    def __init__(self, train_x, train_y, likelihood):
        super(ExactGPModel, self).__init__(train_x, train_y, likelihood)
        self.mean_module = ConstantMean(constant_bounds=(-10, 10))
        self.covar_module = RBFKernel(log_lengthscale_bounds=(-5, 5))
        self.fc = torch.nn.Linear(1, 2)

    def forward(self, x):
        x_ = self.fc(x)
        mean_x = self.mean_module(x_)
        covar_x = self.covar_module(x_)
        return GaussianRandomVariable(mean_x, covar_x)

likelihood = GaussianLikelihood(log_noise_bounds=(-5, 5))
model = ExactGPModel(train_x.data, train_y.data, likelihood)

model.train()
likelihood.train()

optimizer = torch.optim.Adam([
    {'params': model.parameters()},  
], lr=0.1)

mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)

training_iter = 1000
for i in range(training_iter):
    optimizer.zero_grad()
    output = model(train_x)
    loss = -mll(output, train_y)
    loss.backward()
    print('Iter %d/%d - Loss: %.3f   log_lengthscale: %.3f   log_noise: %.3f' % (
        i + 1, training_iter, loss.data[0],
        model.covar_module.log_lengthscale.data[0, 0],
        model.likelihood.log_noise.data[0]
    ))
    optimizer.step()
```

However, now I get this runtime error because of the linear fc layer:
`AttributeError: 'Linear' object has no attribute '_get_prior_for'`

How can I get this to work with the latest version of gpytorch? DKL does something similar to what I am trying to do but implements AdditiveGridInducingVariationalGP and softmax likelihood, however, in my application I'd like to use ExactGP and gaussian likelihood. Is it possible to do so? 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gpytorch/module.py`
Content:
```
1 from __future__ import absolute_import
2 from __future__ import division
3 from __future__ import print_function
4 from __future__ import unicode_literals
5 
6 import torch
7 from collections import OrderedDict
8 from torch import nn
9 from .random_variables import RandomVariable
10 from .lazy import LazyVariable
11 from .variational import VariationalStrategy
12 
13 
14 class Module(nn.Module):
15     def __init__(self):
16         super(Module, self).__init__()
17         self._priors = OrderedDict()
18         self._derived_priors = OrderedDict()
19         self._variational_strategies = OrderedDict()
20 
21     def _get_module_and_name(self, parameter_name):
22         """Get module and name from full parameter name."""
23         module, name = parameter_name.split(".", 1)
24         if module in self._modules:
25             return self.__getattr__(module), name
26         else:
27             raise AttributeError(
28                 "Invalid parameter name {}. {} has no module {}".format(parameter_name, type(self).__name__, module)
29             )
30 
31     def _get_prior_for(self, parameter_name):
32         """
33         Get prior for parameter
34 
35         parameter_name (str): parameter name
36         """
37         if "." in parameter_name:
38             module, parameter_name = self._get_module_and_name(parameter_name)
39             return module._get_prior_for(parameter_name)
40         else:
41             if parameter_name in self._parameters:
42                 return self._priors.get(parameter_name)
43             else:
44                 raise AttributeError(
45                     "Module {module} has no parameter {name}".format(module=type(self).__name__, name=parameter_name)
46                 )
47 
48     def _get_derived_prior(self, prior_name):
49         """
50         Get derived prior from prior name
51 
52         prior_name (str): the name of the derived prior
53         """
54         if "." in prior_name:
55             module, prior_name = self._get_module_and_name(prior_name)
56             return module._get_derived_prior(prior_name)
57         else:
58             if prior_name in self._parameters:
59                 return self._derived_priors.get(prior_name)
60             else:
61                 raise AttributeError(
62                     "Module {module} has no derived prior {name}".format(module=type(self).__name__, name=prior_name)
63                 )
64 
65     def forward(self, *inputs, **kwargs):
66         raise NotImplementedError
67 
68     def initialize(self, **kwargs):
69         """
70         Set a value for a parameter
71 
72         kwargs: (param_name, value) - parameter to initialize
73         Value can take the form of a tensor, a float, or an int
74         """
75         for name, val in kwargs.items():
76             if name not in self._parameters:
77                 raise AttributeError("Unknown parameter {p} for {c}".format(p=name, c=self.__class__.__name__))
78             if torch.is_tensor(val):
79                 self.__getattr__(name).data.copy_(val)
80             elif isinstance(val, float) or isinstance(val, int):
81                 self.__getattr__(name).data.fill_(val)
82             else:
83                 raise AttributeError("Type {t} not valid to initialize parameter {p}".format(t=type(val), p=name))
84 
85             # Ensure value is contained in support of prior (if present)
86             prior = self._priors.get(name)
87             if prior is not None:
88                 param = self._parameters[name]
89                 if not prior.is_in_support(param):
90                     raise ValueError(
91                         "Value of parameter {param} not contained in support of specified prior".format(param=param)
92                     )
93         return self
94 
95     def named_parameter_priors(self):
96         """
97         Returns an iterator over module parameter priors, yielding the name of
98         the parameter, the parameter itself, as well as the associated prior
99         (excludes parameters for which no prior has been registered)
100         """
101         for name, param in self.named_parameters():
102             prior = self._get_prior_for(name)
103             if prior is not None:
104                 yield name, param, prior
105 
106     def named_derived_priors(self, memo=None, prefix=""):
107         """Returns an iterator over module derived priors, yielding both the
108         name of the prior as well as the prior, the associated parameters, and
109         the transformation callable.
110 
111         Yields:
112             (string, Prior, tuple(string), callable): Tuple containing the name
113                 of the prior, the prior itself, its parameters, and the transform
114                 to be called on the parameters.
115 
116         """
117         if memo is None:
118             memo = set()
119         for name, (prior, pnames, tf) in self._derived_priors.items():
120             if prior is not None and prior not in memo:
121                 memo.add(prior)
122                 parameters = tuple(getattr(self, pname) for pname in pnames)
123                 yield prefix + ("." if prefix else "") + name, prior, parameters, tf
124         for mname, module in self.named_children():
125             submodule_prefix = prefix + ("." if prefix else "") + mname
126             if hasattr(module, "_derived_priors"):
127                 for name, prior, parameters, tf in module.named_derived_priors(memo, submodule_prefix):
128                     yield name, prior, parameters, tf
129 
130     def named_variational_strategies(self, memo=None, prefix=""):
131         """Returns an iterator over module variational strategies, yielding both
132         the name of the variational strategy as well as the strategy itself.
133 
134         Yields:
135             (string, VariationalStrategy): Tuple containing the name of the
136                 strategy and the strategy
137 
138         """
139         if memo is None:
140             memo = set()
141         for name, strategy in self._variational_strategies.items():
142             if strategy is not None and strategy not in memo:
143                 memo.add(strategy)
144                 yield prefix + ("." if prefix else "") + name, strategy
145         for mname, module in self.named_children():
146             submodule_prefix = prefix + ("." if prefix else "") + mname
147             if hasattr(module, "named_variational_strategies"):
148                 for name, strategy in module.named_variational_strategies(memo, submodule_prefix):
149                     yield name, strategy
150 
151     def register_parameter(self, name, parameter, prior=None):
152         """
153         Adds a parameter to the module.
154         The parameter can be accessed as an attribute using given name.
155 
156         name (str): name of parameter
157         param (torch.nn.Parameter): parameter
158         prior (Prior): prior for parameter (default: None)
159         """
160         if "_parameters" not in self.__dict__:
161             raise AttributeError("Cannot assign parameter before Module.__init__() call")
162         super(Module, self).register_parameter(name, parameter)
163         if prior is not None:
164             self.set_parameter_priors(**{name: prior})
165 
166     def register_derived_prior(self, name, prior, parameter_names, transform):
167         """
168         Adds a derived prior to the module.
169         The prior can be accessed as an attribute using the given name.
170 
171         name (str): name of the derived prior
172         prior (Prior): the prior object
173         parameter_names (tuple(str)): The parameters the transform operaters on,
174             in the same order as expected by the transform callable.
175         transform (Callable): The function called on the specified parameters. The
176             log-pdf of the prior will be evaluating on the output of this transform.
177 
178         A derived prior operates on a transform of one or multiple parameters.
179         This can be used, for instance, to put a prior over the ICM Kernel
180         covariance matrix generated from covar_factor and log_var parameters.
181 
182         """
183         self.add_module(name, prior)
184         self._derived_priors[name] = (prior, tuple(parameter_names), transform)
185 
186     def register_variational_strategy(self, name):
187         self._variational_strategies[name] = None
188 
189     def set_parameter_priors(self, **kwargs):
190         """
191         Set prior for a parameter.
192         The prior can be accessed as an attribute using <PARAMETER_NAME>_prior.
193 
194         kwargs: (param_name, prior) - parameter to initialize
195         prior must be a gpytorch Prior
196         """
197         for name, prior in kwargs.items():
198             if name not in self._parameters:
199                 raise AttributeError(
200                     "Unknown parameter {name} for {module}".format(name=name, module=self.__class__.__name__)
201                 )
202             self.add_module("_".join([name, "prior"]), prior)
203             self._priors[name] = prior
204         return self
205 
206     def variational_strategies(self):
207         for _, strategy in self.named_variational_strategies():
208             yield strategy
209 
210     def update_variational_strategy(self, name, variational_strategy):
211         if not isinstance(variational_strategy, VariationalStrategy):
212             raise RuntimeError("variational_strategy must be a VariationalStrategy")
213         if name not in self._variational_strategies.keys():
214             raise RuntimeError("variational strategy {} not registered".format(name))
215         self._variational_strategies[name] = variational_strategy
216 
217     def __call__(self, *inputs, **kwargs):
218         outputs = self.forward(*inputs, **kwargs)
219         if torch.is_tensor(outputs) or isinstance(outputs, RandomVariable) or isinstance(outputs, LazyVariable):
220             return outputs
221         for output in outputs:
222             if not (isinstance(output, RandomVariable) or torch.is_tensor(output) or isinstance(output, LazyVariable)):
223                 raise RuntimeError(
224                     "Output must be a RandomVariable, torch.Tensor, or LazyVariable. "
225                     "Was a {}".format(input.__class__.__name__)
226                 )
227         if len(outputs) == 1:
228             outputs = outputs[0]
229         return outputs
230
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/gpytorch/module.py b/gpytorch/module.py
--- a/gpytorch/module.py
+++ b/gpytorch/module.py
@@ -28,40 +28,6 @@
                 "Invalid parameter name {}. {} has no module {}".format(parameter_name, type(self).__name__, module)
             )
 
-    def _get_prior_for(self, parameter_name):
-        """
-        Get prior for parameter
-
-        parameter_name (str): parameter name
-        """
-        if "." in parameter_name:
-            module, parameter_name = self._get_module_and_name(parameter_name)
-            return module._get_prior_for(parameter_name)
-        else:
-            if parameter_name in self._parameters:
-                return self._priors.get(parameter_name)
-            else:
-                raise AttributeError(
-                    "Module {module} has no parameter {name}".format(module=type(self).__name__, name=parameter_name)
-                )
-
-    def _get_derived_prior(self, prior_name):
-        """
-        Get derived prior from prior name
-
-        prior_name (str): the name of the derived prior
-        """
-        if "." in prior_name:
-            module, prior_name = self._get_module_and_name(prior_name)
-            return module._get_derived_prior(prior_name)
-        else:
-            if prior_name in self._parameters:
-                return self._derived_priors.get(prior_name)
-            else:
-                raise AttributeError(
-                    "Module {module} has no derived prior {name}".format(module=type(self).__name__, name=prior_name)
-                )
-
     def forward(self, *inputs, **kwargs):
         raise NotImplementedError
 
@@ -92,16 +58,24 @@
                     )
         return self
 
-    def named_parameter_priors(self):
+    def named_parameter_priors(self, memo=None, prefix=""):
         """
         Returns an iterator over module parameter priors, yielding the name of
         the parameter, the parameter itself, as well as the associated prior
         (excludes parameters for which no prior has been registered)
         """
-        for name, param in self.named_parameters():
-            prior = self._get_prior_for(name)
-            if prior is not None:
-                yield name, param, prior
+        if memo is None:
+            memo = set()
+        for name, parameter in self._parameters.items():
+            if name in self._priors and self._priors[name] not in memo:
+                prior = self._priors[name]
+                memo.add(prior)
+                yield prefix + ("." if prefix else "") + name, parameter, prior
+        for mname, module in self.named_children():
+            submodule_prefix = prefix + ("." if prefix else "") + mname
+            if hasattr(module, "named_parameter_priors"):
+                for name, parameter, prior in module.named_parameter_priors(memo, submodule_prefix):
+                    yield name, parameter, prior
 
     def named_derived_priors(self, memo=None, prefix=""):
         """Returns an iterator over module derived priors, yielding both the

{"golden_diff": "diff --git a/gpytorch/module.py b/gpytorch/module.py\n--- a/gpytorch/module.py\n+++ b/gpytorch/module.py\n@@ -28,40 +28,6 @@\n                 \"Invalid parameter name {}. {} has no module {}\".format(parameter_name, type(self).__name__, module)\n             )\n \n-    def _get_prior_for(self, parameter_name):\n-        \"\"\"\n-        Get prior for parameter\n-\n-        parameter_name (str): parameter name\n-        \"\"\"\n-        if \".\" in parameter_name:\n-            module, parameter_name = self._get_module_and_name(parameter_name)\n-            return module._get_prior_for(parameter_name)\n-        else:\n-            if parameter_name in self._parameters:\n-                return self._priors.get(parameter_name)\n-            else:\n-                raise AttributeError(\n-                    \"Module {module} has no parameter {name}\".format(module=type(self).__name__, name=parameter_name)\n-                )\n-\n-    def _get_derived_prior(self, prior_name):\n-        \"\"\"\n-        Get derived prior from prior name\n-\n-        prior_name (str): the name of the derived prior\n-        \"\"\"\n-        if \".\" in prior_name:\n-            module, prior_name = self._get_module_and_name(prior_name)\n-            return module._get_derived_prior(prior_name)\n-        else:\n-            if prior_name in self._parameters:\n-                return self._derived_priors.get(prior_name)\n-            else:\n-                raise AttributeError(\n-                    \"Module {module} has no derived prior {name}\".format(module=type(self).__name__, name=prior_name)\n-                )\n-\n     def forward(self, *inputs, **kwargs):\n         raise NotImplementedError\n \n@@ -92,16 +58,24 @@\n                     )\n         return self\n \n-    def named_parameter_priors(self):\n+    def named_parameter_priors(self, memo=None, prefix=\"\"):\n         \"\"\"\n         Returns an iterator over module parameter priors, yielding the name of\n         the parameter, the parameter itself, as well as the associated prior\n         (excludes parameters for which no prior has been registered)\n         \"\"\"\n-        for name, param in self.named_parameters():\n-            prior = self._get_prior_for(name)\n-            if prior is not None:\n-                yield name, param, prior\n+        if memo is None:\n+            memo = set()\n+        for name, parameter in self._parameters.items():\n+            if name in self._priors and self._priors[name] not in memo:\n+                prior = self._priors[name]\n+                memo.add(prior)\n+                yield prefix + (\".\" if prefix else \"\") + name, parameter, prior\n+        for mname, module in self.named_children():\n+            submodule_prefix = prefix + (\".\" if prefix else \"\") + mname\n+            if hasattr(module, \"named_parameter_priors\"):\n+                for name, parameter, prior in module.named_parameter_priors(memo, submodule_prefix):\n+                    yield name, parameter, prior\n \n     def named_derived_priors(self, memo=None, prefix=\"\"):\n         \"\"\"Returns an iterator over module derived priors, yielding both the\n", "issue": "Fully connected layer before mean and covariance modules\nI am trying to do a non-linear transformation of input before forwarding it through mean and covariance modules. Before master branch was merged to priors (commit 1f5491e3edcac6497d3370c8aaef9a9362048a3e), I can add a fully connected layer before passing the input through mean and covariance modules to learn a non-linear representation. For example, the following script worked fine. \r\n\r\n```\r\nimport math\r\nimport torch\r\nimport gpytorch\r\nfrom matplotlib import pyplot as plt\r\n\r\nfrom torch import optim\r\nfrom gpytorch.kernels import RBFKernel\r\nfrom gpytorch.means import ConstantMean\r\nfrom gpytorch.likelihoods import GaussianLikelihood\r\nfrom gpytorch.random_variables import GaussianRandomVariable\r\n\r\ntrain_x = torch.linspace(0, 1, 11)\r\ntrain_y = torch.sin(train_x.data * (2 * math.pi)) + torch.randn(train_x.size()) * 0.2\r\n\r\nclass ExactGPModel(gpytorch.models.ExactGP):\r\n    def __init__(self, train_x, train_y, likelihood):\r\n        super(ExactGPModel, self).__init__(train_x, train_y, likelihood)\r\n        self.mean_module = ConstantMean(constant_bounds=(-10, 10))\r\n        self.covar_module = RBFKernel(log_lengthscale_bounds=(-5, 5))\r\n        self.fc = torch.nn.Linear(1, 2)\r\n\r\n    def forward(self, x):\r\n        x_ = self.fc(x)\r\n        mean_x = self.mean_module(x_)\r\n        covar_x = self.covar_module(x_)\r\n        return GaussianRandomVariable(mean_x, covar_x)\r\n\r\nlikelihood = GaussianLikelihood(log_noise_bounds=(-5, 5))\r\nmodel = ExactGPModel(train_x.data, train_y.data, likelihood)\r\n\r\nmodel.train()\r\nlikelihood.train()\r\n\r\noptimizer = torch.optim.Adam([\r\n    {'params': model.parameters()},  \r\n], lr=0.1)\r\n\r\nmll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)\r\n\r\ntraining_iter = 1000\r\nfor i in range(training_iter):\r\n    optimizer.zero_grad()\r\n    output = model(train_x)\r\n    loss = -mll(output, train_y)\r\n    loss.backward()\r\n    print('Iter %d/%d - Loss: %.3f   log_lengthscale: %.3f   log_noise: %.3f' % (\r\n        i + 1, training_iter, loss.data[0],\r\n        model.covar_module.log_lengthscale.data[0, 0],\r\n        model.likelihood.log_noise.data[0]\r\n    ))\r\n    optimizer.step()\r\n```\r\n\r\nHowever, now I get this runtime error because of the linear fc layer:\r\n`AttributeError: 'Linear' object has no attribute '_get_prior_for'`\r\n\r\nHow can I get this to work with the latest version of gpytorch? DKL does something similar to what I am trying to do but implements AdditiveGridInducingVariationalGP and softmax likelihood, however, in my application I'd like to use ExactGP and gaussian likelihood. Is it possible to do so? \r\n\n", "before_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport torch\nfrom collections import OrderedDict\nfrom torch import nn\nfrom .random_variables import RandomVariable\nfrom .lazy import LazyVariable\nfrom .variational import VariationalStrategy\n\n\nclass Module(nn.Module):\n    def __init__(self):\n        super(Module, self).__init__()\n        self._priors = OrderedDict()\n        self._derived_priors = OrderedDict()\n        self._variational_strategies = OrderedDict()\n\n    def _get_module_and_name(self, parameter_name):\n        \"\"\"Get module and name from full parameter name.\"\"\"\n        module, name = parameter_name.split(\".\", 1)\n        if module in self._modules:\n            return self.__getattr__(module), name\n        else:\n            raise AttributeError(\n                \"Invalid parameter name {}. {} has no module {}\".format(parameter_name, type(self).__name__, module)\n            )\n\n    def _get_prior_for(self, parameter_name):\n        \"\"\"\n        Get prior for parameter\n\n        parameter_name (str): parameter name\n        \"\"\"\n        if \".\" in parameter_name:\n            module, parameter_name = self._get_module_and_name(parameter_name)\n            return module._get_prior_for(parameter_name)\n        else:\n            if parameter_name in self._parameters:\n                return self._priors.get(parameter_name)\n            else:\n                raise AttributeError(\n                    \"Module {module} has no parameter {name}\".format(module=type(self).__name__, name=parameter_name)\n                )\n\n    def _get_derived_prior(self, prior_name):\n        \"\"\"\n        Get derived prior from prior name\n\n        prior_name (str): the name of the derived prior\n        \"\"\"\n        if \".\" in prior_name:\n            module, prior_name = self._get_module_and_name(prior_name)\n            return module._get_derived_prior(prior_name)\n        else:\n            if prior_name in self._parameters:\n                return self._derived_priors.get(prior_name)\n            else:\n                raise AttributeError(\n                    \"Module {module} has no derived prior {name}\".format(module=type(self).__name__, name=prior_name)\n                )\n\n    def forward(self, *inputs, **kwargs):\n        raise NotImplementedError\n\n    def initialize(self, **kwargs):\n        \"\"\"\n        Set a value for a parameter\n\n        kwargs: (param_name, value) - parameter to initialize\n        Value can take the form of a tensor, a float, or an int\n        \"\"\"\n        for name, val in kwargs.items():\n            if name not in self._parameters:\n                raise AttributeError(\"Unknown parameter {p} for {c}\".format(p=name, c=self.__class__.__name__))\n            if torch.is_tensor(val):\n                self.__getattr__(name).data.copy_(val)\n            elif isinstance(val, float) or isinstance(val, int):\n                self.__getattr__(name).data.fill_(val)\n            else:\n                raise AttributeError(\"Type {t} not valid to initialize parameter {p}\".format(t=type(val), p=name))\n\n            # Ensure value is contained in support of prior (if present)\n            prior = self._priors.get(name)\n            if prior is not None:\n                param = self._parameters[name]\n                if not prior.is_in_support(param):\n                    raise ValueError(\n                        \"Value of parameter {param} not contained in support of specified prior\".format(param=param)\n                    )\n        return self\n\n    def named_parameter_priors(self):\n        \"\"\"\n        Returns an iterator over module parameter priors, yielding the name of\n        the parameter, the parameter itself, as well as the associated prior\n        (excludes parameters for which no prior has been registered)\n        \"\"\"\n        for name, param in self.named_parameters():\n            prior = self._get_prior_for(name)\n            if prior is not None:\n                yield name, param, prior\n\n    def named_derived_priors(self, memo=None, prefix=\"\"):\n        \"\"\"Returns an iterator over module derived priors, yielding both the\n        name of the prior as well as the prior, the associated parameters, and\n        the transformation callable.\n\n        Yields:\n            (string, Prior, tuple(string), callable): Tuple containing the name\n                of the prior, the prior itself, its parameters, and the transform\n                to be called on the parameters.\n\n        \"\"\"\n        if memo is None:\n            memo = set()\n        for name, (prior, pnames, tf) in self._derived_priors.items():\n            if prior is not None and prior not in memo:\n                memo.add(prior)\n                parameters = tuple(getattr(self, pname) for pname in pnames)\n                yield prefix + (\".\" if prefix else \"\") + name, prior, parameters, tf\n        for mname, module in self.named_children():\n            submodule_prefix = prefix + (\".\" if prefix else \"\") + mname\n            if hasattr(module, \"_derived_priors\"):\n                for name, prior, parameters, tf in module.named_derived_priors(memo, submodule_prefix):\n                    yield name, prior, parameters, tf\n\n    def named_variational_strategies(self, memo=None, prefix=\"\"):\n        \"\"\"Returns an iterator over module variational strategies, yielding both\n        the name of the variational strategy as well as the strategy itself.\n\n        Yields:\n            (string, VariationalStrategy): Tuple containing the name of the\n                strategy and the strategy\n\n        \"\"\"\n        if memo is None:\n            memo = set()\n        for name, strategy in self._variational_strategies.items():\n            if strategy is not None and strategy not in memo:\n                memo.add(strategy)\n                yield prefix + (\".\" if prefix else \"\") + name, strategy\n        for mname, module in self.named_children():\n            submodule_prefix = prefix + (\".\" if prefix else \"\") + mname\n            if hasattr(module, \"named_variational_strategies\"):\n                for name, strategy in module.named_variational_strategies(memo, submodule_prefix):\n                    yield name, strategy\n\n    def register_parameter(self, name, parameter, prior=None):\n        \"\"\"\n        Adds a parameter to the module.\n        The parameter can be accessed as an attribute using given name.\n\n        name (str): name of parameter\n        param (torch.nn.Parameter): parameter\n        prior (Prior): prior for parameter (default: None)\n        \"\"\"\n        if \"_parameters\" not in self.__dict__:\n            raise AttributeError(\"Cannot assign parameter before Module.__init__() call\")\n        super(Module, self).register_parameter(name, parameter)\n        if prior is not None:\n            self.set_parameter_priors(**{name: prior})\n\n    def register_derived_prior(self, name, prior, parameter_names, transform):\n        \"\"\"\n        Adds a derived prior to the module.\n        The prior can be accessed as an attribute using the given name.\n\n        name (str): name of the derived prior\n        prior (Prior): the prior object\n        parameter_names (tuple(str)): The parameters the transform operaters on,\n            in the same order as expected by the transform callable.\n        transform (Callable): The function called on the specified parameters. The\n            log-pdf of the prior will be evaluating on the output of this transform.\n\n        A derived prior operates on a transform of one or multiple parameters.\n        This can be used, for instance, to put a prior over the ICM Kernel\n        covariance matrix generated from covar_factor and log_var parameters.\n\n        \"\"\"\n        self.add_module(name, prior)\n        self._derived_priors[name] = (prior, tuple(parameter_names), transform)\n\n    def register_variational_strategy(self, name):\n        self._variational_strategies[name] = None\n\n    def set_parameter_priors(self, **kwargs):\n        \"\"\"\n        Set prior for a parameter.\n        The prior can be accessed as an attribute using <PARAMETER_NAME>_prior.\n\n        kwargs: (param_name, prior) - parameter to initialize\n        prior must be a gpytorch Prior\n        \"\"\"\n        for name, prior in kwargs.items():\n            if name not in self._parameters:\n                raise AttributeError(\n                    \"Unknown parameter {name} for {module}\".format(name=name, module=self.__class__.__name__)\n                )\n            self.add_module(\"_\".join([name, \"prior\"]), prior)\n            self._priors[name] = prior\n        return self\n\n    def variational_strategies(self):\n        for _, strategy in self.named_variational_strategies():\n            yield strategy\n\n    def update_variational_strategy(self, name, variational_strategy):\n        if not isinstance(variational_strategy, VariationalStrategy):\n            raise RuntimeError(\"variational_strategy must be a VariationalStrategy\")\n        if name not in self._variational_strategies.keys():\n            raise RuntimeError(\"variational strategy {} not registered\".format(name))\n        self._variational_strategies[name] = variational_strategy\n\n    def __call__(self, *inputs, **kwargs):\n        outputs = self.forward(*inputs, **kwargs)\n        if torch.is_tensor(outputs) or isinstance(outputs, RandomVariable) or isinstance(outputs, LazyVariable):\n            return outputs\n        for output in outputs:\n            if not (isinstance(output, RandomVariable) or torch.is_tensor(output) or isinstance(output, LazyVariable)):\n                raise RuntimeError(\n                    \"Output must be a RandomVariable, torch.Tensor, or LazyVariable. \"\n                    \"Was a {}\".format(input.__class__.__name__)\n                )\n        if len(outputs) == 1:\n            outputs = outputs[0]\n        return outputs\n", "path": "gpytorch/module.py"}], "after_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport torch\nfrom collections import OrderedDict\nfrom torch import nn\nfrom .random_variables import RandomVariable\nfrom .lazy import LazyVariable\nfrom .variational import VariationalStrategy\n\n\nclass Module(nn.Module):\n    def __init__(self):\n        super(Module, self).__init__()\n        self._priors = OrderedDict()\n        self._derived_priors = OrderedDict()\n        self._variational_strategies = OrderedDict()\n\n    def _get_module_and_name(self, parameter_name):\n        \"\"\"Get module and name from full parameter name.\"\"\"\n        module, name = parameter_name.split(\".\", 1)\n        if module in self._modules:\n            return self.__getattr__(module), name\n        else:\n            raise AttributeError(\n                \"Invalid parameter name {}. {} has no module {}\".format(parameter_name, type(self).__name__, module)\n            )\n\n    def forward(self, *inputs, **kwargs):\n        raise NotImplementedError\n\n    def initialize(self, **kwargs):\n        \"\"\"\n        Set a value for a parameter\n\n        kwargs: (param_name, value) - parameter to initialize\n        Value can take the form of a tensor, a float, or an int\n        \"\"\"\n        for name, val in kwargs.items():\n            if name not in self._parameters:\n                raise AttributeError(\"Unknown parameter {p} for {c}\".format(p=name, c=self.__class__.__name__))\n            if torch.is_tensor(val):\n                self.__getattr__(name).data.copy_(val)\n            elif isinstance(val, float) or isinstance(val, int):\n                self.__getattr__(name).data.fill_(val)\n            else:\n                raise AttributeError(\"Type {t} not valid to initialize parameter {p}\".format(t=type(val), p=name))\n\n            # Ensure value is contained in support of prior (if present)\n            prior = self._priors.get(name)\n            if prior is not None:\n                param = self._parameters[name]\n                if not prior.is_in_support(param):\n                    raise ValueError(\n                        \"Value of parameter {param} not contained in support of specified prior\".format(param=param)\n                    )\n        return self\n\n    def named_parameter_priors(self, memo=None, prefix=\"\"):\n        \"\"\"\n        Returns an iterator over module parameter priors, yielding the name of\n        the parameter, the parameter itself, as well as the associated prior\n        (excludes parameters for which no prior has been registered)\n        \"\"\"\n        if memo is None:\n            memo = set()\n        for name, parameter in self._parameters.items():\n            if name in self._priors and self._priors[name] not in memo:\n                prior = self._priors[name]\n                memo.add(prior)\n                yield prefix + (\".\" if prefix else \"\") + name, parameter, prior\n        for mname, module in self.named_children():\n            submodule_prefix = prefix + (\".\" if prefix else \"\") + mname\n            if hasattr(module, \"named_parameter_priors\"):\n                for name, parameter, prior in module.named_parameter_priors(memo, submodule_prefix):\n                    yield name, parameter, prior\n\n    def named_derived_priors(self, memo=None, prefix=\"\"):\n        \"\"\"Returns an iterator over module derived priors, yielding both the\n        name of the prior as well as the prior, the associated parameters, and\n        the transformation callable.\n\n        Yields:\n            (string, Prior, tuple(string), callable): Tuple containing the name\n                of the prior, the prior itself, its parameters, and the transform\n                to be called on the parameters.\n\n        \"\"\"\n        if memo is None:\n            memo = set()\n        for name, (prior, pnames, tf) in self._derived_priors.items():\n            if prior is not None and prior not in memo:\n                memo.add(prior)\n                parameters = tuple(getattr(self, pname) for pname in pnames)\n                yield prefix + (\".\" if prefix else \"\") + name, prior, parameters, tf\n        for mname, module in self.named_children():\n            submodule_prefix = prefix + (\".\" if prefix else \"\") + mname\n            if hasattr(module, \"_derived_priors\"):\n                for name, prior, parameters, tf in module.named_derived_priors(memo, submodule_prefix):\n                    yield name, prior, parameters, tf\n\n    def named_variational_strategies(self, memo=None, prefix=\"\"):\n        \"\"\"Returns an iterator over module variational strategies, yielding both\n        the name of the variational strategy as well as the strategy itself.\n\n        Yields:\n            (string, VariationalStrategy): Tuple containing the name of the\n                strategy and the strategy\n\n        \"\"\"\n        if memo is None:\n            memo = set()\n        for name, strategy in self._variational_strategies.items():\n            if strategy is not None and strategy not in memo:\n                memo.add(strategy)\n                yield prefix + (\".\" if prefix else \"\") + name, strategy\n        for mname, module in self.named_children():\n            submodule_prefix = prefix + (\".\" if prefix else \"\") + mname\n            if hasattr(module, \"named_variational_strategies\"):\n                for name, strategy in module.named_variational_strategies(memo, submodule_prefix):\n                    yield name, strategy\n\n    def register_parameter(self, name, parameter, prior=None):\n        \"\"\"\n        Adds a parameter to the module.\n        The parameter can be accessed as an attribute using given name.\n\n        name (str): name of parameter\n        param (torch.nn.Parameter): parameter\n        prior (Prior): prior for parameter (default: None)\n        \"\"\"\n        if \"_parameters\" not in self.__dict__:\n            raise AttributeError(\"Cannot assign parameter before Module.__init__() call\")\n        super(Module, self).register_parameter(name, parameter)\n        if prior is not None:\n            self.set_parameter_priors(**{name: prior})\n\n    def register_derived_prior(self, name, prior, parameter_names, transform):\n        \"\"\"\n        Adds a derived prior to the module.\n        The prior can be accessed as an attribute using the given name.\n\n        name (str): name of the derived prior\n        prior (Prior): the prior object\n        parameter_names (tuple(str)): The parameters the transform operaters on,\n            in the same order as expected by the transform callable.\n        transform (Callable): The function called on the specified parameters. The\n            log-pdf of the prior will be evaluating on the output of this transform.\n\n        A derived prior operates on a transform of one or multiple parameters.\n        This can be used, for instance, to put a prior over the ICM Kernel\n        covariance matrix generated from covar_factor and log_var parameters.\n\n        \"\"\"\n        self.add_module(name, prior)\n        self._derived_priors[name] = (prior, tuple(parameter_names), transform)\n\n    def register_variational_strategy(self, name):\n        self._variational_strategies[name] = None\n\n    def set_parameter_priors(self, **kwargs):\n        \"\"\"\n        Set prior for a parameter.\n        The prior can be accessed as an attribute using <PARAMETER_NAME>_prior.\n\n        kwargs: (param_name, prior) - parameter to initialize\n        prior must be a gpytorch Prior\n        \"\"\"\n        for name, prior in kwargs.items():\n            if name not in self._parameters:\n                raise AttributeError(\n                    \"Unknown parameter {name} for {module}\".format(name=name, module=self.__class__.__name__)\n                )\n            self.add_module(\"_\".join([name, \"prior\"]), prior)\n            self._priors[name] = prior\n        return self\n\n    def variational_strategies(self):\n        for _, strategy in self.named_variational_strategies():\n            yield strategy\n\n    def update_variational_strategy(self, name, variational_strategy):\n        if not isinstance(variational_strategy, VariationalStrategy):\n            raise RuntimeError(\"variational_strategy must be a VariationalStrategy\")\n        if name not in self._variational_strategies.keys():\n            raise RuntimeError(\"variational strategy {} not registered\".format(name))\n        self._variational_strategies[name] = variational_strategy\n\n    def __call__(self, *inputs, **kwargs):\n        outputs = self.forward(*inputs, **kwargs)\n        if torch.is_tensor(outputs) or isinstance(outputs, RandomVariable) or isinstance(outputs, LazyVariable):\n            return outputs\n        for output in outputs:\n            if not (isinstance(output, RandomVariable) or torch.is_tensor(output) or isinstance(output, LazyVariable)):\n                raise RuntimeError(\n                    \"Output must be a RandomVariable, torch.Tensor, or LazyVariable. \"\n                    \"Was a {}\".format(input.__class__.__name__)\n                )\n        if len(outputs) == 1:\n            outputs = outputs[0]\n        return outputs\n", "path": "gpytorch/module.py"}]}