메뉴 건너뛰기

enjoyTools.net

dlib dnn_metric_learning_ex.cpp

2020.02.07 02:46

꿈돌이 조회 수:4880

번역기 돌린 거

 

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*

    This is an example illustrating the use of the deep learning tools from the

    dlib C++ Library.  In it, we will show how to use the loss_metric layer to do

    metric learning.  

 

    The main reason you might want to use this kind of algorithm is because you

    would like to use a k-nearest neighbor classifier or similar algorithm, but

    you don't know a good way to calculate the distance between two things.  A

    popular example would be face recognition.  There are a whole lot of papers

    that train some kind of deep metric learning algorithm that embeds face

    images in some vector space where images of the same person are close to each

    other and images of different people are far apart.  Then in that vector

    space it's very easy to do face recognition with some kind of k-nearest

    neighbor classifier.  

 

    To keep this example as simple as possible we won't do face recognition.

    Instead, we will create a very simple network and use it to learn a mapping

    from 8D vectors to 2D vectors such that vectors with the same class labels

    are near each other.  If you want to see a more complex example that learns

    the kind of network you would use for something like face recognition read

    the dnn_metric_learning_on_images_ex.cpp example.

 

    You should also have read the examples that introduce the dlib DNN API before 

    continuing.  These are dnn_introduction_ex.cpp and dnn_introduction2_ex.cpp.

 

    이것은 Dlib C++ 라이브러리의 딥러닝 도구 사용을 보여 주는 예입니다.

    여기서는 loss_metric 계층을 사용하여 메트릭 학습을 수행하는 방법을 보여줍니다.

 

    이러한 종류의 알고리즘을 사용하는 주된 이유는 k-최근접 이웃 분류기 또는 비슷한 알고리즘을 사용하려고 하지만,

    두 사물 사이의 거리를 계산하는 좋은 방법을 모르기 때문입니다.

    일반적인 예는 얼굴 인식입니다.

    같은 사람의 이미지가 서로 가깝고 다른 사람의 이미지가 멀리 떨어져 있는 벡터 공간에 얼굴 이미지를 심는

    일종의 deep metric learning 알고리즘을 훈련시키는 논문들이 많이 있습니다.

    그 벡터 공간에서는 가장 k-최근접 이웃 분류기로 얼굴 인식을 하는 것이 매우 쉽습니다.

 

    이 예제를 최대한 간단하게 유지하기 위해 얼굴 인식은 하지 않겠습니다.

    대신, 매우 간단한 네트워크를 생성하여 동일한 클래스 레이블을 가진 벡터가 서로 가까이 있도록

    8D 벡터에서 2D 벡터로 매핑하는 방법을 배우도록 하겠습니다.

    얼굴 인식에 사용할 네트워크 종류를 배우는 더 복잡한 예를 보려면 dnn_metric_learning_on_images_ex.cpp 예제를 읽어보십시오.

 

    계속하기 전에 dlib DNN API를 소개하는 예제인

    dnn_instruction_ex.cpp 및 dnn_instruction2_ex.cpp를 읽어보십시오.

*/

 

#include <dlib/dnn.h>

#include <iostream>

 

using namespace std;

using namespace dlib;

 

 

int main() try

