当前,我有以下版本,但这是我的主要瓶颈,而且速度很慢。
def intToBinary(Input):
bStrInput = format(Input, "016b")
bStrInput = list(bStrInput)
bInput = list(map(int, bStrInput))
return bInput
有什么想法可以加快这段代码的速度吗?
我在Tensorflow项目中使用它,用于整数的热编码转换。该函数接受2个字节的整数(范围为[0,65536]),并输出值0和1的整数列表:
>>> intToBinary(50411)
[1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1]
结果通过tInput = torch.tensor(bInput, dtype=torch.uint8)
传递给张量。
答案 0 :(得分:6)
您的版本可以通过不使用中间变量和列表转换来避免一些操作码:
def intToBinary(Input):
return list(map(int, format(Input, "016b")))
但是,您可以通过不先转换为字符串然后再转换为整数来加快速度。如果您只需要位,请使用位操作:
def int_to_binary(v):
return [(v >> i) & 1 for i in range(15, -1, -1)]
这会将输入整数的位向右移15、14等步长,然后用1
屏蔽掉该移位的整数,以每次获取最右边位的位值。 / p>
速度比较,使用1000个随机整数将方差减小到可接受的水平:
>>> import sys, platform, psutil
>>> sys.version_info
sys.version_info(major=3, minor=7, micro=0, releaselevel='final', serial=0)
>>> platform.platform(), psutil.cpu_freq().current / 1000, psutil.cpu_count(), psutil.virtual_memory().total // (1024 ** 3)
('Darwin-17.7.0-x86_64-i386-64bit', 2.9, 8, 16)
>>> from timeit import Timer
>>> from random import randrange
>>> testvalues = [randrange(2**16) for _ in range(1000)]
>>> count, total = Timer("for i in tv: t(i)", "from __main__ import intToBinary as t, testvalues as tv").autorange()
>>> (total / count) * (10 ** 3) # milliseconds
3.2812212200224167
>>> count, total = Timer("for i in tv: t(i)", "from __main__ import int_to_binary as t, testvalues as tv").autorange()
>>> (total / count) * (10 ** 3) # milliseconds
2.2861225200176705
所以int_to_binary()
的速度大约是1.5倍,大约2.3毫秒,可以产生1000个结果,而对于优化的字符串操作版本,它的速度略高于3.3。
在我的计算机上,基本循环和函数调用花费7.4微秒:
>>> count, total = Timer("for i in tv: pass", "from __main__ import testvalues as tv; t = lambda i: None").autorange()
>>> (total / count) * (10 ** 3)
0.007374252940062434
因此基本每次呼叫时间约为3.27微秒,而位操作版本为2.28微秒。
如果您正在使用Tensorflow,您还将有numpy操作可用,它们可以使用numpy.unpackbits()
function将uint8转换为二进制; uint16首先必须是'viewed'作为uint8:
import numpy as np
def int_to_bits_np(v):
return np.unpackbits(np.array([v], dtype=np.uint16).view(np.uint8)).tolist()
这将再次转换为numpy数组back to a list of Python integers,因此仅对一个值进行转换效率不高:
>>> count, total = Timer("for i in tv: t(i)", "from __main__ import int_to_bits_np as t, testvalues as tv").autorange()
>>> (total / count) * (10 ** 3)
2.654717969999183
比您的版本快,比移位快。
您可能可能不想转换回列表,因为numpy数组已经具有适合您的张量的dtype。您还可以在大量值上使用它;例如输入中的全部1000个整数:
def int_to_bits_array(varray):
"""Convert an array of uint16 values to binary"""
return np.unpackbits(varray.reshape(varray.shape[0], 1).view(np.uint8), axis=1)
这是一种更快的方式, 方法 :
>>> testvalues_array = np.array(testvalues, dtype=np.uint16)
>>> int_to_bits_array(testvalues_array)
array([[1, 1, 0, ..., 1, 1, 0],
[0, 1, 1, ..., 1, 0, 0],
[1, 1, 1, ..., 0, 0, 0],
...,
[1, 1, 1, ..., 0, 1, 0],
[0, 0, 0, ..., 1, 1, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=uint8)
>>> count, total = Timer("t(tva)", "from __main__ import int_to_bits_array as t, testvalues_array as tva").autorange()
>>> (total / count) * (10 ** 3) # milliseconds
0.007919690339913358
>>> (total / count) * (10 ** 6) # microseconds
7.919690339913359
是的,即一步将1000个值转换为二进制,并在8微秒内处理所有值。这会线性扩展到更大的数字;在8毫秒内转换了100万个随机值:
>>> million_testvalues_array = np.random.randint(2 ** 16, size=10 ** 6, dtype=np.uint16)
>>> count, total = Timer("t(tva)", "from __main__ import int_to_bits_array as t, million_testvalues_array as tva").autorange()
>>> (total / count) * (10 ** 3) # milliseconds
7.9162722200271665