Skip to content

Commit b455502

Browse files
authored
Merge pull request #7723 from reyoung/feature/wrap_nce_loss
Wrap NCE to python
2 parents 88a95a0 + deb7509 commit b455502

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

paddle/operators/nce_op.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ class NCEOpMaker : public framework::OpProtoAndCheckerMaker {
124124
"This attribute only be used in unitest. Classes "
125125
"in this list wiil be used as negative classes "
126126
"for every samples. Under normal conditions, "
127-
"user should avoid setting this attribute.");
127+
"user should avoid setting this attribute.")
128+
.SetDefault({});
128129
AddComment(R"DOC(
129130
Compute and return the noise-contrastive estimation training loss.
130131
See [Noise-contrastive estimation: A new estimation principle for unnormalized statistical models](http://www.jmlr.org/proceedings/papers/v9/gutmann10a/gutmann10a.pdf).

paddle/operators/nce_op.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ class NCEGradKernel : public framework::OpKernel<T> {
197197
// get d_x
198198
auto d_x = context.Output<Tensor>(framework::GradVarName("Input"));
199199
if (d_x != nullptr) {
200-
d_x->mutable_data<T>(context.GetPlace());
200+
auto* d_x_data = d_x->mutable_data<T>(context.GetPlace());
201+
std::fill(d_x_data, d_x_data + d_x->numel(), 0.0);
201202
auto d_x_matrix = EigenMatrix<T>::From(*d_x);
202203
auto w_matrix = EigenMatrix<T>::From(*(context.Input<Tensor>("Weight")));
203204
for (int64_t i = 0; i < sample_labels->numel(); ++i) {

python/paddle/v2/fluid/layers/nn.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from ..initializer import Normal, Constant
2020
from ..framework import Variable
2121
from ..param_attr import ParamAttr
22+
from layer_function_generator import autodoc
2223
from tensor import concat
2324

2425
__all__ = [
@@ -57,6 +58,7 @@
5758
'warpctc',
5859
'sequence_reshape',
5960
'transpose',
61+
'nce',
6062
]
6163

6264

@@ -2190,6 +2192,61 @@ def sequence_reshape(input, new_dim):
21902192
return out
21912193

21922194

2195+
@autodoc()
2196+
def nce(input,
2197+
label,
2198+
num_total_classes,
2199+
sample_weight=None,
2200+
param_attr=None,
2201+
bias_attr=None,
2202+
num_neg_samples=None):
2203+
helper = LayerHelper('nce', **locals())
2204+
assert isinstance(input, Variable)
2205+
dim = input.shape[1]
2206+
assert isinstance(label, Variable)
2207+
num_true_class = label.shape[1]
2208+
w = helper.create_parameter(
2209+
attr=helper.param_attr,
2210+
shape=[num_total_classes, dim],
2211+
is_bias=False,
2212+
dtype=input.dtype)
2213+
b = helper.create_parameter(
2214+
attr=helper.bias_attr,
2215+
shape=[num_total_classes, 1],
2216+
is_bias=True,
2217+
dtype=input.dtype)
2218+
cost = helper.create_tmp_variable(dtype=input.dtype)
2219+
sample_logits = helper.create_tmp_variable(dtype=input.dtype)
2220+
sample_labels = helper.create_tmp_variable(dtype=label.dtype)
2221+
2222+
if num_neg_samples is None:
2223+
num_neg_samples = 10
2224+
else:
2225+
num_neg_samples = int(num_neg_samples)
2226+
2227+
attrs = {
2228+
'num_total_classes': int(num_total_classes),
2229+
'num_neg_samples': num_neg_samples
2230+
}
2231+
2232+
helper.append_op(
2233+
type='nce',
2234+
inputs={
2235+
'Input': input,
2236+
'Label': label,
2237+
'Weight': w,
2238+
'Bias': b,
2239+
'SampleWeight': sample_weight if sample_weight is not None else []
2240+
},
2241+
outputs={
2242+
'Cost': cost,
2243+
'SampleLogits': sample_logits,
2244+
'SampleLabels': sample_labels
2245+
},
2246+
attrs=attrs)
2247+
return cost / (num_neg_samples + 1)
2248+
2249+
21932250
def transpose(x, perm, name=None):
21942251
"""
21952252
**transpose Layer**

python/paddle/v2/fluid/tests/test_layers.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717

1818
import paddle.v2.fluid.layers as layers
1919
import paddle.v2.fluid.nets as nets
20-
from paddle.v2.fluid.framework import Program, program_guard
20+
from paddle.v2.fluid.framework import Program, program_guard, default_main_program
2121
from paddle.v2.fluid.param_attr import ParamAttr
22+
import decorators
2223

2324

2425
class TestBook(unittest.TestCase):
@@ -225,6 +226,41 @@ def test_sequence_reshape(self):
225226
self.assertIsNotNone(out)
226227
print(str(program))
227228

229+
@decorators.prog_scope()
230+
def test_nce(self):
231+
window_size = 5
232+
words = []
233+
for i in xrange(window_size):
234+
words.append(
235+
layers.data(
236+
name='word_{0}'.format(i), shape=[1], dtype='int64'))
237+
238+
dict_size = 10000
239+
label_word = int(window_size / 2) + 1
240+
241+
embs = []
242+
for i in xrange(window_size):
243+
if i == label_word:
244+
continue
245+
246+
emb = layers.embedding(
247+
input=words[i],
248+
size=[dict_size, 32],
249+
param_attr='emb.w',
250+
is_sparse=True)
251+
252+
embs.append(emb)
253+
254+
embs = layers.concat(input=embs, axis=1)
255+
loss = layers.nce(input=embs,
256+
label=words[label_word],
257+
num_total_classes=dict_size,
258+
param_attr='nce.w',
259+
bias_attr='nce.b')
260+
avg_loss = layers.mean(x=loss)
261+
self.assertIsNotNone(avg_loss)
262+
print(str(default_main_program()))
263+
228264

229265
if __name__ == '__main__':
230266
unittest.main()

0 commit comments

Comments
 (0)