본문 바로가기
machine learning

[DeepLearning] Caffe Nets, Layers, Blobs

by 유주원 2015. 5. 13.

이번 포스팅에서는 Caffe를 쓰기 위한 Caffe 내의 모델 구조를 어떤 식으로 구성하는가를 알아보려고 한다.

모델은 크게 Nets, Layers, Blobs으로 구성되어 있다고 할 수 있다.


1. Blobs



Blob은 Caffe 내에서 데이터 처리나 Layer 간의 communite을 위한 구조체라고 생각하면 쉬울 것 같다. Caffe에서 Layer간의 데이터 통신은 Blob을 통해 연결된다.

Blob은 실제 아래와 같은 역할을 한다.


- 실제 데이터를 Caffe 내에서 알맞게 처리할 수 있도록 wrapping 시켜주는 역할을 한다.

- CPU와 GPU 간의 동기화를 지원하고, lazy allocation memory 방식으로 메모리를 할당한다. 

(lazy allocation memnory란 선언이나 파라미터를 받았을 때 메모리를 할당하는게 아니라 실제 해당 요소가 필요할때에만 메모리에 적재해서 사용하는 방식을 말한다.)

- 통합 메모리 인터페이스를 제공하고 image batch, model parameter, 최적화 계수 등을 저장하는 용도로 사용되기도 한다.


Blob 데이터를 CPU 혹은 GPU를 이용해서 계산할 수가 있는데, 아래와 같은 방법으로 Blob 데이터를 가져올 수가 있다.


const Dtype* cpu_data() const;

Dtype* mutable_cpu_data();


위의 방법은 immutable하게 데이터를 접근할 때 사용하고, 아래 방식은 실제 데이터를 가져와서 수정작업을 해야 할 때 사용한다.

Caffe에서는 데이터를 수정할때에는 반드시 데이터가 위치한 포인터를 가져올 수 있는 함수를 호출하는 방식을 장려하고 있으며, 직접 포인터 변수를 가져와서 수정하는 것은 금지하고 있다.

또한 아래와 같은 방법으로 CPU, GPU를 호환하여 연산을 수행할 수가 있다.


// 현재 CPU 상에서 동작하고 있으며, 하나의 blob을 가지고 있다고 가정한다. 

const Dtype* foo;

Dtype* bar;

foo = blob.gpu_data();         // gpu에서 데이터 가져오도록 호출하였기 때문에, 현재 CPU에 있는 데이터가 GPU로 복사된다.

foo = blob.cpu_data();         // cpu에서 데이터를 가져오도록 호출하였고, cpu는 아무런 데이터 변화가 없기 때문에 데이터 복사가 발생하지 않는다.

bar = blob.mutable_gpu_data();    // gpu에서 수정 가능한 데이터를 가져오도록 호출하였다. 데이터 복사는 발생하지 않는다.

// .. blob 연산 작업이 진행되었다고 가정하자.

bar = blob.mutable_gpu_data();          // 현재 계속 gpu에서 동작하고 있기 때문에 데이터 복사가 발생하지 않는다.

foo = blob.cpu_data();                           // GPU 상에서 데이터가 수정되었기 때문에 CPU로의 복사가 이루어진다.

foo = blob.gpu_data();                          // gpu에서는 데이터 변경이 없기 때문에 복사가 이루어지지 않는다.

bar = blob.mutable_cpu_data();         // cpu에서는 데이터 변경이 없으므로 복사가 발생하지 않는다.

bar = blob.mutable_gpu_data();         // mutable로 cpu에서 gpu로 변환이 발생했기 때문에 CPU에서 GPU로 데이터 복사가 발생한다.

bar = blob.mutable_cpu_data();         // mutable로 gpu에서 cpu로 변환이 발생했기 때문에 GPU에서 CPU로 데이터 복사가 발생한다.




2. Layer

Blob에 어떠한 처리를 하기 위한 단계를 Layer라고 하며 아래 사이트에 들어가면 개발자가 직접 사용할 수 있는 많은 종류의 Layer가 나열되어 있다.


http://caffe.berkeleyvision.org/tutorial/layers.html


그렇다면 이 Layer를 어떻게 정의하고 쓸까??

Caffe에서는 text형태로 Layer를 선언해서 Layer를 정의하고 구동시킬수가 있다.


아까 Blob 설명 시에 나타났던 그림을 Layer로 정의해보자.


name : "conv1"

type : CONVOLUTION

bottom : "data"

top : "conv1"

convolution_param {

    num_output : 20

    kernel_size : 5

    stride : 1

    weight_filler{

        type: "xavier"

    }

}


정확하게 어떻게 동작하는지 확인할 수는 없지만 대략적으로 이해하자면, 해당 Layer는 이름이 conv1이고 CONVOLUTION이란 타입의 Layer이다. input으로는 "data" blob을 받아서 "conv1" blob을 output으로 출력한다. 

convolution_param은 해당 layer에서 입력받는 파라미터 값인데 이것은 caffe를 점차 공부하며 알아가야 할 것 같다.


일단은 Caffe에서는 이런식으로 Layer를 구성할 수 있다는 것만 알면 될 것 같다.


Layer에서는 3단계 연산 작업이 이루어진다.


- Setep : layer와 layer 간의 연결 관계를 초기화한다.

- Forward : 주어진 input으로부터 output을 계산하고 다음 layer에 전달한다.

- Backward : output 결과를 정답지와 비교하여 오차가 있을 경우 다시 이전 layer로 전달한다.


3. Net


Net은 Layer들의 집합이라고 할 수 있겠다. Layer들의 집합이지만 Layer들의 연결 관계에는 반드시 방향성이 있어야 하고 순환을 해서는 안된다. (Layer 간에 무한 루프를 돌면 안되기 때문에) 



위와 같이 연결되어 있는 Net을 Caffe에서 정의해보면 아래와 같다.


name: "LogReg"

layer {

   name: "mnist"

    type: DATA

    top: "data"

    top: "label"

    data_param {

        source: "input_leveldb"

        batch_size: 64

    }

}

layer {

    name: "ip"

    type: INNER_PRODUCT

    bottom: "data"

    top: "ip"

    inner_product_param{

        num_output: 2

    }

}

layer {

    name: "loss"

    type: SOFTMAX_LOSS

    bottom: "ip"

    bottom: "label"

    top: "loss"

}