model_develop.md 5.7 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

当您希望开发自定义模型时,需要继承模型的模板基类,并实现三个必要的方法`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的构造方法。

M
doc  
malin10 已提交
116 117
除可以使用Paddle的Metrics接口外,PaddleRec也统一封装了一些常见的Metrics评价指标,并允许开发者定义自己的Metrics类,相关文件参考[Metrics开发文档](metrics.md)

C
chengmo 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
## 如何运行自定义模型

记录`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
J
Jinhua Liang 已提交
141
  class: train
C
chengmo 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
  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)提出,我们会第一时间跟进解决。