特征生成(FeatureGenerator,下文简称FG)是一套把原始输入转换为模型所需输入(特征)的数据变换过程,用来保证离线、在线样本生成结果的一致性。特征生成也可以理解为特征变换,对单个特征或者多个特征做变换。我们提供了各种类型的FG来完成各种特征变换操作。
特征生成只关注同时需要在离线和在线样本生成过程中的变换操作。如果某个变换操作只需要作用在离线阶段,则不需要定义为FG的操作。 FG模块在推荐系统架构中的位置如下图所示:
特征生成过程由一系列特征变换算子(下文简称为FG算子)按照配置文件定义的DAG图的拓扑顺序并行执行。
配置文件示例
features列表配置特征算子,每个特征算子必须包含feature_name
、feature_type
两项,其余配置项请参见内置特征算子。
reserves指定离线任务时透传出的字段,这些字段会原样输出,不会做特征变换。
{
"features": [
{
"feature_name": "goods_id",
"feature_type": "id_feature",
"value_type": "string",
"expression": "item:goods_id",
"default_value": "-1024",
"need_prefix": false
},
{
"feature_name": "color_pair",
"feature_type": "combo_feature",
"value_type": "string",
"expression": ["user:query_color", "item:color"],
"default_value": "",
"need_prefix": false
},
{
"feature_name": "current_price",
"feature_type": "raw_feature",
"value_type": "double",
"expression": "item:current_price",
"default_value": "0",
"need_prefix": false
},
{
"feature_name": "usr_cate1_clk_cnt_1d",
"feature_type": "lookup_feature",
"map": "user:usr_cate1_clk_cnt_1d",
"key": "item:cate1",
"need_discrete": false,
"need_key": false,
"default_value": "0",
"combiner": "max",
"need_prefix": false,
"value_type": "double"
},
{
"feature_name": "recommend_match",
"feature_type": "overlap_feature",
"method": "is_contain",
"query": "user:query_recommend",
"title": "item:recommend",
"default_value": "0"
},
{
"feature_name": "norm_title",
"feature_type": "text_normalizer",
"expression": "item:title",
"max_length": 512,
"parameter": 0,
"remove_space": false,
"is_gbk_input": false,
"is_gbk_output": false
},
{
"feature_name": "title_terms",
"feature_type": "tokenize_feature",
"expression": "feature:norm_title",
"default_value": "",
"vocab_file": "tokenizer.json",
"output_type": "word_id",
"output_delim": ","
},
{
"feature_name": "query_title_match_ratio",
"feature_type": "overlap_feature",
"method": "query_common_ratio",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
},
{
"feature_name": "title_term_match_ratio",
"feature_type": "overlap_feature",
"method": "title_common_ratio",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
},
{
"feature_name": "term_proximity_min_cover",
"feature_type": "overlap_feature",
"method": "proximity_min_cover",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
}
],
"reserves": [
"request_id",
"user_id",
"is_click",
"is_pay",
"sample_weight",
"event_unix_time"
]
}
输入域
输入域表示当前输入来自哪个实体,目前支持以下4种类型:
user:用户侧特征,包括user profile、user维度的统计特征等。
context:上下文特征,时间、地点、天气等随时变化的特征。
item:物品侧特征,包括静态内容特征、item维度的统计特征等。
feature:表示当前输入是另一个特征变换的输出。
其中,feature输入域比较特殊,通过该输入域配置特征算子之间的依赖关系。从整体来看,所有特征算子构成一个有向无环图(DAG),框架会按照拓扑顺序来并行执行这些特征变换操作。对应的拓扑结构如下:
一般情况下,DAG的中间节点的输出不会作为FG的输出。可以用特征配置项stub_type
来改变这一行为。
多值类型及分隔符
FG支持复杂类型的输入,如Array、Map等,与MaxCompute的复杂类型一致。
字符串类型的多值特征可以使用chr(29)
分隔符。
例如v1^]v2^]v3
,^]
表示多值分隔符,这是⼀个符号,其ASCII编码是"\x1D"
,不是两个符号。该字符在emacs中的输⼊⽅式是C-q C-5,在vi中的输⼊⽅式是C-v C-5。
特征分箱(离散化)
框架支持如下6种类型的分箱操作:
hash_bucket_size:对特征变换结果进行hash和取模。
vocab_list:把特征变换结果转化为列表的索引。
vocab_dict:把特征变换结果转化为字典的值(必须可转化为int64类型)。
vocab_file: 从文件读入vocab_list或vocab_dict。
boundaries:指定分箱边界,把特征变换结果转化为对应的桶号。
num_buckets:直接使用特征变换结果作为分箱桶号。
hash_bucket_size
对特征变换结果进行hash和取模,适用于任意类型的特征值。
结果范围:[0,
hash_bucket_size
)空的特征分箱结果为
hash(default_value)%hash_bucket_size
{
"hash_bucket_size": 128000,
"default_value": "默认值"
}
vocab_list
根据词汇表分箱,把输入映射到词汇表的索引;分箱结果为特征值对应的vocab_list
数组的索引。
vocab_list
数组的元素类型需要与value_type
的配置相同num_oov_bucket
: Non-negative integer, the number of out-of-vocabulary buckets.All out-of-vocabulary inputs will be assigned IDs in the range [vocabulary_size, vocabulary_size+num_oov_buckets) based on a hash of the input value.
A positive num_oov_buckets can not be specified with
default_bucketize_value
.
default_bucketize_value
: The integer ID value to return for out-of-vocabulary feature values.This can not be specified with a positive
num_oov_buckets
.默认值为
vocab_list.size()
{
"vocab_list": [
"",
"<OOV>",
"token1",
"token2",
"token3",
"token4"
],
"num_oov_bucket": 0,
"default_bucketize_value": 1
}
vocab_dict
分箱结果为特征值对应的vocab_dict
字典的值,支持不同的特征值映射到相同的分箱结果。
vocab_dict
字典的键的类型需要与value_type
的配置相同要求
vocab_dict
的值必须能够转换为int64
类型num_oov_bucket
: Non-negative integer, the number of out-of-vocabulary buckets.All out-of-vocabulary inputs will be assigned IDs in the range [vocabulary_size, vocabulary_size+num_oov_buckets) based on a hash of the input value.
A positive num_oov_buckets can not be specified with
default_bucketize_value
.
default_bucketize_value
: The integer ID value to return for out-of-vocabulary feature values.This can not be specified with a positive
num_oov_buckets
.默认值为
vocab_dict.size()
{
"vocab_dict": {
"token1": 1,
"token2": 2,
"token3": 3,
"token4": 1
},
"num_oov_bucket": 0,
"default_bucketize_value": 4
}
vocab_file
从文件读入vocab_list或vocab_dict
{
"vocab_file": "vocab.txt",
"num_oov_bucket": 0,
"default_bucketize_value": 4
}
vocab_file: 文件路径,文件内容是词汇表,每行一个词汇,支持指定映射值(可选);
支持相对路径;部署线服务时,需要与
fg.json
放置在同一个目录下只有token时,映射为行号(从0开始);有value时,token-value之间用空白符(空格或Tab)分割;value必须为
int64
类型
num_oov_bucket
与default_bucketize_value
的含义同上文
boundaries
对数值型特征安装指定的分箱边界分箱。 Represents discretized dense input bucketed by boundaries.
boundaries
数组的元素类型需要与value_type
的配置相同。Buckets include the left boundary, and exclude the right boundary.
Namely, boundaries=[0., 1., 2.] generates buckets (-inf, 0.), [0., 1.), [1., 2.), and [2., +inf).
{
"boundaries": [0.0, 1.0, 2.0],
"default_value": -1
}
num_buckets
直接使用特征变换结果作为分箱桶号,适用于特征值可以转换为整数的情况。
结果范围:[0,
num_buckets
)如果特征值超出配置的范围,则赋值为
default_bucketize_value
。
{
"num_buckets": 128000,
"default_bucketize_value": 127999
}
内置特征算子
每个特征算子的配置方法不同,所有能够作为DAG叶子节点的特征算子都支持配置特征分箱。
更多信息,请参见内置特征算子。
特征类型 | 说明 |
id_feature | 类别型特征 |
raw_feature | 数值型特征 |
expr_feature | 表达式特征 |
combo_feature | 组合特征 |
lookup_feature | 字典查询特征 |
match_feature | 主从键字典查询特征 |
overlap_feature | 交叠特征 |
sequence_feature | 序列特征 |
text_normalizer | 文本归一化 |
tokenize_feature | 文本分词特征 |
bm25_feature | BM25文本相关性特征 |
kv_dot_product | kv向量内积 |
regex_replace_feature | 正则表达式替换 |
自定义特征算子
自定义特征算子能够以插件的形式被框架动态加载并执行。
更多信息,请参见自定义特征算子。
全局配置
配置项 | 类型 | 默认值 | 说明 |
USE_CITY_HASH_TO_BUCKETIZE | string | 'false' | 是否使用CityHash作为特征分箱的hash函数 |
USE_MULTIPLICATIVE_HASH | string | 'false' | 是否使用乘法hash替代特征hash的取余操作,建议开启 |
DISABLE_FG_PRECISION | string | 'true' | 是否禁用浮点型特征精度约束; 禁用后,浮点型的特征FG只保留6位精度 |
DISABLE_STRING_TRIM | strig | 'false' | 是否禁用多值字符串特征split后去除前后空格 |
注意:上述配置需要在各种执行环境保持一致:离线与在线一致;训练与推理一致;否则会出现离在线打分不一致的问题。
Hash冲突率
在某数据集上,共计26个不同基数的特征,每个特征都设置hash_bucket_size
为特征基数的10倍,测试结果如下:
hash类型 | 特征基数总和 | 分箱数总和 | hash冲突率 |
std::hash | 882774549 | 840065238 | 4.8381% |
cityhash | 882774549 | 840072446 | 4.8373% |
std+cityhash | 882774549 | 840075948 | 4.8369% |
cityhash+multiplicative | 882774549 | 840072195 | 4.8373% |
std+multiplicative | 882774549 | 840077306 | 4.8367% |
综上,推荐使用std::hash
+ MultiplicativeHash
相结合的方式来优化模型效果,其中std::hash
已默认开启;MultiplicativeHash
因为需要向下兼容的原因,默认关闭,需要用户按照以下方法手动开启。
另外,CityHash
是一种理论上均匀性更好的方法,但在该数据集上并未体现出明显的优势,用户可在自己的数据集上进一步测试。
在线打分服务端配置
通过服务端的环境变量来配置;具体可以通过EasyRec Processor或者TorchEasyRec Processor的服务配置来设置。
{
"processor_envs": [
{
"name": "USE_MULTIPLICATIVE_HASH",
"value": "true"
}
]
}
离线作业的配置
在MaxCompute
环境执行FG的离线任务,具体可参考在离线任务中使用FG。
具体地,参考如下代码:
from pyfg066 import run_on_odps
fg_task = run_on_odps.FgTask(...)
fg_task.add_fg_setting('USE_CITY_HASH_TO_BUCKETIZE', 'false')
fg_task.add_fg_setting('USE_MULTIPLICATIVE_HASH', 'true')
fg_task.run(o)
使用pyfg API时的配置
在使用pyfg API时,比如,一边训练一边做FG,可以通过如下方法来配置。
import pyfg
pyfg.set_env('USE_MULTIPLICATIVE_HASH', 'true')
pyfg.set_env('USE_CITY_HASH_TO_BUCKETIZE', 'false')