【人工智能笔记】第十九节 efficientdet 目标检测模型,官方源码分析系列,Backbone实现细节(一)

读 DeepFake detection with multi-scale convolution and vision transformer 第一期:MBConv MBConv由下图组成。MBConv6指第一层1*1卷积层的卷积核个数为6,若是MBConv1则第一层可以省略。以下是MBConv网络的详细代码及注释,主要是根据上图的流程搭建。 阅读详情

这次是根据官方源码,分析efficientdet模型实现细节。因官方代码基于谷歌的automl框架实现,有很多选项配置,该系列基于默认配置,只关注一些实现细节,一些简单的层会粗略带过,计划分为如下章节:

  • Backbone实现细节分析
  • BiFPN实现细节分析
  • Box与Class回归细节分析
  • Loss计算分析
  • Optimizer梯度计算分析

官方源码:https://github.com/google/automl

efficientdet模型结构如下:

 

代码结构如下:

对应代码位于efficientdet/keras/efficientdet_keras.py: 

class EfficientDetNet(tf.keras.Model):
  """EfficientDet keras network without pre/post-processing."""
  '''EfficientDet模型主体'''

  def __init__(self, model_name=None, config=None, name=''):
    """Initialize model."""
    super().__init__(name=name)
    # 根据模型名称,取默认配置hparams_config.get_efficientdet_config
    config = config or hparams_config.get_efficientdet_config(model_name)
    self.config = config

    # Backbone.
    # 主体名称,默认:efficientnet-b1
    backbone_name = config.backbone_name
    # is_training_bn:True
    is_training_bn = config.is_training_bn
    if 'efficientnet' in backbone_name:
      # utils.batch_norm_class,根据硬件选择BatchNormalization
      # utils.activation_fn,选择激活函数,默认swish
      override_params = {
          'batch_norm':
              utils.batch_norm_class(is_training_bn, config.strategy),
          'relu_fn':
              functools.partial(utils.activation_fn, act_type=config.act_type),
      }
      if 'b0' in backbone_name:
        override_params['survival_prob'] = 0.0
      # backbone_config:None
      if config.backbone_config is not None:
        override_params['blocks_args'] = (
            efficientnet_builder.BlockDecoder().encode(
                config.backbone_config.blocks))
      # data_format:channels_last,通道在最后一个维度
      override_params['data_format'] = config.data_format
      # 构建主体
      self.backbone = backbone_factory.get_model(
          backbone_name, override_params=override_params)

    # Feature network.
    # 特征网络
    self.resample_layers = []  # additional resampling layers.
    # 共7层,主体只有5层,补了两层ResampleFeatureMap
    for level in range(6, config.max_level + 1):
      # Adds a coarser level by downsampling the last feature map.
      self.resample_layers.append(
          ResampleFeatureMap(
              feat_level=(level - config.min_level),
              target_num_channels=config.fpn_num_filters,
              # apply_bn_for_resampling:True
              apply_bn=config.apply_bn_for_resampling,
              # is_training_bn:True
              is_training_bn=config.is_training_bn,
              # conv_after_downsample:False
              conv_after_downsample=config.conv_after_downsample,
              # strategy:None
              strategy=config.strategy,
              data_format=config.data_format,
              name='resample_p%d' % level,
          ))
    # 这里是
    self.fpn_cells = FPNCells(config)

    # class/box output prediction network.
    # aspect_ratios:3种形状,3种大小,共9个候选框
    num_anchors = len(config.aspect_ratios) * config.num_scales
    # fpn通道数
    num_filters = config.fpn_num_filters
    for head in config.heads:
      if head == 'object_detection':
        # 目标检测
        self.class_net = ClassNet(
            num_classes=config.num_classes,
            num_anchors=num_anchors,
            num_filters=num_filters,
            min_level=config.min_level,
            max_level=config.max_level,
            is_training_bn=config.is_training_bn,
            act_type=config.act_type,
            repeats=config.box_class_repeats,
            separable_conv=config.separable_conv,
            survival_prob=config.survival_prob,
            strategy=config.strategy,
            data_format=config.data_format)

        self.box_net = BoxNet(
            num_anchors=num_anchors,
            num_filters=num_filters,
            min_level=config.min_level,
            max_level=config.max_level,
            is_training_bn=config.is_training_bn,
            act_type=config.act_type,
            repeats=config.box_class_repeats,
            separable_conv=config.separable_conv,
            survival_prob=config.survival_prob,
            strategy=config.strategy,
            data_format=config.data_format)

      if head == 'segmentation':
        # 目标分割
        self.seg_head = SegmentationHead(
            num_classes=config.seg_num_classes,
            num_filters=num_filters,
            min_level=config.min_level,
            max_level=config.max_level,
            is_training_bn=config.is_training_bn,
            act_type=config.act_type,
            strategy=config.strategy,
            data_format=config.data_format)

  def _init_set_name(self, name, zero_based=True):
    """A hack to allow empty model name for legacy checkpoint compitability."""
    if name == '':  # pylint: disable=g-explicit-bool-comparison
      self._name = name
    else:
      self._name = super().__init__(name, zero_based)

  def call(self, inputs, training):
    config = self.config
    # call backbone network.
    all_feats = self.backbone(inputs, training=training, features_only=True)
    # 5层特征
    feats = all_feats[config.min_level:config.max_level + 1]

    # Build additional input features that are not from backbone.
    for resample_layer in self.resample_layers:
      feats.append(resample_layer(feats[-1], training, None))

    # call feature network.
    fpn_feats = self.fpn_cells(feats, training)

    # call class/box/seg output network.
    outputs = []
    if 'object_detection' in config.heads:
      class_outputs = self.class_net(fpn_feats, training)
      box_outputs = self.box_net(fpn_feats, training)
      outputs.extend([class_outputs, box_outputs])
    if 'segmentation' in config.heads:
      seg_outputs = self.seg_head(fpn_feats, training)
      outputs.append(seg_outputs)
    return tuple(outputs)

