国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

開(kāi)源庫(kù) timm | 基于 Pytorch 的28個(gè)視覺(jué) Transformer 實(shí)現(xiàn)方法

共 31180字,需瀏覽 63分鐘

 ·

2021-02-22 11:41

作者丨科技猛獸
轉(zhuǎn)自丨極市平臺(tái)

導(dǎo)讀

?

本文將介紹一個(gè)優(yōu)秀的PyTorch開(kāi)源庫(kù)——timm庫(kù),并對(duì)其中的vision transformer.py代碼進(jìn)行了詳細(xì)解讀。

Transformer 架構(gòu)早已在自然語(yǔ)言處理任務(wù)中得到廣泛應(yīng)用,但在計(jì)算機(jī)視覺(jué)領(lǐng)域中仍然受到限制。在計(jì)算機(jī)視覺(jué)領(lǐng)域,目前已有大量工作表明模型對(duì) CNN 的依賴(lài)不是必需的,當(dāng)直接應(yīng)用于圖像塊序列時(shí),Transformer 也能很好地執(zhí)行圖像分類(lèi)任務(wù)。
本文將簡(jiǎn)要介紹了優(yōu)秀的 PyTorch Image Model 庫(kù):timm庫(kù)。與此同時(shí),將會(huì)為大家詳細(xì)介紹其中的視覺(jué)Transformer代碼以及一個(gè)優(yōu)秀的視覺(jué)Transformer 的PyTorch實(shí)現(xiàn),以幫助大家更快地開(kāi)展相關(guān)實(shí)驗(yàn)。

什么是timm庫(kù)?

PyTorchImageModels,簡(jiǎn)稱(chēng)timm,是一個(gè)巨大的PyTorch代碼集合,包括了一系列:

  • image models
  • layers
  • utilities
  • optimizers
  • schedulers
  • data-loaders / augmentations
  • training / validation scripts

旨在將各種SOTA模型整合在一起,并具有復(fù)現(xiàn)ImageNet訓(xùn)練結(jié)果的能力。

timm庫(kù)作者是來(lái)自加拿大溫哥華的Ross Wightman。

作者github鏈接:

https://github.com/rwightman

timm庫(kù)鏈接:

https://github.com/rwightman/pytorch-image-models

所有的PyTorch模型及其對(duì)應(yīng)arxiv鏈接如下:


  • Big Transfer ResNetV2 (BiT) - https://arxiv.org/abs/1912.11370

  • CspNet (Cross-Stage Partial Networks) - https://arxiv.org/abs/1911.11929

  • DeiT (Vision Transformer) - https://arxiv.org/abs/2012.12877

  • DenseNet - https://arxiv.org/abs/1608.06993

  • DLA - https://arxiv.org/abs/1707.06484

  • DPN (Dual-Path Network) - https://arxiv.org/abs/1707.01629

  • EfficientNet (MBConvNet Family)

  • EfficientNet NoisyStudent (B0-B7, L2) - https://arxiv.org/abs/1911.04252

  • EfficientNet AdvProp (B0-B8) - https://arxiv.org/abs/1911.09665

  • EfficientNet (B0-B7) - https://arxiv.org/abs/1905.11946

  • EfficientNet-EdgeTPU (S, M, L) - https://ai.googleblog.com/2019/08/efficientnet-edgetpu-creating.html

  • FBNet-C - https://arxiv.org/abs/1812.03443

  • MixNet - https://arxiv.org/abs/1907.09595

  • MNASNet B1, A1 (Squeeze-Excite), and Small - https://arxiv.org/abs/1807.11626

  • MobileNet-V2 - https://arxiv.org/abs/1801.04381

  • Single-Path NAS - https://arxiv.org/abs/1904.02877

  • GPU-Efficient Networks - https://arxiv.org/abs/2006.14090

  • HRNet - https://arxiv.org/abs/1908.07919

  • Inception-V3 - https://arxiv.org/abs/1512.00567

  • Inception-ResNet-V2 and Inception-V4 - https://arxiv.org/abs/1602.07261

  • MobileNet-V3 (MBConvNet w/ Efficient Head) - https://arxiv.org/abs/1905.02244

  • NASNet-A - https://arxiv.org/abs/1707.07012

  • NFNet-F - https://arxiv.org/abs/2102.06171

  • NF-RegNet / NF-ResNet - https://arxiv.org/abs/2101.08692

  • PNasNet - https://arxiv.org/abs/1712.00559

  • RegNet - https://arxiv.org/abs/2003.13678

  • RepVGG - https://arxiv.org/abs/2101.03697

  • ResNet/ResNeXt

  • ResNet (v1b/v1.5) - https://arxiv.org/abs/1512.03385

  • ResNeXt - https://arxiv.org/abs/1611.05431

  • 'Bag of Tricks' / Gluon C, D, E, S variations - https://arxiv.org/abs/1812.01187

  • Weakly-supervised (WSL) Instagram pretrained / ImageNet tuned ResNeXt101 - https://arxiv.org/abs/1805.00932

  • Semi-supervised (SSL) / Semi-weakly Supervised (SWSL) ResNet/ResNeXts - https://arxiv.org/abs/1905.00546

  • ECA-Net (ECAResNet) - https://arxiv.org/abs/1910.03151v4

  • Squeeze-and-Excitation Networks (SEResNet) - https://arxiv.org/abs/1709.01507

  • Res2Net - https://arxiv.org/abs/1904.01169

  • ResNeSt - https://arxiv.org/abs/2004.08955

  • ReXNet - https://arxiv.org/abs/2007.00992

  • SelecSLS - https://arxiv.org/abs/1907.00837

  • Selective Kernel Networks - https://arxiv.org/abs/1903.06586

  • TResNet - https://arxiv.org/abs/2003.13630

  • Vision Transformer - https://arxiv.org/abs/2010.11929

  • VovNet V2 and V1 - https://arxiv.org/abs/1911.06667

  • Xception - https://arxiv.org/abs/1610.02357

  • Xception (Modified Aligned, Gluon) - https://arxiv.org/abs/1802.02611

  • Xception (Modified Aligned, TF) - https://arxiv.org/abs/1802.02611


timm庫(kù)特點(diǎn)

所有的模型都有默認(rèn)的API:

  • accessing/changing the classifier -?get_classifier?and?reset_classifier
  • 只對(duì)features做前向傳播 -?forward_features

所有模型都支持多尺度特征提取 (feature pyramids) (通過(guò)create_model函數(shù)):

  • create_model(name, features_only=True, out_indices=..., output_stride=...)

out_indices?指定返回哪個(gè)feature maps to return, 從0開(kāi)始,out_indices[i]對(duì)應(yīng)著?C(i + 1)?feature level。

output_stride?通過(guò)dilated convolutions控制網(wǎng)絡(luò)的output stride。大多數(shù)網(wǎng)絡(luò)默認(rèn) stride 32 。

所有的模型都有一致的pretrained weight loader,adapts last linear if necessary。

訓(xùn)練方式支持:

  • NVIDIA DDP w/ a single GPU per process, multiple processes with APEX present (AMP mixed-precision optional)
  • PyTorch DistributedDataParallel w/ multi-gpu, single process (AMP disabled as it crashes when enabled)
  • PyTorch w/ single GPU single process (AMP optional)

動(dòng)態(tài)的全局池化方式可以選擇:?average pooling, max pooling, average + max, or concat([average, max]),默認(rèn)是adaptive average。

Schedulers:

Schedulers 包括step,cosinew/ restarts,tanhw/ restarts,plateau?。

