layers.py 7.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

X
Xin Pan 已提交
15
import collections
16 17 18
import contextlib
import sys
import numpy as np
M
minqiyang 已提交
19
import collections
X
Xin Pan 已提交
20
from .. import unique_name
21 22 23 24
from paddle.fluid import core
from paddle.fluid import framework
from paddle.fluid.imperative import base

X
Xin Pan 已提交
25
__all__ = ['Layer', 'PyLayer']
26 27


X
Xin Pan 已提交
28
class Layer(core.Layer):
X
Xin Pan 已提交
29 30 31 32 33 34 35 36 37
    """Layers composed of operators.

    Args:
        name_scope: prefix name used by the layer to name parameters.
            If prefix is "my_model/layer_1", parameter name in MyLayer
            can be "my_model/layer_1/MyLayer/w_n", where w is the parameter
            base name and n is an unique suffix auto-generated.
        dtype: data type for the variables in the layer.
    """
X
Xin Pan 已提交
38

X
Xin Pan 已提交
39 40 41
    def __init__(self, name_scope, dtype=core.VarDesc.VarType.FP32):
        self._full_name = unique_name.generate(name_scope + "/" +
                                               self.__class__.__name__)
X
Xin Pan 已提交
42
        self._built = False
M
minqiyang 已提交
43
        self._dtype = dtype
X
Xin Pan 已提交
44 45
        self._parameters = collections.OrderedDict()
        self._sub_layers = collections.OrderedDict()
46

X
Xin Pan 已提交
47 48 49 50 51 52 53 54 55
    def full_name(self):
        """Full name for this layers.

          Full name is composed by name_scope + "/" + MyLayer.__class__.__name__

        Returns full name of this name.
        """
        return self._full_name

X
polish  
Xin Pan 已提交
56 57
    def parameters(self, include_sublayers=True):
        """Returns a list of Parameters from current and sub-layers.
X
Xin Pan 已提交
58 59 60 61 62 63

        Args:
            include_sublayers: If true, also include the parameters from
            sublayers.

        Returns a list of Parameters.
X
Xin Pan 已提交
64
        """
X
polish  
Xin Pan 已提交
65 66 67 68 69 70
        ret = [p for p in self._parameters.values()]
        if include_sublayers:
            for l in self._sub_layers.values():
                for p in l.parameters(include_sublayers):
                    ret.append(p)
        return ret
X
Xin Pan 已提交
71

X
Xin Pan 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
    def sublayers(self, include_sublayers=True):
        """Returns a list of sub layers.

        Args:
            include_sublayers: If true, also include the layers from sublayers.

        Returns a list of sub layers.
        """
        ret = [l for l in self._sub_layers.values()]
        if include_sublayers:
            for l in self._sub_layers.values():
                for sub_l in l.sublayers(include_sublayers):
                    ret.append(sub_l)
        return ret

X
Xin Pan 已提交
87 88
    def clear_gradients(self):
        for p in self.parameters():
M
minqiyang 已提交
89
            p._clear_gradient()
X
Xin Pan 已提交
90

X
polish  
Xin Pan 已提交
91
    def _build_once(self, *args):
92 93
        pass

94
    def __call__(self, *inputs):
X
Xin Pan 已提交
95
        if not self._built:
96 97
            self._build_once(*inputs)

98
        outputs = self.forward(*inputs)
X
Xin Pan 已提交
99
        self._built = True
M
minqiyang 已提交
100
        return outputs
M
minqiyang 已提交
101

102 103
    def forward(self, *inputs):
        raise NotImplementedError
X
Xin Pan 已提交
104 105 106 107

    def backward(self, *inputs):
        raise ValueError("Layer shouldn't implement backward")

X
Xin Pan 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    def add_sublayer(self, name, sublayer):
        """Adds a sub Layer instance.

          Added sublayer can be access like self.name.

        Args:
            name: name of this sublayer.
            sublayer: an instance of Layer.
        Returns:
            the sublayer passed in.
        """
        assert isinstance(sublayer, core.Layer)
        self._sub_layers[name] = sublayer
        return sublayer

    def add_parameter(self, name, parameter):
        """Adds a Parameter instance.

          Added parameter can be access like self.name.

        Args:
            name: name of this sublayer.
            parameter: an instance of Parameter.
        Returns:
            the parameter passed in.
        """
        assert isinstance(parameter, framework.Parameter)
        self._parameters[name] = parameter
        return parameter

