accuracy_layer

本文详细解析了Caffe框架中的AccuracyLayer实现原理,包括层设置、形状调整、前向传播等核心过程,并介绍了如何计算整体及各类别的准确率。
#include <functional>
#include <utility>
#include <vector>

#include "caffe/layers/accuracy_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void AccuracyLayer<Dtype>::LayerSetUp(
  const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  top_k_ = this->layer_param_.accuracy_param().top_k();//获得k,也就是正确类别排前k名算个入acc

  has_ignore_label_ =
    this->layer_param_.accuracy_param().has_ignore_label();//有没有要忽略的标签
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.accuracy_param().ignore_label();
  }
}
/*定义中关于axis的说明:
axis指出在预测blob中,哪一维是label轴,如(N x C x H x W)的blob,axis=0,则N为label对应的维度。
axis=1,则C为label对应的维度,而剩下的N为outer样本数量, H x W为inner样本数量。由代码可知,
当axis=k时outer_num_=blob.shape[0,..,k),inner_num_=blob.shape[k+1,..,shape.size)。一般的,
label blob的维度为(N x C),N为样本数量,C为标签数量(即类别个数)。
axis=1,outer_num_=N,inner_num_=shape[2,2)=1(即没有inner)
*/
template <typename Dtype>
void AccuracyLayer<Dtype>::Reshape(
  const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  CHECK_LE(top_k_, bottom[0]->count() / bottom[1]->count())//要取的k不能比总类别数大
      << "top_k must be less than or equal to the number of classes.";
  label_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.accuracy_param().axis());//label的坐标轴
  outer_num_ = bottom[0]->count(0, label_axis_);//基本可以理解为batch中的样本数
  inner_num_ = bottom[0]->count(label_axis_ + 1);//1
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if label axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  vector<int> top_shape(0);  // Accuracy is a scalar; 0 axes.
  top[0]->Reshape(top_shape);//top[0]是总体样本正确率,标量top[1]为每个类别的正确率,向量
  if (top.size() > 1) {
    // Per-class accuracy is a vector; 1 axes.
    vector<int> top_shape_per_class(1);
    top_shape_per_class[0] = bottom[0]->shape(label_axis_);
    top[1]->Reshape(top_shape_per_class);
    nums_buffer_.Reshape(top_shape_per_class);
  }
}

template <typename Dtype>
void AccuracyLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  Dtype accuracy = 0;
  const Dtype* bottom_data = bottom[0]->cpu_data();//样本数*标签个数(也就是最后一个全链接的输出层节点个数)
  const Dtype* bottom_label = bottom[1]->cpu_data();
  const int dim = bottom[0]->count() / outer_num_;
  const int num_labels = bottom[0]->shape(label_axis_);
  vector<Dtype> maxval(top_k_+1);
  vector<int> max_id(top_k_+1);
  if (top.size() > 1) {
    caffe_set(nums_buffer_.count(), Dtype(0), nums_buffer_.mutable_cpu_data());
    caffe_set(top[1]->count(), Dtype(0), top[1]->mutable_cpu_data());
  }
  int count = 0;
  for (int i = 0; i < outer_num_; ++i) {//对于每个样本
    for (int j = 0; j < inner_num_; ++j) {
      const int label_value =
          static_cast<int>(bottom_label[i * inner_num_ + j]);//第i个样本的label
      if (has_ignore_label_ && label_value == ignore_label_) {//如果这个类别被忽略就计算下一个。
        continue;
      }
      if (top.size() > 1) ++nums_buffer_.mutable_cpu_data()[label_value];//batch中每个类别的总样本数,为了计算类内正确率
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, num_labels);
      // Top-k accuracy
      std::vector<std::pair<Dtype, int> > bottom_data_vector;
      for (int k = 0; k < num_labels; ++k) {
        bottom_data_vector.push_back(std::make_pair(
            bottom_data[i * dim + k * inner_num_ + j], k));//完成带序号的排序
      }
      std::partial_sort(
          bottom_data_vector.begin(), bottom_data_vector.begin() + top_k_,
          bottom_data_vector.end(), std::greater<std::pair<Dtype, int> >());
      // check if true label is in top k predictions
      for (int k = 0; k < top_k_; k++) {
        if (bottom_data_vector[k].second == label_value) { //如果标定的label在预测的前k个label中
          ++accuracy;
          if (top.size() > 1) ++top[1]->mutable_cpu_data()[label_value];
          break;
        }
      }
      ++count;
    }
  }

  // LOG(INFO) << "Accuracy: " << accuracy;
  top[0]->mutable_cpu_data()[0] = accuracy / count;
  if (top.size() > 1) {
    for (int i = 0; i < top[1]->count(); ++i) {
      top[1]->mutable_cpu_data()[i] =
          nums_buffer_.cpu_data()[i] == 0 ? 0 //batch中没有某一类样本就把这类样本的正确率设置为0,不然的话就正常计算
          : top[1]->cpu_data()[i] / nums_buffer_.cpu_data()[i];
    }
  }
  // Accuracy layer should not be used as a loss function.
}

