ChunML / ssd-tf2

A super clean implementation of SSD (Single Shot MultiBox Detector) made possible by Tensorflow 2.0
MIT License
115 stars 54 forks source link

I have a Question of your config.yaml, anchor.py #5

Closed wjddyd66 closed 4 years ago

wjddyd66 commented 4 years ago

Your Code work well! But I have Some question

I read this Paper and I don't know why you define this parameter

config.yml

SSD300:
  ratios: [[2], [2, 3], [2, 3], [2, 3], [2], [2]]
  scales: [0.1, 0.2, 0.375, 0.55, 0.725, 0.9, 1.075]
  fm_sizes: [38, 19, 10, 5, 3, 1]
  image_size: 300

SSD512:
  ratios: [[2], [2, 3], [2, 3], [2, 3], [2], [2], [2]]
  scales: [0.07, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 1.05]
  fm_sizes: [64, 32, 16, 8, 6, 4, 1]
  image_size: 512


anchor.py

import itertools
import math
import tensorflow as tf

def generate_default_boxes(config):
    """ Generate default boxes for all feature maps

    Args:
        config: information of feature maps
            scales: boxes' size relative to image's size
            fm_sizes: sizes of feature maps
            ratios: box ratios used in each feature maps

    Returns:
        default_boxes: tensor of shape (num_default, 4)
                       with format (cx, cy, w, h)
    """
    default_boxes = []
    scales = config['scales']
    fm_sizes = config['fm_sizes']
    ratios = config['ratios']

    for m, fm_size in enumerate(fm_sizes):
        for i, j in itertools.product(range(fm_size), repeat=2):
            cx = (j + 0.5) / fm_size
            cy = (i + 0.5) / fm_size
            default_boxes.append([
                cx,
                cy,
                scales[m],
                scales[m]
            ])

            default_boxes.append([
                cx,
                cy,
                math.sqrt(scales[m] * scales[m + 1]),
                math.sqrt(scales[m] * scales[m + 1])
            ])

            for ratio in ratios[m]:
                r = math.sqrt(ratio)
                default_boxes.append([
                    cx,
                    cy,
                    scales[m] * r,
                    scales[m] / r
                ])

                default_boxes.append([
                    cx,
                    cy,
                    scales[m] / r,
                    scales[m] * r
                ])

    default_boxes = tf.constant(default_boxes)
    default_boxes = tf.clip_by_value(default_boxes, 0.0, 1.0)

    return default_boxes

In paper Description if Use SSD300 $$m=6, s{min}=0.1, s{max}=0.9$$ $$ sk = s{min}+\frac{s{max}-s{min}}{m}(k-1) \rightarrow 0.1+\frac{0.8}{5}(k-1)$$ So, I think

config.yml SSD300: ratios: [2,3] scales: [0.1, 0.26, 0.42, 0.58, 0.74, 0.9,1.06] fm_sizes: [38, 19, 10, 5, 3, 1] image_size: 300

...

anchor.py

import itertools
import math
import tensorflow as tf

def generate_default_boxes(config):
    """ Generate default boxes for all feature maps

    Args:
        config: information of feature maps
            scales: boxes' size relative to image's size
            fm_sizes: sizes of feature maps
            ratios: box ratios used in each feature maps

    Returns:
        default_boxes: tensor of shape (num_default, 4)
                       with format (cx, cy, w, h)
    """
    default_boxes = []
    scales = config['scales']
    fm_sizes = config['fm_sizes']
    ratios = config['ratios']

    for m, fm_size in enumerate(fm_sizes):
        for i, j in itertools.product(range(fm_size), repeat=2):
            cx = (j + 0.5) / fm_size
            cy = (i + 0.5) / fm_size
            default_boxes.append([
                cx,
                cy,
                scales[m],
                scales[m]
            ])

            default_boxes.append([
                cx,
                cy,
                math.sqrt(scales[m] * scales[m + 1]),
                math.sqrt(scales[m] * scales[m + 1])
            ])

            for ratio in ratios:
                r = math.sqrt(ratio)
                default_boxes.append([
                    cx,
                    cy,
                    scales[m] * r,
                    scales[m] / r
                ])

                default_boxes.append([
                    cx,
                    cy,
                    scales[m] / r,
                    scales[m] * r
                ])

    default_boxes = tf.constant(default_boxes)
    default_boxes = tf.clip_by_value(default_boxes, 0.0, 1.0)

    return default_boxes
wjddyd66 commented 4 years ago

Sorry I read Paper Again..... Your Code is Correct But i have a question more.....

In paper Loss Function is Like this image

And your code is Like this

@tf.function
def train_step(imgs, gt_confs, gt_locs, ssd, criterion, optimizer):
    with tf.GradientTape() as tape:
        confs, locs = ssd(imgs)
        conf_loss, loc_loss = criterion(
            confs, locs, gt_confs, gt_locs)
        loss = conf_loss + loc_loss
        l2_loss = [tf.nn.l2_loss(t) for t in ssd.trainable_variables]
        l2_loss = args.weight_decay * tf.math.reduce_sum(l2_loss)
        loss += l2_loss

    gradients = tape.gradient(loss, ssd.trainable_variables)
    optimizer.apply_gradients(zip(gradients, ssd.trainable_variables))

    return loss, conf_loss, loc_loss, l2_loss