X
Xin Pan 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
    def __getattr__(self, name):
        if name in self._parameters:
            return self._parameters[name]
        elif name in self._sub_layers:
            return self._sub_layers[name]

    def __setattr__(self, name, value):
        if isinstance(value, framework.Parameter):
            params = self.__dict__.get('_parameters', None)
            if params is None:
                raise ValueError(
                    "super(YourLayer, self).__init__() should be called first")
            params[name] = value
        elif isinstance(value, core.Layer):
            layers = self.__dict__.get('_sub_layers', None)
            if layers is None:
                raise ValueError(
                    "super(YourLayer, self).__init__() should be called first")
            layers[name] = value
        else:
            object.__setattr__(self, name, value)

    def __delattr__(self, name):
        if name in self._parameters:
            del self._parameters[name]
        elif name in self._sub_layers:
            del self._sub_layers[name]
        else:
            object.__delattr__(self, name)

X
Xin Pan 已提交
168

X
Xin Pan 已提交
169
class PyLayer(core.PyLayer):
X
Xin Pan 已提交
170 171
    """Layers composed of user-defined python codes."""

X
Xin Pan 已提交
172 173
    def __init__(self):
        super(PyLayer, self).__init__()
X
Xin Pan 已提交
174

X
Xin Pan 已提交
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    @classmethod
    def _do_forward(cls, inputs):
        return cls._to_tuple(cls.forward(inputs))

    @classmethod
    def _do_backward(cls, inputs):
        return cls._to_tuple(cls.backward(inputs))

    @staticmethod
    def _to_tuple(inputs):
        if not isinstance(inputs, list) and not isinstance(inputs, tuple):
            inputs = [inputs]
        ret = []
        for inp in inputs:
            tensor = core.LoDTensor()
            tensor.set(inp, core.CPUPlace())
            ret.append(tensor)
        return tuple(ret)

X
Xin Pan 已提交
194
    @staticmethod
M
minqiyang 已提交
195
    def forward(*inputs):
X
Xin Pan 已提交
196 197
        raise NotImplementedError

X
Xin Pan 已提交
198
    @staticmethod
M
minqiyang 已提交
199
    def backward(*douts):
X
Xin Pan 已提交
200
        raise NotImplementedError
X
Xin Pan 已提交
201 202

    @classmethod
M
minqiyang 已提交
203
    def __call__(cls, *inputs):
X
Xin Pan 已提交
204 205
        tracer = framework._imperative_tracer()
        block = framework.default_main_program().current_block()
M
minqiyang 已提交
206
        ivar_inputs = [x._ivar for x in inputs]
X
Xin Pan 已提交
207

X
polish  
Xin Pan 已提交
208 209
        if not hasattr(cls, 'forward_id'):
            cls.forward_id = core.PyLayer.num_funcs() + 1
X
Xin Pan 已提交
210
            PyLayer.register_func(cls.forward_id, cls._do_forward)
X
polish  
Xin Pan 已提交
211
            cls.backward_id = core.PyLayer.num_funcs() + 1
X
Xin Pan 已提交
212
            PyLayer.register_func(cls.backward_id, cls._do_backward)
X
Xin Pan 已提交
213 214

        iop = core.OpBase()
X
polish  
Xin Pan 已提交
215 216
        iop.forward_id = cls.forward_id
        iop.backward_id = cls.backward_id
X
Xin Pan 已提交
217
        block.ops.append(iop)
M
minqiyang 已提交
218
        ivars = tracer.py_trace(iop, ivar_inputs, False)
X
Xin Pan 已提交
219 220
        ret = []
        for ivar in ivars:
M
minqiyang 已提交
221
            tensor = ivar.value().get_tensor()
X
Xin Pan 已提交
222 223 224 225 226 227 228 229 230
            py_var = framework.Variable(
                block,
                type=core.VarDesc.VarType.LOD_TENSOR,
                name=None,
                shape=tensor.shape(),
                dtype=tensor._dtype(),
                ivar=ivar)
            ret.append(py_var)
        return ret