Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/source/models/dcn.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,42 @@ model_config {
- embedding_regularization: 对embedding部分加regularization, 减少overfit

### 示例Config
- 现在除了通过 backbone 组件化方式外,也支持在内置 `DCN` 模型中开启 v2 的矩阵/低秩 Cross:

```protobuf
model_config: {
model_class: 'DCN'
feature_groups: { group_name: 'all' ... }
dcn {
deep_tower { input: "all" dnn { hidden_units: [256, 128, 64] } }
cross_tower {
input: "all"
cross_num: 3
version: 2 # 开启 DCN-V2
projection_dim: 64 # 低秩 U*V,省略则使用 full-rank
diag_scale: 0.1 # 训练稳定性增强
preactivation: "relu" # 与 Cross 层一致的预激活
use_bias: true
}
final_dnn { hidden_units: [64, 32, 16] }
l2_regularization: 1e-4
}
embedding_regularization: 1e-4
}
```


1. DCN V1: [DCN_demo.config](https://easyrec.oss-cn-beijing.aliyuncs.com/config/dcn.config)
1. DCN V2: [dcn_backbone_on_movielens.config](https://github.com/alibaba/EasyRec/tree/master/examples/configs/dcn_backbone_on_movielens.config)

1. DCN V2(内置模型写法):[dcn_v2_on_taobao.config](file:///mlx_devbox/users/zhaohao.9426/playground/EasyRec/samples/model_config/dcn_v2_on_taobao.config)

本地直接训练命令:

```bash
python -m easy_rec.python.train_eval --pipeline_config_path samples/model_config/dcn_v2_on_taobao.config
```

### 参考论文

1. [DCN v1](https://arxiv.org/abs/1708.05123)
Expand Down
58 changes: 57 additions & 1 deletion easy_rec/python/model/dcn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
# Copyright (c) Alibaba, Inc. and its affiliates.

import tensorflow as tf
import os

from easy_rec.python.layers import dnn
from easy_rec.python.model.rank_model import RankModel
from easy_rec.python.layers.keras.interaction import Cross
from easy_rec.python.layers.utils import Parameter

from easy_rec.python.protos.dcn_pb2 import DCN as DCNConfig # NOQA

Expand Down Expand Up @@ -44,6 +47,45 @@ def _cross_net(self, tensor, num_cross_layers):
x = tf.math.add(tf.math.add(x0 * xw, b), x)
return x

def _cross_net_v2(self, tensor, num_cross_layers):
x0 = tensor
x = tensor
params = {} # picked from proto, env acts only as fallback
cross_tower = self._model_config.cross_tower
if getattr(cross_tower, 'projection_dim', 0):
params['projection_dim'] = int(cross_tower.projection_dim)
preact = getattr(cross_tower, 'preactivation', '')
if preact:
params['preactivation'] = preact
diag = getattr(cross_tower, 'diag_scale', 0.0)
if diag:
params['diag_scale'] = float(diag)
if hasattr(cross_tower, 'use_bias'):
params['use_bias'] = bool(cross_tower.use_bias)
# env fallback
proj_env = os.getenv('EASYREC_DCN_V2_PROJ', None)
if 'projection_dim' not in params and proj_env:
try:
params['projection_dim'] = int(proj_env)
except Exception:
pass
preact_env = os.getenv('EASYREC_DCN_V2_PREACT', None)
if 'preactivation' not in params and preact_env:
params['preactivation'] = preact_env
diag_env = os.getenv('EASYREC_DCN_V2_DIAG', None)
if 'diag_scale' not in params and diag_env:
try:
params['diag_scale'] = float(diag_env)
except Exception:
pass
use_bias_env = os.getenv('EASYREC_DCN_V2_USE_BIAS', None)
if 'use_bias' not in params and use_bias_env:
params['use_bias'] = use_bias_env.lower() in ('1', 'true', 'yes')
layer_params = Parameter(params, True)
for i in range(num_cross_layers):
x = Cross(layer_params, name='cross_v2_%d' % i)([x0, x])
return x

def build_predict_graph(self):
tower_fea_arr = []
# deep tower
Expand All @@ -56,7 +98,21 @@ def build_predict_graph(self):
# cross tower
cross_tower_config = self._model_config.cross_tower
num_cross_layers = cross_tower_config.cross_num
cross_tensor = self._cross_net(self._features, num_cross_layers)
use_v2 = getattr(cross_tower_config, 'version', 1) == 2
if not use_v2:
# auto-enable v2 if v2-specific params are set
if getattr(cross_tower_config, 'projection_dim', 0) or \
getattr(cross_tower_config, 'preactivation', '') or \
getattr(cross_tower_config, 'diag_scale', 0.0) != 0.0:
use_v2 = True
# env fallback switch
if not use_v2:
if os.getenv('EASYREC_DCN_V2', '0').lower() in ('1', 'true', 'yes'):
use_v2 = True
if use_v2:
cross_tensor = self._cross_net_v2(self._features, num_cross_layers)
else:
cross_tensor = self._cross_net(self._features, num_cross_layers)
tower_fea_arr.append(cross_tensor)
# final tower
all_fea = tf.concat(tower_fea_arr, axis=1)
Expand Down
11 changes: 11 additions & 0 deletions easy_rec/python/protos/dcn.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ message CrossTower {
required string input = 1;
// The number of cross layers
required uint32 cross_num = 2 [default = 3];
// DCN version: 1 for vector cross, 2 for matrix/low-rank cross
optional uint32 version = 3 [default = 1];
// Parameters for DCN v2 (matrix/low-rank)
// If projection_dim is set, use low-rank U*V; otherwise use full-rank.
optional uint32 projection_dim = 4;
// Add diag scale to improve stability: W + diag_scale * I
optional float diag_scale = 5 [default = 0.0];
// Preactivation applied to Dense output before element-wise product with x0
optional string preactivation = 6;
// Whether to include bias terms in cross layers
optional bool use_bias = 7 [default = true];
};

message DCN {
Expand Down
Loading