Do not call this function from user code. It is called by __call__(). Args: xs, Tensor instance(s) Returns: Tensor instance(s)
(self, *xs)
| 268 | return "{}_g".format(self.output_name(idx)) |
| 269 | |
| 270 | def _do_forward(self, *xs): |
| 271 | """ |
| 272 | Do not call this function from user code. It is called by __call__(). |
| 273 | Args: |
| 274 | xs, Tensor instance(s) |
| 275 | Returns: |
| 276 | Tensor instance(s) |
| 277 | """ |
| 278 | # TODO add the pre hook |
| 279 | assert all([isinstance(x, Tensor) for x in xs |
| 280 | ]), "xs should include only Tensor instances" |
| 281 | |
| 282 | # need to do backward if any of its input arg needs gradient |
| 283 | self.requires_grad = any([x.requires_grad for x in xs]) |
| 284 | |
| 285 | self.src = [] |
| 286 | for x in xs: |
| 287 | if x.stores_grad: |
| 288 | # store the tensor whose gradient needs be returned in |
| 289 | # backward(), e.g. if x is parameter |
| 290 | self.src.append((x.creator, id(x), x, x.stores_grad)) |
| 291 | else: |
| 292 | # for intermediate tensors, they will be released soon; |
| 293 | # no need to store them --> use None |
| 294 | self.src.append((x.creator, id(x), None, x.stores_grad)) |
| 295 | |
| 296 | # get the CTensor (data) if the input arg is Tensor |
| 297 | xs = tuple(x.data for x in xs) |
| 298 | ys = self.forward(*xs) |
| 299 | if not isinstance(ys, tuple): |
| 300 | ys = (ys,) |
| 301 | # create Tensor based on CTensor(data); |
| 302 | # assume outputs are all Tensor instances |
| 303 | ys = tuple( |
| 304 | Tensor( |
| 305 | device=y.device(), |
| 306 | data=y, |
| 307 | requires_grad=self.requires_grad, |
| 308 | creator=self, |
| 309 | name=self.output_name(idx), |
| 310 | ) for idx, y in enumerate(ys)) |
| 311 | # map from python id to output index |
| 312 | self.y_id2idx = {id(y): i for i, y in enumerate(ys)} |
| 313 | # TODO add the post hook |
| 314 | return ys |
| 315 | |
| 316 | def _do_backward(self, *dys): |
| 317 | dxs = self.backward(*dys) |