Как tensorflow boolean_mask маскирует между двумя тензорами?

#python #tensorflow #keras

#python #тензорный поток #keras

Вопрос:

У меня есть код, как показано ниже:

 def yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = .6):
    """Filters YOLO boxes by thresholding on object and class confidence.

    Arguments:
    box_confidence -- tensor of shape (3, 3, 5, 1)
    boxes -- tensor of shape (3, 3, 5, 4)
    box_class_probs -- tensor of shape (3, 3, 5, 80)
    threshold -- real value, if [ highest class probability score < threshold], then get rid of the corresponding box

    Returns:
    scores -- tensor of shape (None,), containing the class probability score for selected boxes
    boxes -- tensor of shape (None, 4), containing (b_x, b_y, b_h, b_w) coordinates of selected boxes
    classes -- tensor of shape (None,), containing the index of the class detected by the selected boxes

    Note: "None" is here because you don't know the exact number of selected boxes, as it depends on the threshold. 
    For example, the actual output size of scores would be (10,) if there are 10 boxes.
    """

    # Step 1: Compute box scores
    box_scores = np.multiply(box_confidence, box_class_probs)

    # Step 2: Find the box_classes thanks to the max box_scores, keep track of the corresponding score
    box_classes = K.argmax(box_scores, -1)
    box_class_scores = K.max(box_scores, -1)

    # Step 3: Create a filtering mask based on "box_class_scores" by using "threshold". The mask should have the
    # same dimension as box_class_scores, and be True for the boxes you want to keep (with probability >= threshold)
    filtering_mask = K.greater_equal(box_class_scores,threshold)
    # Step 4: Apply the mask to scores, boxes and classes

    print(filtering_mask.shape)
    print(filtering_mask.eval())

    print(box_class_scores.shape)
    print(box_class_scores.eval())
    scores = tf.boolean_mask(box_class_scores, filtering_mask)
    print(scores.eval())
    boxes = tf.boolean_mask(boxes, filtering_mask)
    classes = tf.boolean_mask(box_classes, filtering_mask)

    return scores, boxes, classes


with tf.Session() as test_a:
    box_confidence = tf.random_normal([3, 3, 5, 1], mean=1, stddev=4, seed = 1)
    boxes = tf.random_normal([3, 3, 5, 4], mean=1, stddev=4, seed = 1)
    box_class_probs = tf.random_normal([3, 3, 5, 80], mean=1, stddev=4, seed = 1)
    scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = 0.5)
    print("scores[2] = "   str(scores[2].eval()))
    print("boxes[2] = "   str(boxes[2].eval()))
    print("classes[2] = "   str(classes[2].eval()))
    print("scores.shape = "   str(scores.shape))
    print("boxes.shape = "   str(boxes.shape))
    print("classes.shape = "   str(classes.shape))
  

и это результат:

 (3, 3, 5)
[[[ True  True  True  True  True]
  [ True  True  True  True  True]
  [ True False  True  True  True]]

 [[ True  True  True  True  True]
  [ True  True  True  True  True]
  [ True  True  True  True  True]]

 [[ True  True  True  True False]
  [ True  True  True  True  True]
  [ True  True  True  True  True]]]
(3, 3, 5)
[[[  45.00004959   21.20238304   17.39275742   26.73288918   49.47431946]
  [  22.16205978   27.96604347   12.38916492   33.66600418   62.04590225]
  [ 113.03194427    2.68868852    6.33391762   45.17211914   10.5103178 ]]

 [[   8.22186852   35.88579941   48.54780579   12.48789883   32.40937042]
  [  75.73269653   17.52830696   62.99983597   29.0468502    42.82471848]
  [  72.42234039  108.19727325   36.93912888   40.9789238    36.91137314]]

 [[   1.57321405    3.35663748   16.33576775    5.16499805   19.43038177]
  [  48.13769913   68.20082092   47.06818008    1.82166731   67.30760956]
  [  33.01203537   63.93298721    9.71860027   49.06838989   60.74739456]]]
