Containing Block

 

Containing Block

hanlray@gmail.com
Reversion:1.0 Date:2006/08/19

稍微复习一下CSS的Visual Formatting Model:display property控制着box的产生,none值不产生box,block等值使element产生一个block box,inline等值使elment产生一个或多个inline box;normal flow里的每个box都参与一个formatting context,具有相同containing block的boxes参与同一个formatting context,block boxes参与block formatting context,inline boxes参与inline formatting context;在一个block formatting context里,boxes(block boxes)从containing block的顶部开始,一个接一个垂直排列,在一个inline formatting context里,boxes(inline boxes)从containing block的顶部开始,一个接一个水平排列。

一个element的containing block是该element产生的box(es)在计算位置和大小时参考的一个矩形。通常在一个html(xhtml)文档中,大多数element的containing block都由一个block box来担当,为该block box的content area,因此我们常直接说这些element的containing block是某个block box,实际指的是该block box的content area。不过并不是所有element的containing block都是由一个containing block来担当的,比如root element的containg block,对continous media来说是anchor在canvas的原点、大小是viewport的矩形,对page media来说是page box的page area,大小也是viewport。一个block box为其descendant boxes建立了一个containing block,对其normal flow里的boxes建立了一个formatting context,该containing block包含的boxes按照这个formatting context的规则进行布局。

如果把一个element的containing block简单地理解为该element的parent element产生的box,在某些情况下你将无法解释浏览器的布局行为,下面是CSS 2.1 Specification上的一个例子:

  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>

      <meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
      <title></title>
      <script type="text/css">
      body {
      display: inline;
      }
      </script>
    </head>

  
    <body>
      This is anonymous text before the p.
      <p>This is the content of p.</p>
      This is anonymous text after the p.
    </body>
  </html>

这里用CSS把body变成了一个inline-level element,但p仍然是一个block-level element,这样body就被p打断而产生两个inline box,分别对应第一句话和第三句话,这时p产生的block box应该以哪个矩形为参考进行放置呢?无论选择第一个inline box或第二个inline box,还是由这两个inline box计算出的矩形,都无法解释其在一个符合CSS2.1的浏览器上的表现。事实上,这里p的containing block由html产生的block box来担当的,其产生的block box应该以html产生的block box的content area为参考进行放置,因为CSS2.1是这么说的:对root element以外的element,如果该element的position为relative或static,其containg block是离该element最近的、block-level或table cell或inline-block的ancestor box的content area。有了这个认识,再来解释这段代码在浏览器上的表现:p的containing block是html产生的block box,因此紧挨页面的左边缘,body产生的两个inline box的containg block也是html的box,但是由于一个containing box只能包含一种box,要么全是block boxes,要么全是inline boxes,因此会产生两个匿名block box,分别包着这两个inline boxes,这样这三个block box都参与到一个block formatting context中,从containing box的顶部,按照文档中出现的次序,从上到下垂直排列;由于在html的default style sheet里,body的margin值为8pt,这个margin应用到两个inline box上,从而使第一句话和第三句话离页面左边缘有了一段8pt的距离。

在default style sheet下,试图仅仅通过把一个block-level element变成inline-level element来把该element的box(es)放置在其上一个element的box的右边,必须满足两个条件: 1.和该element属于同一个containing block的element必须都是inline-level的,否则inline-level element产生的inline box(es)都将被包在一个匿名block box里,从而垂直排列 2.该element的子女也必须是inline-level的,原因上面已经解释过了。