Optimizer:

  • rmsprop_tf?adapted from PyTorch RMSProp by myself. Reproduces much improved Tensorflow RMSProp behaviour.
  • radam?by Liyuan Liu (https://arxiv.org/abs/1908.03265)
  • novograd?by Masashi Kimura (https://arxiv.org/abs/1905.11286)
  • lookahead?adapted from impl by Liam (https://arxiv.org/abs/1907.08610)
  • fused?optimizers by name with NVIDIA Apex installed
  • adamp?and?sgdp?by Naver ClovAI (https://arxiv.org/abs/2006.08217)
  • adafactor?adapted from FAIRSeq impl (https://arxiv.org/abs/1804.04235)
  • adahessian?by David Samuel (https://arxiv.org/abs/2006.00719)

timm庫(kù) vision_transformer.py代碼解讀

代碼來(lái)自:

https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/vision_transformer.py

對(duì)應(yīng)的論文是ViT,是除了官方開(kāi)源的代碼之外的又一個(gè)優(yōu)秀的PyTorch implement。

An Image Is Worth 16 x 16 Words: Transformers for Image Recognition at Scale

An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale

https://arxiv.org/abs/2010.11929

另一篇工作DeiT也大量借鑒了timm庫(kù)這份代碼的實(shí)現(xiàn):

Training data-efficient image transformers & distillation through attention

Training data-efficient image transformers & distillation through attention

https://arxiv.org/abs/2012.12877

vision_transformer.py:

代碼中定義的變量的含義如下:

img_size:tuple?類(lèi)型,里面是int類(lèi)型,代表輸入的圖片大小,默認(rèn)是?224。
patch_size:tuple?類(lèi)型,里面是int類(lèi)型,代表Patch的大小,默認(rèn)是?16
in_chans:int?類(lèi)型,代表輸入圖片的channel數(shù),默認(rèn)是3
num_classes:int?類(lèi)型classification head的分類(lèi)數(shù),比如CIFAR100就是100,默認(rèn)是?1000。
embed_dim:int?類(lèi)型Transformer的embedding dimension,默認(rèn)是?768。
depth:int??類(lèi)型,Transformer的Block的數(shù)量,默認(rèn)是?12。
num_heads:int?類(lèi)型,attention heads的數(shù)量,默認(rèn)是12
mlp_ratio:int?類(lèi)型,mlp hidden dim/embedding dim的值,默認(rèn)是?4。
qkv_bias:bool?類(lèi)型,attention模塊計(jì)算qkv時(shí)需要bias嗎,默認(rèn)是?True。
qk_scale:?一般設(shè)置成?None?就行。
drop_rate:float?類(lèi)型,dropout rate,默認(rèn)是?0。
attn_drop_rate:float?類(lèi)型,attention模塊的dropout rate,默認(rèn)是?0。
drop_path_rate:float?類(lèi)型,默認(rèn)是?0
hybrid_backbone:nn.Module?類(lèi)型,在把圖片轉(zhuǎn)換成Patch之前,需要先通過(guò)一個(gè)Backbone嗎?默認(rèn)是?None
如果是None,就直接把圖片轉(zhuǎn)化成Patch。
如果不是None,就先通過(guò)這個(gè)Backbone,再轉(zhuǎn)化成Patch。
norm_layer:nn.Module?類(lèi)型,歸一化層類(lèi)型,默認(rèn)是?None

1. 導(dǎo)入必要的庫(kù)和模型

import mathimport loggingfrom functools import partialfrom collections import OrderedDict
import torchimport torch.nn as nnimport torch.nn.functional as F
from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STDfrom .helpers import load_pretrainedfrom .layers import StdConv2dSame, DropPath, to_2tuple, trunc_normal_from .resnet import resnet26d, resnet50dfrom .resnetv2 import ResNetV2from?.registry?import?register_model
2. 定義一個(gè)字典,代表標(biāo)準(zhǔn)的模型,如果需要更改模型超參數(shù)只需要改變_cfg
的傳入的參數(shù)即可。
def _cfg(url='', **kwargs):    return {        'url': url,        'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None,        'crop_pct': .9, 'interpolation': 'bicubic',        'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD,        'first_conv': 'patch_embed.proj', 'classifier': 'head',        **kwargs    }

3. default_cfgs代表支持的所有模型,也定義成字典的形式:

vit_small_patch16_224里面的small代表小模型。
ViT的第一步要把圖片分成一個(gè)個(gè)patch,然后把這些patch組合在一起作為對(duì)圖像的序列化操作,比如一張224 × 224的圖片分成大小為16 × 16的patch,那一共可以分成196個(gè)。所以這個(gè)圖片就序列化成了(196, 256)的tensor。所以這里的:
16:?就代表patch的大小。
224:?就代表輸入圖片的大小。
按照這個(gè)命名方式,支持的模型有:vit_base_patch16_224,vit_base_patch16_384等等。

后面的vit_deit_base_patch16_224等等模型代表DeiT這篇論文的模型。

default_cfgs = {    # patch models (my experiments)    'vit_small_patch16_224': _cfg(        url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-weights/vit_small_p16_224-15ec54c9.pth',    ),
# patch models (weights ported from official Google JAX impl) 'vit_base_patch16_224': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_224-80ecf9dd.pth', mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), ), 'vit_base_patch32_224': _cfg( url='', # no official model weights for this combo, only for in21k mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)), 'vit_base_patch16_384': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p16_384-83fb41ba.pth', input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0), 'vit_base_patch32_384': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_p32_384-830016f5.pth', input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0), 'vit_large_patch16_224': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p16_224-4ee7a4dc.pth', mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)), 'vit_large_patch32_224': _cfg( url='', # no official model weights for this combo, only for in21k mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)), 'vit_large_patch16_384': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p16_384-b3be5167.pth', input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0), 'vit_large_patch32_384': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_p32_384-9b920ba8.pth', input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0),
# patch models, imagenet21k (weights ported from official Google JAX impl) 'vit_base_patch16_224_in21k': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_patch16_224_in21k-e5005f0a.pth', num_classes=21843, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)), 'vit_base_patch32_224_in21k': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_patch32_224_in21k-8db57226.pth', num_classes=21843, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)), 'vit_large_patch16_224_in21k': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_patch16_224_in21k-606da67d.pth', num_classes=21843, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)), 'vit_large_patch32_224_in21k': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_large_patch32_224_in21k-9046d2e7.pth', num_classes=21843, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)), 'vit_huge_patch14_224_in21k': _cfg( url='', # FIXME I have weights for this but > 2GB limit for github release binaries num_classes=21843, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)),
# hybrid models (weights ported from official Google JAX impl) 'vit_base_resnet50_224_in21k': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_resnet50_224_in21k-6f7c7740.pth', num_classes=21843, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=0.9, first_conv='patch_embed.backbone.stem.conv'), 'vit_base_resnet50_384': _cfg( url='https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-vitjx/jx_vit_base_resnet50_384-9fd3c705.pth', input_size=(3, 384, 384), mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), crop_pct=1.0, first_conv='patch_embed.backbone.stem.conv'),
# hybrid models (my experiments) 'vit_small_resnet26d_224': _cfg(), 'vit_small_resnet50d_s3_224': _cfg(), 'vit_base_resnet26d_224': _cfg(), 'vit_base_resnet50d_224': _cfg(),
# deit models (FB weights) 'vit_deit_tiny_patch16_224': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_tiny_patch16_224-a1311bcf.pth'), 'vit_deit_small_patch16_224': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_small_patch16_224-cd65a155.pth'), 'vit_deit_base_patch16_224': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_base_patch16_224-b5f2ef4d.pth',), 'vit_deit_base_patch16_384': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_base_patch16_384-8de9b5d1.pth', input_size=(3, 384, 384), crop_pct=1.0), 'vit_deit_tiny_distilled_patch16_224': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_tiny_distilled_patch16_224-b40b3cf7.pth'), 'vit_deit_small_distilled_patch16_224': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_small_distilled_patch16_224-649709d9.pth'), 'vit_deit_base_distilled_patch16_224': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_base_distilled_patch16_224-df68dfff.pth', ), 'vit_deit_base_distilled_patch16_384': _cfg( url='https://dl.fbaipublicfiles.com/deit/deit_base_distilled_patch16_384-d0272ac0.pth', input_size=(3, 384, 384), crop_pct=1.0),}

4. FFN實(shí)現(xiàn):

class Mlp(nn.Module):    def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):        super().__init__()        out_features = out_features or in_features        hidden_features = hidden_features or in_features        self.fc1 = nn.Linear(in_features, hidden_features)        self.act = act_layer()        self.fc2 = nn.Linear(hidden_features, out_features)        self.drop = nn.Dropout(drop)
def forward(self, x): x = self.fc1(x) x = self.act(x) x = self.drop(x) x = self.fc2(x) x = self.drop(x)????????return?x

5. Attention實(shí)現(xiàn):

在python 3.5以后,@是一個(gè)操作符,表示矩陣-向量乘法
A@x 就是矩陣-向量乘法A*x: np.dot(A, x)。

class Attention(nn.Module):    def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):        super().__init__()        self.num_heads = num_heads        head_dim = dim // num_heads        # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights        self.scale = qk_scale or head_dim ** -0.5
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) self.attn_drop = nn.Dropout(attn_drop) self.proj = nn.Linear(dim, dim) self.proj_drop = nn.Dropout(proj_drop)
def forward(self, x): B, N, C = x.shape qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
attn = (q @ k.transpose(-2, -1)) * self.scale attn = attn.softmax(dim=-1) attn = self.attn_drop(attn)
x = (attn @ v).transpose(1, 2).reshape(B, N, C) x = self.proj(x) x = self.proj_drop(x)
# x: (B, N, C) return x

6. 包含Attention和Add & Norm的Block實(shí)現(xiàn):

圖1:Block類(lèi)對(duì)應(yīng)結(jié)構(gòu)

不同之處是:
先進(jìn)行Norm,再Attention;先進(jìn)行Norm,再通過(guò)FFN (MLP)。

class Block(nn.Module):    def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,                 drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm):        super().__init__()        self.norm1 = norm_layer(dim)        self.attn = Attention(            dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)        # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()        self.norm2 = norm_layer(dim)        mlp_hidden_dim = int(dim * mlp_ratio)        self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
def forward(self, x): x = x + self.drop_path(self.attn(self.norm1(x))) x = x + self.drop_path(self.mlp(self.norm2(x))) return x

7. 接下來(lái)要把圖片轉(zhuǎn)換成Patch,一種做法是直接把Image轉(zhuǎn)化成Patch,另一種做法是把Backbone輸出的特征轉(zhuǎn)化成Patch。

1) 直接把Image轉(zhuǎn)化成Patch:

輸入的x的維度是:(B, C, H, W)
輸出的PatchEmbedding的維度是:(B, 14*14, 768),768表示embed_dim,14*14表示一共有196個(gè)Patches。

class PatchEmbed(nn.Module):    """ Image to Patch Embedding    """    def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768):        super().__init__()        img_size = to_2tuple(img_size)        patch_size = to_2tuple(patch_size)        num_patches = (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0])        self.img_size = img_size        self.patch_size = patch_size        self.num_patches = num_patches
self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)
def forward(self, x): B, C, H, W = x.shape # FIXME look at relaxing size constraints assert H == self.img_size[0] and W == self.img_size[1], \ f"Input image size ({H}*{W}) doesn't match model ({self.img_size[0]}*{self.img_size[1]})." x = self.proj(x).flatten(2).transpose(1, 2)
# x: (B, 14*14, 768)????????return?x

