본문 바로가기

DeepLearning Specialization(Andrew Ng)/Convolutional Neural Networks

[Week 3] Quiz & Programming Assignments

728x90

# Quiz

 앞서 IoU threshold를 왜 정하나 했는데, 위 사진에서 나무에 2가지 박스가 겹쳐있다. 위와 같은 경우, 두 박스가 겹친부분이 0.5를 넘지 않으므로 다른 객체로 보는 것. 

 따라서 위 사진에서 남는 박스 수는 5개.

 

# Programming Assignments

1. YOLO, Anchor box

 

 

- YOLO와 Anchor box를 이해하기 쉬운 아주 좋은 그림이다.

 

- 모델을 만들고 실제로 image를 넣으면, 알고리즘에 따라 Pc의 확률은 각각 다르겠지만, (anchor box가 5개, 19x19 image, 80 class)라고 했을 때, 각 셀마다 5개의 box를 만들어 낼 것이다(물론 그 중에서 Pcxclass값이 최고인게 의미가 있겠지만은...). 총 19x19x5 개의 박스가 만들어지며 우리는 non-max suppression으로 필요없는 박스들을 정리해야한다.

 

cf) non-max suppression은 낮은 score의 박스들을 제거하고(Pc던 Pc x class던) -> 많이 겹쳐있는 박스들이 있으면 하나만 고른다. 

 

2. Keras.argmax() 함수

a= np.random.randn(19*19, 5,4)
b= K.argmax(a, axis = -1)
print(b)
sess = tf.Session()
sess.run(b)

#output
'''
Tensor("ArgMax_2:0", shape=(361, 5), dtype=int64)
array([[0, 0, 3, 2, 3],
       [3, 2, 1, 2, 2],
       [3, 3, 3, 3, 1],
       ..., 
       [0, 0, 2, 3, 3],
       [2, 0, 2, 1, 2],
       [2, 0, 0, 3, 0]])
       '''

 이걸 실행하면 위와 같은 결과가 나온다. 즉, axis를 마지막 dimension으로 했으므로 0~4 중 제일 큰 값의 인덱스값을 반환하는 것.

 

3. def yolo_filter_boxes

# GRADED FUNCTION: yolo_filter_boxes

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 (19, 19, 5, 1)
    boxes -- tensor of shape (19, 19, 5, 4)
    box_class_probs -- tensor of shape (19, 19, 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
    ### START CODE HERE ### (≈ 1 line)
    box_scores = box_confidence * box_class_probs
    ### END CODE HERE ###
    
    # Step 2: Find the box_classes using the max box_scores, keep track of the corresponding score
    ### START CODE HERE ### (≈ 2 lines)
    box_classes = K.argmax(box_scores, axis = -1)
    box_class_scores = K.max(box_scores, axis=-1)
    ### END CODE HERE ###
    
    # 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)
    ### START CODE HERE ### (≈ 1 line)
    filtering_mask = box_class_scores >= threshold
    ### END CODE HERE ###
    
    # Step 4: Apply the mask to box_class_scores, boxes and box_classes
    ### START CODE HERE ### (≈ 3 lines)
    scores = tf.boolean_mask(box_class_scores, filtering_mask)
    boxes = tf.boolean_mask(boxes, filtering_mask)
    classes = tf.boolean_mask(box_classes, filtering_mask)
    ### END CODE HERE ###
    
    return scores, boxes, classes

- box_scores = (19,19,5,80)

- box_classes = (19,19,5,1)

- box_class_scores = (19,19,5,1)

- filtering_mask = (19,19,5,1)

- scores = box_class_scores 중에서 mask에서 True인 것만 쭈욱 벡터로 나열됨 => (?,)

- boxes = 원래 (19,19,5,4) 였는데, mask 적용되어서 (,4)로 됨. 예를 들어 어떤 cell에 특정 box가 mask를 충족시켰다면,충족시킨 bx,by,bh,bw 모두 broadcast되어 나옴. 

- classes = (?,)

 

with tf.Session() as test_a:
    box_confidence = tf.random_normal([19, 19, 5, 1], mean=1, stddev=4, seed = 1)
    boxes = tf.random_normal([19, 19, 5, 4], mean=1, stddev=4, seed = 1)
    box_class_probs = tf.random_normal([19, 19, 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))

output:

scores[2] = 10.7506
boxes[2] = [ 8.42653275  3.27136683 -0.5313437  -4.94137383]
classes[2] = 7
scores.shape = (?,)
boxes.shape = (?, 4)
classes.shape = (?,)

 ?는 mask를 통과한 cell, box의 개수를 의미함. 이게 벡터형식으로 쭉 나열되도 상관없는 이유는, 어차피 우리가 알고자 하는 것은 bounding box의 위치과 score, class 이기 때문이다. 19x19 셀 중 어느 셀이 박스와 매칭이 되는지, 어떤 anchor box인지는 필요없음. 

 

 왜 tf.boolean_mask가 shape를 ?로 출력하는지는 모르겠다. 

 

- 위의 코드를 정리하자면,

  • box_scores 는 Pc x Class 값을 나타내는 것으로 (19,19,5,80) 형태이다.
  • 여기서 각 box 별 최대값을 뽑아내어 class를 할당한 것이 box_classes
  • 그리고 그 class에 해당하는 Pc x Class 값(box 별 최대값) 을 box_score에 할당.
  • 그리고 mask를 씌어서 벡터로 쭈욱 나열한 것은 위의 설명과 같다.
  • 즉, 지금까지 한 것은 각 셀의 박스별 최대 prob를 갖는 bounding box를 구한 것. 
  • 따라서 mask 를 적용하기 전에는 19x19x5 개의 box가 있는 것.

4. non-max

 

앞서 19x19x5 개의 bounding box를 만들었다면, score 값이 thresohold 이상인 box들만 쭈욱 뽑는다.

그리고 그 수많은 박스들 중 겹치는 것을 non-max 기법으로 제거한다. 

728x90