FeatureGenerator (FG) は、生データをモデルで利用可能な特徴量に変換するプロセスです。オフラインサンプル生成とオンラインサンプル生成の一貫性を確保するように設計されています。このプロセスは特徴量変換とも呼ばれ、1つ以上の特徴量を変換します。これらの処理を実行するために、さまざまな種類の特徴量オペレーターを利用できます。
特徴量生成は、オフラインサンプル生成とオンラインサンプル生成の両方で必要となる変換のみに焦点を当てます。オフライン段階でのみ必要な変換処理がある場合は、それを FG のオペレーションとして定義しないでください。次の図は、レコメンデーションシステムのアーキテクチャにおける FG モジュールの位置を示しています。
特徴量生成プロセスは、設定ファイルで定義された有向非巡回グラフ (DAG) のトポロジカル順序に従って並列実行される、一連の特徴量オペレーター (FG オペレーター) で構成されます。
設定ファイルの例
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"
}
],
"input_alias": {
"non_exist_field1": "exist_field1",
"non_exist_field2": "exist_field2"
},
"reserves": [
"request_id",
"user_id",
"is_click",
"is_pay",
"sample_weight",
"event_unix_time"
]
}特別な設定項目 input_alias:存在しない可能性のある入力フィールド名を実際のフィールド名に対応付けるディクショナリです。(input_alias 設定は、バージョン 1.0.0 以降でサポートされています。通常、この設定は省略できます。)
ユースケース 1: 長いフィールド名に対して短いエイリアスを設定します。
ユースケース 2: カスタム特徴量オペレーターが 2 つの異なるパラメーターで同じ入力を使用する場合に、2 番目のパラメーター用のエイリアスを設定します。
同じ入力フィールドは、異なる特徴間で再利用できますが、単一の特徴変換内では再利用できません。input_alias を設定することで、この制限を回避できます。
たとえば、カスタム特徴量オペレーターに、両方とも同じフィールド
Aを必要とする 2 つの入力パラメーターがある場合、入力としてAとBの 2 つを設定し、input_aliasを使用して"B": "A"のようにマッピングできます。実行時に、カスタム特徴量オペレーターのパラメーターは (A, B) から (A, A) に変更されます。
入力ドメイン
入力ドメインは、入力の起点となるエンティティを示します。次の 4 種類がサポートされています。
user: ユーザー側の特徴量。ユーザープロファイルとユーザーレベルの統計特徴量が含まれます。
context: 時間、位置、天候など、リクエストごとに変化するコンテキスト特徴量。
item: アイテム側の特徴量。静的なコンテンツ特徴量とアイテムレベルの統計特徴量が含まれます。
feature: 別の特徴量オペレーターの出力。
feature の入力ドメインは特殊で、特徴量オペレーター間の依存関係を設定します。すべての特徴量オペレーターは、有向非巡回グラフ (DAG) を構成します。フレームワークは、トポロジカル順序に従ってこれらの特徴量変換操作を並列実行します。トポロジーは次の図のとおりです。
デフォルトでは、DAG の中間ノードの出力は FG の出力として使用されません。この動作は、stub_type 特徴量設定パラメーターで変更できます。
複数値型と区切り文字
FG は、MaxCompute の複合型と整合する Array や Map などの複雑な入力型をサポートします。
文字列型の多値特徴量は、chr(29) を区切り文字として使用できます。
たとえば、v1^]v2^]v3 では、^] が複数値区切り文字です。これは 2 文字ではなく、ASCII コードが "\x1D" の 1 文字です。この文字を入力するには、emacs では C-q C-5 を、vi では C-v C-5 を押します。
特徴量ビニング (離散化)
フレームワークは、次の 6 種類のビニング操作をサポートします。
hash_bucket_size: 特徴量変換結果をハッシュ化し、剰余演算を適用します。
vocab_list: 特徴量変換結果をリスト内のインデックスにマッピングします。
vocab_dict: 特徴量変換結果を辞書内の値にマッピングします。値は int64 型に変換できる必要があります。vocab_file: ファイルからvocab_listまたはvocab_dictを読み込みます。boundaries: 指定した境界に基づいて、特徴量変換結果を対応するバケット ID に変換します。
num_buckets: 特徴量変換結果をそのままバケット ID として使用します。
hash_bucket_size
変換結果をハッシュ化し、剰余演算を適用します。この方法は、任意の特徴量値型に適用できます。
結果の範囲: [0,
hash_bucket_size)空の値の場合、特徴量ビニングの結果は
hash(default_value)%hash_bucket_sizeとなります。
{
"hash_bucket_size": 128000,
"default_value": "default_value"
}vocab_list
特徴値を vocab_list 配列内の対応するインデックスにマッピングすることで、入力をビン分割します。
vocab_list配列の要素型は、value_typeの設定と同じでなければなりません。num_oov_bucket: 0 以上の整数。未登録語バケットの数。語彙にない (OOV) 入力はすべて、入力値のハッシュに基づいて、
[vocab_list.size(), vocab_list.size()+num_oov_buckets)の範囲の ID が割り当てられます。num_oov_bucketsが正の値の場合、default_bucketize_valueと併用できません。
default_bucketize_value: 語彙にない (OOV) 特徴量値の場合に返される整数の ID 値です。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: 非負の整数。語彙にない (OOV) バケットの数です。語彙にない (OOV) 入力はすべて、入力値のハッシュに基づいて、
[vocab_dict.size(), vocab_dict.size()+num_oov_buckets)の範囲の ID が割り当てられます。num_oov_bucketsが正の値の場合、default_bucketize_valueと併用できません。
default_bucketize_value: 語彙にない (OOV) 特徴量値の場合に返される整数の ID 値です。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: 語彙ファイルへのパスです。ファイルには語彙が含まれ、1 行に 1 つの用語が記載されます。必要に応じてマッピング値を指定できます。相対パスがサポートされています。オンラインサービスをデプロイする際は、
fg.jsonと同じディレクトリに配置する必要があります。トークンのみが存在する場合、行番号 (0 から始まる) にマッピングされます。 値が存在する場合、トークンと値は空白文字 (スペースまたはタブ) で区切られます。 値は
int64型である必要があります。
num_oov_bucketとdefault_bucketize_valueは、上記と同じ意味です。
boundaries
指定したビン境界に基づいて数値特徴量をバケット化します。
boundaries配列の要素型は、value_typeの設定と同じでなければなりません。バケットは左側の境界を含み、右側の境界を含みません。
例えば、
boundaries=[0., 1., 2.]は (-inf, 0.)、[0., 1.)、[1., 2.)、および [2., +inf.) のバケットを生成します。
{
"boundaries": [0.0, 1.0, 2.0],
"default_value": -1
}num_buckets
特徴量変換結果をそのままバケット ID として使用します。この方法は、整数に変換可能な特徴量値に適しています。
結果の範囲: [0,
num_buckets)特徴量値が設定した範囲外の場合は、
default_bucketize_valueが割り当てられます。
{
"num_buckets": 128000,
"default_bucketize_value": 127999
}組み込み特徴量オペレーター
設定方法は特徴量オペレーターによって異なります。DAG のリーフノードになりうるすべての特徴量オペレーターは、特徴量ビニングをサポートします。
詳細については、「組み込み特徴量オペレーター」をご参照ください。
タイプ | 説明 |
id_feature | カテゴリカル特徴量 |
raw_feature | 数値特徴量 |
expr_feature | 式特徴量 |
combo_feature | 組み合わせ特徴量 |
combine_feature | 組み合わせ特徴量 (単一の値に集約) |
lookup_feature | 辞書ルックアップ特徴量 |
match_feature | 主キー-副キー辞書ルックアップ特徴量 |
overlap_feature | オーバーラップ特徴量 |
sequence_feature | シーケンス特徴量 |
text_normalizer | テキスト正規化 |
tokenize_feature | テキストのトークン化 |
bm25_feature | BM25 テキスト関連度特徴量 |
kv_dot_product | KV ベクトル内積 |
str_replace_feature | 文字列置換 |
regex_replace_feature | 正規表現置換 |
slice_feature | 配列スライシング |
オペレーターの組み合わせ
DAG を設定することで、さまざまな組み込みオペレーターを組み合わせて強力な特徴量変換を実行できます。
例 1:シーケンスの先頭 4 要素の平均
{
"features": [
{
"feature_name": "top_n_prices",
"feature_type": "sequence_raw_feature",
"expression": "user:clk_prices",
"separator": ",",
"sequence_length": 4,
"stub_type": true
},
{
"feature_name": "top_n_avg_price",
"feature_type": "expr_feature",
"expression":"reduce_mean(top_n_prices)",
"default_value": "-1",
"variables":["feature:top_n_prices"]
}
]
}例 2:シーケンス要素の条件付き平均
{
"features": [
{
"feature_name": "valid_list",
"feature_type": "expr_feature",
"expression":"clk_times < 10",
"variables":["user:clk_times"],
"value_dimension": 5
},
{
"feature_name": "top_n_prices",
"feature_type": "bool_mask_feature",
"expression": ["user:clk_prices", "feature:valid_list"],
"value_type": "float",
"separator": ","
},
{
"feature_name": "top_n_avg_price",
"feature_type": "expr_feature",
"expression":"reduce_mean(top_n_prices)",
"default_value": "-1",
"variables":["feature:top_n_prices"]
}
]
}注:上記の例では、clk_prices と clk_times は 2 つの並列シーケンスです。
カスタム特徴量オペレーター
カスタム特徴量オペレーターは、プラグインとしてフレームワークにより動的にロードされ、実行されます。
詳細については、「カスタム特徴量オペレーター」をご参照ください。
パフォーマンス最適化
FG モジュールのパフォーマンスは、設定に大きく依存します。 一般原則は、不要なデータ (特徴量) 変換を最小化することです。
オフラインまたはニアライン段階でデータを処理および変換できる場合は、FG 段階 (オンラインスコアリングサービス) で実行しないでください。
パフォーマンスを向上させるために、次のガイドラインに従ってください。
構造化された入力データでは、文字列解析のオーバーヘッドを削減するために、STRING 型ではなく MaxCompute テーブルの複合型 (例:Map、Array) の使用を優先してください。
オンラインスコアリングサービス (「EasyRec Processor」や「TorchEasyRec Processor」など) では、複合型をサポートするために、オンラインストレージとして FeatureStore および FeatureDB を使用します。
lookup_featureでは、mapフィールドに Map 型を使用することを強く推奨します。sequence_feature、overlap_feature、bm25_featureでは、Array 型入力の使用を強く推奨します。match_featureは複合型をサポートしないため、使用を避けてください。代わりに、pkeyとskeyを組み合わせてlookup_featureを使用してください。
データ型変換のオーバーヘッドを回避してください。
raw_featureのvalue_typeは、特別な理由がない限り float 以外の型に設定しないでください。lookup_featureでは、Map<Key, Value>入力のキー型がクエリフィールドの型と一致するようにしてください。num_bucketsタイプの特徴ビニングを設定する場合、value_typeはint64に設定する必要があります。データ列の最適な型がシナリオによって異なる場合は、別の型で列のコピーを追加することを検討してください。
たとえば、フィールドは
lookup_featureのルックアップフィールドとして使用される場合は BIGINT、combo_featureの一部として使用される場合は STRING である必要があります。この場合、必要な型ごとに列のコピーを追加します (BIGINT を 1 つ、STRING を 1 つ)。次は SQL のサンプルコードです。
SELECT int_data, int_data as str_data FROM ...
特徴量の依存関係 (DAG モード) を使用して、共有ロジックと計算を可能な限り再利用してください。
グローバル設定
パラメーター | 型 | デフォルト | 説明 |
USE_CITY_HASH_TO_BUCKETIZE | string | 'false' | 特徴量ビニングのハッシュ関数として CityHash を使用するかどうかを指定します。 |
USE_MULTIPLICATIVE_HASH | string | 'false' | 特徴量ハッシュで剰余演算の代わりに乗法ハッシュを使用するかどうかを指定します。このオプションを推奨します。 |
DISABLE_FG_PRECISION | string | 'true' | 浮動小数点特徴量を小数点以下 6 桁に制約するには 'false' に設定します。デフォルトは 'true' で、この制約を無効にします。 |
DISABLE_STRING_TRIM | string | 'false' | 複数値の文字列特徴量を分割した後に、前後の空白をトリムする処理を無効にするかどうかを指定します。 |
MONITOR_CUSTOM_OP_EVERY_N_SECONDS | string | '0' | カスタムオペレーターのパフォーマンスを監視してパフォーマンスデータを出力する間隔 (秒) を指定します。'0' を指定すると監視は無効になります。 |
注: 上記の設定は、オフラインとオンライン、学習と推論を含むすべての実行環境で一致している必要があります。一致していない場合、オンラインとオフラインのスコアリングに不整合が生じる可能性があります。
ハッシュ衝突率
各特徴量の hash_bucket_size をそのカーディナリティの 10 倍に設定し、カーディナリティが異なる 26 個の特徴量を持つデータセットでテストした結果を以下に示します。
ハッシュタイプ | 総特徴量カーディナリティ | 総ビン数 | ハッシュ衝突率 |
std::hash | 882,774,549 | 840,065,238 | 4.8381% |
cityhash | 882,774,549 | 840,072,446 | 4.8373% |
std+cityhash | 882,774,549 | 840,075,948 | 4.8369% |
cityhash+multiplicative | 882,774,549 | 840,072,195 | 4.8373% |
std+multiplicative | 882,774,549 | 840,077,306 | 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 pyfg105 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 を使用する場合 (例えば、学習時に特徴量生成を実行する場合) は、次の方法で設定できます。
import pyfg
pyfg.set_env('USE_MULTIPLICATIVE_HASH', 'true')
pyfg.set_env('USE_CITY_HASH_TO_BUCKETIZE', 'false')