Dua*_*ane 5 python artificial-intelligence numpy redis
我在AI项目上使用Redis。
这个想法是让多个环境模拟器在许多cpu内核上运行策略。模拟器将体验(状态/操作/奖励元组列表)写入Redis服务器(重播缓冲区)。然后,培训过程将经验作为数据集读取以生成新策略。将新策略部署到模拟器,删除先前运行的数据,然后继续该过程。
大部分经验都记录在“状态”中。通常将其表示为尺寸为80 x 80的大型numpy数组。模拟器会以cpu允许的最快速度生成它们。
为此,是否有人有最好的/最快/最简单的方法来编写大量的numpy数组来进行redis的构想或经验。这些都在同一台计算机上,但是以后可以在一组云服务器上。代码示例欢迎!
我不知道它是否最快,但是您可以尝试类似的方法...
将一个Numpy数组存储到Redis就像这样-see function toRedis():
检索一个Numpy数组是这样的-see function fromRedis():
#!/usr/bin/env python3
import struct
import redis
import numpy as np
def toRedis(r,a,n):
   """Store given Numpy array 'a' in Redis under key 'n'"""
   h, w = a.shape
   shape = struct.pack('>II',h,w)
   encoded = shape + a.tobytes()
   # Store encoded data in Redis
   r.set(n,encoded)
   return
def fromRedis(r,n):
   """Retrieve Numpy array from Redis key 'n'"""
   encoded = r.get(n)
   h, w = struct.unpack('>II',encoded[:8])
   a = np.frombuffer(encoded, dtype=np.uint16, offset=8).reshape(h,w)
   return a
# Create 80x80 numpy array to store
a0 = np.arange(6400,dtype=np.uint16).reshape(80,80) 
# Redis connection
r = redis.Redis(host='localhost', port=6379, db=0)
# Store array a0 in Redis under name 'a0array'
toRedis(r,a0,'a0array')
# Retrieve from Redis
a1 = fromRedis(r,'a0array')
np.testing.assert_array_equal(a0,a1)
Run Code Online (Sandbox Code Playgroud)
您可以通过dtype对Numpy数组的形状进行编码来增加灵活性。我之所以没有这样做,是因为您可能已经知道所有数组都属于一种特定类型,然后代码会变得更大且更难无故读取。
在现代iMac上的大致基准:
80x80 Numpy array of np.uint16   => 58 microseconds to write
200x200 Numpy array of np.uint16 => 88 microseconds to write
Run Code Online (Sandbox Code Playgroud)
关键字:Python,Numpy,Redis,数组,序列化,序列化,键,incr,唯一
小智 7
您还可以考虑使用msgpack-numpy,它提供“编码和解码例程,可以使用高效的 msgpack 格式对 numpy 提供的数值和数组数据类型进行序列化和反序列化。” - 请参阅https://msgpack.org/。
快速概念验证:
import msgpack
import msgpack_numpy as m
import numpy as np
m.patch()               # Important line to monkey-patch for numpy support!
from redis import Redis
r = Redis('127.0.0.1')
# Create an array, then use msgpack to serialize it 
d_orig = np.array([1,2,3,4])
d_orig_packed = m.packb(d_orig)
# Set the data in redis
r.set('d', d_orig_packed)
# Retrieve and unpack the data
d_out = m.unpackb(r.get('d'))
# Check they match
assert np.alltrue(d_orig == d_out)
assert d_orig.dtype == d_out.dtype
Run Code Online (Sandbox Code Playgroud)
在我的机器上,msgpack 的运行速度比使用 struct 快得多:
In: %timeit struct.pack('4096L', *np.arange(0, 4096))
1000 loops, best of 3: 443 µs per loop
In: %timeit m.packb(np.arange(0, 4096))
The slowest run took 7.74 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 32.6 µs per loop
Run Code Online (Sandbox Code Playgroud)
        您可以查看 Mark Setchell 的答案,了解如何将字节实际写入 Redis。下面我重写了函数fromRedis并toRedis考虑了可变维度大小的数组,并且还包括数组形状。
def toRedis(arr: np.array) -> str:
    arr_dtype = bytearray(str(arr.dtype), 'utf-8')
    arr_shape = bytearray(','.join([str(a) for a in arr.shape]), 'utf-8')
    sep = bytearray('|', 'utf-8')
    arr_bytes = arr.ravel().tobytes()
    to_return = arr_dtype + sep + arr_shape + sep + arr_bytes
    return to_return
def fromRedis(serialized_arr: str) -> np.array:
    sep = '|'.encode('utf-8')
    i_0 = serialized_arr.find(sep)
    i_1 = serialized_arr.find(sep, i_0 + 1)
    arr_dtype = serialized_arr[:i_0].decode('utf-8')
    arr_shape = tuple([int(a) for a in serialized_arr[i_0 + 1:i_1].decode('utf-8').split(',')])
    arr_str = serialized_arr[i_1 + 1:]
    arr = np.frombuffer(arr_str, dtype = arr_dtype).reshape(arr_shape)
    return arr
Run Code Online (Sandbox Code Playgroud)