Создайте счетчик состояний с TF Dataset и Eager

1

Я пытаюсь добавить накопитель в конвейер Dasaset Tensorflow. В принципе, у меня есть это:

  def _filter_bcc_labels(self, labels, labels_table, bcc_count):
        bg_counter = tf.zeros(shape=(), dtype=tf.int32)

        def _add_to_counter():
            tf.add(bg_counter, 1)
            # Here the bg_counter is always equal to 0
            tf.Print(bg_counter, [bg_counter])
            return tf.constant(True)

        return tf.cond(tf.greater_equal(bg_counter, tf.constant(bcc_count, dtype=tf.int32)),
                                        true_fn=lambda: tf.constant(False),
                                        false_fn=_add_to_counter)


ds = ds.filter(lambda file, position, img, lbls: self._filter_bcc_labels(lbls, {"BCC": 0, "BACKGROUND": 1}, 10))

Моя цель здесь - bg_counter при достижении tf.cond false_fn но моя переменная всегда имеет значение 0, оно никогда не увеличивается. Кто-то может объяснить мне, что происходит?

Имейте в виду, что я использую TF нетерпеливо, и я не могу использовать ds.make_initializable_iterator() затем bg_counter исходное значение bg_counter. Спасибо

Теги:
tensorflow
tensorflow-datasets

3 ответа

0
Лучший ответ

Я действительно нашел ответ на свой вопрос благодаря @MPękalski за то, что указал мне в правильном направлении. Теперь код выглядит следующим образом:

def _filter_bcc_labels(self, bg_counter, labels, labels_table, bcc_count):
        bg_counter = tf.zeros(shape=(), dtype=tf.int32)

        def _add_to_counter():
            nonlocal bg_counter
            bg_counter.assign_add(1)
            # Prints the counter value
            tf.Print(bg_counter, [bg_counter])
            return tf.constant(True)

        return tf.cond(tf.greater_equal(bg_counter, tf.constant(bcc_count, dtype=tf.int32)),
                                        true_fn=lambda: tf.constant(False),
                                        false_fn=_add_to_counter)


bg_counter = tf.get_variable("bg_counter_" + step, initializer=lambda: tf.zeros(shape=[], dtype=tf.int32), dtype=tf.int32, trainable=False)
ds = ds.filter(lambda file, position, img, lbls: self._filter_bcc_labels(bg_counter, lbls, {"BCC": 0, "BACKGROUND": 1}, 10))

Имейте в виду, что это решение не работает, если вы дважды повторяете в своем наборе данных, поскольку счетчик не получает повторной инициализации в этом случае. И если вы переместите bg_counter = tf.get_variable("bg_counter_" + step, initializer=lambda: tf.zeros(shape=[], dtype=tf.int32), dtype=tf.int32, trainable=False) внутри ds.filter то вы получаете объект 'Tensor' object has no attribute 'assign_add' из-за режима ожидания.

Если вы действительно хотите сделать это правильно, вам нужно создать счетчик, когда вы перебираете свои партии, за пределами конвейера набора данных.

1

Возможно, вы захотите обернуть свой счетчик в классе, поскольку переменные в Eager будут удалены, когда они выйдут из области видимости.

Код:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
tf.enable_eager_execution()
import tensorflow.contrib.eager as tfe

dataset = tf.data.Dataset.from_tensor_slices(([1,2,3,4,5], [-1,-2,-3,-4,-5]))

class My(object):
    def __init__(self):
        self.x = tf.get_variable("mycounter", initializer=lambda: tf.zeros(shape=[], dtype=tf.float32), dtype=tf.float32
                                 , trainable=False) 

v = My()
print(v.x)
tf.assign(v.x,tf.add(v.x,1.0))
print(v.x)

def map_fn(x,v):
    tf.cond(tf.greater_equal(v.x, tf.constant(5.0))
           ,lambda: tf.constant(0.0)
           ,lambda: tf.assign(v.x,tf.add(v.x,1.0))
           )
    return x

dataset = dataset.map(lambda x,y: map_fn(x,v)).batch(1)

for batch in tfe.Iterator(dataset):
    print("{} | {}".format(batch, v.x))

Журнал:

<tf.Variable 'mycounter:0' shape=() dtype=float32, numpy=0.0>    
<tf.Variable 'mycounter:0' shape=() dtype=float32, numpy=1.0>    
[1] | <tf.Variable 'mycounter:0' shape=() dtype=float32, numpy=2.0>
[2] | <tf.Variable 'mycounter:0' shape=() dtype=float32, numpy=3.0>
[3] | <tf.Variable 'mycounter:0' shape=() dtype=float32, numpy=4.0>
[4] | <tf.Variable 'mycounter:0' shape=() dtype=float32, numpy=5.0>    
[5] | <tf.Variable 'mycounter:0' shape=() dtype=float32, numpy=5.0>

Рабочий пример: https://www.kaggle.com/mpekalski/tfe-conditional-stateful-counter

0

Я думаю, что то, что вы пытаетесь сделать, требует метода assign_add(), а не метода add. Обратите внимание, что аргумент должен быть переменной.

Также будьте осторожны с tf.cond для общего использования за пределами нетерпения. Здесь обсуждается одно и то же.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню