[caffe 노트 006]:caffe의softmax층 유도

7772 단어 카페 링거
1. SoftmaxParameter
  • engine
  • CAFFE = 1
  • CUDNN = 2

  • axis는 몇 차원에서softmax를 따라 정수(정수)와 음수(역순)
  • 로 할 수 있다.
    // Message that stores parameters used by SoftmaxLayer, SoftmaxWithLossLayer
    message SoftmaxParameter {
      enum Engine {
        DEFAULT = 0;
        CAFFE = 1;
        CUDNN = 2;
      }
      optional Engine engine = 1 [default = DEFAULT];
    
      // The axis along which to perform the softmax -- may be negative to index
      // from the end (e.g., -1 for the last axis).
      // Any other axes will be evaluated as independent softmaxes.
      optional int32 axis = 2 [default = 1];
    }
    

    2. 구조
    ffe의softmax 층값은softmax 함수 자체를 주목하고 두 개의 그림이다.입력
    zi(i=1,⋯,k),
    해당 출력은 다음과 같습니다.
    ai=ezi∑j=1kezj.
  • bottom [N C H W]의 행렬이 N은batchsize, C는 카테고리수, HxW는spatial dimention이라고 하는데 이때zi가 바로 2차원의 요소
  • 이다.
  • top [N C H W]의 행렬, 대응 출력
  • 3. 정방향 전파
    계산 프로세스 Step1: 계산 입력 최대값
    z=max{zi}
    Step2:최대값 빼기
    zi=zi−z
    Step3: 지수 구하기
    zi=ezi
    Step4: 구화
    zsum=∑i=1kezi
    Step5: softmax
    zi=zizsum
    코드
    template <typename Dtype>
    void SoftmaxLayer::Forward_cpu(const vector*>& bottom,
        const vector*>& top) {
      const Dtype* bottom_data = bottom[0]->cpu_data();
      Dtype* top_data = top[0]->mutable_cpu_data();
      Dtype* scale_data = scale_.mutable_cpu_data();
      // channles       
      int channels = bottom[0]->shape(softmax_axis_);
      int dim = bottom[0]->count() / outer_num_;
      //  top     ,    bottom  
      caffe_copy(bottom[0]->count(), bottom_data, top_data);
      // We need to subtract the max to avoid numerical issues, compute the exp,
      // and then normalize.
      //  outer_num_       
      for (int i = 0; i < outer_num_; ++i) {
        //    scale_data  i   ,   softmax           
        // Step1:
        // initialize scale_data to the first plane
        caffe_copy(inner_num_, bottom_data + i * dim, scale_data);
        for (int j = 0; j < channels; j++) {
          for (int k = 0; k < inner_num_; k++) {
            scale_data[k] = std::max(scale_data[k],
                bottom_data[i * dim + j * inner_num_ + k]);
          }
        }
        // subtraction, Step2:
        caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, channels, inner_num_,
            1, -1., sum_multiplier_.cpu_data(), scale_data, 1., top_data);
        // exponentiation, Step3:
        caffe_exp(dim, top_data, top_data);
        // sum after exp, Step4:
        caffe_cpu_gemv(CblasTrans, channels, inner_num_, 1.,
            top_data, sum_multiplier_.cpu_data(), 0., scale_data);
        // division, Step5:
        for (int j = 0; j < channels; j++) {
          caffe_div(inner_num_, top_data, scale_data, top_data);
          top_data += inner_num_;
        }
      }
    }

    4. 역방향 전파
    계산 프로세스 Step1: top데이터 및 topdiff 내적 Step2: 차액을 구하고, 대응 유도 과정(∂l ∂ai --∂l ∂a ⋅a) Step3: 곱하기, 편도 구하기
    유도 과정
    ∂l∂z=∂l∂a∂a∂z
    여기에서:
    ∂l∂a=top−diff ,
    a=top−data .
    다음을 수행합니다.
    ∂ai∂zj=∂(ezi∑kezk)∂zj
    해당
    i≠j시
    ∂ai∂zj=−eziezj(∑kezk)2=−aiaj
    해당
    i=j 시:
    ∂ai∂zj=ezi∑kezk−eziezj(∑kezk)2=aj−ajaj
    다음과 같은 이점을 제공합니다.
    ∂l∂zj=∂l∂a∂a∂zj=∑i∂l∂ai∂ai∂zj=−(∂l∂a⋅a)aj+∂l∂ajaj=(∂l∂aj−∂l∂a⋅a)aj
    코드
    template <typename Dtype>
    void SoftmaxLayer::Backward_cpu(const vector*>& top,
        const vector<bool>& propagate_down,
        const vector*>& bottom) {
      const Dtype* top_diff = top[0]->cpu_diff();
      const Dtype* top_data = top[0]->cpu_data();
      Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
      Dtype* scale_data = scale_.mutable_cpu_data();
      int channels = top[0]->shape(softmax_axis_);
      int dim = top[0]->count() / outer_num_;
      caffe_copy(top[0]->count(), top_diff, bottom_diff);
      for (int i = 0; i < outer_num_; ++i) {
        // compute dot(top_diff, top_data) and subtract them from the bottom diff, Step1:
        for (int k = 0; k < inner_num_; ++k) {
          scale_data[k] = caffe_cpu_strided_dot(channels,
              bottom_diff + i * dim + k, inner_num_,
              top_data + i * dim + k, inner_num_);
        }
        // subtraction, Step2:
        caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, channels, inner_num_, 1,
            -1., sum_multiplier_.cpu_data(), scale_data, 1., bottom_diff + i * dim);
      }
      // elementwise multiplication, Step3:
      caffe_mul(top[0]->count(), bottom_diff, top_data, bottom_diff);
    }

    좋은 웹페이지 즐겨찾기