如何使用 MNIST 在张量流中减少权重位或更改为较低位的类型?



我正在执行CNN模型压缩,并试图减少重量位以获得位长度和准确性之间的关系。但是,当我使用TensorFlow网站更改重量的CNN类型时,出现了一个错误:

" TypeError:值传递给paramter'a'的值在允许值列表中没有数据类型INT8:float16,float32,float64,int32,int32,complect64,confffec128"。

似乎重量不能是其他dtype。但是我读了一些论文,例如https://arxiv.org/pdf/1502.02551.pdf。可以将重量的碎屑减少到6磅,4磅,甚至较低位。

我的代码在这里(忽略导入物):

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)
x = tf.placeholder(tf.int8,[None,784])
W = tf.Variable(tf.zeros([784,10]),tf.int8)
b = tf.Variable(tf.zeros([10]),tf.int8)
y = tf.nn.softmax(tf.matmul(x,W)+b)
#the error come out with "y = tf.nn.softmax(tf.matmul(x,W)+b)"

它只是标准张量官方代码,只是更改变量的dtype。我也尝试了tf.cast,但仍然出现错误。

tf.cast(W,tf.int8)
tf.cast(b,tf.int8)

谁能告诉我如何克服这种情况?非常感谢!

TensorFlow不允许少于16位的数字。无论如何,无论如何,少于16位都是不切实际的,因为假设您使用8位(整数4位,4位用于小数),最低的小数为0.0625(1/16-> 4位只有16个不同的数字)。

您所引用的纸张使用16位数字,其中16位在8-8、10-6和14-2位(最初是小数位)分开。它还将变量四舍五入,然后将它们转换为上述位分布,而不仅仅是切断变量而不舍入的变量。


更新:我做了一些挖掘,如果您使用float16或14-2固定的位分布,实际上并没有什么区别:

  • 最低float16小数号: 0.0000610352
  • A或14-2固定位分布的最低小数号: 0.00006103515625

所以我建议,您只使用 float16 instad 位分布,只使用随机舍入算法, 在论文中描述。


更新2:我使用float32float16训练了MNIST数据集。float16网络的执行方式与float32网络几乎相同。该网络具有两个隐藏的层,每个1000个神经元和tf.nn.relu作为激活函数。我使用的标准张量tf.train.GradientDescentOptimizer优化器的学习率为0.1。作为成本函数,我使用了tf.nn.softmax_cross_entropy_with_logits。该网络经过了120个时期的培训,每个600步,批量大小为100。float16网络的测试准确性为 98.1899997673 ,而float32测试准确性为 98.159999986553

一些有趣的链接:

  • GTC关于混合精确培训的讨论
  • caffe的nvidia fork

更新3:我认为在Tensorflow中实现混合精度会很难,因为您必须编写自定义处理以进行后传播。Tensorflow团队已经致力于实施Nativ的一半精度。同时,我认为实现此目的的最佳方法是使用Caffe,那里已经实现了本机混合精度(至少在NVIDIA分支中)。请参阅此票。

由于OP涉及减少权重的精度,但不愿意在实现级别上进行相同的操作,所以我认为这可能会有所帮助:

您可以通过在keras中编写自己的自定义层来降低权重的精度(通过近似于高精度值):/p>

您可以在此处找到一个二进制重量模型的示例:https://github.com/dingke/nn_playground/blob/master/master/binarynet/binarynet/binary_layers.py

您必须编辑层的call()方法,并将权重近似于所需的零件。请参阅下面:

```
def call(self, inputs):
    low_precision_kernel = reduce_precision_by_round_off(self.kernel)
    <--- Use the low precision kernel get the outputs --->
    return outputs
```

self.kernel是在自定义层的build()中定义的。

最新更新