Backbone主体部分

MBConvBlock一共有7层,参数分别是:

  • r1_k3_s11_e1_i32_o16_se0.25
  • r2_k3_s22_e6_i16_o24_se0.25
  • r2_k5_s22_e6_i24_o40_se0.25
  • r3_k3_s22_e6_i40_o80_se0.25
  • r3_k5_s11_e6_i80_o112_se0.25
  • r4_k5_s22_e6_i112_o192_se0.25
  • r1_k3_s11_e6_i192_o320_se0.25

r:重复次数,k:卷积核大小,s:步长1*1,e:扩大层倍数,与瓶颈层相反(输入通道数的百分比,为1时无操作)

i:输入通道数,o:输出通道数,se:瓶颈层倍数(输出通道数的百分比)

最终参数会根据模型进行4个维度的缩放,4个维度分别是:宽度系数(width_coefficient),深度系数(depth_coefficient),分辨率(resolution),dropout比例(dropout_rate)

结构如下,其中橙色层数后的特征,用于最后回归结果:

具体代码位于efficientdet/backbone/efficientnet_model.py 文件,具体如下:

class Model(tf.keras.Model):
  """A class implements tf.keras.Model.

    Reference: https://arxiv.org/abs/1807.11626
  """

  def __init__(self, blocks_args=None, global_params=None, name=None):
    """Initializes an `Model` instance.

    Args:
      blocks_args: A list of BlockArgs to construct block modules.
      global_params: GlobalParams, a set of global parameters.
      name: A string of layer name.

    Raises:
      ValueError: when blocks_args is not specified as a list.
    """
    super().__init__(name=name)

    if not isinstance(blocks_args, list):
      raise ValueError('blocks_args should be a list.')
    self._global_params = global_params
    self._blocks_args = blocks_args
    self._relu_fn = global_params.relu_fn or tf.nn.swish
    self._batch_norm = global_params.batch_norm
    # fix_head_stem:None
    self._fix_head_stem = global_params.fix_head_stem

    self.endpoints = None

    self._build()

  def _get_conv_block(self, conv_type):
    conv_block_map = {0: MBConvBlock, 1: MBConvBlockWithoutDepthwise}
    return conv_block_map[conv_type]

  def _build(self):
    """Builds a model."""
    self._blocks = []

    # Stem part.
    # input_filters:32
    self._stem = Stem(self._global_params, self._blocks_args[0].input_filters)

    # Builds blocks.
    # 迭代器,从0开始,返回结果不断加1
    block_id = itertools.count(0)
    block_name = lambda: 'blocks_%d' % next(block_id)
    # _blocks_args默认值
    # _blocks_args = [
    #     'r1_k3_s11_e1_i32_o16_se0.25', 'r2_k3_s22_e6_i16_o24_se0.25',
    #     'r2_k5_s22_e6_i24_o40_se0.25', 'r3_k3_s22_e6_i40_o80_se0.25',
    #     'r3_k5_s11_e6_i80_o112_se0.25', 'r4_k5_s22_e6_i112_o192_se0.25',
    #     'r1_k3_s11_e6_i192_o320_se0.25',
    # ]
    for i, block_args in enumerate(self._blocks_args):
      assert block_args.num_repeat > 0
      # block_args.super_pixel默认为0
      assert block_args.super_pixel in [0, 1, 2]
      # Update block input and output filters based on depth multiplier.
      # 维度缩放
      input_filters = round_filters(block_args.input_filters,
                                    self._global_params)

      output_filters = round_filters(block_args.output_filters,
                                     self._global_params)
      kernel_size = block_args.kernel_size
      if self._fix_head_stem and (i == 0 or i == len(self._blocks_args) - 1):
        repeats = block_args.num_repeat
      else:
        # 默认采用,按深度系数*默认重复次数,计算出实际重复次数
        repeats = round_repeats(block_args.num_repeat, self._global_params)
      # 更新每个block的参数,为实际数
      block_args = block_args._replace(
          input_filters=input_filters,
          output_filters=output_filters,
          num_repeat=repeats)

      # The first block needs to take care of stride and filter size increase.
      # conv_type默认为0
      conv_block = self._get_conv_block(block_args.conv_type)
      # 默认True
      if not block_args.super_pixel:  #  no super_pixel at all
        self._blocks.append(
            conv_block(block_args, self._global_params, name=block_name()))
      else:
        # if superpixel, adjust filters, kernels, and strides.
        depth_factor = int(4 / block_args.strides[0] / block_args.strides[1])
        block_args = block_args._replace(
            input_filters=block_args.input_filters * depth_factor,
            output_filters=block_args.output_filters * depth_factor,
            kernel_size=((block_args.kernel_size + 1) //
                         2 if depth_factor > 1 else block_args.kernel_size))
        # if the first block has stride-2 and super_pixel trandformation
        if (block_args.strides[0] == 2 and block_args.strides[1] == 2):
          block_args = block_args._replace(strides=[1, 1])
          self._blocks.append(
              conv_block(block_args, self._global_params, name=block_name()))
          block_args = block_args._replace(  # sp stops at stride-2
              super_pixel=0,
              input_filters=input_filters,
              output_filters=output_filters,
              kernel_size=kernel_size)
        elif block_args.super_pixel == 1:
          self._blocks.append(
              conv_block(block_args, self._global_params, name=block_name()))
          block_args = block_args._replace(super_pixel=2)
        else:
          self._blocks.append(
              conv_block(block_args, self._global_params, name=block_name()))
      # 重复次数大于1,后面的重复层输入维度等于输出维度,strides=[1, 1]
      if block_args.num_repeat > 1:  # rest of blocks with the same block_arg
        # pylint: disable=protected-access
        block_args = block_args._replace(
            input_filters=block_args.output_filters, strides=[1, 1])
        # pylint: enable=protected-access
      for _ in xrange(block_args.num_repeat - 1):
        self._blocks.append(
            conv_block(block_args, self._global_params, name=block_name()))

    # Head part.
    self._head = Head(self._global_params)

  def call(self,
           inputs,
           training,
           features_only=None,
           pooled_features_only=False):
    """Implementation of call().

    Args:
      inputs: input tensors.
      training: boolean, whether the model is constructed for training.
      features_only: build the base feature network only.
      pooled_features_only: build the base network for features extraction
        (after 1x1 conv layer and global pooling, but before dropout and fc
        head).

    Returns:
      output tensors.
    """
    outputs = None
    self.endpoints = {}
    reduction_idx = 0

    # Calls Stem layers
    outputs = self._stem(inputs, training)
    logging.info('Built stem %s : %s', self._stem.name, outputs.shape)
    self.endpoints['stem'] = outputs

    # Calls blocks.
    for idx, block in enumerate(self._blocks):
      is_reduction = False  # reduction flag for blocks after the stem layer
      # If the first block has super-pixel (space-to-depth) layer, then stem is
      # the first reduction point.
      # False
      if (block.block_args.super_pixel == 1 and idx == 0):
        reduction_idx += 1
        self.endpoints['reduction_%s' % reduction_idx] = outputs

      elif ((idx == len(self._blocks) - 1) or
            self._blocks[idx + 1].block_args.strides[0] > 1):
        # 最后一层或strides>1时
        is_reduction = True
        reduction_idx += 1
      # survival_prob:None
      survival_prob = self._global_params.survival_prob
      if survival_prob:
        drop_rate = 1.0 - survival_prob
        survival_prob = 1.0 - drop_rate * float(idx) / len(self._blocks)
        logging.info('block_%s survival_prob: %s', idx, survival_prob)
      # 调用块
      outputs = block(outputs, training=training, survival_prob=survival_prob)
      # 记录每个block结果
      self.endpoints['block_%s' % idx] = outputs
      if is_reduction:
        print('block.block_args:', block.block_args)
        # 记录每个block维度下降后的结果
        self.endpoints['reduction_%s' % reduction_idx] = outputs
      if block.endpoints:
        # 记录每个block的子结果
        for k, v in six.iteritems(block.endpoints):
          self.endpoints['block_%s/%s' % (idx, k)] = v
          if is_reduction:
            self.endpoints['reduction_%s/%s' % (reduction_idx, k)] = v
    self.endpoints['features'] = outputs

    if not features_only:
      # Calls final layers and returns logits.
      # 调用head层,把结果加入
      outputs = self._head(outputs, training, pooled_features_only)
      self.endpoints.update(self._head.endpoints)

    return [outputs] + list(filter(lambda endpoint: endpoint is not None, [
      self.endpoints.get('reduction_1'),
      self.endpoints.get('reduction_2'),
      self.endpoints.get('reduction_3'),
      self.endpoints.get('reduction_4'),
      self.endpoints.get('reduction_5'),
    ]))

 Stem结构如下:

