model.py 4.7 KB
Newer Older
T
tangwei 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#   Copyright (c) 2020 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
xujiaqi01 已提交
15 16 17 18
import paddle.fluid as fluid
import paddle.fluid.layers.nn as nn
import paddle.fluid.layers.tensor as tensor
import paddle.fluid.layers.control_flow as cf
C
Chengmo 已提交
19
from paddlerec.core.model import ModelBase
T
for mat  
tangwei 已提交
20
from paddlerec.core.utils import envs
T
tangwei 已提交
21 22


X
xujiaqi01 已提交
23 24 25 26 27
class Model(ModelBase):
    def __init__(self, config):
        ModelBase.__init__(self, config)
        self.cost = None
        self.metrics = {}
X
xjqbest 已提交
28 29 30 31 32 33 34 35 36
        self.vocab_text_size = envs.get_global_env(
            "hyper_parameters.vocab_text_size")
        self.vocab_tag_size = envs.get_global_env(
            "hyper_parameters.vocab_tag_size")
        self.emb_dim = envs.get_global_env("hyper_parameters.emb_dim")
        self.hid_dim = envs.get_global_env("hyper_parameters.hid_dim")
        self.win_size = envs.get_global_env("hyper_parameters.win_size")
        self.margin = envs.get_global_env("hyper_parameters.margin")
        self.neg_size = envs.get_global_env("hyper_parameters.neg_size")
X
xujiaqi01 已提交
37

X
xjqbest 已提交
38
    def input_data(self, is_infer=False, **kwargs):
T
tangwei 已提交
39 40
        text = fluid.data(
            name="text", shape=[None, 1], lod_level=1, dtype='int64')
X
xujiaqi01 已提交
41 42 43 44
        pos_tag = fluid.data(
            name="pos_tag", shape=[None, 1], lod_level=1, dtype='int64')
        neg_tag = fluid.data(
            name="neg_tag", shape=[None, 1], lod_level=1, dtype='int64')
X
xjqbest 已提交
45
        return [text, pos_tag, neg_tag]
X
xujiaqi01 已提交
46

X
xjqbest 已提交
47 48 49 50 51
    def net(self, input, is_infer=False):
        """ network"""
        text = input[0]
        pos_tag = input[1]
        neg_tag = input[2]
X
xujiaqi01 已提交
52 53

        text_emb = fluid.embedding(
T
tangwei 已提交
54 55 56
            input=text,
            size=[self.vocab_text_size, self.emb_dim],
            param_attr="text_emb")
X
xujiaqi01 已提交
57 58
        text_emb = fluid.layers.squeeze(input=text_emb, axes=[1])
        pos_tag_emb = fluid.embedding(
T
tangwei 已提交
59 60 61
            input=pos_tag,
            size=[self.vocab_tag_size, self.emb_dim],
            param_attr="tag_emb")
X
xujiaqi01 已提交
62 63
        pos_tag_emb = fluid.layers.squeeze(input=pos_tag_emb, axes=[1])
        neg_tag_emb = fluid.embedding(
T
tangwei 已提交
64 65 66
            input=neg_tag,
            size=[self.vocab_tag_size, self.emb_dim],
            param_attr="tag_emb")
X
xujiaqi01 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79
        neg_tag_emb = fluid.layers.squeeze(input=neg_tag_emb, axes=[1])

        conv_1d = fluid.nets.sequence_conv_pool(
            input=text_emb,
            num_filters=self.hid_dim,
            filter_size=self.win_size,
            act="tanh",
            pool_type="max",
            param_attr="cnn")
        text_hid = fluid.layers.fc(input=conv_1d,
                                   size=self.emb_dim,
                                   param_attr="text_hid")
        cos_pos = nn.cos_sim(pos_tag_emb, text_hid)
T
tangwei 已提交
80 81
        mul_text_hid = fluid.layers.sequence_expand_as(
            x=text_hid, y=neg_tag_emb)
X
xujiaqi01 已提交
82 83 84
        mul_cos_neg = nn.cos_sim(neg_tag_emb, mul_text_hid)
        cos_neg_all = fluid.layers.sequence_reshape(
            input=mul_cos_neg, new_dim=self.neg_size)
C
Chengmo 已提交
85
        # choose max negtive cosine
X
xujiaqi01 已提交
86
        cos_neg = nn.reduce_max(cos_neg_all, dim=1, keep_dim=True)
C
Chengmo 已提交
87
        # calculate hinge loss
X
xujiaqi01 已提交
88 89
        loss_part1 = nn.elementwise_sub(
            tensor.fill_constant_batch_size_like(
T
tangwei 已提交
90 91 92 93
                input=cos_pos,
                shape=[-1, 1],
                value=self.margin,
                dtype='float32'),
X
xujiaqi01 已提交
94 95 96 97 98 99
            cos_pos)
        loss_part2 = nn.elementwise_add(loss_part1, cos_neg)
        loss_part3 = nn.elementwise_max(
            tensor.fill_constant_batch_size_like(
                input=loss_part2, shape=[-1, 1], value=0.0, dtype='float32'),
            loss_part2)
100 101
        avg_cost = fluid.layers.mean(loss_part3)

X
xujiaqi01 已提交
102
        less = tensor.cast(cf.less_than(cos_neg, cos_pos), dtype='float32')
103 104
        label_ones = fluid.layers.fill_constant_batch_size_like(
            input=cos_neg, dtype='float32', shape=[-1, 1], value=1.0)
X
xujiaqi01 已提交
105
        correct = nn.reduce_sum(less)
106 107
        total = fluid.layers.reduce_sum(label_ones)
        acc = fluid.layers.elementwise_div(correct, total)
X
xjqbest 已提交
108
        self._cost = avg_cost
X
xujiaqi01 已提交
109

X
xjqbest 已提交
110
        if is_infer:
111 112
            self._infer_results["acc"] = acc
            self._infer_results["loss"] = self._cost
X
xjqbest 已提交
113
        else:
114 115
            self._metrics["acc"] = acc
            self._metrics["loss"] = self._cost