Why you add l2_loss??....

GreenD93 commented 4 years ago

@wjddyd66 I think it is just the additional term for preventing overfitting called by "L2 regularization".

ChunML commented 4 years ago

Sorry, I'm late. As @GreenD93 has already stated, that's L2 loss is for preventing overfishing. In the paper, there will be something about decay = 5e-4. That decay stands for L2 term. In PyTorch, you can add decay when initializing the optimizer and l2 loss will be computed automatically. But we have to do it by ourselves in Tensorflow.

dae-sun commented 3 years ago

Your Code work well! But I have Some question

I read this Paper and I don't know why you define this parameter

config.yml

SSD300:
  ratios: [[2], [2, 3], [2, 3], [2, 3], [2], [2]]
  scales: [0.1, 0.2, 0.375, 0.55, 0.725, 0.9, 1.075]
  fm_sizes: [38, 19, 10, 5, 3, 1]
  image_size: 300

SSD512:
  ratios: [[2], [2, 3], [2, 3], [2, 3], [2], [2], [2]]
  scales: [0.07, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 1.05]
  fm_sizes: [64, 32, 16, 8, 6, 4, 1]
  image_size: 512

anchor.py

import itertools
import math
import tensorflow as tf

def generate_default_boxes(config):
    """ Generate default boxes for all feature maps

    Args:
        config: information of feature maps
            scales: boxes' size relative to image's size
            fm_sizes: sizes of feature maps
            ratios: box ratios used in each feature maps

    Returns:
        default_boxes: tensor of shape (num_default, 4)
                       with format (cx, cy, w, h)
    """
    default_boxes = []
    scales = config['scales']
    fm_sizes = config['fm_sizes']
    ratios = config['ratios']

    for m, fm_size in enumerate(fm_sizes):
        for i, j in itertools.product(range(fm_size), repeat=2):
            cx = (j + 0.5) / fm_size
            cy = (i + 0.5) / fm_size
            default_boxes.append([
                cx,
                cy,
                scales[m],
                scales[m]
            ])

            default_boxes.append([
                cx,
                cy,
                math.sqrt(scales[m] * scales[m + 1]),
                math.sqrt(scales[m] * scales[m + 1])
            ])

            for ratio in ratios[m]:
                r = math.sqrt(ratio)
                default_boxes.append([
                    cx,
                    cy,
                    scales[m] * r,
                    scales[m] / r
                ])

                default_boxes.append([
                    cx,
                    cy,
                    scales[m] / r,
                    scales[m] * r
                ])

    default_boxes = tf.constant(default_boxes)
    default_boxes = tf.clip_by_value(default_boxes, 0.0, 1.0)

    return default_boxes

In paper Description if Use SSD300 $$m=6, s{min}=0.1, s{max}=0.9$$ $$ sk = s{min}+\frac{s{max}-s{min}}{m}(k-1) \rightarrow 0.1+\frac{0.8}{5}(k-1)$$ So, I think

config.yml SSD300: ratios: [2,3] scales: [0.1, 0.26, 0.42, 0.58, 0.74, 0.9,1.06] fm_sizes: [38, 19, 10, 5, 3, 1] image_size: 300

...

anchor.py

import itertools
import math
import tensorflow as tf

def generate_default_boxes(config):
    """ Generate default boxes for all feature maps

    Args:
        config: information of feature maps
            scales: boxes' size relative to image's size
            fm_sizes: sizes of feature maps
            ratios: box ratios used in each feature maps

    Returns:
        default_boxes: tensor of shape (num_default, 4)
                       with format (cx, cy, w, h)
    """
    default_boxes = []
    scales = config['scales']
    fm_sizes = config['fm_sizes']
    ratios = config['ratios']

    for m, fm_size in enumerate(fm_sizes):
        for i, j in itertools.product(range(fm_size), repeat=2):
            cx = (j + 0.5) / fm_size
            cy = (i + 0.5) / fm_size
            default_boxes.append([
                cx,
                cy,
                scales[m],
                scales[m]
            ])

            default_boxes.append([
                cx,
                cy,
                math.sqrt(scales[m] * scales[m + 1]),
                math.sqrt(scales[m] * scales[m + 1])
            ])

            for ratio in ratios:
                r = math.sqrt(ratio)
                default_boxes.append([
                    cx,
                    cy,
                    scales[m] * r,
                    scales[m] / r
                ])

                default_boxes.append([
                    cx,
                    cy,
                    scales[m] / r,
                    scales[m] * r
                ])

    default_boxes = tf.constant(default_boxes)
    default_boxes = tf.clip_by_value(default_boxes, 0.0, 1.0)

    return default_boxes

Could you explain why this repo is right? I didn't understand...