代码如下:

class Stem(tf.keras.layers.Layer):
  """Stem layer at the begining of the network."""

  def __init__(self, global_params, stem_filters, name=None):
    super().__init__(name=name)
    self._conv_stem = tf.keras.layers.Conv2D(
        # (stem_filters * width_coefficient + 4) // 64 
        filters=round_filters(stem_filters, global_params,
                              global_params.fix_head_stem),
        kernel_size=[3, 3],
        strides=[2, 2],
        kernel_initializer=conv_kernel_initializer,
        padding='same',
        data_format=global_params.data_format,
        use_bias=False)
    self._bn = global_params.batch_norm(
        axis=(1 if global_params.data_format == 'channels_first' else -1),
        momentum=global_params.batch_norm_momentum,
        epsilon=global_params.batch_norm_epsilon)
    self._relu_fn = global_params.relu_fn or tf.nn.swish

  def call(self, inputs, training):
    return self._relu_fn(self._bn(self._conv_stem(inputs), training=training))

 MBConvBlock结构如图,里面有个判断,在第一层少一个Conv:

代码如下:

class MBConvBlock(tf.keras.layers.Layer):
  """A class of MBConv: Mobile Inverted Residual Bottleneck.

  Attributes:
    endpoints: dict. A list of internal tensors.
  """

  def __init__(self, block_args, global_params, name=None):
    """Initializes a MBConv block.

    Args:
      block_args: BlockArgs, arguments to create a Block.
      global_params: GlobalParams, a set of global parameters.
      name: layer name.
    """
    super().__init__(name=name)

    self._block_args = block_args
    self._global_params = global_params
    # local_pooling默认为False
    self._local_pooling = global_params.local_pooling
    self._batch_norm_momentum = global_params.batch_norm_momentum
    self._batch_norm_epsilon = global_params.batch_norm_epsilon
    self._batch_norm = global_params.batch_norm
    # condconv_num_experts默认为None
    self._condconv_num_experts = global_params.condconv_num_experts
    self._data_format = global_params.data_format
    self._channel_axis = 1 if self._data_format == 'channels_first' else -1

    self._relu_fn = global_params.relu_fn or tf.nn.swish
    # 默认True
    self._has_se = (
        global_params.use_se and self._block_args.se_ratio is not None and
        0 < self._block_args.se_ratio <= 1)
    # 默认False
    self._clip_projection_output = global_params.clip_projection_output

    self.endpoints = None

    # 默认False
    if self._block_args.condconv:
      raise ValueError('Condconv is not supported.')

    # Builds the block accordings to arguments.
    self._build()

  @property
  def block_args(self):
    return self._block_args

  def _build(self):
    """Builds block according to the arguments."""
    # pylint: disable=g-long-lambda
    bid = itertools.count(0)
    # 这里一个方法调用了两次next(bid),因此要除以2
    get_bn_name = lambda: 'tpu_batch_normalization' + ('' if not next(
        bid) else '_' + str(next(bid) // 2))
    cid = itertools.count(0)
    get_conv_name = lambda: 'conv2d' + ('' if not next(cid) else '_' + str(
        next(cid) // 2))
    # pylint: enable=g-long-lambda
    
    # self._block_args.super_pixel默认为0
    if self._block_args.super_pixel == 1:
      self.super_pixel = SuperPixel(
          self._block_args, self._global_params, name='super_pixel')
    else:
      self.super_pixel = None

    # self._block_args.expand_ratio扩大倍率
    filters = self._block_args.input_filters * self._block_args.expand_ratio
    kernel_size = self._block_args.kernel_size

    # self._block_args.fused_conv默认为0
    # False
    if self._block_args.fused_conv:
      # Fused expansion phase. Called if using fused convolutions.
      self._fused_conv = tf.keras.layers.Conv2D(
          filters=filters,
          kernel_size=[kernel_size, kernel_size],
          strides=self._block_args.strides,
          kernel_initializer=conv_kernel_initializer,
          padding='same',
          data_format=self._data_format,
          use_bias=False,
          name=get_conv_name())
    else:
      # Expansion phase. Called if not using fused convolutions and expansion
      # phase is necessary.
      # 第一层不执行
      if self._block_args.expand_ratio != 1:
        self._expand_conv = tf.keras.layers.Conv2D(
            filters=filters,
            kernel_size=[1, 1],
            strides=[1, 1],
            kernel_initializer=conv_kernel_initializer,
            padding='same',
            data_format=self._data_format,
            use_bias=False,
            name=get_conv_name())
        self._bn0 = self._batch_norm(
            axis=self._channel_axis,
            momentum=self._batch_norm_momentum,
            epsilon=self._batch_norm_epsilon,
            name=get_bn_name())

      # Depth-wise convolution phase. Called if not using fused convolutions.
      # 深度卷积输出维度与输入维度一样,每个输入经过一个卷积核得到一个输出
      self._depthwise_conv = tf.keras.layers.DepthwiseConv2D(
          kernel_size=[kernel_size, kernel_size],
          strides=self._block_args.strides,
          depthwise_initializer=conv_kernel_initializer,
          padding='same',
          data_format=self._data_format,
          use_bias=False,
          name='depthwise_conv2d')

    self._bn1 = self._batch_norm(
        axis=self._channel_axis,
        momentum=self._batch_norm_momentum,
        epsilon=self._batch_norm_epsilon,
        name=get_bn_name())

    # True
    if self._has_se:
      num_reduced_filters = max(
          1, int(self._block_args.input_filters * self._block_args.se_ratio))
      self._se = SE(
          self._global_params, num_reduced_filters, filters, name='se')
    else:
      self._se = None

    # Output phase.
    filters = self._block_args.output_filters
    self._project_conv = tf.keras.layers.Conv2D(
        filters=filters,
        kernel_size=[1, 1],
        strides=[1, 1],
        kernel_initializer=conv_kernel_initializer,
        padding='same',
        data_format=self._data_format,
        use_bias=False,
        name=get_conv_name())
    self._bn2 = self._batch_norm(
        axis=self._channel_axis,
        momentum=self._batch_norm_momentum,
        epsilon=self._batch_norm_epsilon,
        name=get_bn_name())

  def call(self, inputs, training, survival_prob=None):
    """Implementation of call().

    Args:
      inputs: the inputs tensor.
      training: boolean, whether the model is constructed for training.
      survival_prob: float, between 0 to 1, drop connect rate.

    Returns:
      A output tensor.
    """
    logging.info('Block %s input shape: %s', self.name, inputs.shape)
    x = inputs

    # creates conv 2x2 kernel
    # None
    if self.super_pixel:
      x = self.super_pixel(x, training)
      logging.info('SuperPixel %s: %s', self.name, x.shape)
    # None
    if self._block_args.fused_conv:
      # If use fused mbconv, skip expansion and use regular conv.
      x = self._relu_fn(self._bn1(self._fused_conv(x), training=training))
      logging.info('Conv2D shape: %s', x.shape)
    else:
      # Otherwise, first apply expansion and then apply depthwise conv.
      # 第一层不执行
      if self._block_args.expand_ratio != 1:
        x = self._relu_fn(self._bn0(self._expand_conv(x), training=training))
        logging.info('Expand shape: %s', x.shape)

      x = self._relu_fn(self._bn1(self._depthwise_conv(x), training=training))
      logging.info('DWConv shape: %s', x.shape)

    # True
    if self._se:
      x = self._se(x)

    self.endpoints = {'expansion_output': x}

    x = self._bn2(self._project_conv(x), training=training)
    # Add identity so that quantization-aware training can insert quantization
    # ops correctly.
    # tf.identity这里相当与克隆
    x = tf.identity(x)
    # False
    if self._clip_projection_output:
      x = tf.clip_by_value(x, -6, 6)
    # False
    if self._block_args.id_skip:
      if all(
          s == 1 for s in self._block_args.strides
      ) and self._block_args.input_filters == self._block_args.output_filters:
        # Apply only if skip connection presents.
        if survival_prob:
          x = utils.drop_connect(x, training, survival_prob)
        x = tf.add(x, inputs)
    logging.info('Project shape: %s', x.shape)
    return x

SE结构图:

代码如下:

class SE(tf.keras.layers.Layer):
  """Squeeze-and-excitation layer."""

  def __init__(self, global_params, se_filters, output_filters, name=None):
    super().__init__(name=name)

    # local_pooling默认为False
    self._local_pooling = global_params.local_pooling
    self._data_format = global_params.data_format
    self._relu_fn = global_params.relu_fn or tf.nn.swish

    # Squeeze and Excitation layer.
    self._se_reduce = tf.keras.layers.Conv2D(
        se_filters,
        kernel_size=[1, 1],
        strides=[1, 1],
        kernel_initializer=conv_kernel_initializer,
        padding='same',
        data_format=self._data_format,
        use_bias=True,
        name='conv2d')
    self._se_expand = tf.keras.layers.Conv2D(
        output_filters,
        kernel_size=[1, 1],
        strides=[1, 1],
        kernel_initializer=conv_kernel_initializer,
        padding='same',
        data_format=self._data_format,
        use_bias=True,
        name='conv2d_1')

  def call(self, inputs):
    h_axis, w_axis = [2, 3] if self._data_format == 'channels_first' else [1, 2]
    if self._local_pooling:
      se_tensor = tf.nn.avg_pool(
          inputs,
          ksize=[1, inputs.shape[h_axis], inputs.shape[w_axis], 1],
          strides=[1, 1, 1, 1],
          padding='VALID')
    else:
      se_tensor = tf.reduce_mean(inputs, [h_axis, w_axis], keepdims=True)
    se_tensor = self._se_expand(self._relu_fn(self._se_reduce(se_tensor)))
    logging.info('Built SE %s : %s', self.name, se_tensor.shape)
    return tf.sigmoid(se_tensor) * inputs

到此本章内容结束,下一章,Box与Class回归细节分析,敬请关注!!! 

 

深度学习论文: MOAT: Alternating Mobile Convolution and Attention Brings Strong Vision Models及其PyTorch实现 MOAT 分析了MBConv和Transformer Block 的优缺点,将二者有效地合并到MOAT Block中。此外,通过简单地将全局注意力转换为窗口注意力,MOAT可以无缝应用于需要大分辨率输入的下游任务。由于 Mobile Convolution 可以有效地在像素之间交换局部信息(从而跨窗口),MOAT不需要额外的窗口移动机制。 阅读详情

相关推荐

高效目标检测:EfficientDet-Pytorch实战指南

随着计算机视觉领域的发展,目标检测技术在安防、自动驾驶、医学影像等领域得到了广泛的应用。为了提高目标检测的准确性与效率,研究人员们提出了各种先进的模型架构。在此背景下,EfficientDet应运而生,作为基于EfficientNet的特征网络扩展,它的提出旨在解决传统目标检测模型在精度与速度之间的权衡问题。

weixin_42509888的博客 1261

09 EfficientNet系列

仅是个人笔记,代码学习资源来源B站博主。

weixin_63510030的博客 581

Tesseract-Ocr踩坑下载以及进行检验

1 OCR,即Optical Character Recognition:光学字符识别,是指通过扫描字符,然后通过其形状将其翻译成电子文本的过程。下载完成后进行解压找到这两个,然后复制到之前下载Tesseract-Ocr的tessdata文件下。可能会出现报错说chi下载的问题咱们不用管继续ok让它先下载完毕,后续会有下载chi的步骤。四、检验tesseract使用(将以下图片进行下载我这里将以下图片命名为3.png)我这里选的是2024年的版本如果下载不了;4 在安装的时候(找到下载的exe文件,双击)

m0_51428325的博客 1916

EfficientDet(EfficientNet+BiFPN)论文超详细解读(翻译+学习笔记+代码实现)

EfficientDet(EfficientNet+BiFPN)论文《EfficientDet: Scalable and Efficient Object Detection》超详细解读,含代码实现

路人贾的博客 1万+

L298N电机驱动模块的接线使用与代码实现

#include "iostm8s208mb.h" #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; // 关于LED灯的宏定义 #define LED2 PI_ODR_ODR2 //输出量 #define LE

Clichong 13万+

Telegram AI Bot自动化实战:5步用Make搭建业务工作台

Telegram Bot 是一种轻量级、高抵达率的消息自动化载体,其核心价值在于将结构化消息(如text、photo、callback_query)转化为可编程的事件流。基于 Bot API 的简洁设计与 Webhook 机制,开发者无需复杂鉴权即可实现毫秒级响应。结合低代码平台 Make,可快速构建具备上下文识别、条件路由、多系统分发与错误熔断能力的自动化流程。该方案特别适用于客服分发、数据同步、IoT告警等高频、规则明确、需即时反馈的业务场景,显著降低对 Python/Node.js 编程与 DevOp

weixin_33158887的博客 301

YOLOV5之backbone介绍与迁移使用

yolov5的特征提取网络:将PAN与PFN深度融合,对不同尺度鲁棒性强,可以即插即用,后接不同的检测器。

qq_45752541的博客 7475

基于微信小程序的扫码签到系统源码

大等于jdk1.8,大于mysql5.5,idea(eclipse),微信开发者工具。代码注释齐全,没有多余代码,适合学习(毕设),二次开发,包含论文技术相关文档。签到管理:新增签到,点击查看码展示二维码(有时效性)springboot mybatis 小程序。签到管理:查看用户创建的签到,可删除。用户管理:查看注册用户信息,及删除。签到记录:查看用户签到记录:可删除。个人信息:展示个人信息,可修改。统计分析:查看用户,签到数量。签到记录:查看用户签到记录。登录注册(含授权登录)我的签到:查看签到记录。

wfuhui的博客 5224

EfficientDet实验笔记

一些自己对EfficientDet的理解、总结以及实验

m0_53232749的博客 2241

SAP 与 Palantir 合作全景解析:这不是普通集成,而是把 ERP、数据语义层、云迁移与企业级 AI 串成一条价值链

SAP与Palantir的战略合作聚焦企业数字化转型核心痛点,通过深度技术整合构建"数据-决策-执行"闭环。合作包含四大主线:云迁移连续性保障、SAP业务数据云与Palantir平台对接、联合工程开发、高监管行业优先落地。技术实现上采用SAP认证插件,支持双向数据交互和实时业务动作触发。该合作突破了传统ERP系统局限,将业务语义与AI执行相结合,特别适合制造业供应链优化、财务争议处理等高价值场景,为企业在云迁移过程中实现业务连续性与智能化升级提供新范式。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 193

Python爬虫抓取淘宝商品详情页信息:从入门到高级技术应用

通过本篇博客,我们了解了如何使用Python爬虫抓取淘宝商品详情页的信息,如何使用requests和Selenium抓取静态和动态内容,如何应对淘宝的反爬虫机制,如何将抓取的数据保存到CSV文件等。随着爬虫技术的不断发展,开发者可以根据需要选择合适的工具和技术,如使用分布式爬虫框架提高抓取效率,或者利用OCR技术处理验证码等问题。在进行淘宝爬虫时,需要注意遵循相关法律法规和平台的爬虫政策,避免对平台造成过度的负担或侵犯其合法权益。

2201_76125261的博客 462

efficientnet

EfficentNet详解之MBConvBlock - 知乎Efficientnet 是基于MBConvBlock建立的网络。MBConvBlock模块的拓朴图如下: class MBConvBlock(nn.Module): """ Mobile Inverted Residual Bottleneck Block Args: block_args (namedtuple): BlockAr…https://zhuanlan.zhihu.com/p/258386372后ResNet时代的顶流Efficie

liguandong 2442

C#上位机性能优化全攻略:彻底解决界面卡顿+多线程死锁+PLC数据延迟,产线实测稳定运行2年

一开始我们用的是网上找的零散优化代码,根本满足不了要求,后来花了2个月的时间,把之前27条产线的代码整理、重构、优化,做了一套这套方案上线后,连续稳定运行2年零3个月:界面响应时间稳定在50ms以内,多线程死锁率持续为0,PLC数据延迟稳定在150ms以内,系统可用率≥99.99%,帮客户一年省下了超过480万的停线损失、罚款损失和人工成本,客户第二年就把剩下的22条产线也全部交给我们做了,还介绍了3家同行。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 294

EfficientDet模型解读(附源码+论文)

(建议看我的,关键部分代码注释详细,参考。

小西几的博客 4404

搞定ESD(九):静电放电之PCB设计

不同信号参考地平面应尽量保持完整,减小静电电流流过参考地平面时造成的电位差,防止电位差导致的信号传输电平错误.主芯片GPIO信号布线应保持最短化,减小与参考地平面之间的电场耦合,同时也防止因信号环路面积较大耦合静电放电噪声干扰。外部端子接地引脚顶层采用分地设计,最好是直接过孔到完整参考地平面接地,避免与顶层信号包地、其它包地相连,防止顶层串扰耦合到其它信号,造成ESD问题。

记得诚 1952

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Channel-separation-based Network for Object Detection under Foggy Conditions

现存的一些方法尝试恢复高质量图像,但这会增加网络复杂性并且丢失图像的潜在信息。在这项研究中,一个基于通道分离的检测网络被提出用来保存潜在信息。特别地,雾过滤器用于在图像处理期间执行修剪,以保持图像的潜在信息。通过把深层特征提取替换为一个即插即用模块(MBConvBlock)和使用一个新的CSPBottleNeck和CrossConv联合,我们的模型克服了卷积神经网络固有的缺点,并具有全局感受野和专注于更关键的特征。这个模型使用端到端的方法和混合数据进行训练,因此课题提高模型网络的泛化能力。

weixin_47020721的博客 1318

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

EfficientDet网络解析

EfficientDet网络解析模型效果模型结构EfficientNet网络BiFPN网络anchorLoss函数Compound Scaling的影响EfficientDet系列参数EfficientDet系列模型效果 模型效果 EfficientDet在COCO上的精度和模型FLOPs如下所示: 模型结构 EfficientDet以EfficientNet网络作为backbone,BiFPN作为特征融合网络, 最终共享class/box预测网络。 EfficientNet网络 EfficientNe

bblingbbling的博客 2827

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

CoAtNet:Marrying Convolution and Attentionfor All Data Sizes文章详解(结合代码)

混合深度卷积和自注意力论文中提到了的 ViT 的主要限制之一是其令人印象深刻的数据需求。虽然 ViT 在庞大的 JFT300M 数据集上显示出令人兴奋的结果,但它在数据量少的情况下性能仍然不如的经典 CNN。这表明 Transformers 可能缺少 CNN 拥有的泛化能力,因此需要大量数据来弥补。但是与 CNN 相比,注意力模型具有更高的模型容量。

Orange_sparkle的博客 2080

【轻量化网络系列(6)】EfficientNetV1论文超详细解读(翻译 +学习笔记+代码实现)

EfficientNetv1论文《EfficientNet:Rethinking Model Scaling for Convolutional Neural Networks》翻译+超详细精读,含代码复现

路人贾的博客 1万+

【人工智能笔记】第二十节 efficientdet 目标检测模型,官方源码分析系列,BiFPN实现细节分析(二)

本章继续分析,BiFPN的实现部分。各种FPN结构如下: 如图,单个BiFPN有8个Node。在Efficientdet模型中,由如下类组成: FPNCells:按fpn_cell_repeats参数生成重复多个BiFPN。 FPNCell:代表单个BiFPN,包含8个Node。 FNode:将当前Node的多个输入融合,产生一个输出。 代码结构如下: FPNCells代码如下: class FPNCells(tf.keras.layers.Layer): .

不定时更新AI技术tensorflow实现方式,欢迎关注,有问题请私信我。 4033

EfficientDet论文讲解

efficientdet论文讲解

整理ing 1085

EfficientNet V2(ICML 2021)原理与代码解析

基于这些观察结果,作者设计了一个包含额外算子ops如Fused-MBConv的搜索空间,并应用训练感知training-aware的NAS和缩放scaling来联合优化模型精度、训练速度和参数大小。最终搜索到的网络即为EfficientNetV2。 此外,本文还提出了一种改进的渐进式训练progressive learning方法:在训练的早期用较小的输入和较弱的正则化,随着训练的进行,逐渐增大输入分辨率和正则化的强度。基于这种训练方法,可以加快训练速度而不会导致准确率下降。

00000cj的博客 2658

MOAT: ALTERNATING MOBILE CONVOLUTION AND ATTENTION BRINGS STRONG VISION MODELS

本文介绍了MOA-T,这是一个建立在MObile卷积(即反向残差块)和Attension之上的神经网络家族。与当前堆叠分离的移动卷积和transformer的工作不同,本文有效地将它们合并为MOA-T。从标准Transformer块开始,将其多层感知器替换为MObile卷积,并在自注意力操作之前对其进行重新排序。MObile卷积不仅增强了网络表示能力,而且产生了更好的下采样特征。简单的MOA-T网络非常有效,通过ImageNet-22K预训练,在ImageNet-1K上实现了89.1%的top1精度。此外,

qq_52302919的博客 2267

你真的理解Faster RCNN吗?捋一捋Pytorch官方Faster RCNN代码

作者丨白裳@知乎来源丨https://zhuanlan.zhihu.com/p/145842317编辑丨极市平台目前 pytorch 已经在 torchvision 模块集成了 Fast...

zandaoguang的博客 2366

[目标检测]EfficientDet

文章目录背景性能模型结构后处理损失函数 背景 模型的效率在计算机视觉中变得越来越重要,作者系统地研究了用于目标检测的神经网络体系结构设计选择并提出一些关键的优化措施以提高效。首先,提出一个新的FPN结构BiFPN。其次,我们提出了一种复合缩放方法,该方法可以在同一时间统一缩放所有主干,特征网络和框/类预测网络的分辨率,深度和宽度。 性能 model AP Params EfficientDet-D0 (512) 34.3 3.9M EfficientDet-D1 (640) 40.2 6

认真写的博客 1207
上一篇: 【人工智能笔记】第十八节 tensorflow 2.0 分布式训练之多服务器的实现方式
下一篇: 【人工智能笔记】第二十节 efficientdet 目标检测模型,官方源码分析系列,BiFPN实现细节分析(二)
PPHT-H
博客等级 码龄18年 6254粉丝 84原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PPHT-H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值