2) 把Backbone輸出的特征轉(zhuǎn)化成Patch:

輸入的x的維度是:(B, C, H, W)
得到Backbone輸出的維度是:(B, feature_size, feature_size, feature_dim)
輸出的PatchEmbedding的維度是:(B, feature_size, feature_size, embed_dim),一共有feature_size * feature_size個(gè)Patches。

class HybridEmbed(nn.Module):    """ CNN Feature Map Embedding    Extract feature map from CNN, flatten, project to embedding dim.    """    def __init__(self, backbone, img_size=224, feature_size=None, in_chans=3, embed_dim=768):        super().__init__()        assert isinstance(backbone, nn.Module)        img_size = to_2tuple(img_size)        self.img_size = img_size        self.backbone = backbone        if feature_size is None:            with torch.no_grad():                # FIXME this is hacky, but most reliable way of determining the exact dim of the output feature                # map for all networks, the feature metadata has reliable channel and stride info, but using                # stride to calc feature dim requires info about padding of each stage that isn't captured.                training = backbone.training                if training:                    backbone.eval()                o = self.backbone(torch.zeros(1, in_chans, img_size[0], img_size[1]))                if isinstance(o, (list, tuple)):                    o = o[-1]  # last feature if backbone outputs list/tuple of features                feature_size = o.shape[-2:]                feature_dim = o.shape[1]                backbone.train(training)        else:            feature_size = to_2tuple(feature_size)            if hasattr(self.backbone, 'feature_info'):                feature_dim = self.backbone.feature_info.channels()[-1]            else:                feature_dim = self.backbone.num_features        self.num_patches = feature_size[0] * feature_size[1]        self.proj = nn.Conv2d(feature_dim, embed_dim, 1)
def forward(self, x): x = self.backbone(x) if isinstance(x, (list, tuple)): x = x[-1] # last feature if backbone outputs list/tuple of features x = self.proj(x).flatten(2).transpose(1, 2) return x

8. 以上是ViT所需的所有模塊的定義,下面是VisionTransformer 這個(gè)類(lèi)的實(shí)現(xiàn):

8.1 使用這個(gè)類(lèi)時(shí)需要傳入的變量,其含義已經(jīng)在本小節(jié)一開(kāi)始介紹。

class VisionTransformer(nn.Module):    """ Vision Transformer
A PyTorch impl of : `An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale` - https://arxiv.org/abs/2010.11929 """ def __init__(self, img_size=224, patch_size=16, in_chans=3, num_classes=1000, embed_dim=768, depth=12, num_heads=12, mlp_ratio=4., qkv_bias=True, qk_scale=None, representation_size=None,?????????????????drop_rate=0.,?attn_drop_rate=0.,?drop_path_rate=0.,?hybrid_backbone=None,?norm_layer=None):

8.2 得到分塊后的Patch的數(shù)量:

super().__init__()self.num_classes = num_classesself.num_features = self.embed_dim = embed_dim  # num_features for consistency with other modelsnorm_layer = norm_layer or partial(nn.LayerNorm, eps=1e-6)
if hybrid_backbone is not None: self.patch_embed = HybridEmbed( hybrid_backbone, img_size=img_size, in_chans=in_chans, embed_dim=embed_dim)else: self.patch_embed = PatchEmbed( img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim)num_patches?=?self.patch_embed.num_patches

8.3 class token:

一開(kāi)始定義成(1, 1, 768),之后再變成(B, 1, 768)。

self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))

8.4 定義位置編碼:

self.pos_embed?=?nn.Parameter(torch.zeros(1,?num_patches?+?1,?embed_dim))

8.5 把12個(gè)Block連接起來(lái):

self.pos_drop = nn.Dropout(p=drop_rate)
dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay ruleself.blocks = nn.ModuleList([ Block( dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale, drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer) for i in range(depth)])self.norm = norm_layer(embed_dim)

8.6 表示層和分類(lèi)頭:

表示層輸出維度是representation_size,分類(lèi)頭輸出維度是num_classes。

# Representation layerif representation_size:    self.num_features = representation_size    self.pre_logits = nn.Sequential(OrderedDict([        ('fc', nn.Linear(embed_dim, representation_size)),        ('act', nn.Tanh())    ]))else:    self.pre_logits = nn.Identity()
# Classifier headself.head?=?nn.Linear(self.num_features,?num_classes)?if?num_classes?>?0?else?nn.Identity()

8.7 初始化各個(gè)模塊:

