Generate a Linear3D operator
| 543 | |
| 544 | |
| 545 | class Linear3D(layer.Layer): |
| 546 | """ |
| 547 | Generate a Linear3D operator |
| 548 | """ |
| 549 | |
| 550 | # TODO: replace current with |
| 551 | # def __init__(self, out_features, bias=True): |
| 552 | def __init__(self, out_features, *args, bias=False, **kwargs): |
| 553 | """ |
| 554 | Args: |
| 555 | ut_channels: int, the channel of output, also is the number of |
| 556 | filters |
| 557 | bias: bool |
| 558 | """ |
| 559 | super(Linear3D, self).__init__() |
| 560 | self.out_features = out_features |
| 561 | |
| 562 | # TODO: for backward compatibility, to remove |
| 563 | if len(args) > 0: |
| 564 | self.in_features = out_features |
| 565 | self.out_features = args[0] |
| 566 | if len(args) > 1: |
| 567 | self.bias = args[1] |
| 568 | else: |
| 569 | self.bias = bias |
| 570 | |
| 571 | def initialize(self, x): |
| 572 | self.in_features = x.shape[-1] |
| 573 | w_shape = (self.in_features, self.out_features) |
| 574 | b_shape = (self.out_features,) |
| 575 | |
| 576 | self.W = Tensor(shape=w_shape, |
| 577 | dtype=x.dtype, |
| 578 | requires_grad=True, |
| 579 | stores_grad=True) |
| 580 | std = math.sqrt(2.0 / (self.in_features + self.out_features)) |
| 581 | self.W.gaussian(0.0, std) |
| 582 | |
| 583 | if self.bias: |
| 584 | self.b = Tensor(shape=b_shape, |
| 585 | dtype=x.dtype, |
| 586 | requires_grad=True, |
| 587 | stores_grad=True) |
| 588 | self.b.set_value(0.0) |
| 589 | else: |
| 590 | self.b = None |
| 591 | |
| 592 | def forward(self, x): |
| 593 | if self.b: |
| 594 | self.device_check(x, self.W, self.b) |
| 595 | self.dtype_check(x, self.W, self.b) |
| 596 | else: |
| 597 | self.device_check(x, self.W) |
| 598 | self.dtype_check(x, self.W) |
| 599 | |
| 600 | assert x.shape[-1] == self.W.shape[0], ( |
| 601 | "Linear3D layer expects input features size %d received %d" % |
| 602 | (self.W.shape[0], x.shape[-1])) |