[  22.63684464   10.29589462   58.76845551   74.67560577   20.25722504
   47.24279022    6.96320772   22.59087944   86.61974335    1.05248117
   57.47060394   92.50878143   16.8335762    23.29385757   78.58971405
    6.95861435   65.61254883   45.47106171   43.53435135   10.0660677
   60.34520721   28.5535984    15.9668026    45.14865494    5.49425364
    2.35473752   29.40540886    2.5579865    46.96302032    9.39739799
   45.78501892   49.42660904   34.68322754   40.72031784   58.91592407
   35.39850616   56.24537277    6.80519342    9.52552414  138.54457092
   14.07888412   56.37608719   69.59171295   25.83714676]
scores[2] = 62.0051
boxes[2] = [-1.89158893  0.7749185   3.57417917 -0.05729628]
classes[2] = 36
scores.shape = (?,)
boxes.shape = (?, 4)
classes.shape = (?,)
  

у меня простой вопрос. как появился scores результат? он содержит 44 элемента, в то время как filtering_mask и box_class_scores имеют 45 элементов(3 * 3 * 5 ) и filtering_mask имеет 2 ложных значения, которые должны составлять 43 элемента. даже если filtering_mask имеет значение 1 false, ни одно из чисел в оценках не совпадает box_class_scores .
кто-нибудь может объяснить мне, как scores вычисляется

Ответ №1:

Проблема не в маскировке, которая работает так, как вы ожидаете. Проблема в том, что вы используете случайные значения в своем графике, поведение которых может быть немного неожиданным. Каждый раз, когда вы вызываете, eval() это действительно вызов run в сеансе по умолчанию. Проблема в том, как случайные значения работают в TensorFlow. Каждый раз, когда run вызывается сеанс, генерируется новое случайное значение. Это означает, что каждый eval вызов выдает результаты, основанные на разных значениях box_confidence , boxes и box_class_probs . Есть возможные способы исправить это, либо просто не использовать генераторы случайных значений в качестве входных данных, либо оценивать все выходные данные в одном вызове run (а не с eval ). Поскольку вы, похоже, пишете тестовый код, один простой способ решить эту проблему — заменить входные данные константами, созданными из случайных значений NumPy.

 import tensorflow as tf
import numpy as np

def yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = .6):
    # ...

with tf.Session() as test_a:
    np.random.seed(1)
    box_confidence = tf.constant(np.random.normal(loc=1, scale=4, size=[3, 3, 5, 1]), dtype=tf.float32)
    boxes = tf.constant(np.random.normal(loc=1, scale=4, size=[3, 3, 5, 4]), dtype=tf.float32)
    box_class_probs = tf.constant(np.random.normal(loc=1, scale=4, size=[3, 3, 5, 80]), dtype=tf.float32
    scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = 0.5)
    print("scores[2] = "   str(scores[2].eval()))
    print("boxes[2] = "   str(boxes[2].eval()))
    print("classes[2] = "   str(classes[2].eval()))
    print("scores.shape = "   str(scores.shape))
    print("boxes.shape = "   str(boxes.shape))
    print("classes.shape = "   str(classes.shape))
  

Или вы все еще можете использовать случайные числа TensorFlow, но использовать переменные для своих входных данных. Разница с переменными заключается в том, что они оценивают свое начальное значение только при инициализации, а затем сохраняют свое значение среди сеансов (до тех пор, пока оно не будет изменено снова), поэтому вы не будете генерировать новые случайные значения каждый раз.

 import tensorflow as tf

def yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = .6):
    # ...

with tf.Session() as test_a:
    box_confidence = tf.Variable(tf.random_normal([3, 3, 5, 1], mean=1, stddev=4, seed = 1)))
    boxes = tf.Variable(tf.random_normal([3, 3, 5, 4], mean=1, stddev=4, seed = 1))
    box_class_probs = tf.Variable(tf.random_normal([3, 3, 5, 80], mean=1, stddev=4, seed = 1))
    # You must initialize the variables
    test_a.run(tf.global_variables_initializer())
    scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = 0.5)
    print("scores[2] = "   str(scores[2].eval()))
    print("boxes[2] = "   str(boxes[2].eval()))
    print("classes[2] = "   str(classes[2].eval()))
    print("scores.shape = "   str(scores.shape))
    print("boxes.shape = "   str(boxes.shape))
    print("classes.shape = "   str(classes.shape))