函數(shù)trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.)的目的是用截?cái)嗟恼龖B(tài)分布繪制的值填充輸入張量,我們只需要輸入均值mean,標(biāo)準(zhǔn)差std,下界a,上界b即可。

self.apply(self._init_weights)表示對(duì)各個(gè)模塊的權(quán)重進(jìn)行初始化。apply函數(shù)的代碼是:

        for module in self.children():            module.apply(fn)        fn(self)        return self

遞歸地將fn應(yīng)用于每個(gè)子模塊,相當(dāng)于在遞歸調(diào)用fn,即_init_weights這個(gè)函數(shù)。
也就是把模型的所有子模塊的nn.Linear和nn.LayerNorm層都初始化掉。

trunc_normal_(self.pos_embed, std=.02)trunc_normal_(self.cls_token, std=.02)self.apply(self._init_weights)
def _init_weights(self, m):if isinstance(m, nn.Linear): trunc_normal_(m.weight, std=.02) if isinstance(m, nn.Linear) and m.bias is not None: nn.init.constant_(m.bias, 0)elif isinstance(m, nn.LayerNorm): nn.init.constant_(m.bias, 0) nn.init.constant_(m.weight, 1.0)

8.8 最后就是整個(gè)ViT模型的forward實(shí)現(xiàn):

def forward_features(self, x):    B = x.shape[0]    x = self.patch_embed(x)
cls_tokens = self.cls_token.expand(B, -1, -1) # stole cls_tokens impl from Phil Wang, thanks x = torch.cat((cls_tokens, x), dim=1) x = x + self.pos_embed x = self.pos_drop(x)
for blk in self.blocks: x = blk(x)
x = self.norm(x)[:, 0] x = self.pre_logits(x) return x
def forward(self, x): x = self.forward_features(x) x = self.head(x)????return?x

9. 下面是Training data-efficient image transformers & distillation through attention這篇論文的DeiT這個(gè)類(lèi)的實(shí)現(xiàn):

整體結(jié)構(gòu)與ViT相似,繼承了上面的VisionTransformer類(lèi)。

class DistilledVisionTransformer(VisionTransformer):

再額外定義以下3個(gè)變量:

  • distillation token:dist_token
  • 新的位置編碼:pos_embed
  • 蒸餾分類(lèi)頭:head_dist

DeiT相關(guān)介紹可以參考:Vision Transformer 超詳細(xì)解讀 (原理分析+代碼解讀) (三)。

self.dist_token = nn.Parameter(torch.zeros(1, 1, self.embed_dim))num_patches = self.patch_embed.num_patchesself.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 2, self.embed_dim))self.head_dist?=?nn.Linear(self.embed_dim,?self.num_classes)?if?self.num_classes?>?0?else?nn.Identity()

初始化新定義的變量:

trunc_normal_(self.dist_token, std=.02)trunc_normal_(self.pos_embed, std=.02)self.head_dist.apply(self._init_weights)

前向函數(shù):

def forward_features(self, x):    B = x.shape[0]    x = self.patch_embed(x)
cls_tokens = self.cls_token.expand(B, -1, -1) # stole cls_tokens impl from Phil Wang, thanks dist_token = self.dist_token.expand(B, -1, -1) x = torch.cat((cls_tokens, dist_token, x), dim=1)
x = x + self.pos_embed x = self.pos_drop(x)
for blk in self.blocks: x = blk(x)
x = self.norm(x) return x[:, 0], x[:, 1]
def forward(self, x): x, x_dist = self.forward_features(x) x = self.head(x) x_dist = self.head_dist(x_dist) if self.training: return x, x_dist else: # during inference, return the average of both classifier predictions return (x + x_dist) / 2

10. 對(duì)位置編碼進(jìn)行插值:

posemb代表未插值的位置編碼權(quán)值,posemb_tok為位置編碼的token部分,posemb_grid為位置編碼的插值部分。
首先把要插值部分posemb_grid給reshape成(1, gs_old, gs_old, -1)的形式,再插值成(1, gs_new, gs_new, -1)的形式,最后與token部分在第1維度拼接在一起,得到插值后的位置編碼posemb。

def resize_pos_embed(posemb, posemb_new):    # Rescale the grid of position embeddings when loading from state_dict. Adapted from    # https://github.com/google-research/vision_transformer/blob/00883dd691c63a6830751563748663526e811cee/vit_jax/checkpoint.py#L224    _logger.info('Resized position embedding: %s to %s', posemb.shape, posemb_new.shape)    ntok_new = posemb_new.shape[1]    if True:        posemb_tok, posemb_grid = posemb[:, :1], posemb[0, 1:]        ntok_new -= 1    else:        posemb_tok, posemb_grid = posemb[:, :0], posemb[0]    gs_old = int(math.sqrt(len(posemb_grid)))    gs_new = int(math.sqrt(ntok_new))    _logger.info('Position embedding grid-size from %s to %s', gs_old, gs_new)    posemb_grid = posemb_grid.reshape(1, gs_old, gs_old, -1).permute(0, 3, 1, 2)    posemb_grid = F.interpolate(posemb_grid, size=(gs_new, gs_new), mode='bilinear')    posemb_grid = posemb_grid.permute(0, 2, 3, 1).reshape(1, gs_new * gs_new, -1)    posemb = torch.cat([posemb_tok, posemb_grid], dim=1)????return?posemb

11. _create_vision_transformer函數(shù)用于創(chuàng)建vision transformer:

checkpoint_filter_fn的作用是加載預(yù)訓(xùn)練權(quán)重。

def checkpoint_filter_fn(state_dict, model):    """ convert patch embedding weight from manual patchify + linear proj to conv"""    out_dict = {}    if 'model' in state_dict:        # For deit models        state_dict = state_dict['model']    for k, v in state_dict.items():        if 'patch_embed.proj.weight' in k and len(v.shape) < 4:            # For old models that I trained prior to conv based patchification            O, I, H, W = model.patch_embed.proj.weight.shape            v = v.reshape(O, -1, H, W)        elif k == 'pos_embed' and v.shape != model.pos_embed.shape:            # To resize pos embedding when using model at different size from pretrained weights            v = resize_pos_embed(v, model.pos_embed)        out_dict[k] = v    return out_dict

def _create_vision_transformer(variant, pretrained=False, distilled=False, **kwargs): default_cfg = default_cfgs[variant] default_num_classes = default_cfg['num_classes'] default_img_size = default_cfg['input_size'][-1]
num_classes = kwargs.pop('num_classes', default_num_classes) img_size = kwargs.pop('img_size', default_img_size) repr_size = kwargs.pop('representation_size', None) if repr_size is not None and num_classes != default_num_classes: # Remove representation layer if fine-tuning. This may not always be the desired action, # but I feel better than doing nothing by default for fine-tuning. Perhaps a better interface? _logger.warning("Removing representation layer for fine-tuning.") repr_size = None
model_cls = DistilledVisionTransformer if distilled else VisionTransformer model = model_cls(img_size=img_size, num_classes=num_classes, representation_size=repr_size, **kwargs) model.default_cfg = default_cfg
if pretrained: load_pretrained( model, num_classes=num_classes, in_chans=kwargs.get('in_chans', 3), filter_fn=partial(checkpoint_filter_fn, model=model)) return model

12. 定義和注冊(cè)vision transformer模型:

@ 指裝飾器。
@register_model代表注冊(cè)器,注冊(cè)這個(gè)新定義的模型。
model_kwargs是一個(gè)存有模型所有超參數(shù)的字典。
最后使用上面定義的_create_vision_transformer函數(shù)創(chuàng)建模型。

@register_modeldef vit_base_patch16_224(pretrained=False, **kwargs):    """ ViT-Base (ViT-B/16) from original paper (https://arxiv.org/abs/2010.11929).    ImageNet-1k weights fine-tuned from in21k @ 224x224, source https://github.com/google-research/vision_transformer.    """    model_kwargs = dict(patch_size=16, embed_dim=768, depth=12, num_heads=12, **kwargs)    model = _create_vision_transformer('vit_base_patch16_224', pretrained=pretrained, **model_kwargs)    return model

