model_develop.md 5.6 KB
Newer Older
C
chengmo 已提交
1
# 如何添加自定义模型
C
chengmo 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

当您希望开发自定义模型时,需要继承模型的模板基类,并实现三个必要的方法`init_hyper_parameter`,`intput_data`,`net`

并按照以下规范添加代码。

### 基类的继承

继承`paddlerec.core.model`的ModelBase,命名为`Class Model`

```python
from paddlerec.core.model import ModelBase


class Model(ModelBase):

    # 构造函数无需显式指定
    # 若继承,务必调用基类的__init__方法
    def __init__(self, config):
        ModelBase.__init__(self, config)
        # ModelBase的__init__方法会调用_init_hyper_parameter()
    
```

### 超参的初始化

继承并实现`_init_hyper_parameter`方法(必要),可以在该方法中,从`yaml`文件获取超参或进行自定义操作。如下面的示例:

所有的envs调用接口在_init_hyper_parameters()方法中实现,同时类成员也推荐在此做声明及初始化。

```python
 def _init_hyper_parameters(self):
    self.feature_size = envs.get_global_env(
        "hyper_parameters.feature_size")
    self.expert_num = envs.get_global_env("hyper_parameters.expert_num")
    self.gate_num = envs.get_global_env("hyper_parameters.gate_num")
    self.expert_size = envs.get_global_env("hyper_parameters.expert_size")
    self.tower_size = envs.get_global_env("hyper_parameters.tower_size")
```


### 数据输入的定义
继承并实现`input_data`方法(非必要)


#### 直接使用基类的数据读取方法

`ModelBase`中的input_data默认实现为slot_reader,在`config.yaml`中分别配置`reader.sparse_slot``reader.dense_slot`选项实现`slog:feasign`模式的数据读取。

> Slot : Feasign 是什么?
>
> Slot直译是槽位,在Rec工程中,是指某一个宽泛的特征类别,比如用户ID、性别、年龄就是Slot,Feasign则是具体值,比如:12345,男,20岁。
> 
> 在实践过程中,很多特征槽位不是单一属性,或无法量化并且离散稀疏的,比如某用户兴趣爱好有三个:游戏/足球/数码,且每个具体兴趣又有多个特征维度,则在兴趣爱好这个Slot兴趣槽位中,就会有多个Feasign值。
>
> PaddleRec在读取数据时,每个Slot ID对应的特征,支持稀疏,且支持变长,可以非常灵活的支持各种场景的推荐模型训练。

使用示例请参考`rank.dnn`模型。

#### 自定义数据输入


如果您不想使用`slot:feasign`模式,则需继承并实现`input_data`接口,接口定义:`def input_data(self, is_infer=False, **kwargs)`

使用示例如下:

```python
def input_data(self, is_infer=False, **kwargs):
    ser_slot_names = fluid.data(
        name='user_slot_names',
        shape=[None, 1],
        dtype='int64',
        lod_level=1)
    item_slot_names = fluid.data(
        name='item_slot_names',
        shape=[None, self.item_len],
        dtype='int64',
        lod_level=1)
    lens = fluid.data(name='lens', shape=[None], dtype='int64')
    labels = fluid.data(
        name='labels',
        shape=[None, self.item_len],
        dtype='int64',
        lod_level=1)
 
    train_inputs = [user_slot_names] + [item_slot_names] + [lens] + [labels]
    infer_inputs = [user_slot_names] + [item_slot_names] + [lens]
 
    if is_infer:
        return infer_inputs
    else:
        return train_inputs
```

更多数据读取教程,请参考[自定义数据集及Reader](custom_dataset_reader.md)


### 组网的定义

继承并实现`net`方法(必要)

- 接口定义`def net(self, inputs, is_infer=False)`
- 自定义网络需在该函数中使用paddle组网,实现前向逻辑,定义网络的Loss及Metrics,通过`is_infer`判断是否为infer网络。
- 我们强烈建议`train``infer`尽量复用相同代码,
- `net`中调用的其他函数以下划线为头进行命名,封装网络中的结构模块,如`_sparse_embedding_layer(self)`
- `inputs``def input_data()`的输出,若使用`slot_reader`方式,inputs为占位符,无实际意义,通过以下方法拿到dense及sparse的输入

  ```python
  self.sparse_inputs = self._sparse_data_var[1:]
  self.dense_input = self._dense_data_var[0]
  self.label_input = self._sparse_data_var[0]
  ```

可以参考官方模型的示例学习net的构造方法。

## 如何运行自定义模型

记录`model.py`,`config.yaml`及数据读取`reader.py`的文件路径,建议置于同一文件夹下,如`/home/custom_model`下,更改`config.yaml`中的配置选项

1. 更改 workerspace为模型文件所在文件夹 
```yaml
workspace: "/home/custom_model"
```

2. 更改数据地址及读取reader地址
```yaml
dataset:
- name: custom_model_train
- data_path: "{workspace}/data/train" # or  "/home/custom_model/data/train"
- data_converter: "{workspace}/reader.py" # or "/home/custom_model/reader.py"
```

3. 更改执行器的路径配置
```yaml
mode: train_runner

runner:
- name: train_runner
  class: single_train
  device: cpu
  epochs: 10
  save_checkpoint_interval: 2
  save_inference_interval: 5
  save_checkpoint_path: "{workspace}/increment" # or  "/home/custom_model/increment"
  save_inference_path: "{workspace}/inference" # or  "/home/custom_model/inference"
  print_interval: 10

phase:
- name: train
  model: "{workspace}/model.py" # or "/home/custom_model/model"
  dataset_name: custom_model_train
  thread_num: 1
```

4. 使用paddlerec.run方法运行自定义模型

```shell
python -m paddlerec.run -m /home/custom_model/config.yaml 
```

以上~请开始享受你的推荐算法高效开发流程。如有任何问题,欢迎在[issue](https://github.com/PaddlePaddle/PaddleRec/issues)提出,我们会第一时间跟进解决。