{

    // The API for doing metric learning is very similar to the API for

    // multi-class classification.  In fact, the inputs are the same, a bunch of

    // labeled objects.  So here we create our dataset.  We make up some simple

    // vectors and label them with the integers 1,2,3,4.  The specific values of

    // the integer labels don't matter.

    /*

    메트릭 학습을 수행하기위한 API는 다중 클래스 분류를위한 API와 매우 유사합니다.

    실제로 입력은 라벨이 붙은 객체 묶음으로써 동일합니다.

    그러니 여기서 우리의 데이터 셋을 만듭니다.

    간단한 벡터를 구성하고 정수 1,2,3,4라는 라벨을 붙입니다.

    정수 라벨에 지정된 값은 중요하지 않습니다.

    */

    std::vector<matrix<double,0,1>> samples;

    std::vector<unsigned long> labels;

 

    // class 1 training vectors

    samples.push_back({1,0,0,0,0,0,0,0}); labels.push_back(1);

    samples.push_back({0,1,0,0,0,0,0,0}); labels.push_back(1);

 

    // class 2 training vectors

    samples.push_back({0,0,1,0,0,0,0,0}); labels.push_back(2);

    samples.push_back({0,0,0,1,0,0,0,0}); labels.push_back(2);

 

    // class 3 training vectors

    samples.push_back({0,0,0,0,1,0,0,0}); labels.push_back(3);

    samples.push_back({0,0,0,0,0,1,0,0}); labels.push_back(3);

 

    // class 4 training vectors

    samples.push_back({0,0,0,0,0,0,1,0}); labels.push_back(4);

    samples.push_back({0,0,0,0,0,0,0,1}); labels.push_back(4);

 

 

    // Make a network that simply learns a linear mapping from 8D vectors to 2D

    // vectors.

    /*

    8D 벡터에서 2D 벡터로 선형 매핑을 학습하는 네트워크를 만듭니다.

    */

    using net_type = loss_metric<fc<2,input<matrix<double,0,1>>>>; 

    net_type net;

    dnn_trainer<net_type> trainer(net);

    trainer.set_learning_rate(0.1);

 

    // It should be emphasized out that it's really important that each mini-batch contain

    // multiple instances of each class of object.  This is because the metric learning

    // algorithm needs to consider pairs of objects that should be close as well as pairs

    // of objects that should be far apart during each training step.  Here we just keep

    // training on the same small batch so this constraint is trivially satisfied.

    /*

    각 미니 배치는 각 개체 클래스의 여러 인스턴스를 포함하는 것이 매우 중요합니다.

    이는 메트릭 학습 알고리즘이 각 교육 단계에서 멀리 떨어져 있어야 하는 개체 쌍뿐만 아니라

    가까이 있어야 하는 개체 쌍을 고려해야 하기 때문입니다.

    여기서는 동일한 소규모 배치로 계속 교육하므로 이 제약 조건이 3가지로 충족됩니다.

    */

    while(trainer.get_learning_rate() >= 1e-4)

        trainer.train_one_step(samples, labels);

 

    // Wait for training threads to stop

    trainer.get_net();

    cout << "done training" << endl;

 

 

    // Run all the samples through the network to get their 2D vector embeddings.

    /*

    모든 샘플을 네트워크를 통해 2D 벡터 임베딩을 가져옵니다.

    */

    std::vector<matrix<float,0,1>> embedded = net(samples);

 

    // Print the embedding for each sample to the screen.  If you look at the

    // outputs carefully you should notice that they are grouped together in 2D

    // space according to their label.

    /*

    각 샘플의 임베딩을 화면에 출력합니다.

    출력을 주의 깊게 살펴보면 라벨에 따라 2D 공간에 함께 그룹화되어 있습니다.

    */

    for (size_t i = 0; i < embedded.size(); ++i)

        cout << "label: " << labels[i] << "\t" << trans(embedded[i]);

 

    // Now, check if the embedding puts things with the same labels near each other and

    // things with different labels far apart.

    /*

    이제, 엠베딩이 같은 라벨을 가진 물건들과 서로 다른 라벨을 가진 물건들을 서로 멀리 떨어져 있는지 확인합니다.

    */

    int num_right = 0;

    int num_wrong = 0;

    for (size_t i = 0; i < embedded.size(); ++i)

    {

        for (size_t j = i+1; j < embedded.size(); ++j)

        {

            if (labels[i] == labels[j])

            {

                // The loss_metric layer will cause things with the same label to be less

                // than net.loss_details().get_distance_threshold() distance from each

                // other.  So we can use that distance value as our testing threshold for

                // "being near to each other".

                /*

                loss_metric 레이어는 같은 라벨을 가진 것들이 서로 "net.loss_details (). get_distance_threshold ()"거리보다 작아지게 합니다.

                따라서 거리 값을 "서로 가까이있는"테스트 임계 값으로 사용할 수 있습니다.

                */

                if (length(embedded[i]-embedded[j]) < net.loss_details().get_distance_threshold())

                    ++num_right;

                else

                    ++num_wrong;

            }

            else

            {

                if (length(embedded[i]-embedded[j]) >= net.loss_details().get_distance_threshold())

                    ++num_right;

                else

                    ++num_wrong;

            }

        }

    }

 

    cout << "num_right: "<< num_right << endl;

    cout << "num_wrong: "<< num_wrong << endl;

}

catch(std::exception& e)

{

    cout << e.what() << endl;

}