INSTANTIATE_CLASS(AccuracyLayer);
REGISTER_LAYER_CLASS(Accuracy);

}  // namespace caffe

def selectun(self, backup_layer, zkLay): """ 对 backup_layer 上的每根阻抗线: - 查找其在原信号层 touch 的非 line/arc 图形 - 复制到 '01' 层 - 局部合并为独立 surface(与其他无关) :return: bool 是否有任何图形被复制 """ sig_layer = self.getinfomation_dict[zkLay]['sigLayerName'] step = 'edit' job = self.JOB self.ico.ClearAll() self.ico.ResetFilter() # self.ico.DispWork(backup_layer) self.incam.COM(f'affected_layer, name={backup_layer}, mode=single, affected=yes') self.incam.COM(f'display_layer, name={sig_layer}, display=yes') self.incam.COM(f'work_layer, name={sig_layer}') features = self.ico.GetFeaturesPro(job=job, step=step, layer=backup_layer) if not features: return False has_copied = False self.ico.CreateLay(['01']) # 确保存在 # self.ico.DispWork('01') for feat in features: # if feat['type'] in ('line', 'arc'): # continue x, y = round(feat['xs'], 3), round(feat['ys'], 3) # --- 清空选择,点选当前网络 --- self.incam.COM("sel_clear_feat") self.incam.COM("clear_highlight") self.incam.COM(f"sel_board_net_feat, operation=select, x={x}, y={y}, tol=1, use_ffilter=no") # --- 获取原信号层上的全部特征 --- sub_features = self.ico.GetFeatureFullInfo(step=step, layer=sig_layer, mode='select') non_line_arcs = [f for f in sub_features if f['type'] not in ('line', 'arc')] if not non_line_arcs: continue # 没有要复制的内容 # --- 复制到 01 层 --- self.incam.COM( "sel_copy_other, dest=layer_name, target_layer=01, invert=no, " "dx=0, dy=0, size=0, x_anchor=0, y_anchor=0" ) has_copied = True # --- 关键:立即在 01 层对刚复制的内容进行局部合并 --- self.ico.DispWork('01') # self.incam.COM("sel_clear_feat") # self.incam.COM(f"sel_all_feat, operation=select, x={x}, y={y}, tol=0.5, use_ffilter=no") # 只选附近 self.incam.COM("get_select_count") count = int(self.incam.COMANS) if count > 0: self.incam.COM( "sel_cont_resize, accuracy=0, break_to_islands=yes, " "island_size=0, hole_size=0, drill_filter=no, corner_ctl=no" ) self.ico.DispWork(backup_layer) # 回到原层继续下一根线 return has_copied 直接这样写会报错,因为back_layer中的坐标信息不能直接作为sel_board_net_feat的参数,但是如果模仿下面这种:self.selectBallPad(zkLay=original_layer, x=xs, y=ys) ,xs,ys都是backup_layer中的坐标点,通过在backup_layer备份层中找到坐标点,然后选中的是原始备份层中相同的位置,其中: def selectBallPad(self, zkLay, x, y): """ 判断指定坐标点是否与背面ball pad导通 :param zkLay: 阻抗层名称 :param x: 检查点的x坐标 :param y: 检查点的y坐标 :return: bool 是否导通 """ # 阻抗层对应的线路层 zk2SigLay = self.getinfomation_dict[zkLay]['sigLayerName']#self.getinfomation_dict得到的是原始阻抗层,而不是_bak备份阻抗层 sigBot = self.layerMatrix['sigAllLay'][-1] # 设置工作环境 self.ico.ClearAll() self.ico.ResetFilter() self.incam.COM(f'affected_layer, name={sigBot}, mode=single, affected=yes') self.incam.COM(f'display_layer, name={zk2SigLay}, display=yes') self.incam.COM(f'work_layer, name={zk2SigLay}') # 执行选择 self.incam.COM("sel_clear_feat") self.incam.COM("clear_highlight") self.incam.COM(f'sel_board_net_feat, operation=select, x={x}, y={y}, tol=1, use_ffilter=no') # 获取选中特征 featureFullInfo_sigBot = self.ico.GetFeatureFullInfo(step=self.STEP, layer=sigBot, mode='select') 重新编写selectun函数
最新发布
11-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值