一共可以選擇的模型包括:

ViT系列:
vit_small_patch16_224
vit_base_patch16_224
vit_base_patch32_224
vit_base_patch16_384
vit_base_patch32_384
vit_large_patch16_224
vit_large_patch32_224
vit_large_patch16_384
vit_large_patch32_384
vit_base_patch16_224_in21k
vit_base_patch32_224_in21k
vit_large_patch16_224_in21k
vit_large_patch32_224_in21k
vit_huge_patch14_224_in21k
vit_base_resnet50_224_in21k
vit_base_resnet50_384
vit_small_resnet26d_224
vit_small_resnet50d_s3_224
vit_base_resnet26d_224
vit_base_resnet50d_224

DeiT系列:
vit_deit_tiny_patch16_224
vit_deit_small_patch16_224
vit_deit_base_patch16_224
vit_deit_base_patch16_384
vit_deit_tiny_distilled_patch16_224
vit_deit_small_distilled_patch16_224
vit_deit_base_distilled_patch16_224
vit_deit_base_distilled_patch16_384

以上就是對(duì)timm庫(kù) vision_transformer.py代碼的分析。

如何使用timm庫(kù)以及 vision_transformer.py代碼搭建自己的模型?

在搭建我們自己的視覺(jué)Transformer模型時(shí),我們可以按照下面的步驟操作:首先

  • 繼承timm庫(kù)的VisionTransformer這個(gè)類(lèi)。
  • 添加上自己模型獨(dú)有的一些變量
  • 重寫(xiě)forward函數(shù)。
  • 通過(guò)timm庫(kù)的注冊(cè)器注冊(cè)新模型。

我們以ViT模型的改進(jìn)版DeiT為例:

首先,DeiT的所有模型列表如下:

__all__ = [    'deit_tiny_patch16_224', 'deit_small_patch16_224', 'deit_base_patch16_224',    'deit_tiny_distilled_patch16_224', 'deit_small_distilled_patch16_224',    'deit_base_distilled_patch16_224', 'deit_base_patch16_384',    'deit_base_distilled_patch16_384',]

導(dǎo)入VisionTransformer這個(gè)類(lèi),注冊(cè)器register_model,以及初始化函數(shù)trunc_normal_:

from timm.models.vision_transformer import VisionTransformer, _cfgfrom timm.models.registry import register_modelfrom?timm.models.layers?import?trunc_normal_
DeiT的class名稱(chēng)是DistilledVisionTransformer,它直接繼承了VisionTransformer這個(gè)類(lèi):
class DistilledVisionTransformer(VisionTransformer):

添加上自己模型獨(dú)有的一些變量:

def __init__(self, *args, **kwargs):    super().__init__(*args, **kwargs)    self.dist_token = nn.Parameter(torch.zeros(1, 1, self.embed_dim))    num_patches = self.patch_embed.num_patches    # 位置編碼不是ViT中的(b, N, 256), 而變成了(b, N+2, 256), 原因是還有class token和distillation token.    self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 2, self.embed_dim))    self.head_dist = nn.Linear(self.embed_dim, self.num_classes) if self.num_classes > 0 else nn.Identity()
trunc_normal_(self.dist_token, std=.02) trunc_normal_(self.pos_embed, std=.02) self.head_dist.apply(self._init_weights)

重寫(xiě)forward函數(shù):

def forward_features(self, x):    # taken from https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/vision_transformer.py    # with slight modifications to add the dist_token    B = x.shape[0]
x = self.patch_embed(x)
cls_tokens = self.cls_token.expand(B, -1, -1) # stole cls_tokens impl from Phil Wang, thanks dist_token = self.dist_token.expand(B, -1, -1)
x = torch.cat((cls_tokens, dist_token, x), dim=1)
x = x + self.pos_embed x = self.pos_drop(x)
for blk in self.blocks: x = blk(x)
x = self.norm(x)
return x[:, 0], x[:, 1]
def forward(self, x): x, x_dist = self.forward_features(x) x = self.head(x) x_dist = self.head_dist(x_dist) if self.training: return x, x_dist else: # during inference, return the average of both classifier predictions return (x + x_dist) / 2

通過(guò)timm庫(kù)的注冊(cè)器注冊(cè)新模型:

@register_modeldef deit_base_patch16_224(pretrained=False, **kwargs):    model = VisionTransformer(        patch_size=16, embed_dim=768, depth=12, num_heads=12, mlp_ratio=4, qkv_bias=True,        norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)    model.default_cfg = _cfg()    if pretrained:        checkpoint = torch.hub.load_state_dict_from_url(            url="https://dl.fbaipublicfiles.com/deit/deit_base_patch16_224-b5f2ef4d.pth",            map_location="cpu", check_hash=True        )        model.load_state_dict(checkpoint["model"])    return model


往期精彩:

【原創(chuàng)首發(fā)】機(jī)器學(xué)習(xí)公式推導(dǎo)與代碼實(shí)現(xiàn)30講.pdf

【原創(chuàng)首發(fā)】深度學(xué)習(xí)語(yǔ)義分割理論與實(shí)戰(zhàn)指南.pdf

?談中小企業(yè)算法崗面試

?算法工程師研發(fā)技能表

?真正想做算法的,不要害怕內(nèi)卷

?技術(shù)學(xué)習(xí)不能眼高手低

?技術(shù)人要學(xué)會(huì)自我營(yíng)銷(xiāo)

?做人不能過(guò)擬合

點(diǎn)個(gè)在看

瀏覽 137
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)
評(píng)論
圖片
表情
推薦
點(diǎn)贊
評(píng)論
收藏
分享

手機(jī)掃一掃分享

