【发布时间】:2021-05-25 07:04:03
【问题描述】:
问题陈述
我正在尝试编写一个函数,该函数将在给定目标稀疏度和一个名为block_shape 的参数的情况下对矩阵进行稀疏化,该参数定义了矩阵中零块的最小大小。目标不必完美实现,但要尽可能接近。
例如,给定以下参数,
>>> matrix = [
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
]
>>> target = 0.5
>>> block_shape = (2, 2)
50% 稀疏度的有效输出可能是
>>> sparse_matrix = sparsify(matrix, target, block_shape)
>>> sparse_matrix
[
[1, 1, 0, 0],
[1, 1, 0, 0],
[0, 0, 1, 1],
[0, 0, 1, 1]
]
>>> sparse_matrix = sparsify(matrix, target, block_shape)
>>> sparse_matrix
[
[1, 0, 0, 1],
[1, 0, 0, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]
]
请注意,输入可能有多个有效的稀疏版本。唯一的标准是尽可能多地到达目标。约束之一是只有形状 block_size 的零点被认为是稀疏的。
例如,在给定参数的情况下,下面的矩阵的稀疏度为 0%
>>> sparse_matrix = sparsify(matrix, target, block_shape)
>>> sparse_matrix
[
[1, 0, 0, 1],
[1, 1, 0, 0],
[0, 1, 1, 1],
[0, 0, 0, 0]
]
到目前为止我所拥有的
目前,我有以下代码
import numpy as np
def sparsify(matrix, target, block_shape=None):
if block_shape is None or block_shape == 1 or block_shape == (1,) or block_shape == (1, 1):
# 1x1 is just bernoulli with p=target
probs = np.random.uniform(size=matrix.shape)
mask = np.zeros(matrix.shape)
mask[probs >= target] = 1.0
else:
if isinstance(block_shape, int):
block_shape = (block_shape, block_shape)
if len(block_shape) == 1:
block_shape = (block_shape[0], block_shape[0])
mask = np.ones(matrix.shape)
rows, cols = matrix.shape
for row in range(rows):
for col in range(cols):
submask = mask[row:row+block_shape[0], col:col+block_shape[1]]
if submask.shape != block_shape:
# we don't care about the edges, cannot partially sparsify
continue
if (submask == 0).any():
# If current (row, col) is already in the sparsified area, skip
continue
prob = np.random.random()
if prob < target:
submask[:, :] = np.zeros(submask.shape)
return matrix * mask, mask
上面代码的问题是,如果块大小不是(1, 1),则与目标不匹配
>>> matrix = np.random.randn(100, 100)
>>> matrix, mask = sparsify(matrix, target=0.5, block_shape=(2, 2))
>>> print((matrix == 0).mean())
0.73
>>> print((mask == 0).mean())
0.73
差异的原因(我认为)
我不确定为什么我没有得到我期望的目标,但我认为这与我检查每个元素的概率而不是整个块的概率有关。但是,我的代码中有跳过条件,所以我认为应该涵盖它
编辑
编辑 1 -- 附加示例
只是再举一些例子。
示例1:给定不同的块大小
>>> sparse_matrix = sparsify(matrix, 0.25, (3, 3))
>>> sparse_matrix
[
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[1, 1, 1, 1]
]
上面的例子是一个有效的稀疏矩阵,虽然稀疏度不是 25%,但另一个有效的结果可能是一个全 1 的矩阵。
示例 2:给定不同的块大小和目标
>>> sparse_matrix = sparsify(matrix, 0.6, (1, 2))
>>> sparse_matrix
[
[0, 0, 0, 0],
[1, 0, 0, 1],
[0, 0, 1, 1],
[1, 1, 0, 0]
]
请注意,(1, 2) 的块中可以放入所有零,并且稀疏度 = 60%
编辑 2 -- 忘记了约束
另一个我忘记提及但尝试合并到我的代码中的约束是零块必须不重叠。
示例 1:以下结果无效
>>> sparse_matrix = sparsify(matrix, 0.5, (2, 2))
>>> sparse_matrix
[
[0, 0, 1, 1],
[0, 0, 0, 1],
[1, 0, 0, 1],
[1, 1, 1, 1]
]
虽然从索引(0, 0) 和(1, 1) 开始的块具有有效的零形状,但结果不符合要求。原因是这些块中只有一个可以被认为是有效的。如果我们将零块标记为z0 和z1,这就是这个矩阵:
[
[z0, z0, 1, 1],
[z0, z0, z1, 1],
[ 1, z1, z1, 1],
[ 1, 1, 1, 1]
]
(1, 1) 处的元素可以被视为属于z0 或z1。这意味着只有一个稀疏块,这使得稀疏度为 25%(而不是 ~44%)。
【问题讨论】: