FreeRec
data
此部分模块包含了一些推荐系统数据集的定义以及预处理方法.
datasets
RecDataSet
freerec.data.RecDataSet 提供了一般 (未处理) 的数据集的框架, 它的子类必须提供:
- _cfg 的类属性, 其中定义了数据集的 Fields;
- raw2data 方法, 其返回迭代器, 该迭代器应当按行输出数据.
此外, 我们默认数据集已经预先区分好了训练集, 验证集, 测试集.
在实例化数据集之后, RecDataSet 会自动将原先的数据集保存为 feather 的二进制格式, 需要特别注意的是, 保存的数据是预处理后 (标准化, 标签映射等) 的. 这一操作在 MovieLens1M 上能够节约 1/3 的时间. 到此我们构建了最基本的 datapipe, 该 datapipe 会返回 _DEFAULT_CHUNK_SIZE = 51200 大小的 DataFrame, 其中每一列均是一个对应的 Field.
Postprocessor [TODO]
Postprocessor 提供了后处理 datapipe 的功能:
- PinMemory|pin_ : 提供了保存 buffer_size 的数据于内存以及 shuffle 的功能;
- [TODO] Sharder|shard_: 在 dataloader num_workers > 0 的时候采用, 但是我不确定这里头是否有 bug, 小心使用 ! 此外根据 PyTorch 官方给出的教程, sharding 操作应当放置于复杂的操作之前, shuffle 操作之后;
- SubFielder|subfield_: 有些时候, 我们只需要部分 fields 训练, 此时用 SubFielder 即可;
- Chunker|chunk_: 提供 batch 功能, 需要设定 batch_size;
- Frame2Dict|dict_: DataFrame -> Dict[str, List];
- List2Dict|list_: DataFrame -> List[List];
- ToTensor|tensor_: Dict -> Dict[str, Tensor], 暂时还不提供 List -> List[Tensor] 功能;
- Grouper|group_: 按照 group 输出, 比如 (USER, ITEM, TARGET), 就会输出 Dict, Dict, List (因为默认target 是默认 List 输出以方便定义 train, evaluate);
- [TODO] NegativeSamper|sample_negative_: 采样负样本, 比如我们采用 100 items 推荐一的类型的 ranking 方式, 以及 BPR 可能会很有用, 但是在需要全部负样本的时候又比较尴尬;
此外, 注意到, 所有的 postprocessors 都以 _ 结尾, 这是为了防止和官方定义发生冲突, 建议遵循这一策略.
basepipe = MovieLens1M_(cfg.root)
datapipe = basepipe.pin_(buffer_size=cfg.buffer_size).shard_().sample_negative_(num_negatives=cfg.num_negs)
datapipe = datapipe.chunk_(batch_size=cfg.batch_size).dict_().tensor_().group_()
fields
Field
Field 包括两种数据类型的 Field:
- SparseField
- DenseField
定义 Field 需要传入属性:
- name;
- na_value: 缺失值;
- dtype: int|str|float, 注意最后转换为 tensor 所对应的 dtype 为 torch.long|torch.long|torch.float32
- transformer: 预处理, 比如标准化, 编码等, 具体参考 preprocessing;
- tags: tags 是每个 Field 的标签, 我们可以通过标签来选择合适的 Field;
一些比较常用的方法:
- match: field.match(tags) 返回该 Field 是否具有指定的 tags;
- embed: 为 Field 设定 embeddings, 其中 SparseField 采用 nn.Embedding, DenseField 采用 nn.Linear 定义;
- loop_up: 查询并返回合适的 embeddings;
- count: 返回 SparseField 中的类别数目;
Tokenizer [TODO]
Tokenizer 将不同的 fields 集中在一起, 其中实现的一些功能会比较有帮助:
- embed: 为满足特定 tags 的 fields 设定 embeddings;
- group_by: 删选出满足 tags 的 fields: List;
- [TODO] flatten_cat: 展开并连接, 是不是应该删掉了, 感觉不具有一般性;
- calculate_dimension: 计算满足 tags 的 fields 的 dimension 之和, 在定义模型的时候会很有用 !
preprocessing
- X2X: x -> x;
- Label2Index: 标签转换为 [0, count - 1];
- Binarizer: 二元化 (> threshold 为 1, 否则为 0);
- StandardScaler: 标准化, (x - mean) / std;
- MinMaxScaler: (x - min) / (max - min);
tags
class Tag:
__slot__ = ('name')
def __init__(self, name) -> None:
self.name = name
def __str__(self) -> str:
return self.name
SPARSE = Tag('Sparse')
DENSE = Tag('Dense')
ID = Tag('ID')
USER = Tag('User')
ITEM = Tag('Item')
FEATURE = Tag('Feature')
TARGET = Tag('Target')
utils [TODO]
- [TODO] dataloder: 以后根据 DataLoader2 可能要修改下
layers
cross
- FM: Tensor: B x [d1 + d2 ...] -> Tensor: B x 1;
models
RecSysArch
目前该框架实现了:
- to: 以保证 self.device 是有效的;
- initialize: 初始化, 现在仅仅是用 xavier_normal_ 初始化;
criterions
Regularizer [TODO]
我发现在推荐系统里面老师喜欢对不同的部分施加不同比例的正则化项, 所以如果只是用 optimizer 中的 weight_decay 就不是那么够了, 所以这里就只能在损失的部分自己加上了. 但是现在的实现有一个确定, 每次迭代都会对固定的参数加惩罚, 我发现比如 LightGCN 是只对当前的 batch 所用到的 embeddings 加惩罚的而不是所有的, 所以这里有一个问题. 此外现在只支持 L1, L2.
BaseCriterion
这是基本的损失的类, 基于此可以通过:
-
regulate: 为部分参数添加正则化项;
-
BCELoss: 要求输入 logits 而非概率;
-
BPRLoss: 输入 pos_scores, neg_scores;
-
MSELoss;
-
L1Loss
launcher
这里提供的 Coach 包含了以下内容:
- compile: 通过 monitors 可以指定需要考察的指标;
- train: 训练, 需要自定义 (因为我发现不同的方法差别实在太大, 很难统一);
- evaluate: 评估;
- fit: 按照 1. 评估; 2. 训练 的方式执行 epochs 次, 并最后做总结;
- save: 保存模型;
- save_checkpoint: 保存 checkpoint;
- load_checkpoint: 加载 checkpoint;
- reusme;
- [TODO] save_best: 保证最好的 checkpoint, 用哪个指标呢 ?
- load_dataloader: 加载 dataloader
metrics
metrics 中的函数要求输入按行收集的信息, 通俗的讲, 每一行都是推荐系统给一个 user 推荐的结果, 然后我们会逐行进行运算.
- mean_abs_error;
- mean_squared_error;
- root_mse;
- precision;
- recall;
- hit_rate;
- normalized_dcg;
- mean_reciprocal_rank;
- mean_average_precision;
注意, 每个函数都包括 reduction 的参数, 通过指定 'none' 可以返回每一行的一个结果, 默认是 'mean'.
parser
parser 中定义了 freerec 用到的一些基本参数.
Parser
- parse: 获取指令;
- add_argument: 设置指令;
- set_defaults: 设置默认指令;
- compile: 通过此方法来生成配置;
utils
这里集成了一些有用的函数:
- AverageMeter: 统计工具;
- getLogger: 获取 Logger;
- timemeter: 通过 @timemter("Event) 来统计某个方法的执行时间;
- set_seed: 设置 seed;
- activate_benchmark: cudnn.benchmark, cudnn.deterministic;