分享
舉報(bào)

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 婷婷久久久久| jlzzzjlzzz国产免费观看 | 无码成人AV| 国产精品欧美7777777| 无码射精电影| 日韩无码乱码| 玖玖爱免费视频| 日韩av免费在线观看| 久热久热| 囯产精品久久| 一卡二卡三卡| 久久久一区二区三区四区| 亚洲国产精品成人综合色五月| 996精品在线| 欧美操逼大片| 99热超碰在线| 日韩一级视频| 青娱乐无码视频| 在线免费观看亚洲| 天堂综合网| 日韩无码高清网站| 欧美日韩亚洲一区二区| 亚洲日本视频| 日韩一级| 丁香六月激情婷婷| 亚洲欧洲AV| 亚洲视屏| 国产女人十八水真多| 粉嫩护士小泬18p| 日韩A片在线观看| 爱爱免费视频| 精品人妻二区三区蜜桃| 成人精品免费视频| av天天av无码av天天爽| 精品成人av| 亚洲激情视频在线观看| 成人三级视频| 北京熟妇搡BBBB搡BBBB电影 | 国产黄片免费在线观看| 浪潮在线观看完整版| 中文字幕精品一级A片| 最近日本中文字幕中文翻译歌词| 亚洲三级片视频| 国产一级精品视频| 丁香五月婷婷中文字幕| 亚洲性爱自拍| 夜夜嗨AV一区二区三区啊| 日韩成人无码免费视频| 日韩少妇| 三级无码高清| 影音先锋国产| 好吊一区二区| 成人久久av| 亚洲高清无码视频在线观看| 豆花成人网站在线看| 中文字幕在线网址| 日本三级片在线动| 一级大片免费看| 黄色无码网站| 黄色视频在线观看| 国内老熟妇对白HDXXXX| 久久精品视频久久| 亚洲视频欧美| 大香伊人久久| 久久艹精品视频| 日韩A片免费看| 最近中文字幕高清2019中文字幕| 高清无码在线视频观看| 欧美肏逼视频| 一级特黄A片| 波多野结衣成人在线| 成人黄网站免费观看| 蜜臀av一区二区| 成人AV免费| 日本黄色毛片| 激情婷婷 | 婷婷精品在线| 欧美作爱| 国产在线视频一区二区三区 | 黄色综合| 亚洲无码中文视频| 3D动漫精品啪啪一区二区免费| 能看的操逼视频| 第一福利视频| 91麻豆精品91久久久久同性| 91人妻最真实刺激绿帽| 成人国产精品秘欧美高清| 无码精品久久| 国产免费黄色视频网站| 日韩午夜剧场| 亚洲综合片| 国产传媒视频| 黄色毛片网| 亚韩无码| 国产黄片一区二区| 青青草免费在线视频| 一区二区三区观看| 韩国午夜电影| 91导航| 性欧美XXXX| 五月天狠狠操| 国产女人十八水真多| 91精品人妻一区二区三区蜜桃欧美 | 精品一区二区三区四区学生| 江苏妇搡BBBB搡BBBB小说| 黄片网址大全| 国产精品久久久久久久久久| 青青草原黄色视频| 中文字幕视频在线直播| 亚洲无码一区二区三区| jzzijzzij亚洲成熟少妇在线观看 九色蝌蚪9l视频蝌蚪9l视频成人熟妇 | 精品人妻二区三区蜜桃| 亚洲中文字幕日韩在线| 日韩人妻视频| 欧美视频区| 亚洲色图15P| 尹人在线视频| 一区二区三区久久久| 国产卡一卡二| 91亚洲在线观看| 午夜看片| 91网站在线播放| 欧美91熟| 日韩欧美中文| 欧美高清另类| 黄色在线欣赏| 亚洲综合视频在线| 四房五月婷婷| 色婷婷一区二区三区四区五区精品视| 久久精品一区二区三区蜜芽的特点| 超碰碰碰| 超碰在线99| 亚洲美女免费视频| 亚洲永久天堂| 欧美三级片网站| 能看的AV网站| 91高潮久久久久久久| 91成人视频| 国产无码中文字幕| 亚洲国产成人无码a在线播放| 欧美日韩成人| 五月伊人激情| 99久久国产热无码精品免费| 激情av在线观看| 人人插人人干| 日韩免费中文字幕A片| 国产激情内射| 亚洲国产成人精品女人| 嫩草视频在线观看| 在线免费观看成人视频| 久久永久免费精品人妻专区| 国产高清自拍视频| 日本黄色大片网站| 亚洲男人综合| 天堂中文字幕| 中国国产乱子伦| 福利视频免费观看| 操逼日爱| 一本色道久久综合亚洲二区三区| ww免费视频| 爱逼爱操| 五月婷婷丁香| 久久久成人视频| 在线免费观看网站| 国产一区二区不卡视频| 亚洲精品视频在线观看网站| 国产中文字幕在线视频| 91香蕉视频免费在线观看| www.射| 天堂A片电影网站在线观看| 白嫩外女BBWBBWBBW| 抽插免费视频| 亚洲乱伦av| 欧美亚洲黄色| 亚洲女人被黑人巨大的原因| 不卡视频在线观看| 欧美二区三区| 午夜福利在线播放| 国产精品午夜在线观看| 久青草视频| 日韩午夜剧场| 欧美亚洲自拍偷拍| 一级a免一级a做免费线看内裤| 中文字幕日日| 无码中文视频| 特级西西444www高清| 欧美操人| 日本成人A片| 中文字幕成| 夏目あきら被续侵犯7天| 91在线亚洲| 成人电影一区| 中日韩免费视频| 精品无码人妻一区二区三区| 亚洲3p| 91成人在线影院| 国产剧情一区二区av在线观看| 大a片| 国产激情在线播放| 91久久婷婷国产| 中文字幕在线观看日本| 5D肉蒲团| 你懂得视频在线观看| 国产免费av在线观看| 激情麻豆论坛| 国产无码免费| 日韩欧美性爱| 人人插人人干| 亚洲AV成人无码精品直播在线 | 91欧美日韩综合| 日韩无码操逼视频| 91麻豆免费视频| 动漫一区二区| 国产亚洲无码激情前后夹击| 99re视频在线播放| 9l视频自拍蝌蚪9l视频成人| 西西4444WWW无视频| 影音先锋一区| 51福利视频| 色色欧美| 不卡av在线| ThePorn日本无码| 亚洲精品久久久久久久久久久| 五月丁香激情婷婷| 欧美mv日韩mv国产| 91久久久久久久18| 一本色道久久综合无码人妻四虎 | 无套内射在线免费观看| 狠狠躁夜夜躁人人爽人妻| 亚洲色图偷拍| 久草人妻| 国内老熟妇对白XXXXHD| 欧美久久久| 激情五月综合网| 精品无码一区二区三| 91香蕉国产| 亚洲免费在线播放| www亚洲无码A片贴吧| 成人网站一区| 中文不卡视频| 一二三四在线视频| 亚洲三级片在线视频| 天天添天天干| 午夜福利亚洲| 在线无码免费观看| 国产精品成人无码免费| 国产精品毛片久久久久久久| 性爱乱伦视频| 人操人| 免费黄色成人网站| 色婷婷在线播放| 一区二区免费| 久久久精品黄色网址| 丝袜诱惑AV| 精品久久免费| 成人黄色毛片视频| 亚洲砖区| 六十路老熟女码视频| 97色色网站| 亚洲欧洲精品视频| 精品少妇人妻一区二区| 尤物精品在线| 偷拍亚洲欧美| 一本高清无码| 亚洲天堂无码在线观看| 免费a在线观看| 国产福利视频在线| 国产亚洲久一区二区| 国产A片录制现场妹子都很多| 久草在在线视频| 免费av网站| 极品美女援交在线| 日本无码片| 97精品无码| 爱爱视频天天操| 亚洲另类av| 色就是欧美| 天堂在线观看AV| 黄色视频在线观看| 亚洲一区翔田千里无码| 围内精品久久久久久久久久‘变脸 | 懂色AV一区二区三区国产中文在线 | 五月丁香在线播放| 高清日韩欧美| 四虎蜜桃| 精品人妻午夜一区二区三区四区| 人人人人人操| 国产麻豆| 成人国产| 激情视频在线播放| 欧洲亚洲在线| 欧美A在线| 亚洲日韩第一页| 美女黄网站| 一区无码免费| 国产小视频在线看| 五月丁香激情婷婷| 2025天天干| 亚洲无码视频免费看| 三级乱伦86丝袜无码| 久久黄色视频免费看| 三级片AV在线| 亚洲无码免费播放| 永久免费看片视频| 激情视频国产| 在线无码免费| 天天爽夜夜爽AA片免费| 蜜桃久久精品成人无码AV| 亚洲男人的天堂视频网在线观看+720P | 免费黄片网站在线观看| 九色在线视频| 国内综合久久| 国产亚洲精品午夜福利巨大软件| 囯产精品一区二区三区线一牛影视1| 中文字幕人妻一区| 国产黄色在线观看| 日韩AV成人无码久久电影| 91免费网站在线观看| A级黄色电影| 五月天堂网| 中文字幕88页| 夜夜骑夜夜撸| 国产小电影在线| 国产视频导航| 国产欧美一区二区精品性色超碰| av免费观看网站| 噼里啪啦免费观看视频大全| 91亚洲精品国偷拍自产在线观看| 日韩欧美精品在线观看| 69精品| 久久艹精品视频| 狼友在线播放| 亚洲A网| 日韩欧美中文字幕在线观看| 人妻丝袜蕾丝高跟双飞| 日韩熟妇无码| 久久久偷拍| 洞av | 波多野结衣网| 亚洲在线无码| 亚洲精品视频在线播放| 欧美footjob高跟脚交| 麻豆秘在线观看国产| 五月丁香电影| 欧美性爱一区二区三区| 欧美性极品少妇精品网站| 麻豆黄片| 亚洲欧美影院| 俺来了俺去了| 欧美精产国品一二三| 国产靠逼| 无码东京热国产| www.大香蕉伊人| 一区二区A片| 日韩人妻av| 黄色av免费| 亚洲久久视频| 欧美性爱操逼视频| 国产精品一级a毛视频| 人人操人人操人人操人人操| 成人黄色性爱视频| www.911国产| 免费成人AV| 五月丁香婷中文字幕| 成人在线毛片| 97在线免费视频| www五月天com| 国产av资源网| 污视频免费在线观看| 人妻无码蜜桃视频| 好操吊| 一区二区三区四区免费| 欧洲肥胖BBBBBBBBBB| 91大神shunv| 成人三级片在线| 影音先锋中文字幕资源| 欧美a∨| 色综合激情| 免费毛片视频| 欧洲无码精品| 99久在线精品99re8热| 日韩gay| 午夜人妻无码| 亚洲日韩三级片| 麻豆AV96熟妇人妻| 日韩美女性爱| 国内精品久久久久| 大奶一区二区| 亚洲精品视频免费在线观看| 亚洲精品福利视频| 无码av网| 91ThePorn国产在线观看| 国产福利视频| 一区二区三区无码区| 毛片网站在线| 翔田千里无码在线观看| 中文字幕免费MV第一季歌词| 中文在线字幕电视剧免费平台| 欧美aⅤ| a免费观看| 乳揉みま痴汉电车羽月希免费观看| 国产精品成人在线视频| 欧美成人精品一区二区三区| 欧美激情中文字幕| 青娱乐欧美| 最新AV在线播放| 久久大鸡巴| 熟妇无码| 欧美日韩一区在线观看| 日韩肏逼| 在线免费三级| 骚妇大战黑人15P| 午夜无码鲁丝午夜免费| 撸一撸免费视频| 成人在线中文字幕| 天天天做夜夜夜爽无码| seseav| 黄色网址在线观看视频| 91丨九色丨蝌蚪丨成人| 蜜芽av在线观看| 中文字幕日本在线| 丁香五月亭亭| 囯产精品久久久久久久| 国产美女18毛片水真多| 青青国产在线| 黄色免费在线观看网站| 黑人狂躁女人高潮视频| 卡一卡二卡三| 91人妻最真实刺激绿帽| 人妻无码蜜桃视频| 国产毛片一区二区| 大香蕉伊人网在线| а√在线中文8| 最新精品视频| 日本大香蕉伊人| 天天爽夜夜爽精品成人免费| 亚洲一区二区在线视频| 日韩无码人妻久久一区二区三区 | 91麻豆精品传媒国产| PORNY九色视频9l自拍| 五月天激情电影| 国产精品久久久久久婷婷天堂 | 看操b视频| 五月天亚洲色图| 国产AV久| 免费v片在线观看| 国产香蕉AV| 久久这里只有| 色中色av| 无码-ThePorn| 97AV人妻无码视频二区| 麻豆免费版在线观看| 天天操天天操天天| 视频一区在线播放| 欧洲一区二区| 操嫩逼视频| 欧美亚洲成人精品| 亚洲日逼视频| 日韩人妻久久| 97爱爱| 国产成人免费做爰视频| 久久久久久无码日韩欧美电影 | 丁香五月成人| 国产乱伦一区| 无毛无码| 亚洲做爱视频| 亚洲日韩国产成人精品久久| 亚州AV无码| 亚洲天堂无码AV| 中国A级片| 欧美色就是色| 日韩高清成人无码| 欧美色视频网| 青青草激情视频| 久久久波多野结衣| 午夜无码鲁丝片午夜精品一区二区 | 中字av| 中文字幕第六页| 黄a无码| 中文字幕免费中文| 91嫖妓站街按摩店老熟女| 极品美鮑20p| 亚洲一区无码在线观看| 日韩一区二区视频| 亚洲精品人人| 午夜亚洲AⅤ无码高潮片苍井空| 大香蕉在线网| 操操av| 日韩av成人| 中文字幕网址在线| 中文字幕日韩亚洲| 一本色道久久综合熟妇人妻| 91嫖妓站街按摩店老熟女| 国产麻豆性爱视频| 国产AV电影网| 黑人又粗又大XXXXOO| 黄片二区| 囯产精品99久久久久久WWW| 91日韩无码| 色婷婷五月天| 中文字幕在线观看免费高清电影| 91成人网站| 黄色a在线| 成人免费观看的毛视频| 天天日天天干天天干| 蜜桃系列一区二区精品| 免费看黄色电影| 东京热视频一区| 日皮视频在线免费观看| 无码不卡在线播放| 98在线++传媒麻豆的视频| 欧美日韩高清在线| 欧美日韩一级A片| 97人人爽人人爽人人爽人人爽| 狠狠躁婷婷天天爽综合| 国产午夜福利视频| 影音先锋资源站| 亚洲人操逼视频| 经典三级在线视频| 高清毛片AAAAAAAAA片| 小黄片网站| 日韩天堂网| 日本中文字幕网| 91精品国产一区二区三区四区大| 麻豆传媒在线观看| 尻屄视频在线观看| 日本欧美黄色| 大香蕉色伊人| 黄片www.| 狠狠干高清成人二区三区| 99色视频| 久草视频观看| 天天爱综合| 国产白丝精品91爽爽久久| 久久久无码AV| 久久国产热在8| 青青草原av| 双飞少妇| 亚洲一区二区三| 久久99人妻无码精品一区| 97大香蕉在线视频| 999这里只有精品| 最新毛片网站〖网:.〗| 亚洲精品国产精品乱玛不99| a片在线免费观看| 国模精品无码一区二区免费蜜桃 | 亚洲av小说| 安微妇搡BBBB搡BBBB日| 亚洲欧美在线综合| 午夜亚洲| 天堂资源网| 国精产品一区一区三区| 色综合天天综合成人网| 青青青青青操| 国产精品同| 天天日天天日天天操| 99久久人妻精品免费二区| 亚洲AV秘一区二区色盗战流出| 精品黄片| 国产激情av| 欧美三级视频在线观看| 日韩欧美中文在线| 99涩涩| 亚洲无码精品久久| 高清无码中文字幕在线观看| 婷婷国产在线| 97中文字幕在线| 国产在线观看不卡| 国内精品久久久久久久久98| 成年人黄色在线观看| 一卡二卡三卡无码| 九九re| 激情五月天在线视频| 久久高清亚洲| 天堂网影音先锋| 免费无码国产在线怀| 男女AV在线免费观看| 99精品一区二区| 91人妻人人澡人人爽人人精品一| 欧美天天性| 波多野结衣视频在线观看| 国产黄色直播| 艹逼视频免费观看| 亚洲免费av在线| 亚洲精品久久久久久久蜜桃| 成年人免费看视频| 国产精品成人3p一区二区三区| 91av天堂| 国产精品H| 国产欧美精品一区二区三区| 国产精品免费人成网站酒店| 天堂av中文字幕| 欧美一级操逼视频| 高清无码视频免费版本在线观看| 欧美一级高清片免费一级a| 老女人肏屄视频| 免费一区视频| 日韩在线观看av| 91网站在线播放| 欧美色视频一区二区三区在线观看| 91精品成人| 密臀av在线| 男人的天堂视频网站| 大香蕉手机在线视频| 青草青草| 一级A片在线观看| 色婷婷丁香五月| 操逼日韩欧美| 亚洲视频1区| 国产伦精品一区二区三区妓女下载| 国产成人精品免高潮在线观看 | 天天天日天天天操| 91美女在线观看| 五月丁香婷中文字幕| 亚洲有码在线视频| 日韩精品免费在线观看| 91精品国产综合久久久蜜臀主演| 92丨九色丨偷拍老熟女| 欧美成人色图| 中文字幕巨乱亚洲高清A片28| 一级黄色大毛片| 国产免费精彩视频| 亚洲无码人妻一区| 东北A片| 日韩A片在线| 91成人国产| 足浴店少妇69XXX| 77777色婷婷| 日本伊人在线综合视频| 人妻无码精品久久人妻成人| 欧美深夜福利视频| 久久精品国产亚洲AV成人婷婷| 在线免费看黄色视频| 日韩特级片| 中文字幕av在线播放| 人妻无码蜜桃视频| 精品视频免费在线| 免费黄色一级电影| 国产成人高潮毛片| 亚洲永久| 午夜成人福利视频| 精品无码免费视频| 成人久久av| 麻豆免费成人视频| 婷婷射| 波多野结衣高清av久久直播免| 国产一级婬乱片免费| 国产成人高清视频| 中文字幕麻豆| 亚洲视频一区| 日韩72页| 日韩无码视频免费| 色色丁香| 精品九九九| 日韩一区二区在线看在线看| 亚洲尤物在线| 中文在线字幕免费观看电视剧大全| 在线播放亚洲| 激情乱伦网站| 97pao| 五月天无码在线| 久热无码| 波多野结衣vs黑人巨大| 99re这里只有精品6| 操操网站| 加勒比精品| 超碰中文在线| 欧美操逼大片| 亚洲网站视频| 超碰自拍私拍二区三区区| 狼友在线播放| 农村老太HD肉HD| 亚洲av免费| 国产一级在线免费观看| 亚洲人成人无码一区二区三区| 亚洲av高清无码| 午夜做爱福利视频| 啊v视频在线| 亚洲无码成人在线观看| 五月婷婷色| 天天干天天肏| 日本三级中文字幕| 久久丁香五月婷婷五月天激情视频| 亚洲国产精品尤物yw在线观看 | 777久久| 国产一区视频在线| 精品无码人妻一区二区媚黑| jizz在线免费观看| 国产精品麻豆视频| 东方av在| 激情网页| 欧美一区二区三区四| 伊人久久国产| 新亚洲天堂男子Av-| 国产九九九视频| 正在播放国产精品| 免费a片观看| 亚洲综合中文字幕在线| 东方成人AV| 夜夜夜夜撸| 亚洲欧美日韩电影| 亚洲中文字幕电影| 懂色av蜜臀av粉嫩av分| 亚洲天堂色| 亚洲无吗在线视频| 草草视频在线观看| 91丨露脸丨熟女| 在线播放91灌醉迷J高跟美女| 99精品免费| 中文在线最新版天堂8| 综合久久中文字幕| 国产美女被操| 日韩在线三级片| 天天操天天拍| 无码不卡在线播放| 成人激情在线观看| 99er这里只有精品| 超碰97在线免费观看| 天天操嫩逼无套视频| 尿在小sao货里面好不好| 黑人操逼视频| 做a视频| 西西特级无码444www| 成人毛片视频网站| 性日韩| 韩国无码AV| 久久91欧美特黄A片| 97视频福利| 豆花网| 精品交换一区二区三区无码| 大香蕉久热| 亚洲小电影在线观看| h片在线看| 大香蕉第一页| 欧美成人性爱网站| 中国人妻HDbute熟睡| 巜痴漢電車~凌脔版2| 摸BBB槡BBBB搡BBB,,,,, | aa无码| 999这里只有精品| 日韩视频一区二区三区| 亚洲免费大片| caobi视频| 亚洲成人a| 亚洲午夜成人| 天天艹天天| 97久久精品国产熟妇高清网| 日韩精品中文无码| 欧美黄片在线免费观看| 大香蕉com| AV毛片| 翔田千里无码播放| 国产精品久久久无码专区| 国产日韩欧美一区| 一级黄A片| 青青草原在线| 久久久久久久久久久国产精品| 伊人导航| 国产成人AV一区二区三区在线观看| 高清无码视频网站| 天天日,天天干,天天操| 牛牛成人在线视频| 亚洲高清无码在线免费观看| 老司机午夜电影| 欧美国产精品一二三产品在哪买 | 人人草大香蕉| 激情黄色毛片| 97资源超碰| 国产酒店自拍| 中文爱爱视频| 91在线无码精品秘国产| 亚洲AV永久无码精品国产精| 欧美三级片网址| 97国产成人| 中文字幕午夜福利| 成人亚洲电影| 激情五月天综合网| 一区二区三区av| 久操不卡| 日韩欧美中文字幕视频| 牛牛在线视频| 欧美VA视频| 影音先锋亚洲无码| av无码高清| 伊人影院久久| 激情乱伦网站| 日韩在线毛片| 国产精品欧美一区二区| 小早川怜子精品一区二区| 理论片熟女奶水哺乳| 狠狠干综合网| 日韩成人无码片| 黄色电影A片| 亚洲一区二区三区在线视频| AV影院在线| 日韩a电影| 一本加勒比HEZYO东京热无码 | 91精品人妻一区二| 激情久久AV一区AV二区AV三区| 佐山爱人妻无码蜜桃| www.黄色在线观看| 亚洲中文字幕2019| 中文字幕精品一区久久久久| 亚洲第一在线| 中文字幕在线网| 国产一级网站| 久久人妻无码| 国产熟妇码视频| 在线日韩AV| 99久久人妻无码中文字幕系列 | 伊人大香蕉在线网| 免费中文字幕日韩欧美| 豆花视频logo进入官网| 日本黄色视频网| 国产精品久久久久的角色| 日逼无码| 91免费高清视频| 永久免费AV| 亚洲综合网在线| 中文字幕无码在线| AAAA毛片| 国产一区在线看| 国产一精品一aⅴ一免费| 日韩中文字幕在线| 老司机免费福利视频| 国产嫩苞又嫩又紧AV在线| 亚洲免费观看在线观看| 麻豆蜜桃wwww精品无码| 五月婷婷av| 欧美三级片在线视频| 亚洲日韩免费| 性爱AV网| 国产a视频| 久草香蕉视频| 不卡视频一区二区三区| 黄色小视频在线| av在线资源网站| 超碰久草| 大色网小色网| 日本一区二区三区免费观看| 天天干天天天天| 五月天福利网| 被男友内S~高H文| 亚洲免费无码视频| 欧美日韩操逼视频| 欧洲成人午夜精品无码区久久| 亚洲精品秘一区二区三区影| 亚洲AV无码成人精品区东京热| 色色成人网| 91无码精品国产| 国产嫩草精品A88AV| 蜜臀久久99精品久久久久久婷婷| 操女人的网站| 五月婷婷开心| 久久福利| 无码精品ThePorn| 日本A片视频| 久久久久久高清毛片一级| 成人午夜在线视频| 无码导航| 亚洲区一区二| 成人黄色视频网| 性爱一级视频| 香蕉操逼小视频| 婷婷五月丁香六月| 成人啪啪视频| 中文字幕-区二区三区四区视频中国| 欧美中文字幕在线播放| 婷婷激情视频| 夜色88V精品国产亚洲| 中文字幕精品一级A片| 黄色性爱网址| 内射日韩| 久久久久久亚洲精品| 麻豆免费版在线观看| 国产成人片| 欧美九九九| 超碰AV在线| 国产成人精品免费视频| 婷婷五月天综合网| 九九性爱视频| 色婷婷色99国产综合精品| 亚洲自拍无码| 国产一级婬片A片免费无成人黑豆 国产真实露脸乱子伦对白高清视频 | 青草中文娱乐网在线| 激情丁香五月| 在线观看日韩| 性v天堂| 在线不欧美| 国产精品秘久久久久久久久| 插菊综合网| 不卡二区| 国产一级无码| 久久五月婷| 亚洲黄色电影网站| 九色91视频| 国产一区二区av| 中文字幕一区在线观看| 久久中文网| 亚洲麻豆|