-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Implement FC layer with helper #4726
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
f5d9005
5488ec9
153d9a8
e016726
f6570b5
f7cffb7
e017ba2
1cf33cb
cd93f12
3e613de
3ab53e4
a281c39
03fc36c
32cdc7b
d28c2c7
647e1eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| from paddle.v2.framework.graph import Variable, g_program | ||
| import paddle.v2.framework.core as core | ||
| import copy | ||
| import itertools | ||
|
|
||
|
|
||
| def unique_name(prefix): | ||
| uid = core.unique_integer() # unique during whole process. | ||
| return "_".join([prefix, str(uid)]) | ||
|
|
||
|
|
||
| class LayerHelper(object): | ||
| def __init__(self, layer_type, **kwargs): | ||
| self.kwargs = kwargs | ||
| self.layer_type = layer_type | ||
| name = self.kwargs.get('name', None) | ||
| if name is None: | ||
| self.kwargs['name'] = unique_name(self.layer_type) | ||
|
|
||
| @property | ||
| def name(self): | ||
| return self.kwargs['name'] | ||
|
|
||
| @property | ||
| def program(self): | ||
| return self.kwargs.get('program', g_program) | ||
|
|
||
| def append_op(self, *args, **kwargs): | ||
| return self.program.current_block().append_op(*args, **kwargs) | ||
|
|
||
| @property | ||
| def multiple_input(self): | ||
|
||
| inputs = self.kwargs.get('input', []) | ||
| type_error = TypeError( | ||
| "Input of {0} layer should be Variable or sequence of Variable". | ||
| format(self.layer_type)) | ||
| if isinstance(inputs, Variable): | ||
| inputs = [inputs] | ||
| elif not isinstance(inputs, list) and not isinstance(inputs, tuple): | ||
| raise type_error | ||
| else: | ||
| for each in inputs: | ||
| if not isinstance(each, Variable): | ||
| raise type_error | ||
| return inputs | ||
|
|
||
| @property | ||
| def input(self): | ||
|
||
| inputs = self.multiple_input | ||
| if len(inputs) != 1: | ||
| raise "{0} layer only takes one input".format(self.layer_type) | ||
| return inputs[0] | ||
|
|
||
| @property | ||
| def param_attr(self): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since there is more than one |
||
| return self.kwargs.get('param_attr', { | ||
| 'name': None, | ||
| 'init_attr': { | ||
| 'type': 'uniform_random', | ||
| 'min': -1.0, | ||
| 'max': 1.0 | ||
| } | ||
| }) | ||
|
|
||
| def bias_attr(self, size): | ||
|
||
| bias_attr = self.kwargs.get('bias_attr', False) | ||
| if bias_attr is None: | ||
| bias_attr = { | ||
| 'name': None, | ||
| 'init_attr': { | ||
| 'type': 'fill', | ||
| 'value': 0.0, | ||
| 'shape': [size] | ||
| } | ||
| } | ||
| return bias_attr | ||
|
|
||
| def multiple_param_attr(self, length): | ||
| param_attr = self.param_attr | ||
| if isinstance(param_attr, dict): | ||
| param_attr = [param_attr] | ||
|
|
||
| if len(param_attr) != 1 and len(param_attr) != length: | ||
| raise ValueError("parameter number mismatch") | ||
| elif len(param_attr) == 1: | ||
| tmp = [None] * length | ||
| for i in xrange(length): | ||
| tmp[i] = copy.deepcopy(param_attr) | ||
| param_attr = tmp | ||
|
|
||
| return param_attr | ||
|
|
||
| def iter_inputs_and_params(self): | ||
| inputs = self.multiple_input | ||
| param_attrs = self.multiple_param_attr(len(inputs)) | ||
| for ipt, param_attr in itertools.izip(inputs, param_attrs): | ||
| yield ipt, param_attr | ||
|
|
||
| @property | ||
| def input_dtype(self): | ||
|
||
| inputs = self.multiple_input | ||
| dtype = None | ||
| for each in inputs: | ||
| if dtype is None: | ||
| dtype = each.data_type | ||
| elif dtype != each.data_type: | ||
| raise ValueError("Data Type mismatch") | ||
|
|
||
| def create_parameter(self, attr, shape, dtype, suffix='w'): | ||
| if attr['name'] is None: | ||
| attr['name'] = unique_name(".".join([self.name, suffix])) | ||
| return self.program.global_block().create_parameter( | ||
| name=attr['name'], | ||
| dtype=dtype, | ||
| shape=shape, | ||
| initialize_attr=attr['init_attr']) | ||
|
|
||
| def create_tmp_variable(self, dtype): | ||
| return self.program.current_block().create_var( | ||
| name=unique_name(".".join([self.name, 'tmp'])), dtype=dtype) | ||
|
|
||
| def append_bias_op(self, input_var): | ||
| bias_attr = self.bias_attr(self.kwargs['size']) | ||
| if not bias_attr: | ||
| return input_var | ||
| b = self.create_parameter( | ||
| bias_attr, | ||
| shape=[self.kwargs['size']], | ||
| dtype=input_var.data_type, | ||
| suffix='b') | ||
| tmp = self.create_tmp_variable(dtype=input_var.data_type) | ||
| self.append_op( | ||
| type='elementwise_add', | ||
| inputs={'X': [input_var], | ||
| 'Y': [b]}, | ||
| outputs={'Out': [tmp]}) | ||
| return tmp | ||
|
|
||
| def append_activation(self, input_var): | ||
| act = self.kwargs.get('act', None) | ||
| if act is None: | ||
| return input_var | ||
|
|
||
| tmp = self.create_tmp_variable(dtype=input_var.data_type) | ||
| act_type = act.pop('type') | ||
| self.append_op( | ||
| type=act_type, | ||
| inputs={"X": [input_var]}, | ||
| outputs={"Y": [tmp]}, | ||
| attrs=act) | ||
| return tmp | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| from paddle.v2.framework.layer_helper import LayerHelper | ||
|
|
||
|
|
||
| def fc_layer(input, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we follow the current name convention in v2 api, which is fc() for fc layer |
||
| size, | ||
| param_attr=None, | ||
| bias_attr=False, | ||
| name=None, | ||
| act=None, | ||
| num_flatten_dims=1): | ||
| # create helper | ||
| helper = LayerHelper(locals()) | ||
|
|
||
| dtype = helper.input_dtype | ||
|
|
||
| # mul | ||
| mul_results = [] | ||
| for input_var, param_attr in helper.iter_inputs_and_params(): | ||
| input_shape = input_var.shape | ||
| param_shape = input_shape[num_flatten_dims:] + [size] | ||
| w = helper.create_parameter(param_attr, param_shape, dtype) | ||
| tmp = helper.create_tmp_variable(dtype) | ||
| helper.append_op( | ||
| type="mul", | ||
| inputs={ | ||
| "X": input_var, | ||
| "Y": w, | ||
| }, | ||
| outputs={"Out": tmp}, | ||
| attrs={'x_num_col_dims': num_flatten_dims}) | ||
| mul_results.append(tmp) | ||
|
|
||
| # sum | ||
| if len(mul_results) == 1: | ||
| pre_bias = mul_results | ||
| else: | ||
| pre_bias = helper.create_tmp_variable(dtype) | ||
| helper.append_op( | ||
| type="sum", inputs={"X": mul_results}, outputs={"Out": pre_bias}) | ||
| # add bias | ||
| pre_activation = helper.append_bias_op(pre_bias) | ||
| # add activation | ||
| return helper.append_activation(pre_activation) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.