9个版本

使用旧的Rust 2015

0.12.4 2022年6月12日
0.12.3 2021年4月15日
0.12.2 2019年7月28日
0.12.1 2019年5月4日
0.9.0 2018年3月1日

#547 in 算法

Download history 13/week @ 2024-03-09 2/week @ 2024-03-16 1/week @ 2024-03-23 12/week @ 2024-03-30 5/week @ 2024-04-06

61 每月下载量

GPL-3.0 许可证

20KB
209

Build Status codecov License

Rust中的多臂老虎机算法

Bandit

Cargo

[dependencies]
bandit = "0.12.3"

描述和范围

此库目前仅实现了退火softmax老虎机算法。未来的工作也可能实现其他老虎机算法变体(欢迎提交pull-requests)。

本项目受到了John Myles White所著《网站优化的老虎机算法》一书的很多启发。版权所有2013年John Myles White,978-1-449-34133-6

使用和配置

首先,你需要创建一个带有三个参数的老虎机

let bandit = AnnealingSoftmax::new(arms, DEFAULT_BANDIT_CONFIG.clone(), DEFAULT_CONFIG);

第一个参数是老虎机将要抽取的臂的列表。一个臂可以是实现 Clone + Hash + Eq + Identifiable 特性的任何东西。你很可能总是会派生前三个特性,但最后一个特性 Identifiable 是特殊的。

pub trait Identifiable {
    fn ident(&self) -> String;
}

其实并不特别,它应该很容易实现。添加此附加特性的原因是完整的老虎机状态可以持久化到磁盘(JSON格式),以便稍后可以在算法的确切状态下继续。不幸的是,Hash 不保证使用的哈希算法,并且可能在Rust版本之间发生变化。由于我们希望能够在不同的Rust版本之间加载状态,我们要求该特性能返回一个唯一的、易于序列化的 String 作为臂的唯一标识符。

下一个参数是通用老虎机配置

#[derive(Debug, PartialEq, Clone)]
pub struct BanditConfig {
    /// Log file for logging details about the bandit algorithm
    /// run. What will be logged depends on the bandit algorithm
    /// implementation.
    pub log_file: Option<PathBuf>
}

允许你可选地提供日志文件的路径,其中算法的每一步都会记录到该文件。日志文件是一个简单的csv文件,记录臂抽取状态和奖励更新

SELECT;threads:5;1529824600935
SELECT;threads:18;1529825031483
UPDATE;threads:18;1529825931520;0.1320011111111111
SELECT;threads:9;1529825931560
UPDATE;threads:9;1529826831455;0.1326688888888889
SELECT;threads:14;1529826831506
UPDATE;threads:14;1529827731423;0.13315000000000002
SELECT;threads:7;1529827731455
UPDATE;threads:7;1529828631384;0.12791666666666668
...

最后一个参数是退火softmax算法的特殊配置

#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)]
pub struct AnnealingSoftmaxConfig {
    /// The higher the value the faster the algorithms tends toward selecting
    /// the arm with highest reward. Should be a number between [0, 1.0)
    pub cooldown_factor : f64
}

它目前只有一个选项:cooldown_factor,它可以是0和1.0之间的浮点数。你可以使用此因子来控制退火的快慢。cooldown_factor 越高,算法越快停止探索新臂,并坚持使用迄今为止发现的最高奖励的臂。你可能需要通过实验来找到最适合你特定设置的因子(还有一些工具可以帮助你,见下文)。

在构造和配置你的老虎机之后,你可以开始选择臂

let arm = bandit.select_arm();

并更新武器的奖励

let reward = ... some f64 value
bandit.update(arm, reward);

基本上就是这样。在某个时候,在获得足够的奖励(以及取决于你选择的 cooldown_factor)之后,系统将完全冷却,并始终选择最高奖励的武器。让系统长时间运行是安全的,因为它始终在选择武器和更新,不用担心溢出错误和不一致的强盗状态(这是在单元测试中发现的,感谢单元测试)。

保存和恢复状态

强盗可以将其自身保存到文件中

bandit.save_bandit(<path to save file>);

可以从特定的实现中再次加载强盗

let arms = ... list of arms, as in the initial creation
let bandit_config = ... BanditConfig, like in second parameter from initial creation
let bandit_loaded = AnnealingSoftmax::load_bandit(arms, bandit_config, <path to save file>);

提供的武器不一定必须与从文件中恢复的武器匹配。如果删除了某个武器,它将在加载后被删除。再次保存强盗后,你将丢失存储的奖励。如果添加了新的武器,它将从零奖励开始。

可视化强盗武器选择数据

强盗工具应用允许你分析存储的状态文件和日志文件。详细信息请参阅单独的仓库 bandit_tool。你可以在这里找到网络应用程序:https://ragnaroek.github.io/bandit-tools/

依赖项

~0.9–1.7MB
~37K SLoC