Ejemplo n.º 1
0
def test_curricularface_inference_mode():
    _check_layer(CurricularFace(5, 10, s=1.31, m=0.5))
Ejemplo n.º 2
0
def test_curricularface_with_cross_entropy_loss():
    emb_size = 4
    n_classes = 3
    s = 3.0
    m = 0.1

    # fmt: off
    features = np.array(
        [
            [1, 2, 3, 4],
            [5, 6, 7, 8],
        ],
        dtype="f",
    )
    target = np.array([0, 2], dtype="l")
    mask = np.array([[1, 0, 0], [0, 0, 1]], dtype="l")  # one_hot(target)

    weight = np.array(
        [
            [0.1, 0.2, 0.3, 0.4],
            [1.1, 3.2, 5.3, 0.4],
            [0.1, 0.2, 6.3, 0.4],
        ],
        dtype="f",
    )
    # fmt: on

    layer = CurricularFace(emb_size, n_classes, s, m)
    layer.weight.data = torch.from_numpy(weight.T)
    loss_fn = nn.CrossEntropyLoss(reduction="none")

    normalized_features = normalize(features)  # 2x4
    normalized_projection = normalize(weight)  # 3x4

    cosine = normalized_features @ normalized_projection.T  # 2x4 * 4x3 = 2x3
    logit = cosine[mask.astype(np.bool)].reshape(-1, 1)

    sine = np.sqrt(1.0 - np.power(logit, 2))
    cos_theta_m = logit * np.cos(m) - sine * np.sin(m)

    final_logit = np.where(logit > np.cos(np.pi - m), cos_theta_m,
                           logit - np.sin(np.pi - m) * m)

    cos_mask = cosine > cos_theta_m
    hard = cosine[cos_mask]

    t = np.mean(logit) * 0.01 - (1 - 0.01) * 0

    cosine[cos_mask] = hard * (t + hard)  # 2x3
    for r, c in enumerate(target):
        cosine[r, c] = final_logit[r, 0]
    cosine = cosine * s  # 2x3

    expected_loss = cross_entropy(cosine, mask, 1)
    actual = (loss_fn(
        layer(torch.from_numpy(features), torch.LongTensor(target)),
        torch.LongTensor(target),
    ).detach().numpy())

    assert np.allclose(expected_loss, actual, atol=EPS)

    # reinitialize layer (t is changed)
    layer = CurricularFace(emb_size, n_classes, s, m)
    layer.weight.data = torch.from_numpy(weight.T)
    loss_fn = nn.CrossEntropyLoss(reduction="mean")

    expected_loss = cross_entropy(cosine, mask, 1)
    actual = (loss_fn(
        layer(torch.from_numpy(features), torch.LongTensor(target)),
        torch.LongTensor(target),
    ).detach().numpy())

    assert np.isclose(expected_loss.mean(), actual, atol=EPS)

    # reinitialize layer (t is changed)
    layer = CurricularFace(emb_size, n_classes, s, m)
    layer.weight.data = torch.from_numpy(weight.T)
    loss_fn = nn.CrossEntropyLoss(reduction="sum")

    expected_loss = cross_entropy(cosine, mask, 1)
    actual = (loss_fn(
        layer(torch.from_numpy(features), torch.LongTensor(target)),
        torch.LongTensor(target),
    ).detach().numpy())
    assert np.isclose(expected_loss.sum(), actual, atol=EPS)