ChunML/ssd-tf2

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

Closed this issue · 4 comments

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$$
$$ s_k = 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

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??....

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

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.

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$$
$$ s_k = 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...