我在一个AI项目中使用redis。
这个项目的想法是让多个环境模拟器在大量CPU核心上运行策略。模拟器将经验(状态/动作/奖励元组列表)写入redis服务器(重播缓冲区)。然后训练过程将经验作为数据集读取,以生成新的策略。新策略被部署到模拟器中,之前运行的数据被删除,过程继续进行。
经验的主要部分被捕获在“状态”中。通常表示为一个大的numpy数组,尺寸例如80 x 80。这些模拟器会尽可能快地生成这些数组。
为此,有没有人有关于将大量numpy数组写入redis的最佳/最快/最简单的办法的好主意或经验?这都是在同一台机器上进行的,但后来可能会在云服务器集群上进行。欢迎提供代码样本!
回答:
我不知道这是否是最快的,但你可以尝试这样做…
将Numpy数组存储到Redis的方式如下 – 见函数toRedis()
:
- 获取Numpy数组的形状并编码
- 将Numpy数组作为字节附加到形状
- 在提供的键下存储编码后的数组
检索Numpy数组的方式如下 – 见函数fromRedis()
:
- 从Redis中检索对应于提供的键的编码字符串
- 从字符串中提取Numpy数组的形状
- 提取数据并重新填充Numpy数组,调整到原始形状
#!/usr/bin/env python3import structimport redisimport numpy as npdef toRedis(r,a,n): """将给定的Numpy数组 'a' 存储在Redis下的键 'n' 中""" h, w = a.shape shape = struct.pack('>II',h,w) encoded = shape + a.tobytes() # 将编码数据存储在Redis中 r.set(n,encoded) returndef fromRedis(r,n): """从Redis键 'n' 中检索Numpy数组""" encoded = r.get(n) h, w = struct.unpack('>II',encoded[:8]) # 在这里添加切片,否则数组将与原始数组不同 a = np.frombuffer(encoded[8:]).reshape(h,w) return a# 创建80x80的numpy数组来存储a0 = np.arange(6400,dtype=np.uint16).reshape(80,80) # Redis连接r = redis.Redis(host='localhost', port=6379, db=0)# 将数组a0存储在Redis下的名称'a0array'中toRedis(r,a0,'a0array')# 从Redis中检索a1 = fromRedis(r,'a0array')np.testing.assert_array_equal(a0,a1)
你可以通过编码Numpy数组的dtype
和形状来增加更多的灵活性。我没有这样做,因为可能你已经知道你所有的数组都是一种特定的类型,这样做的话代码会变得更大并且更难读,没有任何理由。
现代iMac上的粗略基准测试:
80x80的np.uint16类型的Numpy数组 => 写入时间58微秒200x200的np.uint16类型的Numpy数组 => 写入时间88微秒
关键词:Python, Numpy, Redis, 数组, 序列化, 键, incr, 唯一