class SqueezeExcite(nn.Module): """ Squeeze-and-Excitation w/ specific features for EfficientNet/MobileNet family Args: in_chs (int): input channels to layer rd_ratio (float): ratio of squeeze reduction act_layer (nn.Module): activation layer of containing block gate_layer (Callable): attention gate function force_act_layer (nn.Module): override block's activation fn if this is set/bound rd_round_fn (Callable): specify a fn to calculate rounding of reduced chs """ def __init__( self, in_chs: int, rd_ratio: float = 0.25, rd_channels: Optional[int] = None, act_layer: LayerType = nn.ReLU, gate_layer: LayerType = nn.Sigmoid, force_act_layer: Optional[LayerType] = None, rd_round_fn: Optional[Callable] = None, ): super(SqueezeExcite, self).__init__() if rd_channels is None: rd_round_fn = rd_round_fn or round rd_channels = rd_round_fn(in_chs * rd_ratio) act_layer = force_act_layer or act_layer self.conv_reduce = nn.Conv2d(in_chs, rd_channels, 1, bias=True) self.act1 = create_act_layer(act_layer, inplace=True) self.conv_expand = nn.Conv2d(rd_channels, in_chs, 1, bias=True) self.gate = create_act_layer(gate_layer) def forward(self, x): x_se = x.mean((2, 3), keepdim=True) x_se = self.conv_reduce(x_se) x_se = self.act1(x_se) x_se = self.conv_expand(x_se) return x * self.gate(x_se) class iRMB(nn.Module): def __init__(self, dim_in, dim_out, norm_in=True, has_skip=True, exp_ratio=1.0, norm_layer='bn_2d', act_layer='relu', v_proj=True, dw_ks=3, stride=1, dilation=1, se_ratio=0.0, dim_head=64, window_size=7, attn_s=True, qkv_bias=False, attn_drop=0., drop=0., drop_path=0., v_group=False, attn_pre=False): super().__init__() self.norm = get_norm(norm_layer)(dim_in) if norm_in else nn.Identity() dim_mid = int(dim_in * exp_ratio) self.has_skip = (dim_in == dim_out and stride == 1) and has_skip self.attn_s = attn_s if self.attn_s: assert dim_in % dim_head == 0, 'dim should be divisible by num_heads' self.dim_head = dim_head self.window_size = window_size self.num_head = dim_in // dim_head self.scale = self.dim_head ** -0.5 self.attn_pre = attn_pre self.qk = ConvNormAct(dim_in, int(dim_in * 2), kernel_size=1, bias=qkv_bias, norm_layer='none', act_layer='none') self.v = ConvNormAct(dim_in, dim_mid, kernel_size=1, groups=self.num_head if v_group else 1, bias=qkv_bias, norm_layer='none', act_layer=act_layer, inplace=inplace) self.attn_drop = nn.Dropout(attn_drop) else: if v_proj: self.v = ConvNormAct(dim_in, dim_mid, kernel_size=1, bias=qkv_bias, norm_layer='none', act_layer=act_layer, inplace=inplace) else: self.v = nn.Identity() self.conv_local = ConvNormAct(dim_mid, dim_mid, kernel_size=dw_ks, stride=stride, dilation=dilation, groups=dim_mid, norm_layer='bn_2d', act_layer='silu', inplace=inplace) self.se = SE(dim_mid, rd_ratio=se_ratio, act_layer=get_act(act_layer)) if se_ratio > 0.0 else nn.Identity() self.proj_drop = nn.Dropout(drop) self.proj = ConvNormAct(dim_mid, dim_out, kernel_size=1, norm_layer='none', act_layer='none', inplace=inplace) self.drop_path = DropPath(drop_path) if drop_path else nn.Identity() def forward(self, x): shortcut = x x = self.norm(x) B, C, H, W = x.shape if self.attn_s: # padding if self.window_size <= 0: window_size_W, window_size_H = W, H else: window_size_W, window_size_H = self.window_size, self.window_size pad_l, pad_t = 0, 0 pad_r = (window_size_W - W % window_size_W) % window_size_W pad_b = (window_size_H - H % window_size_H) % window_size_H x = F.pad(x, (pad_l, pad_r, pad_t, pad_b, 0, 0,)) n1, n2 = (H + pad_b) // window_size_H, (W + pad_r) // window_size_W x = rearrange(x, 'b c (h1 n1) (w1 n2) -> (b n1 n2) c h1 w1', n1=n1, n2=n2).contiguous() # attention b, c, h, w = x.shape qk = self.qk(x) qk = rearrange(qk, 'b (qk heads dim_head) h w -> qk b heads (h w) dim_head', qk=2, heads=self.num_head, dim_head=self.dim_head).contiguous() q, k = qk[0], qk[1] attn_spa = (q @ k.transpose(-2, -1)) * self.scale attn_spa = attn_spa.softmax(dim=-1) attn_spa = self.attn_drop(attn_spa) if self.attn_pre: x = rearrange(x, 'b (heads dim_head) h w -> b heads (h w) dim_head', heads=self.num_head).contiguous() x_spa = attn_spa @ x x_spa = rearrange(x_spa, 'b heads (h w) dim_head -> b (heads dim_head) h w', heads=self.num_head, h=h, w=w).contiguous() x_spa = self.v(x_spa) else: v = self.v(x) v = rearrange(v, 'b (heads dim_head) h w -> b heads (h w) dim_head', heads=self.num_head).contiguous() x_spa = attn_spa @ v x_spa = rearrange(x_spa, 'b heads (h w) dim_head -> b (heads dim_head) h w', heads=self.num_head, h=h, w=w).contiguous() # unpadding x = rearrange(x_spa, '(b n1 n2) c h1 w1 -> b c (h1 n1) (w1 n2)', n1=n1, n2=n2).contiguous() if pad_r > 0 or pad_b > 0: x = x[:, :, :H, :W].contiguous() else: x = self.v(x) x = x + self.se(self.conv_local(x)) if self.has_skip else self.se(self.conv_local(x)) x = self.proj_drop(x) x = self.proj(x) x = (shortcut + self.drop_path(x)) if self.has_skip else x return x 这是SE模块和iRMB的代码,请你根据代码帮我绘制详细的结构图
最新发布
06-29
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值