国产无遮挡裸体免费直播视频,久久精品国产蜜臀av,动漫在线视频一区二区,欧亚日韩一区二区三区,久艹在线 免费视频,国产精品美女网站免费,正在播放 97超级视频在线观看,斗破苍穹年番在线观看免费,51最新乱码中文字幕

yolov5中train.py代碼注釋詳解與使用教程

 更新時間:2022年09月09日 08:57:45   作者:Charms@  
train.py里面加了很多額外的功能,使得整體看起來比較復雜,其實核心部分主要就是 讀取數(shù)據(jù)集,加載模型,訓練中損失的計算,下面這篇文章主要給大家介紹了關于yolov5中train.py代碼注釋詳解與使用的相關資料,需要的朋友可以參考下

前言

最近在用yolov5參加比賽,yolov5的技巧很多,僅僅用來參加比賽,著實有點浪費,所以有必要好好學習一番,在認真學習之前,首先向yolov5的作者致敬,對了我是用的版本是v6。每每看到這些大神的作品,實在是有點慚愧,要學的太多了

1. parse_opt函數(shù)

def parse_opt(known=False):
    """
    argparse 使用方法:
    parse = argparse.ArgumentParser()
    parse.add_argument('--s', type=int, default=2, help='flag_int')
    """
    parser = argparse.ArgumentParser()
    # weights 權重的路徑./weights/yolov5s.pt.... 
    # yolov5提供4個不同深度不同寬度的預訓練權重 用戶可以根據(jù)自己的需求選擇下載
    parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='initial weights path')
    # cfg 配置文件(網(wǎng)絡結構) anchor/backbone/numclasses/head,訓練自己的數(shù)據(jù)集需要自己生成
    # 生成方式——例如我的yolov5s_mchar.yaml 根據(jù)自己的需求選擇復制./models/下面.yaml文件,5個文件的區(qū)別在于模型的深度和寬度依次遞增
    parser.add_argument('--cfg', type=str, default='', help='model.yaml path')
    # data 數(shù)據(jù)集配置文件(路徑) train/val/label/, 該文件需要自己生成
    # 生成方式——例如我的/data/mchar.yaml 訓練集和驗證集的路徑 + 類別數(shù) + 類別名稱
    parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path')
    # hpy超參數(shù)設置文件(lr/sgd/mixup)./data/hyps/下面有5個超參數(shù)設置文件,每個文件的超參數(shù)初始值有細微區(qū)別,用戶可以根據(jù)自己的需求選擇其中一個
    parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path')
    # epochs 訓練輪次, 默認輪次為300次
    parser.add_argument('--epochs', type=int, default=300)
    # batchsize 訓練批次, 默認bs=16
    parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch')
    # imagesize 設置圖片大小, 默認640*640
    parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)')
    # rect 是否采用矩形訓練,默認為False
    parser.add_argument('--rect', action='store_true', help='rectangular training')
    # resume 是否接著上次的訓練結果,繼續(xù)訓練
    parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training')
    # nosave 不保存模型  默認False(保存)  在./runs/exp*/train/weights/保存兩個模型 一個是最后一次的模型 一個是最好的模型
    # best.pt/ last.pt 不建議運行代碼添加 --nosave 
    parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
    # noval 最后進行測試, 設置了之后就是訓練結束都測試一下, 不設置每輪都計算mAP, 建議不設置
    parser.add_argument('--noval', action='store_true', help='only validate final epoch')
    # noautoanchor 不自動調整anchor, 默認False, 自動調整anchor
    parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor')
    # evolve參數(shù)進化, 遺傳算法調參
    parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations')
    # bucket谷歌優(yōu)盤 / 一般用不到
    parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
    # cache 是否提前緩存圖片到內(nèi)存,以加快訓練速度,默認False
    parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"')
    # mage-weights 使用圖片采樣策略,默認不使用
    parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
    # device 設備選擇
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    # multi-scale 多測度訓練
    parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%')
    # single-cls 數(shù)據(jù)集是否多類/默認True
    parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
    # optimizer 優(yōu)化器選擇 / 提供了三種優(yōu)化器
    parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer')
    # sync-bn:是否使用跨卡同步BN,在DDP模式使用
    parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
    # workers/dataloader的最大worker數(shù)量
    parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)')
    # 保存路徑 / 默認保存路徑 ./runs/ train
    parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name')
    # 實驗名稱
    parser.add_argument('--name', default='exp', help='save to project/name')
    # 項目位置是否存在 / 默認是都不存在
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    parser.add_argument('--quad', action='store_true', help='quad dataloader')
    # cos-lr 余弦學習率
    parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler')
    # 標簽平滑 / 默認不增強, 用戶可以根據(jù)自己標簽的實際情況設置這個參數(shù),建議設置小一點 0.1 / 0.05
    parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')
    # 早停止忍耐次數(shù) / 100次不更新就停止訓練
    parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)')
    # --freeze凍結訓練 可以設置 default = [0] 數(shù)據(jù)量大的情況下,建議不設置這個參數(shù)
    parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2')
    # --save-period 多少個epoch保存一下checkpoint
    parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)')
    # --local_rank 進程編號 / 多卡使用
    parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')

    # Weights & Biases arguments
    # 在線可視化工具,類似于tensorboard工具,想了解這款工具可以查看https://zhuanlan.zhihu.com/p/266337608
    parser.add_argument('--entity', default=None, help='W&B: Entity')
    # upload_dataset: 是否上傳dataset到wandb tabel(將數(shù)據(jù)集作為交互式 dsviz表 在瀏覽器中查看、查詢、篩選和分析數(shù)據(jù)集) 默認False
    parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='W&B: Upload data, "val" option')
    # bbox_interval: 設置界框圖像記錄間隔 Set bounding-box image logging interval for W&B 默認-1   opt.epochs // 10
    parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval')
    # 使用數(shù)據(jù)的版本
    parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use')

    # 傳入的基本配置中沒有的參數(shù)也不會報錯# parse_args()和parse_known_args() 
    # parse = argparse.ArgumentParser()
    # parse.add_argument('--s', type=int, default=2, help='flag_int')
    # parser.parse_args() / parse_args()
    opt = parser.parse_known_args()[0] if known else parser.parse_args()
    return opt

2. main函數(shù)

2.1 main函數(shù)——打印關鍵詞/安裝環(huán)境

def main(opt, callbacks=Callbacks()):
    ############################################### 1. Checks ##################################################
    if RANK in [-1, 0]:
        # 輸出所有訓練參數(shù) / 參數(shù)以彩色的方式表現(xiàn)
        print_args(FILE.stem, opt)
        # 檢查代碼版本是否更新
        check_git_status()
        # 檢查安裝是否都安裝了 requirements.txt, 缺少安裝包安裝。
        # 缺少安裝包:建議使用 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
        check_requirements(exclude=['thop'])

2.2 main函數(shù)——是否進行斷點訓練

############################################### 2. Resume ##################################################
    # 初始化可視化工具wandb,wandb使用教程看https://zhuanlan.zhihu.com/p/266337608
    # 斷點訓練使用教程可以查看:https://blog.csdn.net/CharmsLUO/article/details/123410081
    if opt.resume and not check_wandb_resume(opt) and not opt.evolve:  # resume an interrupted run
        # isinstance()是否是已經(jīng)知道的類型
        # 如果resume是True,則通過get_lastest_run()函數(shù)找到runs為文件夾中最近的權重文件last.pt
        ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run()  # specified or most recent path
        # 判斷是否是文件
        assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist'
        #  # 相關的opt參數(shù)也要替換成last.pt中的opt參數(shù) safe_load()yaml文件加載數(shù)據(jù)
        with open(Path(ckpt).parent.parent / 'opt.yaml', errors='ignore') as f:
            # argparse.Namespace 可以理解為字典
            opt = argparse.Namespace(**yaml.safe_load(f))  # replace
        opt.cfg, opt.weights, opt.resume = '', ckpt, True  # reinstate
        # 打印斷點訓練信息
        LOGGER.info(f'Resuming training from {ckpt}')
    else:
        # 不使用斷點訓練就在加載輸入的參數(shù)
        opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \
            check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project)  # checks
        assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified'
        # opt.evolve=False,opt.name='exp'    opt.evolve=True,opt.name='evolve'
        if opt.evolve:
            if opt.project == str(ROOT / 'runs/train'):  # if default project name, rename to runs/evolve
                opt.project = str(ROOT / 'runs/evolve')
            opt.exist_ok, opt.resume = opt.resume, False  # pass resume to exist_ok and disable resume
        # 保存相關信息
        opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok))

2.3 main函數(shù)——是否分布式訓練

# ############################################## 3.DDP mode ###############################################
    # 選擇設備cpu/cuda
    device = select_device(opt.device, batch_size=opt.batch_size)
    # 多卡訓練GPU
    if LOCAL_RANK != -1:
        msg = 'is not compatible with YOLOv5 Multi-GPU DDP training'
        assert not opt.image_weights, f'--image-weights {msg}'
        assert not opt.evolve, f'--evolve {msg}'
        assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size'
        assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE'
        assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command'
        # 根據(jù)編號選擇設備
        #使用torch.cuda.set_device()可以更方便地將模型和數(shù)據(jù)加載到對應GPU上, 直接定義模型之前加入一行代碼即可
        # torch.cuda.set_device(gpu_id) #單卡
        # torch.cuda.set_device('cuda:'+str(gpu_ids)) #可指定多卡
        torch.cuda.set_device(LOCAL_RANK)
        device = torch.device('cuda', LOCAL_RANK)
        # 初始化多進程
        dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo")

2.4 main函數(shù)——是否進化訓練/遺傳算法調參

################################################ 4. Train #################################################
    # 不設置evolve直接調用train訓練
    if not opt.evolve:
        train(opt.hyp, opt, device, callbacks)
        # 分布式訓練 WORLD_SIZE=主機的數(shù)量
        # 如果是使用多卡訓練, 那么銷毀進程組
        if WORLD_SIZE > 1 and RANK == 0:
            LOGGER.info('Destroying process group... ')
            # 使用多卡訓練, 那么銷毀進程組
            dist.destroy_process_group()

    # Evolve hyperparameters (optional)
    # 遺傳凈化算法/一邊訓練一遍進化
    # 了解遺傳算法可以查看我的博客:
    else:
        # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit)
        # 超參數(shù)列表(突變范圍 - 最小值 - 最大值)
        meta = {'lr0': (1, 1e-5, 1e-1),  # initial learning rate (SGD=1E-2, Adam=1E-3)
                'lrf': (1, 0.01, 1.0),  # final OneCycleLR learning rate (lr0 * lrf)
                'momentum': (0.3, 0.6, 0.98),  # SGD momentum/Adam beta1
                'weight_decay': (1, 0.0, 0.001),  # optimizer weight decay
                'warmup_epochs': (1, 0.0, 5.0),  # warmup epochs (fractions ok)
                'warmup_momentum': (1, 0.0, 0.95),  # warmup initial momentum
                'warmup_bias_lr': (1, 0.0, 0.2),  # warmup initial bias lr
                'box': (1, 0.02, 0.2),  # box loss gain
                'cls': (1, 0.2, 4.0),  # cls loss gain
                'cls_pw': (1, 0.5, 2.0),  # cls BCELoss positive_weight
                'obj': (1, 0.2, 4.0),  # obj loss gain (scale with pixels)
                'obj_pw': (1, 0.5, 2.0),  # obj BCELoss positive_weight
                'iou_t': (0, 0.1, 0.7),  # IoU training threshold
                'anchor_t': (1, 2.0, 8.0),  # anchor-multiple threshold
                'anchors': (2, 2.0, 10.0),  # anchors per output grid (0 to ignore)
                'fl_gamma': (0, 0.0, 2.0),  # focal loss gamma (efficientDet default gamma=1.5)
                'hsv_h': (1, 0.0, 0.1),  # image HSV-Hue augmentation (fraction)
                'hsv_s': (1, 0.0, 0.9),  # image HSV-Saturation augmentation (fraction)
                'hsv_v': (1, 0.0, 0.9),  # image HSV-Value augmentation (fraction)
                'degrees': (1, 0.0, 45.0),  # image rotation (+/- deg)
                'translate': (1, 0.0, 0.9),  # image translation (+/- fraction)
                'scale': (1, 0.0, 0.9),  # image scale (+/- gain)
                'shear': (1, 0.0, 10.0),  # image shear (+/- deg)
                'perspective': (0, 0.0, 0.001),  # image perspective (+/- fraction), range 0-0.001
                'flipud': (1, 0.0, 1.0),  # image flip up-down (probability)
                'fliplr': (0, 0.0, 1.0),  # image flip left-right (probability)
                'mosaic': (1, 0.0, 1.0),  # image mixup (probability)
                'mixup': (1, 0.0, 1.0),  # image mixup (probability)
                'copy_paste': (1, 0.0, 1.0)}  # segment copy-paste (probability)

        with open(opt.hyp, errors='ignore') as f:
            # 加載yaml超參數(shù)
            hyp = yaml.safe_load(f)  # load hyps dict
            if 'anchors' not in hyp:  # anchors commented in hyp.yaml
                hyp['anchors'] = 3
        opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir)  # only val/save final epoch
        # ei = [isinstance(x, (int, float)) for x in hyp.values()]  # evolvable indices
        # 保存進化的超參數(shù)列表
        evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv'
        if opt.bucket:
            os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}')  # download evolve.csv if exists
        """
        遺傳算法調參:遵循適者生存、優(yōu)勝劣汰的法則,即尋優(yōu)過程中保留有用的,去除無用的。
        遺傳算法需要提前設置4個參數(shù): 群體大小/進化代數(shù)/交叉概率/變異概率

        """

        # 默認選擇進化300代
        for _ in range(opt.evolve):  # generations to evolve
            if evolve_csv.exists():  # if evolve.csv exists: select best hyps and mutate
                # Select parent(s)
                # 進化方式--single / --weight
                parent = 'single'  # parent selection method: 'single' or 'weighted'
                # 加載evolve.txt文件
                x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1)
                # 選取進化結果代數(shù)
                n = min(5, len(x))  # number of previous results to consider
                x = x[np.argsort(-fitness(x))][:n]  # top n mutations
                 # 根據(jù)resluts計算hyp權重
                w = fitness(x) - fitness(x).min() + 1E-6  # weights (sum > 0)
                # 根據(jù)不同進化方式獲得base hyp
                if parent == 'single' or len(x) == 1:
                    # x = x[random.randint(0, n - 1)]  # random selection
                    x = x[random.choices(range(n), weights=w)[0]]  # weighted selection
                elif parent == 'weighted':
                    x = (x * w.reshape(n, 1)).sum(0) / w.sum()  # weighted combination

                # Mutate
                # # 獲取突變初始值
                mp, s = 0.8, 0.2  # mutation probability, sigma
                npr = np.random
                npr.seed(int(time.time()))
                g = np.array([meta[k][0] for k in hyp.keys()])  # gains 0-1
                ng = len(meta)
                v = np.ones(ng)
                # 設置突變
                while all(v == 1):  # mutate until a change occurs (prevent duplicates)
                    # 將突變添加到base hyp上
                    # [i+7]是因為x中前7個數(shù)字為results的指標(P,R,mAP,F1,test_loss=(box,obj,cls)),之后才是超參數(shù)hyp
                    v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0)
                for i, k in enumerate(hyp.keys()):  # plt.hist(v.ravel(), 300)
                    hyp[k] = float(x[i + 7] * v[i])  # mutate

            # Constrain to limits
            # 限制超參再規(guī)定范圍
            for k, v in meta.items():
                hyp[k] = max(hyp[k], v[1])  # lower limit
                hyp[k] = min(hyp[k], v[2])  # upper limit
                hyp[k] = round(hyp[k], 5)  # significant digits

            # Train mutation
            # 訓練 使用突變后的參超 測試其效果
            results = train(hyp.copy(), opt, device, callbacks)
            callbacks = Callbacks()
            # Write mutation results
            # Write mutation results
            # 將結果寫入results 并將對應的hyp寫到evolve.txt evolve.txt中每一行為一次進化的結果
            # 每行前七個數(shù)字 (P, R, mAP, F1, test_losses(GIOU, obj, cls)) 之后為hyp
            # 保存hyp到y(tǒng)aml文件
            print_mutation(results, hyp.copy(), save_dir, opt.bucket)

        # Plot results
        # 將結果可視化 / 輸出保存信息
        plot_evolve(evolve_csv)
        LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n'
                    f"Results saved to {colorstr('bold', save_dir)}\n"
                    f'Usage example: $ python train.py --hyp {evolve_yaml}')

3. train函數(shù)

3.1 train函數(shù)——基本配置信息

################################################ 1. 傳入?yún)?shù)/基本配置 #############################################
    # opt傳入的參數(shù)
    save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \
        Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \
        opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze

    # Directories
    w = save_dir / 'weights'  # weights dir
    # 新建文件夾 weights train evolve
    (w.parent if evolve else w).mkdir(parents=True, exist_ok=True)  # make dir
    # 保存訓練結果的目錄  如runs/train/exp*/weights/last.pt
    last, best = w / 'last.pt', w / 'best.pt'

    # Hyperparameters # isinstance()是否是已知類型
    if isinstance(hyp, str):
        with open(hyp, errors='ignore') as f:
            # 加載yaml文件
            hyp = yaml.safe_load(f)  # load hyps dict
    # 打印超參數(shù) 彩色字體
    LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items()))

    # Save run settings
    # 如果不使用進化訓練
    if not evolve:
        # safe_dump() python值轉化為yaml序列化
        with open(save_dir / 'hyp.yaml', 'w') as f:
            yaml.safe_dump(hyp, f, sort_keys=False)
        with open(save_dir / 'opt.yaml', 'w') as f:
            # vars(opt) 的作用是把數(shù)據(jù)類型是Namespace的數(shù)據(jù)轉換為字典的形式。
            yaml.safe_dump(vars(opt), f, sort_keys=False)

    # Loggers
    data_dict = None
    if RANK in [-1, 0]:
        loggers = Loggers(save_dir, weights, opt, hyp, LOGGER)  # loggers instance
        if loggers.wandb:
            data_dict = loggers.wandb.data_dict
            if resume:
                weights, epochs, hyp, batch_size = opt.weights, opt.epochs, opt.hyp, opt.batch_size

        # Register actions
        for k in methods(loggers):
            callbacks.register_action(k, callback=getattr(loggers, k))

    # Config 畫圖
    plots = not evolve  # create plots
    # GPU / CPU
    cuda = device.type != 'cpu'
    # 隨機種子
    init_seeds(1 + RANK)
    # 存在子進程-分布式訓練
    with torch_distributed_zero_first(LOCAL_RANK):
        data_dict = data_dict or check_dataset(data)  # check if None
    # 訓練集和驗證集的位路徑
    train_path, val_path = data_dict['train'], data_dict['val']
    # 設置類別 是否單類
    nc = 1 if single_cls else int(data_dict['nc'])  # number of classes
    # 類別對應的名稱
    names = ['item'] if single_cls and len(data_dict['names']) != 1 else data_dict['names']  # class names
    # 判斷類別長度和文件是否對應
    assert len(names) == nc, f'{len(names)} names found for nc={nc} dataset in {data}'  # check
    # 當前數(shù)據(jù)集是否是coco數(shù)據(jù)集(80個類別) 
    is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt')  # COCO dataset

3.2 train函數(shù)——模型加載/斷點訓練

################################################### 2. Model ###########################################
    # 檢查文件后綴是否是.pt
    check_suffix(weights, '.pt')  # check weights
    # 加載預訓練權重 yolov5提供了5個不同的預訓練權重,大家可以根據(jù)自己的模型選擇預訓練權重
    pretrained = weights.endswith('.pt')
    if pretrained:
        # # torch_distributed_zero_first(RANK): 用于同步不同進程對數(shù)據(jù)讀取的上下文管理器
        with torch_distributed_zero_first(LOCAL_RANK):
            # 如果本地不存在就從網(wǎng)站上下載
            weights = attempt_download(weights)  # download if not found locally
        # 加載模型以及參數(shù)
        ckpt = torch.load(weights, map_location='cpu')  # load checkpoint to CPU to avoid CUDA memory leak
        """
        兩種加載模型的方式: opt.cfg / ckpt['model'].yaml
        使用resume-斷點訓練: 選擇ckpt['model']yaml創(chuàng)建模型, 且不加載anchor
        使用斷點訓練時,保存的模型會保存anchor,所以不需要加載

        """
        model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device)  # create
        exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else []  # exclude keys
        csd = ckpt['model'].float().state_dict()  # checkpoint state_dict as FP32
        # 篩選字典中的鍵值對  把exclude刪除
        csd = intersect_dicts(csd, model.state_dict(), exclude=exclude)  # intersect
        model.load_state_dict(csd, strict=False)  # load
        LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}')  # report
    else:
        # 不適用預訓練權重
        model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device)  # create

3.3 train函數(shù)——凍結訓練/凍結層設置

################################################ 3. Freeze/凍結訓練 #########################################
    # 凍結訓練的網(wǎng)絡層
    freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))]  # layers to freeze
    for k, v in model.named_parameters():
        v.requires_grad = True  # train all layers
        if any(x in k for x in freeze):
            LOGGER.info(f'freezing {k}')
            # 凍結訓練的層梯度不更新
            v.requires_grad = False

3.4 train函數(shù)——圖片大小/batchsize設置

# Image size
    gs = max(int(model.stride.max()), 32)  # grid size (max stride)
    # 檢查圖片的大小
    imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2)  # verify imgsz is gs-multiple

    # Batch size
    if RANK == -1 and batch_size == -1:  # single-GPU only, estimate best batch size
        batch_size = check_train_batch_size(model, imgsz)
        loggers.on_params_update({"batch_size": batch_size})

3.5 train函數(shù)——優(yōu)化器選擇 / 分組優(yōu)化設置

############################################ 4. Optimizer/優(yōu)化器 ###########################################
    """
    nbs = 64
    batchsize = 16
    accumulate = 64 / 16 = 4
    模型梯度累計accumulate次之后就更新一次模型 相當于使用更大batch_size
    """
    nbs = 64  # nominal batch size
    accumulate = max(round(nbs / batch_size), 1)  # accumulate loss before optimizing
    # 權重衰減參數(shù)
    hyp['weight_decay'] *= batch_size * accumulate / nbs  # scale weight_decay
    # 打印日志
    LOGGER.info(f"Scaled weight_decay = {hyp['weight_decay']}")

    # 將模型參數(shù)分為三組(weights、biases、bn)來進行分組優(yōu)化
    g0, g1, g2 = [], [], []  # optimizer parameter groups
    for v in model.modules():
        if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):  # bias
            g2.append(v.bias)
        if isinstance(v, nn.BatchNorm2d):  # weight (no decay)
            g0.append(v.weight)
        elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):  # weight (with decay)
            g1.append(v.weight)
    # 選擇優(yōu)化器 / 提供了三個優(yōu)化器——g0
    if opt.optimizer == 'Adam':
        optimizer = Adam(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))  # adjust beta1 to momentum
    elif opt.optimizer == 'AdamW':
        optimizer = AdamW(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))  # adjust beta1 to momentum
    else:
        optimizer = SGD(g0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True)
    # 設置優(yōu)化的方式——g1 / g2
    optimizer.add_param_group({'params': g1, 'weight_decay': hyp['weight_decay']})  # add g1 with weight_decay
    optimizer.add_param_group({'params': g2})  # add g2 (biases)
    # 打印log日志 優(yōu)化信息
    LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__} with parameter groups "
                f"{len(g0)} weight (no decay), {len(g1)} weight, {len(g2)} bias")
    # 刪除變量
    del g0, g1, g2

3.6 train函數(shù)——學習率/ema/歸一化/單機多卡

############################################ 5. Scheduler ##############################################
    # 是否余弦學習率調整方式
    if opt.cos_lr:
        lf = one_cycle(1, hyp['lrf'], epochs)  # cosine 1->hyp['lrf']
    else:
        lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf']  # linear
    scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)  # plot_lr_scheduler(optimizer, scheduler, epochs)

    # EMA
    # 使用EMA(指數(shù)移動平均)對模型的參數(shù)做平均, 一種給予近期數(shù)據(jù)更高權重的平均方法, 以求提高測試指標并增加模型魯棒。
    ema = ModelEMA(model) if RANK in [-1, 0] else None

    # Resume
    start_epoch, best_fitness = 0, 0.0
    if pretrained:
        # Optimizer
        if ckpt['optimizer'] is not None:
            optimizer.load_state_dict(ckpt['optimizer'])
            best_fitness = ckpt['best_fitness']

        # EMA
        if ema and ckpt.get('ema'):
            ema.ema.load_state_dict(ckpt['ema'].float().state_dict())
            ema.updates = ckpt['updates']

        # Epochs
        start_epoch = ckpt['epoch'] + 1
        if resume:
            assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.'
        if epochs < start_epoch:
            LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.")
            epochs += ckpt['epoch']  # finetune additional epochs

        del ckpt, csd

    # DP mode
    # DP: 單機多卡模式
    if cuda and RANK == -1 and torch.cuda.device_count() > 1:
        LOGGER.warning('WARNING: DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n'
                       'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.')
        model = torch.nn.DataParallel(model)

    # SyncBatchNorm 多卡歸一化
    if opt.sync_bn and cuda and RANK != -1:
        model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device)
        # 打印信息
        LOGGER.info('Using SyncBatchNorm()')

3.7 train函數(shù)——數(shù)據(jù)加載 / anchor調整

# ############################################## 6. Trainloader / 數(shù)據(jù)加載 ######################################
    # 訓練集數(shù)據(jù)加載
    train_loader, dataset = create_dataloader(train_path, imgsz, batch_size // WORLD_SIZE, gs, single_cls,
                                              hyp=hyp, augment=True, cache=None if opt.cache == 'val' else opt.cache,
                                              rect=opt.rect, rank=LOCAL_RANK, workers=workers,
                                              image_weights=opt.image_weights, quad=opt.quad,
                                              prefix=colorstr('train: '), shuffle=True)
    # 標簽編號最大值
    mlc = int(np.concatenate(dataset.labels, 0)[:, 0].max())  # max label class
    # 類別總數(shù)
    nb = len(train_loader)  # number of batches
    # 判斷編號是否正確
    assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}'

    # Process 0
    # 驗證集數(shù)據(jù)集加載
    if RANK in [-1, 0]:
        val_loader = create_dataloader(val_path, imgsz, batch_size // WORLD_SIZE * 2, gs, single_cls,
                                       hyp=hyp, cache=None if noval else opt.cache,
                                       rect=True, rank=-1, workers=workers * 2, pad=0.5,
                                       prefix=colorstr('val: '))[0]
        # 沒有使用斷點訓練
        if not resume:
            labels = np.concatenate(dataset.labels, 0)
            # c = torch.tensor(labels[:, 0])  # classes
            # cf = torch.bincount(c.long(), minlength=nc) + 1.  # frequency
            # model._initialize_biases(cf.to(device))
            if plots:
                # 畫出標簽信息
                plot_labels(labels, names, save_dir)

            # Anchors
            # 自適應anchor / anchor可以理解為程序預測的box
            # 根據(jù)k-mean算法聚類生成新的錨框
            if not opt.noautoanchor:
                # 參數(shù)dataset代表的是訓練集,hyp['anchor_t']是從配置文件hpy.scratch.yaml讀取的超參數(shù) anchor_t:4.0
                # 當配置文件中的anchor計算bpr(best possible recall)小于0.98時才會重新計算anchor。
                # best possible recall最大值1,如果bpr小于0.98,程序會根據(jù)數(shù)據(jù)集的label自動學習anchor的尺寸
                check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz)
            # 半進度
            model.half().float()  # pre-reduce anchor precision
        callbacks.run('on_pretrain_routine_end')

3.8 train函數(shù)——訓練配置/多尺度訓練/熱身訓練

# #################################################### 7. 訓練 ###############################################
    # DDP mode
    # DDP:多機多卡
    if cuda and RANK != -1:
        model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK)

    # Model attributes
    nl = de_parallel(model).model[-1].nl  # number of detection layers (to scale hyps)
    hyp['box'] *= 3 / nl  # scale to layers
    hyp['cls'] *= nc / 80 * 3 / nl  # scale to classes and layers
    hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl  # scale to image size and layers
    # 標簽平滑
    hyp['label_smoothing'] = opt.label_smoothing
    model.nc = nc  # attach number of classes to model
    model.hyp = hyp  # attach hyperparameters to model
    # 從訓練樣本標簽得到類別權重(和類別中的目標數(shù)即類別頻率成反比)
    model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc  # attach class weights
    model.names = names

    # Start training
    t0 = time.time()
    # # 獲取熱身迭代的次數(shù)iterations: 3
    nw = max(round(hyp['warmup_epochs'] * nb), 100)  # number of warmup iterations, max(3 epochs, 100 iterations)
    # nw = min(nw, (epochs - start_epoch) / 2 * nb)  # limit warmup to < 1/2 of training
    last_opt_step = -1
    # # 初始化maps(每個類別的map)和results
    maps = np.zeros(nc)  # mAP per class
    results = (0, 0, 0, 0, 0, 0, 0)  # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls)
    # 設置學習率衰減所進行到的輪次,即使打斷訓練,使用resume接著訓練也能正常銜接之前的訓練進行學習率衰減
    scheduler.last_epoch = start_epoch - 1  # do not move
    # 設置amp混合精度訓練
    scaler = amp.GradScaler(enabled=cuda)
    # 早停止,不更新結束訓練
    stopper = EarlyStopping(patience=opt.patience)
    # 初始化損失函數(shù)
    compute_loss = ComputeLoss(model)  # init loss class
    # 打印信息
    LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n'
                f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n'
                f"Logging results to {colorstr('bold', save_dir)}\n"
                f'Starting training for {epochs} epochs...')
    # 開始走起訓練
    for epoch in range(start_epoch, epochs):  # epoch ------------------------------------------------------------------
        model.train()

        # Update image weights (optional, single-GPU only)
        # opt.image_weights
        if opt.image_weights:
            """
            如果設置進行圖片采樣策略,
            則根據(jù)前面初始化的圖片采樣權重model.class_weights以及maps配合每張圖片包含的類別數(shù)
            通過random.choices生成圖片索引indices從而進行采樣
            """
            cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc  # class weights
            iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw)  # image weights
            dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n)  # rand weighted idx

        # Update mosaic border (optional)
        # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs)
        # dataset.mosaic_border = [b - imgsz, -b]  # height, width borders

        mloss = torch.zeros(3, device=device)  # mean losses
        if RANK != -1:
            train_loader.sampler.set_epoch(epoch)
        pbar = enumerate(train_loader)
        LOGGER.info(('\n' + '%10s' * 7) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'labels', 'img_size'))
        if RANK in [-1, 0]:
            # 進度條顯示
            pbar = tqdm(pbar, total=nb, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}')  # progress bar
        # 梯度清零
        optimizer.zero_grad()
        for i, (imgs, targets, paths, _) in pbar:  # batch -------------------------------------------------------------
            ni = i + nb * epoch  # number integrated batches (since train start)
            imgs = imgs.to(device, non_blocking=True).float() / 255  # uint8 to float32, 0-255 to 0.0-1.0

            """
            熱身訓練(前nw次迭代)
            在前nw次迭代中, 根據(jù)以下方式選取accumulate和學習率
            """
            # Warmup
            if ni <= nw:
                xi = [0, nw]  # x interp
                # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0])  # iou loss ratio (obj_loss = 1.0 or iou)
                accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round())
                for j, x in enumerate(optimizer.param_groups):
                    """
                    bias的學習率從0.1下降到基準學習率lr*lf(epoch),
                    其他的參數(shù)學習率從0增加到lr*lf(epoch).
                    lf為上面設置的余弦退火的衰減函數(shù)
                    動量momentum也從0.9慢慢變到hyp['momentum'](default=0.937)
                    """

                    # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0
                    x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)])
                    if 'momentum' in x:
                        x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']])

            # Multi-scale
            if opt.multi_scale:
                """
                Multi-scale  設置多尺度訓練,從imgsz * 0.5, imgsz * 1.5 + gs隨機選取尺寸
                """
                sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs  # size
                sf = sz / max(imgs.shape[2:])  # scale factor
                if sf != 1:
                    ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]]  # new shape (stretched to gs-multiple)
                    imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False)

            # Forward / 前向傳播
            with amp.autocast(enabled=cuda):
                pred = model(imgs)  # forward
                # # 計算損失,包括分類損失,objectness損失,框的回歸損失
                # loss為總損失值,loss_items為一個元組,包含分類損失,objectness損失,框的回歸損失和總損失
                loss, loss_items = compute_loss(pred, targets.to(device))  # loss scaled by batch_size
                if RANK != -1:
                    # 平均不同gpu之間的梯度
                    loss *= WORLD_SIZE  # gradient averaged between devices in DDP mode
                if opt.quad:
                    loss *= 4.

            # Backward
            scaler.scale(loss).backward()

            # Optimize  # 模型反向傳播accumulate次之后再根據(jù)累積的梯度更新一次參數(shù)
            if ni - last_opt_step >= accumulate:
                scaler.step(optimizer)  # optimizer.step
                scaler.update()
                optimizer.zero_grad()
                if ema:
                    ema.update(model)
                last_opt_step = ni

            # Log
            if RANK in [-1, 0]:
                mloss = (mloss * i + loss_items) / (i + 1)  # update mean losses
                mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G'  # (GB)
                pbar.set_description(('%10s' * 2 + '%10.4g' * 5) % (
                    f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1]))
                callbacks.run('on_train_batch_end', ni, model, imgs, targets, paths, plots, opt.sync_bn)
                if callbacks.stop_training:
                    return
            # end batch ------------------------------------------------------------------------------------------------

        # Scheduler 進行學習率衰減
        lr = [x['lr'] for x in optimizer.param_groups]  # for loggers
        scheduler.step()

        if RANK in [-1, 0]:
            # mAP
            callbacks.run('on_train_epoch_end', epoch=epoch)
            # 將model中的屬性賦值給ema
            ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights'])
            # 判斷當前的epoch是否是最后一輪
            final_epoch = (epoch + 1 == epochs) or stopper.possible_stop
            # notest: 是否只測試最后一輪  True: 只測試最后一輪   False: 每輪訓練完都測試mAP
            if not noval or final_epoch:  # Calculate mAP
                """
                測試使用的是ema(指數(shù)移動平均 對模型的參數(shù)做平均)的模型
                results: [1] Precision 所有類別的平均precision(最大f1時)
                         [1] Recall 所有類別的平均recall
                         [1] map@0.5 所有類別的平均mAP@0.5
                         [1] map@0.5:0.95 所有類別的平均mAP@0.5:0.95
                         [1] box_loss 驗證集回歸損失, obj_loss 驗證集置信度損失, cls_loss 驗證集分類損失
                maps: [80] 所有類別的mAP@0.5:0.95
                """
                results, maps, _ = val.run(data_dict,
                                           batch_size=batch_size // WORLD_SIZE * 2,
                                           imgsz=imgsz,
                                           model=ema.ema,
                                           single_cls=single_cls,
                                           dataloader=val_loader,
                                           save_dir=save_dir,
                                           plots=False,
                                           callbacks=callbacks,
                                           compute_loss=compute_loss)

            # Update best mAP
            # Update best mAP 這里的best mAP其實是[P, R, mAP@.5, mAP@.5-.95]的一個加權值
            # fi: [P, R, mAP@.5, mAP@.5-.95]的一個加權值 = 0.1*mAP@.5 + 0.9*mAP@.5-.95
            fi = fitness(np.array(results).reshape(1, -1))  # weighted combination of [P, R, mAP@.5, mAP@.5-.95]
            if fi > best_fitness:
                best_fitness = fi
            log_vals = list(mloss) + list(results) + lr
            callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi)

            # Save model
            """
            保存帶checkpoint的模型用于inference或resuming training
            保存模型, 還保存了epoch, results, optimizer等信息
            optimizer將不會在最后一輪完成后保存
            model保存的是EMA的模型
            """
            if (not nosave) or (final_epoch and not evolve):  # if save
                ckpt = {'epoch': epoch,
                        'best_fitness': best_fitness,
                        'model': deepcopy(de_parallel(model)).half(),
                        'ema': deepcopy(ema.ema).half(),
                        'updates': ema.updates,
                        'optimizer': optimizer.state_dict(),
                        'wandb_id': loggers.wandb.wandb_run.id if loggers.wandb else None,
                        'date': datetime.now().isoformat()}

                # Save last, best and delete
                torch.save(ckpt, last)
                if best_fitness == fi:
                    torch.save(ckpt, best)
                if (epoch > 0) and (opt.save_period > 0) and (epoch % opt.save_period == 0):
                    torch.save(ckpt, w / f'epoch{epoch}.pt')
                del ckpt
                callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi)

            # Stop Single-GPU
            if RANK == -1 and stopper(epoch=epoch, fitness=fi):
                break

            # Stop DDP TODO: known issues shttps://github.com/ultralytics/yolov5/pull/4576
            # stop = stopper(epoch=epoch, fitness=fi)
            # if RANK == 0:
            #    dist.broadcast_object_list([stop], 0)  # broadcast 'stop' to all ranks

        # Stop DPP
        # with torch_distributed_zero_first(RANK):
        # if stop:
        #    break  # must break all DDP ranks

3.9 train函數(shù)——訓練結束/打印信息/保存結果

############################################### 8. 打印訓練信息 ##########################################
    if RANK in [-1, 0]:
        LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.')
        for f in last, best:
            if f.exists():
                # 模型訓練完后, strip_optimizer函數(shù)將optimizer從ckpt中刪除
                # 并對模型進行model.half() 將Float32->Float16 這樣可以減少模型大小, 提高inference速度
                strip_optimizer(f)  # strip optimizers
                if f is best:
                    LOGGER.info(f'\nValidating {f}...')
                    results, _, _ = val.run(data_dict,
                                            batch_size=batch_size // WORLD_SIZE * 2,
                                            imgsz=imgsz,
                                            model=attempt_load(f, device).half(),
                                            iou_thres=0.65 if is_coco else 0.60,  # best pycocotools results at 0.65
                                            single_cls=single_cls,
                                            dataloader=val_loader,
                                            save_dir=save_dir,
                                            save_json=is_coco,
                                            verbose=True,
                                            plots=True,
                                            callbacks=callbacks,
                                            compute_loss=compute_loss)  # val best model with plots
                    if is_coco:
                        callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi)
        # 回調函數(shù)
        callbacks.run('on_train_end', last, best, plots, epoch, results)
        LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}")
    # 釋放顯存
    torch.cuda.empty_cache()
    return results

4. run函數(shù)

def run(**kwargs):
    # 執(zhí)行這個腳本/ 調用train函數(shù) / 開啟訓練
    # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt')
    opt = parse_opt(True)
    for k, v in kwargs.items():
        # setattr() 賦值屬性,屬性不存在則創(chuàng)建一個賦值
        setattr(opt, k, v)
    main(opt)
    return opt

5.全部代碼注釋

# YOLOv5 ?? by Ultralytics, GPL-3.0 license
"""
Train a YOLOv5 model on a custom dataset.

Models and datasets download automatically from the latest YOLOv5 release.
Models: https://github.com/ultralytics/yolov5/tree/master/models
Datasets: https://github.com/ultralytics/yolov5/tree/master/data
Tutorial: https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data

Usage:
    $ python path/to/train.py --data coco128.yaml --weights yolov5s.pt --img 640  # from pretrained (RECOMMENDED)
    $ python path/to/train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640  # from scratch
"""

import argparse
import math
import os
import random
import sys
import time
from copy import deepcopy
from datetime import datetime
from pathlib import Path

import numpy as np
import torch
import torch.distributed as dist
import torch.nn as nn
import yaml
from torch.cuda import amp
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.optim import SGD, Adam, AdamW, lr_scheduler
from tqdm import tqdm

FILE = Path(__file__).resolve()
ROOT = FILE.parents[0]  # YOLOv5 root directory
if str(ROOT) not in sys.path:
    sys.path.append(str(ROOT))  # add ROOT to PATH
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relative

import val  # for end-of-epoch mAP
from models.experimental import attempt_load
from models.yolo import Model
from utils.autoanchor import check_anchors
from utils.autobatch import check_train_batch_size
from utils.callbacks import Callbacks
from utils.datasets import create_dataloader
from utils.downloads import attempt_download
from utils.general import (LOGGER, check_dataset, check_file, check_git_status, check_img_size, check_requirements,
                           check_suffix, check_yaml, colorstr, get_latest_run, increment_path, init_seeds,
                           intersect_dicts, labels_to_class_weights, labels_to_image_weights, methods, one_cycle,
                           print_args, print_mutation, strip_optimizer)
from utils.loggers import Loggers
from utils.loggers.wandb.wandb_utils import check_wandb_resume
from utils.loss import ComputeLoss
from utils.metrics import fitness
from utils.plots import plot_evolve, plot_labels
from utils.torch_utils import EarlyStopping, ModelEMA, de_parallel, select_device, torch_distributed_zero_first

LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1))  # https://pytorch.org/docs/stable/elastic/run.html
RANK = int(os.getenv('RANK', -1))
WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1))


def train(hyp,  # path/to/hyp.yaml or hyp dictionary
          opt,
          device,
          callbacks
          ):
    ################################################ 1. 傳入?yún)?shù)/基本配置 #############################################
    # opt傳入的參數(shù)
    save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \
        Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \
        opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze

    # Directories
    w = save_dir / 'weights'  # weights dir
    # 新建文件夾 weights train evolve
    (w.parent if evolve else w).mkdir(parents=True, exist_ok=True)  # make dir
    # 保存訓練結果的目錄  如runs/train/exp*/weights/last.pt
    last, best = w / 'last.pt', w / 'best.pt'

    # Hyperparameters # isinstance()是否是已知類型
    if isinstance(hyp, str):
        with open(hyp, errors='ignore') as f:
            # 加載yaml文件
            hyp = yaml.safe_load(f)  # load hyps dict
    # 打印超參數(shù) 彩色字體
    LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items()))

    # Save run settings
    # 如果不使用進化訓練
    if not evolve:
        # safe_dump() python值轉化為yaml序列化
        with open(save_dir / 'hyp.yaml', 'w') as f:
            yaml.safe_dump(hyp, f, sort_keys=False)
        with open(save_dir / 'opt.yaml', 'w') as f:
            # vars(opt) 的作用是把數(shù)據(jù)類型是Namespace的數(shù)據(jù)轉換為字典的形式。
            yaml.safe_dump(vars(opt), f, sort_keys=False)

    # Loggers
    data_dict = None
    if RANK in [-1, 0]:
        loggers = Loggers(save_dir, weights, opt, hyp, LOGGER)  # loggers instance
        if loggers.wandb:
            data_dict = loggers.wandb.data_dict
            if resume:
                weights, epochs, hyp, batch_size = opt.weights, opt.epochs, opt.hyp, opt.batch_size

        # Register actions
        for k in methods(loggers):
            callbacks.register_action(k, callback=getattr(loggers, k))

    # Config 畫圖
    plots = not evolve  # create plots
    # GPU / CPU
    cuda = device.type != 'cpu'
    # 隨機種子
    init_seeds(1 + RANK)
    # 存在子進程-分布式訓練
    with torch_distributed_zero_first(LOCAL_RANK):
        data_dict = data_dict or check_dataset(data)  # check if None
    # 訓練集和驗證集的位路徑
    train_path, val_path = data_dict['train'], data_dict['val']
    # 設置類別 是否單類
    nc = 1 if single_cls else int(data_dict['nc'])  # number of classes
    # 類別對應的名稱
    names = ['item'] if single_cls and len(data_dict['names']) != 1 else data_dict['names']  # class names
    # 判斷類別長度和文件是否對應
    assert len(names) == nc, f'{len(names)} names found for nc={nc} dataset in {data}'  # check
    # 當前數(shù)據(jù)集是否是coco數(shù)據(jù)集(80個類別) 
    is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt')  # COCO dataset

    ################################################### 2. Model ###########################################
    # 檢查文件后綴是否是.pt
    check_suffix(weights, '.pt')  # check weights
    # 加載預訓練權重 yolov5提供了5個不同的預訓練權重,大家可以根據(jù)自己的模型選擇預訓練權重
    pretrained = weights.endswith('.pt')
    if pretrained:
        # # torch_distributed_zero_first(RANK): 用于同步不同進程對數(shù)據(jù)讀取的上下文管理器
        with torch_distributed_zero_first(LOCAL_RANK):
            # 如果本地不存在就從網(wǎng)站上下載
            weights = attempt_download(weights)  # download if not found locally
        # 加載模型以及參數(shù)
        ckpt = torch.load(weights, map_location='cpu')  # load checkpoint to CPU to avoid CUDA memory leak
        """
        兩種加載模型的方式: opt.cfg / ckpt['model'].yaml
        使用resume-斷點訓練: 選擇ckpt['model']yaml創(chuàng)建模型, 且不加載anchor
        使用斷點訓練時,保存的模型會保存anchor,所以不需要加載

        """
        model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device)  # create
        exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else []  # exclude keys
        csd = ckpt['model'].float().state_dict()  # checkpoint state_dict as FP32
        # 篩選字典中的鍵值對  把exclude刪除
        csd = intersect_dicts(csd, model.state_dict(), exclude=exclude)  # intersect
        model.load_state_dict(csd, strict=False)  # load
        LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}')  # report
    else:
        # 不適用預訓練權重
        model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device)  # create

    ################################################ 3. Freeze/凍結訓練 #########################################
    # 凍結訓練的網(wǎng)絡層
    freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))]  # layers to freeze
    for k, v in model.named_parameters():
        v.requires_grad = True  # train all layers
        if any(x in k for x in freeze):
            LOGGER.info(f'freezing {k}')
            # 凍結訓練的層梯度不更新
            v.requires_grad = False

    # Image size
    gs = max(int(model.stride.max()), 32)  # grid size (max stride)
    # 檢查圖片的大小
    imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2)  # verify imgsz is gs-multiple

    # Batch size
    if RANK == -1 and batch_size == -1:  # single-GPU only, estimate best batch size
        batch_size = check_train_batch_size(model, imgsz)
        loggers.on_params_update({"batch_size": batch_size})

    ############################################ 4. Optimizer/優(yōu)化器 ###########################################
    """
    nbs = 64
    batchsize = 16
    accumulate = 64 / 16 = 4
    模型梯度累計accumulate次之后就更新一次模型 相當于使用更大batch_size
    """
    nbs = 64  # nominal batch size
    accumulate = max(round(nbs / batch_size), 1)  # accumulate loss before optimizing
    # 權重衰減參數(shù)
    hyp['weight_decay'] *= batch_size * accumulate / nbs  # scale weight_decay
    # 打印日志
    LOGGER.info(f"Scaled weight_decay = {hyp['weight_decay']}")

    # 將模型參數(shù)分為三組(weights、biases、bn)來進行分組優(yōu)化
    g0, g1, g2 = [], [], []  # optimizer parameter groups
    for v in model.modules():
        if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):  # bias
            g2.append(v.bias)
        if isinstance(v, nn.BatchNorm2d):  # weight (no decay)
            g0.append(v.weight)
        elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):  # weight (with decay)
            g1.append(v.weight)
    # 選擇優(yōu)化器 / 提供了三個優(yōu)化器——g0
    if opt.optimizer == 'Adam':
        optimizer = Adam(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))  # adjust beta1 to momentum
    elif opt.optimizer == 'AdamW':
        optimizer = AdamW(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))  # adjust beta1 to momentum
    else:
        optimizer = SGD(g0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True)
    # 設置優(yōu)化的方式——g1 / g2
    optimizer.add_param_group({'params': g1, 'weight_decay': hyp['weight_decay']})  # add g1 with weight_decay
    optimizer.add_param_group({'params': g2})  # add g2 (biases)
    # 打印log日志 優(yōu)化信息
    LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__} with parameter groups "
                f"{len(g0)} weight (no decay), {len(g1)} weight, {len(g2)} bias")
    # 刪除變量
    del g0, g1, g2

    ############################################ 5. Scheduler ##############################################
    # 是否余弦學習率調整方式
    if opt.cos_lr:
        lf = one_cycle(1, hyp['lrf'], epochs)  # cosine 1->hyp['lrf']
    else:
        lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf']  # linear
    scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)  # plot_lr_scheduler(optimizer, scheduler, epochs)

    # EMA
    # 使用EMA(指數(shù)移動平均)對模型的參數(shù)做平均, 一種給予近期數(shù)據(jù)更高權重的平均方法, 以求提高測試指標并增加模型魯棒。
    ema = ModelEMA(model) if RANK in [-1, 0] else None

    # Resume
    start_epoch, best_fitness = 0, 0.0
    if pretrained:
        # Optimizer
        if ckpt['optimizer'] is not None:
            optimizer.load_state_dict(ckpt['optimizer'])
            best_fitness = ckpt['best_fitness']

        # EMA
        if ema and ckpt.get('ema'):
            ema.ema.load_state_dict(ckpt['ema'].float().state_dict())
            ema.updates = ckpt['updates']

        # Epochs
        start_epoch = ckpt['epoch'] + 1
        if resume:
            assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.'
        if epochs < start_epoch:
            LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.")
            epochs += ckpt['epoch']  # finetune additional epochs

        del ckpt, csd

    # DP mode
    # DP: 單機多卡模式
    if cuda and RANK == -1 and torch.cuda.device_count() > 1:
        LOGGER.warning('WARNING: DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n'
                       'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.')
        model = torch.nn.DataParallel(model)

    # SyncBatchNorm 多卡歸一化
    if opt.sync_bn and cuda and RANK != -1:
        model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device)
        # 打印信息
        LOGGER.info('Using SyncBatchNorm()')

    # ############################################## 6. Trainloader / 數(shù)據(jù)加載 ######################################
    # 訓練集數(shù)據(jù)加載
    train_loader, dataset = create_dataloader(train_path, imgsz, batch_size // WORLD_SIZE, gs, single_cls,
                                              hyp=hyp, augment=True, cache=None if opt.cache == 'val' else opt.cache,
                                              rect=opt.rect, rank=LOCAL_RANK, workers=workers,
                                              image_weights=opt.image_weights, quad=opt.quad,
                                              prefix=colorstr('train: '), shuffle=True)
    # 標簽編號最大值
    mlc = int(np.concatenate(dataset.labels, 0)[:, 0].max())  # max label class
    # 類別總數(shù)
    nb = len(train_loader)  # number of batches
    # 判斷編號是否正確
    assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}'

    # Process 0
    # 驗證集數(shù)據(jù)集加載
    if RANK in [-1, 0]:
        val_loader = create_dataloader(val_path, imgsz, batch_size // WORLD_SIZE * 2, gs, single_cls,
                                       hyp=hyp, cache=None if noval else opt.cache,
                                       rect=True, rank=-1, workers=workers * 2, pad=0.5,
                                       prefix=colorstr('val: '))[0]
        # 沒有使用斷點訓練
        if not resume:
            labels = np.concatenate(dataset.labels, 0)
            # c = torch.tensor(labels[:, 0])  # classes
            # cf = torch.bincount(c.long(), minlength=nc) + 1.  # frequency
            # model._initialize_biases(cf.to(device))
            if plots:
                # 畫出標簽信息
                plot_labels(labels, names, save_dir)

            # Anchors
            # 自適應anchor / anchor可以理解為程序預測的box
            # 根據(jù)k-mean算法聚類生成新的錨框
            if not opt.noautoanchor:
                # 參數(shù)dataset代表的是訓練集,hyp['anchor_t']是從配置文件hpy.scratch.yaml讀取的超參數(shù) anchor_t:4.0
                # 當配置文件中的anchor計算bpr(best possible recall)小于0.98時才會重新計算anchor。
                # best possible recall最大值1,如果bpr小于0.98,程序會根據(jù)數(shù)據(jù)集的label自動學習anchor的尺寸
                check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz)
            # 半進度
            model.half().float()  # pre-reduce anchor precision
        callbacks.run('on_pretrain_routine_end')

    # #################################################### 7. 訓練 ###############################################
    # DDP mode
    # DDP:多機多卡
    if cuda and RANK != -1:
        model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK)

    # Model attributes
    nl = de_parallel(model).model[-1].nl  # number of detection layers (to scale hyps)
    hyp['box'] *= 3 / nl  # scale to layers
    hyp['cls'] *= nc / 80 * 3 / nl  # scale to classes and layers
    hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl  # scale to image size and layers
    # 標簽平滑
    hyp['label_smoothing'] = opt.label_smoothing
    model.nc = nc  # attach number of classes to model
    model.hyp = hyp  # attach hyperparameters to model
    # 從訓練樣本標簽得到類別權重(和類別中的目標數(shù)即類別頻率成反比)
    model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc  # attach class weights
    model.names = names

    # Start training
    t0 = time.time()
    # # 獲取熱身迭代的次數(shù)iterations: 3
    nw = max(round(hyp['warmup_epochs'] * nb), 100)  # number of warmup iterations, max(3 epochs, 100 iterations)
    # nw = min(nw, (epochs - start_epoch) / 2 * nb)  # limit warmup to < 1/2 of training
    last_opt_step = -1
    # # 初始化maps(每個類別的map)和results
    maps = np.zeros(nc)  # mAP per class
    results = (0, 0, 0, 0, 0, 0, 0)  # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls)
    # 設置學習率衰減所進行到的輪次,即使打斷訓練,使用resume接著訓練也能正常銜接之前的訓練進行學習率衰減
    scheduler.last_epoch = start_epoch - 1  # do not move
    # 設置amp混合精度訓練
    scaler = amp.GradScaler(enabled=cuda)
    # 早停止,不更新結束訓練
    stopper = EarlyStopping(patience=opt.patience)
    # 初始化損失函數(shù)
    compute_loss = ComputeLoss(model)  # init loss class
    # 打印信息
    LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n'
                f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n'
                f"Logging results to {colorstr('bold', save_dir)}\n"
                f'Starting training for {epochs} epochs...')
    # 開始走起訓練
    for epoch in range(start_epoch, epochs):  # epoch ------------------------------------------------------------------
        model.train()

        # Update image weights (optional, single-GPU only)
        # opt.image_weights
        if opt.image_weights:
            """
            如果設置進行圖片采樣策略,
            則根據(jù)前面初始化的圖片采樣權重model.class_weights以及maps配合每張圖片包含的類別數(shù)
            通過random.choices生成圖片索引indices從而進行采樣
            """
            cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc  # class weights
            iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw)  # image weights
            dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n)  # rand weighted idx

        # Update mosaic border (optional)
        # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs)
        # dataset.mosaic_border = [b - imgsz, -b]  # height, width borders

        mloss = torch.zeros(3, device=device)  # mean losses
        if RANK != -1:
            train_loader.sampler.set_epoch(epoch)
        pbar = enumerate(train_loader)
        LOGGER.info(('\n' + '%10s' * 7) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'labels', 'img_size'))
        if RANK in [-1, 0]:
            # 進度條顯示
            pbar = tqdm(pbar, total=nb, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}')  # progress bar
        # 梯度清零
        optimizer.zero_grad()
        for i, (imgs, targets, paths, _) in pbar:  # batch -------------------------------------------------------------
            ni = i + nb * epoch  # number integrated batches (since train start)
            imgs = imgs.to(device, non_blocking=True).float() / 255  # uint8 to float32, 0-255 to 0.0-1.0

            """
            熱身訓練(前nw次迭代)
            在前nw次迭代中, 根據(jù)以下方式選取accumulate和學習率
            """
            # Warmup
            if ni <= nw:
                xi = [0, nw]  # x interp
                # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0])  # iou loss ratio (obj_loss = 1.0 or iou)
                accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round())
                for j, x in enumerate(optimizer.param_groups):
                    """
                    bias的學習率從0.1下降到基準學習率lr*lf(epoch),
                    其他的參數(shù)學習率從0增加到lr*lf(epoch).
                    lf為上面設置的余弦退火的衰減函數(shù)
                    動量momentum也從0.9慢慢變到hyp['momentum'](default=0.937)
                    """

                    # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0
                    x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)])
                    if 'momentum' in x:
                        x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']])

            # Multi-scale
            if opt.multi_scale:
                """
                Multi-scale  設置多尺度訓練,從imgsz * 0.5, imgsz * 1.5 + gs隨機選取尺寸
                """
                sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs  # size
                sf = sz / max(imgs.shape[2:])  # scale factor
                if sf != 1:
                    ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]]  # new shape (stretched to gs-multiple)
                    imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False)

            # Forward / 前向傳播
            with amp.autocast(enabled=cuda):
                pred = model(imgs)  # forward
                # # 計算損失,包括分類損失,objectness損失,框的回歸損失
                # loss為總損失值,loss_items為一個元組,包含分類損失,objectness損失,框的回歸損失和總損失
                loss, loss_items = compute_loss(pred, targets.to(device))  # loss scaled by batch_size
                if RANK != -1:
                    # 平均不同gpu之間的梯度
                    loss *= WORLD_SIZE  # gradient averaged between devices in DDP mode
                if opt.quad:
                    loss *= 4.

            # Backward
            scaler.scale(loss).backward()

            # Optimize  # 模型反向傳播accumulate次之后再根據(jù)累積的梯度更新一次參數(shù)
            if ni - last_opt_step >= accumulate:
                scaler.step(optimizer)  # optimizer.step
                scaler.update()
                optimizer.zero_grad()
                if ema:
                    ema.update(model)
                last_opt_step = ni

            # Log
            if RANK in [-1, 0]:
                mloss = (mloss * i + loss_items) / (i + 1)  # update mean losses
                mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G'  # (GB)
                pbar.set_description(('%10s' * 2 + '%10.4g' * 5) % (
                    f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1]))
                callbacks.run('on_train_batch_end', ni, model, imgs, targets, paths, plots, opt.sync_bn)
                if callbacks.stop_training:
                    return
            # end batch ------------------------------------------------------------------------------------------------

        # Scheduler 進行學習率衰減
        lr = [x['lr'] for x in optimizer.param_groups]  # for loggers
        scheduler.step()

        if RANK in [-1, 0]:
            # mAP
            callbacks.run('on_train_epoch_end', epoch=epoch)
            # 將model中的屬性賦值給ema
            ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights'])
            # 判斷當前的epoch是否是最后一輪
            final_epoch = (epoch + 1 == epochs) or stopper.possible_stop
            # notest: 是否只測試最后一輪  True: 只測試最后一輪   False: 每輪訓練完都測試mAP
            if not noval or final_epoch:  # Calculate mAP
                """
                測試使用的是ema(指數(shù)移動平均 對模型的參數(shù)做平均)的模型
                results: [1] Precision 所有類別的平均precision(最大f1時)
                         [1] Recall 所有類別的平均recall
                         [1] map@0.5 所有類別的平均mAP@0.5
                         [1] map@0.5:0.95 所有類別的平均mAP@0.5:0.95
                         [1] box_loss 驗證集回歸損失, obj_loss 驗證集置信度損失, cls_loss 驗證集分類損失
                maps: [80] 所有類別的mAP@0.5:0.95
                """
                results, maps, _ = val.run(data_dict,
                                           batch_size=batch_size // WORLD_SIZE * 2,
                                           imgsz=imgsz,
                                           model=ema.ema,
                                           single_cls=single_cls,
                                           dataloader=val_loader,
                                           save_dir=save_dir,
                                           plots=False,
                                           callbacks=callbacks,
                                           compute_loss=compute_loss)

            # Update best mAP
            # Update best mAP 這里的best mAP其實是[P, R, mAP@.5, mAP@.5-.95]的一個加權值
            # fi: [P, R, mAP@.5, mAP@.5-.95]的一個加權值 = 0.1*mAP@.5 + 0.9*mAP@.5-.95
            fi = fitness(np.array(results).reshape(1, -1))  # weighted combination of [P, R, mAP@.5, mAP@.5-.95]
            if fi > best_fitness:
                best_fitness = fi
            log_vals = list(mloss) + list(results) + lr
            callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi)

            # Save model
            """
            保存帶checkpoint的模型用于inference或resuming training
            保存模型, 還保存了epoch, results, optimizer等信息
            optimizer將不會在最后一輪完成后保存
            model保存的是EMA的模型
            """
            if (not nosave) or (final_epoch and not evolve):  # if save
                ckpt = {'epoch': epoch,
                        'best_fitness': best_fitness,
                        'model': deepcopy(de_parallel(model)).half(),
                        'ema': deepcopy(ema.ema).half(),
                        'updates': ema.updates,
                        'optimizer': optimizer.state_dict(),
                        'wandb_id': loggers.wandb.wandb_run.id if loggers.wandb else None,
                        'date': datetime.now().isoformat()}

                # Save last, best and delete
                torch.save(ckpt, last)
                if best_fitness == fi:
                    torch.save(ckpt, best)
                if (epoch > 0) and (opt.save_period > 0) and (epoch % opt.save_period == 0):
                    torch.save(ckpt, w / f'epoch{epoch}.pt')
                del ckpt
                callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi)

            # Stop Single-GPU
            if RANK == -1 and stopper(epoch=epoch, fitness=fi):
                break

            # Stop DDP TODO: known issues shttps://github.com/ultralytics/yolov5/pull/4576
            # stop = stopper(epoch=epoch, fitness=fi)
            # if RANK == 0:
            #    dist.broadcast_object_list([stop], 0)  # broadcast 'stop' to all ranks

        # Stop DPP
        # with torch_distributed_zero_first(RANK):
        # if stop:
        #    break  # must break all DDP ranks

        # end epoch ----------------------------------------------------------------------------------------------------
    # end training --------------------------------------------------------------------------------------------------
    ############################################### 8. 打印訓練信息 ##########################################
    if RANK in [-1, 0]:
        LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.')
        for f in last, best:
            if f.exists():
                # 模型訓練完后, strip_optimizer函數(shù)將optimizer從ckpt中刪除
                # 并對模型進行model.half() 將Float32->Float16 這樣可以減少模型大小, 提高inference速度
                strip_optimizer(f)  # strip optimizers
                if f is best:
                    LOGGER.info(f'\nValidating {f}...')
                    results, _, _ = val.run(data_dict,
                                            batch_size=batch_size // WORLD_SIZE * 2,
                                            imgsz=imgsz,
                                            model=attempt_load(f, device).half(),
                                            iou_thres=0.65 if is_coco else 0.60,  # best pycocotools results at 0.65
                                            single_cls=single_cls,
                                            dataloader=val_loader,
                                            save_dir=save_dir,
                                            save_json=is_coco,
                                            verbose=True,
                                            plots=True,
                                            callbacks=callbacks,
                                            compute_loss=compute_loss)  # val best model with plots
                    if is_coco:
                        callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi)
        # 回調函數(shù)
        callbacks.run('on_train_end', last, best, plots, epoch, results)
        LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}")
    # 釋放顯存
    torch.cuda.empty_cache()
    return results


def parse_opt(known=False):
    parser = argparse.ArgumentParser()
    # weights 權重的路徑./weights/yolov5s.pt....
    parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='initial weights path')
    # cfg 配置文件(網(wǎng)絡結構) anchor/backbone/numclasses/head,該文件需要自己生成
    parser.add_argument('--cfg', type=str, default='', help='model.yaml path')
    # data 數(shù)據(jù)集配置文件(路徑) train/val/label/, 該文件需要自己生成
    parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path')
    # hpy超參數(shù)設置文件(lr/sgd/mixup)
    parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path')
    # epochs 訓練輪次
    parser.add_argument('--epochs', type=int, default=300)
    # batchsize 訓練批次
    parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch')
    # imagesize 設置圖片大小
    parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)')
    # rect 是否采用矩形訓練,默認為False
    parser.add_argument('--rect', action='store_true', help='rectangular training')
    # resume 是否接著上次的訓練結果,繼續(xù)訓練
    parser.add_argument('--resume', nargs='?', const=True, default=True, help='resume most recent training')
    # nosave 保存最好的模型
    parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
    # noval 最后進行測試
    parser.add_argument('--noval', action='store_true', help='only validate final epoch')
    # noautoanchor 不自動調整anchor, 默認False
    parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor')
    # evolve參數(shù)進化
    parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations')
    # bucket谷歌優(yōu)盤
    parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
    # cache 是否提前緩存圖片到內(nèi)存,以加快訓練速度,默認False
    parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"')
    # mage-weights 加載的權重文件
    parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
    # device 設備選擇
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    # multi-scale 多測度訓練
    parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%')
    # single-cls 數(shù)據(jù)集是否多類/默認True
    parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
    # optimizer 優(yōu)化器選擇
    parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer')
    # sync-bn:是否使用跨卡同步BN,在DDP模式使用
    parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
    # workers/dataloader的最大worker數(shù)量
    parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)')
    # 保存路徑
    parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name')
    # 實驗名稱
    parser.add_argument('--name', default='exp', help='save to project/name')
    # 項目位置是否存在
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    parser.add_argument('--quad', action='store_true', help='quad dataloader')
    # cos-lr 余弦學習率
    parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler')
    # 標簽平滑
    parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')
    # 早停止忍耐次數(shù)
    parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)')
    # 凍結訓練次數(shù)
    parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2')
    parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)')
    parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')

    # Weights & Biases arguments
    # 在線可視化工具,類似于tensorboard工具,想了解這款工具可以查看https://zhuanlan.zhihu.com/p/266337608
    parser.add_argument('--entity', default=None, help='W&B: Entity')
    # upload_dataset: 是否上傳dataset到wandb tabel(將數(shù)據(jù)集作為交互式 dsviz表 在瀏覽器中查看、查詢、篩選和分析數(shù)據(jù)集) 默認False
    parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='W&B: Upload data, "val" option')
    # bbox_interval: 設置界框圖像記錄間隔 Set bounding-box image logging interval for W&B 默認-1   opt.epochs // 10
    parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval')
    # 使用數(shù)據(jù)的版本
    parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use')

    # 傳入的基本配置中沒有的參數(shù)也不會報錯# parse_args()和parse_known_args() 
    # parse = argparse.ArgumentParser()
    # parse.add_argument('--s', type=int, default=2, help='flag_int')
    # parser.parse_args() / parse_args()
    opt = parser.parse_known_args()[0] if known else parser.parse_args()
    return opt


def main(opt, callbacks=Callbacks()):
    ############################################### 1. Checks ##################################################
    if RANK in [-1, 0]:
        # 輸出所有訓練參數(shù) / 參數(shù)以彩色的方式表現(xiàn)
        print_args(FILE.stem, opt)
        # 檢查代碼版本是否更新
        check_git_status()
        # 檢查安裝是否都安裝了 requirements.txt, 缺少安裝包安裝。
        # 缺少安裝包:建議使用 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
        check_requirements(exclude=['thop'])

    ############################################### 2. Resume ##################################################
    # 初始化可視化工具wandb,wandb使用教程看https://zhuanlan.zhihu.com/p/266337608
    # 斷點訓練使用教程可以查看:https://blog.csdn.net/CharmsLUO/article/details/123410081
    if opt.resume and not check_wandb_resume(opt) and not opt.evolve:  # resume an interrupted run
        # isinstance()是否是已經(jīng)知道的類型
        # 如果resume是True,則通過get_lastest_run()函數(shù)找到runs為文件夾中最近的權重文件last.pt
        ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run()  # specified or most recent path
        # 判斷是否是文件
        assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist'
        #  # 相關的opt參數(shù)也要替換成last.pt中的opt參數(shù) safe_load()yaml文件加載數(shù)據(jù)
        with open(Path(ckpt).parent.parent / 'opt.yaml', errors='ignore') as f:
            # argparse.Namespace 可以理解為字典
            opt = argparse.Namespace(**yaml.safe_load(f))  # replace
        opt.cfg, opt.weights, opt.resume = '', ckpt, True  # reinstate
        # 打印斷點訓練信息
        LOGGER.info(f'Resuming training from {ckpt}')
    else:
        # 不使用斷點訓練就在加載輸入的參數(shù)
        opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \
            check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project)  # checks
        assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified'
        # opt.evolve=False,opt.name='exp'    opt.evolve=True,opt.name='evolve'
        if opt.evolve:
            if opt.project == str(ROOT / 'runs/train'):  # if default project name, rename to runs/evolve
                opt.project = str(ROOT / 'runs/evolve')
            opt.exist_ok, opt.resume = opt.resume, False  # pass resume to exist_ok and disable resume
        # 保存相關信息
        opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok))

    # ############################################## 3.DDP mode ###############################################
    # 選擇設備cpu/cuda
    device = select_device(opt.device, batch_size=opt.batch_size)
    # 多卡訓練GPU
    if LOCAL_RANK != -1:
        msg = 'is not compatible with YOLOv5 Multi-GPU DDP training'
        assert not opt.image_weights, f'--image-weights {msg}'
        assert not opt.evolve, f'--evolve {msg}'
        assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size'
        assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE'
        assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command'
        # 根據(jù)編號選擇設備
        #使用torch.cuda.set_device()可以更方便地將模型和數(shù)據(jù)加載到對應GPU上, 直接定義模型之前加入一行代碼即可
        # torch.cuda.set_device(gpu_id) #單卡
        # torch.cuda.set_device('cuda:'+str(gpu_ids)) #可指定多卡
        torch.cuda.set_device(LOCAL_RANK)
        device = torch.device('cuda', LOCAL_RANK)
        # 初始化多進程
        dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo")

    ################################################ 4. Train #################################################
    # 不設置evolve直接調用train訓練
    if not opt.evolve:
        train(opt.hyp, opt, device, callbacks)
        # 分布式訓練 WORLD_SIZE=主機的數(shù)量
        # 如果是使用多卡訓練, 那么銷毀進程組
        if WORLD_SIZE > 1 and RANK == 0:
            LOGGER.info('Destroying process group... ')
            # 使用多卡訓練, 那么銷毀進程組
            dist.destroy_process_group()

    # Evolve hyperparameters (optional)
    # 遺傳凈化算法/一邊訓練一遍進化
    # 了解遺傳算法可以查看我的博客:
    else:
        # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit)
        # 超參數(shù)列表(突變范圍 - 最小值 - 最大值)
        meta = {'lr0': (1, 1e-5, 1e-1),  # initial learning rate (SGD=1E-2, Adam=1E-3)
                'lrf': (1, 0.01, 1.0),  # final OneCycleLR learning rate (lr0 * lrf)
                'momentum': (0.3, 0.6, 0.98),  # SGD momentum/Adam beta1
                'weight_decay': (1, 0.0, 0.001),  # optimizer weight decay
                'warmup_epochs': (1, 0.0, 5.0),  # warmup epochs (fractions ok)
                'warmup_momentum': (1, 0.0, 0.95),  # warmup initial momentum
                'warmup_bias_lr': (1, 0.0, 0.2),  # warmup initial bias lr
                'box': (1, 0.02, 0.2),  # box loss gain
                'cls': (1, 0.2, 4.0),  # cls loss gain
                'cls_pw': (1, 0.5, 2.0),  # cls BCELoss positive_weight
                'obj': (1, 0.2, 4.0),  # obj loss gain (scale with pixels)
                'obj_pw': (1, 0.5, 2.0),  # obj BCELoss positive_weight
                'iou_t': (0, 0.1, 0.7),  # IoU training threshold
                'anchor_t': (1, 2.0, 8.0),  # anchor-multiple threshold
                'anchors': (2, 2.0, 10.0),  # anchors per output grid (0 to ignore)
                'fl_gamma': (0, 0.0, 2.0),  # focal loss gamma (efficientDet default gamma=1.5)
                'hsv_h': (1, 0.0, 0.1),  # image HSV-Hue augmentation (fraction)
                'hsv_s': (1, 0.0, 0.9),  # image HSV-Saturation augmentation (fraction)
                'hsv_v': (1, 0.0, 0.9),  # image HSV-Value augmentation (fraction)
                'degrees': (1, 0.0, 45.0),  # image rotation (+/- deg)
                'translate': (1, 0.0, 0.9),  # image translation (+/- fraction)
                'scale': (1, 0.0, 0.9),  # image scale (+/- gain)
                'shear': (1, 0.0, 10.0),  # image shear (+/- deg)
                'perspective': (0, 0.0, 0.001),  # image perspective (+/- fraction), range 0-0.001
                'flipud': (1, 0.0, 1.0),  # image flip up-down (probability)
                'fliplr': (0, 0.0, 1.0),  # image flip left-right (probability)
                'mosaic': (1, 0.0, 1.0),  # image mixup (probability)
                'mixup': (1, 0.0, 1.0),  # image mixup (probability)
                'copy_paste': (1, 0.0, 1.0)}  # segment copy-paste (probability)

        with open(opt.hyp, errors='ignore') as f:
            # 加載yaml超參數(shù)
            hyp = yaml.safe_load(f)  # load hyps dict
            if 'anchors' not in hyp:  # anchors commented in hyp.yaml
                hyp['anchors'] = 3
        opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir)  # only val/save final epoch
        # ei = [isinstance(x, (int, float)) for x in hyp.values()]  # evolvable indices
        # 保存進化的超參數(shù)列表
        evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv'
        if opt.bucket:
            os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}')  # download evolve.csv if exists
        """
        遺傳算法調參:遵循適者生存、優(yōu)勝劣汰的法則,即尋優(yōu)過程中保留有用的,去除無用的。
        遺傳算法需要提前設置4個參數(shù): 群體大小/進化代數(shù)/交叉概率/變異概率

        """

        # 默認選擇進化300代
        for _ in range(opt.evolve):  # generations to evolve
            if evolve_csv.exists():  # if evolve.csv exists: select best hyps and mutate
                # Select parent(s)
                # 進化方式--single / --weight
                parent = 'single'  # parent selection method: 'single' or 'weighted'
                # 加載evolve.txt文件
                x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1)
                # 選取進化結果代數(shù)
                n = min(5, len(x))  # number of previous results to consider
                x = x[np.argsort(-fitness(x))][:n]  # top n mutations
                 # 根據(jù)resluts計算hyp權重
                w = fitness(x) - fitness(x).min() + 1E-6  # weights (sum > 0)
                # 根據(jù)不同進化方式獲得base hyp
                if parent == 'single' or len(x) == 1:
                    # x = x[random.randint(0, n - 1)]  # random selection
                    x = x[random.choices(range(n), weights=w)[0]]  # weighted selection
                elif parent == 'weighted':
                    x = (x * w.reshape(n, 1)).sum(0) / w.sum()  # weighted combination

                # Mutate
                # # 獲取突變初始值
                mp, s = 0.8, 0.2  # mutation probability, sigma
                npr = np.random
                npr.seed(int(time.time()))
                g = np.array([meta[k][0] for k in hyp.keys()])  # gains 0-1
                ng = len(meta)
                v = np.ones(ng)
                # 設置突變
                while all(v == 1):  # mutate until a change occurs (prevent duplicates)
                    # 將突變添加到base hyp上
                    # [i+7]是因為x中前7個數(shù)字為results的指標(P,R,mAP,F1,test_loss=(box,obj,cls)),之后才是超參數(shù)hyp
                    v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0)
                for i, k in enumerate(hyp.keys()):  # plt.hist(v.ravel(), 300)
                    hyp[k] = float(x[i + 7] * v[i])  # mutate

            # Constrain to limits
            # 限制超參再規(guī)定范圍
            for k, v in meta.items():
                hyp[k] = max(hyp[k], v[1])  # lower limit
                hyp[k] = min(hyp[k], v[2])  # upper limit
                hyp[k] = round(hyp[k], 5)  # significant digits

            # Train mutation
            # 訓練 使用突變后的參超 測試其效果
            results = train(hyp.copy(), opt, device, callbacks)
            callbacks = Callbacks()
            # Write mutation results
            # Write mutation results
            # 將結果寫入results 并將對應的hyp寫到evolve.txt evolve.txt中每一行為一次進化的結果
            # 每行前七個數(shù)字 (P, R, mAP, F1, test_losses(GIOU, obj, cls)) 之后為hyp
            # 保存hyp到y(tǒng)aml文件
            print_mutation(results, hyp.copy(), save_dir, opt.bucket)

        # Plot results
        # 將結果可視化 / 輸出保存信息
        plot_evolve(evolve_csv)
        LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n'
                    f"Results saved to {colorstr('bold', save_dir)}\n"
                    f'Usage example: $ python train.py --hyp {evolve_yaml}')


def run(**kwargs):
    # 執(zhí)行這個腳本/ 調用train函數(shù) / 開啟訓練
    # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt')
    opt = parse_opt(True)
    for k, v in kwargs.items():
        # setattr() 賦值屬性,屬性不存在則創(chuàng)建一個賦值
        setattr(opt, k, v)
    main(opt)
    return opt


if __name__ == "__main__":
    # 接著上次訓練
    # python train.py --data ./data/mchar.yaml --cfg yolov5l_mchar.yaml --epochs 80 --batch-size 8 --weights ./runs/train/exp7/weights/last.pt
    opt = parse_opt()
    main(opt)

使用教程

下面我把大家能使用到的參數(shù),給大家打個樣,大家可以一葫蘆畫瓢,根據(jù)自己的情況設置這些參數(shù),運行代碼如下

python train.py --cfg yolov5l_mchar.yaml --weights ./weights/yolov5s.pt  --data ./data/mchar.yaml --epoch 200 --batch-size 8 --rect --noval --evolve 300 --image-weights --multi-scale --optimizer Adam --cos-lr --freeze 3 --bbox_interval 20

n

總結 

到此這篇關于yolov5中train.py代碼注釋詳解與使用的文章就介紹到這了,更多相關yolov5 train.py代碼注釋內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關文章

最新評論

国产成人小视频在线观看无遮挡| 日本裸体熟妇区二区欧美| 在线免费观看黄页视频| 日本最新一二三区不卡在线| 动漫精品视频在线观看| 93精品视频在线观看| 日日夜夜大香蕉伊人| 天天操,天天干,天天射| 91精品视频在线观看免费| 91人妻精品久久久久久久网站| 日韩av熟妇在线观看| 日本高清撒尿pissing| 亚洲综合自拍视频一区| 国产精品系列在线观看一区二区| av中文字幕在线导航| aaa久久久久久久久| 免费观看丰满少妇做受| huangse网站在线观看| 日本精品视频不卡一二三| caoporn蜜桃视频| 久久久久只精品国产三级| 中英文字幕av一区| 激情啪啪啪啪一区二区三区| 青青青青爽手机在线| 最新中文字幕乱码在线| 蜜桃色婷婷久久久福利在线| 中文字幕国产专区欧美激情| 91九色porny蝌蚪国产成人| 色偷偷伊人大杳蕉综合网| 免费在线播放a级片| 最新激情中文字幕视频| 青春草视频在线免费播放| 又大又湿又爽又紧A视频| 九一传媒制片厂视频在线免费观看 | jiujiure精品视频在线| 熟女人妻三十路四十路人妻斩| 97人人妻人人澡人人爽人人精品| 天天操夜夜操天天操天天操| 在线观看911精品国产| 4个黑人操素人视频网站精品91| 亚洲精品乱码久久久本| 99精品国产自在现线观看| 班长撕开乳罩揉我胸好爽| 国产黄色a级三级三级三级| 在线免费视频 自拍| 一区二区三区四区中文| 中出中文字幕在线观看| 日本美女成人在线视频| 亚洲高清国产拍青青草原| 超级av免费观看一区二区三区| 欧美一区二区三区激情啪啪啪 | 亚洲熟女女同志女同| 97精品成人一区二区三区| 中文字幕无码一区二区免费| 大鸡八强奸视频在线观看| 黑人大几巴狂插日本少妇| 久碰精品少妇中文字幕av| av高潮迭起在线观看| 色综合久久久久久久久中文| 偷青青国产精品青青在线观看| 欧洲亚洲欧美日韩综合| 不戴胸罩引我诱的隔壁的人妻| 动漫黑丝美女的鸡巴| 大黑人性xxxxbbbb| 成人资源在线观看免费官网| 大屁股熟女一区二区三区| 蜜桃视频17c在线一区二区| 日韩a级精品一区二区| 青青草国内在线视频精选| 欧美日韩人妻久久精品高清国产| 久久午夜夜伦痒痒想咳嗽P| 久久久久久久久久久久久97| 亚洲综合另类精品小说| 久久免费看少妇高潮完整版| 国产极品精品免费视频| 一区二区在线观看少妇| 亚洲视频在线视频看视频在线| 啊用力插好舒服视频| 在线亚洲天堂色播av电影| 成人sm视频在线观看| 国产片免费观看在线观看| 精品人妻每日一部精品| 狍和女人的王色毛片| 亚洲精品国产综合久久久久久久久 | 亚洲第一伊人天堂网| 人妻爱爱 中文字幕| 9l人妻人人爽人人爽| 欧美色呦呦最新网址| 日本少妇的秘密免费视频| 九色精品视频在线播放| 日本成人一区二区不卡免费在线| av成人在线观看一区| 亚洲免费在线视频网站| 丰满的子国产在线观看| 日韩欧美高清免费在线| 欧美专区第八页一区在线播放| 久久久久久久久久一区二区三区| 色偷偷伊人大杳蕉综合网| 91麻豆精品久久久久| 91 亚洲视频在线观看| 可以在线观看的av中文字幕| 最新国产精品网址在线观看| 国产白袜脚足J棉袜在线观看| 在线免费视频 自拍| 黑人大几巴狂插日本少妇| 欧美在线精品一区二区三区视频| 91社福利《在线观看| 天天操夜夜操天天操天天操| 青青青视频手机在线观看| 少妇人妻二三区视频| 成人蜜桃美臀九一一区二区三区| 麻豆精品成人免费视频| nagger可以指黑人吗| 天天做天天干天天舔| 天天日天天干天天要| 免费国产性生活视频| 亚洲综合图片20p| 亚洲av色图18p| 天堂av在线播放免费| 福利视频一区二区三区筱慧 | 亚洲一级av无码一级久久精品| japanese日本熟妇另类| 亚洲va国产va欧美va在线| 免费看美女脱光衣服的视频| sspd152中文字幕在线| 888欧美视频在线| 国产精品久久久黄网站| 精品久久久久久久久久中文蒉| 国产精品人久久久久久| 亚洲在线一区二区欧美| 阿v天堂2014 一区亚洲| 亚洲另类综合一区小说| av中文字幕电影在线看| 久久农村老妇乱69系列| 欧洲精品第一页欧洲精品亚洲| 精品国产在线手机在线| 偷拍自拍 中文字幕| 亚洲的电影一区二区三区| 中文字幕无码一区二区免费| 九色精品视频在线播放| 日本a级视频老女人| 午夜在线观看岛国av,com| 午夜美女福利小视频| 超碰97人人澡人人| 1区2区3区不卡视频| 99热久久这里只有精品| 一区二区三区的久久的蜜桃的视频 | 日本最新一二三区不卡在线| 免费黄色成人午夜在线网站| 丝袜国产专区在线观看| 亚洲激情偷拍一区二区| 国产一区二区欧美三区| 午夜极品美女福利视频| 激情国产小视频在线| 91欧美在线免费观看| 男人的天堂在线黄色| 黄片大全在线观看观看| 一区二区熟女人妻视频| 93精品视频在线观看| 99精品视频之69精品视频 | 黄网十四区丁香社区激情五月天| 91老师蜜桃臀大屁股| 亚洲中文字字幕乱码| 亚洲国产美女一区二区三区软件 | 中文字幕免费福利视频6| 超碰97免费人妻麻豆| 91精品激情五月婷婷在线| 都市家庭人妻激情自拍视频| 国产精品国产精品一区二区| 人妻少妇性色欲欧美日韩| 91精品国产高清自在线看香蕉网| 边摸边做超爽毛片18禁色戒| 二区中出在线观看老师| 偷拍自拍亚洲视频在线观看| 在线不卡成人黄色精品| 欧美伊人久久大香线蕉综合| 成年午夜影片国产片| 粉嫩小穴流水视频在线观看| 密臀av一区在线观看| 极品丝袜一区二区三区| 啪啪啪啪啪啪啪免费视频| 91精品国产91久久自产久强| 亚洲免费视频欧洲免费视频| 99国内精品永久免费视频| avjpm亚洲伊人久久| 亚洲精品久久视频婷婷| sejizz在线视频| 国产欧美日韩第三页| 91麻豆精品久久久久| 曰本无码人妻丰满熟妇啪啪| 视频久久久久久久人妻| 久草视频中文字幕在线观看| av网站色偷偷婷婷网男人的天堂| 色天天天天射天天舔| 亚洲欧美自拍另类图片| av新中文天堂在线网址| 狠狠嗨日韩综合久久| 日本性感美女写真视频| 欧美va亚洲va天堂va| 中文字幕之无码色多多| 熟女人妻在线观看视频| 国产激情av网站在线观看| 亚洲国产免费av一区二区三区| 青青青青视频在线播放| 国产三级片久久久久久久| 黄色视频成年人免费观看| 在线免费观看黄页视频| 快点插进来操我逼啊视频| 五月激情婷婷久久综合网| 亚洲欧美久久久久久久久| 国产精品亚洲在线观看| 日本免费午夜视频网站| 亚洲视频在线观看高清| av线天堂在线观看| 精品国产午夜视频一区二区| 国内精品在线播放第一页| 啊啊好慢点插舔我逼啊啊啊视频| 亚洲激情偷拍一区二区| 午夜场射精嗯嗯啊啊视频| 免费黄高清无码国产| 免费观看国产综合视频| 日韩美女综合中文字幕pp| av无限看熟女人妻另类av| 亚洲一区二区三区五区| 久久久久久久99精品| 视频一区二区在线免费播放| 中文字幕人妻三级在线观看| 91高清成人在线视频| okirakuhuhu在线观看| 日本少妇人妻xxxxx18| 特黄老太婆aa毛毛片| 日本三极片视频网站观看| 11久久久久久久久久久| 欧美aa一级一区三区四区| 日本性感美女写真视频| 亚洲午夜精品小视频| 中文字幕综合一区二区| 偷青青国产精品青青在线观看| 中文字幕在线一区精品| 内射久久久久综合网| 男人和女人激情视频| 免费在线看的黄网站| 午夜精彩视频免费一区| 狠狠躁夜夜躁人人爽天天久天啪| 亚洲av无硬久久精品蜜桃| 9色精品视频在线观看| 一区二区三区的久久的蜜桃的视频 | av在线资源中文字幕| 成人av久久精品一区二区| 亚洲变态另类色图天堂网| 制丝袜业一区二区三区| 水蜜桃国产一区二区三区| 成年美女黄网站18禁久久| 老司机99精品视频在线观看 | 不卡精品视频在线观看| 国产麻豆乱子伦午夜视频观看| 欧美日韩不卡一区不区二区| 偷拍美女一区二区三区| 日韩精品二区一区久久| 国产极品精品免费视频| av在线免费中文字幕| 亚洲av人人澡人人爽人人爱| 夜女神免费福利视频| 亚洲视频乱码在线观看| 一区二区三区 自拍偷拍| 青青青激情在线观看视频| 男女啪啪视频免费在线观看| 亚洲va天堂va国产va久| 大香蕉伊人中文字幕| 超级碰碰在线视频免费观看| 大胸性感美女羞爽操逼毛片| 日韩亚国产欧美三级涩爱| 日韩加勒比东京热二区| 北条麻妃av在线免费观看| 亚洲精品三级av在线免费观看| 亚洲精品av在线观看| 91精品高清一区二区三区| 毛片一级完整版免费| 在线播放国产黄色av| 国产精品3p和黑人大战| 精品一线二线三线日本| 日本精品美女在线观看| 狠狠鲁狠狠操天天晚上干干| 男生用鸡操女生视频动漫| 视频一区 二区 三区 综合| 色狠狠av线不卡香蕉一区二区| 天天日天天舔天天射进去| aⅴ五十路av熟女中出| 天天做天天爽夜夜做少妇| 亚洲公开视频在线观看| 黄片大全在线观看观看| 18禁精品网站久久| 国产精品人妻66p| 最新激情中文字幕视频| 91精品激情五月婷婷在线| av森泽佳奈在线观看 | 亚国产成人精品久久久| 亚洲天堂av最新网址| 亚洲 自拍 色综合图| 99精品免费久久久久久久久a| 中文字幕熟女人妻久久久| 欧洲黄页网免费观看| 2022天天干天天操| 国产精品久久9999| 快点插进来操我逼啊视频| 福利一二三在线视频观看| 亚洲精品av在线观看| www,久久久,com| 六月婷婷激情一区二区三区| 亚洲av黄色在线网站| 亚洲精品 欧美日韩| 521精品视频在线观看| 做爰视频毛片下载蜜桃视频1| 亚洲欧美精品综合图片小说| 久久香蕉国产免费天天| 大香蕉伊人国产在线| 蜜桃视频17c在线一区二区| 岛国av高清在线成人在线| 精品视频国产在线观看| 久久久噜噜噜久久熟女av| 亚洲一级特黄特黄黄色录像片| 欧美特级特黄a大片免费| 久草视频中文字幕在线观看| 成人av电影免费版| 日本男女操逼视频免费看 | 大屁股熟女一区二区三区| 国产av福利网址大全| 五十路在线观看完整版| 一区二区视频在线观看视频在线| 经典av尤物一区二区| 黑人借宿ntr人妻的沦陷2| 伊人精品福利综合导航| 成人性爱在线看四区| 久久久久久久久久性潮| 国产精品人久久久久久| 在线观看黄色成年人网站| 亚洲最大黄 嗯色 操 啊| 99精品亚洲av无码国产另类| 激情伦理欧美日韩中文字幕| caoporn蜜桃视频| 亚洲熟色妇av日韩熟色妇在线| 日本后入视频在线观看| 亚洲精品在线资源站| 在线国产中文字幕视频| 久草电影免费在线观看| 四川乱子伦视频国产vip| 精品人妻每日一部精品| 欧美一区二区三区四区性视频| 久久久久久久久久久免费女人| 亚洲精品av在线观看| 欧美乱妇无乱码一区二区| 成年人午夜黄片视频资源| 欧美一区二区三区在线资源| 亚洲最大黄 嗯色 操 啊| 在线观看视频 你懂的| 九色精品视频在线播放| 爆乳骚货内射骚货内射在线| 97人人模人人爽人人喊| 40道精品招牌菜特色| 亚洲欧美色一区二区| 99精品亚洲av无码国产另类| 日韩在线视频观看有码在线| aiss午夜免费视频| 久久久精品国产亚洲AV一 | 最后99天全集在线观看| 中文字日产幕乱六区蜜桃| 高潮喷水在线视频观看| 国产精品久久久久久久久福交| 欧美80老妇人性视频| 爱有来生高清在线中文字幕| 国产精品人久久久久久| 国产日本欧美亚洲精品视| 美女张开腿让男生操在线看| 大胆亚洲av日韩av| 婷婷久久一区二区字幕网址你懂得| 国产av欧美精品高潮网站| 日本韩国免费一区二区三区视频| 国产男女视频在线播放| 日本三极片视频网站观看| 在线免费观看99视频| 国产老熟女伦老熟妇ⅹ| 亚洲成人国产综合一区| 欧美精品国产综合久久| 亚洲最大黄了色网站| 国产精品久久久久网| xxx日本hd高清| 久久精品视频一区二区三区四区| 污污小视频91在线观看| 激情人妻校园春色亚洲欧美 | 韩国爱爱视频中文字幕| 人妻久久久精品69系列| 日韩亚洲高清在线观看| 做爰视频毛片下载蜜桃视频1| 国产精品午夜国产小视频| 激情伦理欧美日韩中文字幕| 欧美国产亚洲中英文字幕| 大香蕉伊人国产在线| 国产精品久久综合久久| 孕妇奶水仑乱A级毛片免费看| 激情国产小视频在线| 骚逼被大屌狂草视频免费看| 337p日本大胆欧美人| gay gay男男瑟瑟在线网站| 国产精品3p和黑人大战| 久久三久久三久久三久久| 亚洲精品一区二区三区老狼| 97瑟瑟超碰在线香蕉| 五十路人妻熟女av一区二区| 欧美爆乳肉感大码在线观看| 在线 中文字幕 一区| 欧美日韩精品永久免费网址| 天天操夜夜操天天操天天操| 欧美另类重口味极品在线观看| 福利午夜视频在线观看| 亚洲精品av在线观看| 亚洲av黄色在线网站| 中文人妻AV久久人妻水| 日本裸体熟妇区二区欧美| 一区二区视频在线观看免费观看| 做爰视频毛片下载蜜桃视频1| 欧美怡红院视频在线观看| 中文字幕人妻熟女在线电影| 亚洲av成人网在线观看| 97国产精品97久久| 大白屁股精品视频国产| 中文字幕乱码人妻电影| 熟女人妻在线观看视频| 欧美精品亚洲精品日韩在线| 亚洲精品麻豆免费在线观看| 伊人综合aⅴ在线网| 国产精品中文av在线播放| 又大又湿又爽又紧A视频| 精产国品久久一二三产区区别| 97人妻无码AV碰碰视频| 中文字幕 人妻精品| 大香蕉大香蕉在线有码 av| 欧美亚洲中文字幕一区二区三区| 五月天久久激情视频| 日韩人妻xxxxx| 最新国产精品拍在线观看| 成人午夜电影在线观看 久久| 一区二区三区综合视频| 蜜桃臀av蜜桃臀av| 女人精品内射国产99| 婷婷久久久综合中文字幕| 2020国产在线不卡视频| yy6080国产在线视频| 免费69视频在线看| 熟女妇女老妇一二三区| 宅男噜噜噜666国产| 老司机在线精品福利视频| 国产精品自拍在线视频| av网站色偷偷婷婷网男人的天堂| av在线播放国产不卡| 99久久99一区二区三区| 精品国产午夜视频一区二区| 大胆亚洲av日韩av| 99精品亚洲av无码国产另类| 午夜精品九一唐人麻豆嫩草成人| 天天日天天日天天擦| 熟女国产一区亚洲中文字幕| 在线免费观看视频一二区| 最新91九色国产在线观看| 久碰精品少妇中文字幕av| 亚洲天天干 夜夜操| 香港一级特黄大片在线播放| 亚洲精品ww久久久久久| 一级黄色片夫妻性生活| 韩国一级特黄大片做受| 国产伊人免费在线播放| 少妇被强干到高潮视频在线观看 | 中文字幕无码日韩专区免费| 国际av大片在线免费观看| 丰满的子国产在线观看| 99热这里只有国产精品6| 国产精品三级三级三级| chinese国产盗摄一区二区| 自拍偷拍日韩欧美亚洲| 中文字母永久播放1区2区3区 | 日本后入视频在线观看| 少妇高潮无套内谢麻豆| 五月天色婷婷在线观看视频免费| 中文字幕1卡1区2区3区| 久久久久久久亚洲午夜综合福利| av在线播放国产不卡| 国产97视频在线精品| 超pen在线观看视频公开97 | 国产高清精品一区二区三区| 在线亚洲天堂色播av电影| 91国偷自产一区二区三区精品| 黄色视频在线观看高清无码| 人妻熟女中文字幕aⅴ在线| 天天操夜夜骑日日摸| 性感美女福利视频网站| 日韩人妻在线视频免费| 欧美韩国日本国产亚洲| 中文字幕之无码色多多| 综合精品久久久久97| 18禁美女羞羞免费网站| 99热久久极品热亚洲| 人人人妻人人澡人人| 亚洲精品高清自拍av| 日韩中文字幕在线播放第二页| 97人人模人人爽人人喊| 天天操天天干天天插| 91精品激情五月婷婷在线| 精品一区二区三区三区色爱| 51精品视频免费在线观看| 国产丰满熟女成人视频| 日本一区二区三区免费小视频| 青青青青青青草国产| 熟女人妻在线中出观看完整版| 在线观看亚洲人成免费网址| 成人国产小视频在线观看| 国产成人精品一区在线观看| 欧美亚洲中文字幕一区二区三区| 国产a级毛久久久久精品| 爱爱免费在线观看视频| 日本www中文字幕| 欧美另类z0z变态| 亚洲日本一区二区久久久精品| 亚洲男人让女人爽的视频| 首之国产AV医生和护士小芳| 中文字幕在线乱码一区二区 | 四川五十路熟女av| 成人久久精品一区二区三区| 精品国产污污免费网站入口自| 天天摸天天亲天天舔天天操天天爽| 91麻豆精品91久久久久同性| 女同久久精品秋霞网| 青青青青操在线观看免费| 日韩欧美中文国产在线| 亚洲一区二区人妻av| 日韩北条麻妃一区在线| 男人插女人视频网站| 亚洲成人精品女人久久久| 欧美日韩亚洲国产无线码| 最新黄色av网站在线观看| 在线免费观看靠比视频的网站| 大鸡吧插入女阴道黄色片| okirakuhuhu在线观看| 清纯美女在线观看国产| 国产伊人免费在线播放| 欧洲亚洲欧美日韩综合| 中文字幕在线免费第一页| 国产精品sm调教视频| 性色蜜臀av一区二区三区| 日韩欧美制服诱惑一区在线| 在线观看av观看av| 欧美视频不卡一区四区| 99精品一区二区三区的区| 天堂av狠狠操蜜桃| 国产亚洲天堂天天一区| 制服丝袜在线人妻中文字幕| 激情图片日韩欧美人妻| 亚洲福利午夜久久久精品电影网| 91人妻精品一区二区在线看| 丝袜美腿视频诱惑亚洲无| 香港一级特黄大片在线播放 | 人人妻人人澡欧美91精品| 久久精品36亚洲精品束缚| 久久艹在线观看视频| 天天操天天爽天天干| 大香蕉玖玖一区2区| 国产一区av澳门在线观看| 青青热久免费精品视频在线观看| 黑人解禁人妻叶爱071| 亚洲高清国产自产av| 国产真实灌醉下药美女av福利| 亚洲欧洲一区二区在线观看| 激情五月婷婷免费视频| 亚洲中文精品字幕在线观看 | 日韩欧美一级黄片亚洲| 成人精品在线观看视频| 大黑人性xxxxbbbb| 熟女人妻在线观看视频| 少妇与子乱在线观看| 快点插进来操我逼啊视频| 鸡巴操逼一级黄色气| 国产白嫩美女一区二区| 91麻豆精品91久久久久同性| 午夜毛片不卡免费观看视频| 久久精品国产亚洲精品166m| 91chinese在线视频| 无码中文字幕波多野不卡| 亚洲国产欧美一区二区丝袜黑人| 成人精品在线观看视频| 2020韩国午夜女主播在线| 少妇人妻二三区视频| 2021年国产精品自拍| 激情伦理欧美日韩中文字幕| 亚洲av天堂在线播放| 熟女少妇激情五十路| 欧美日韩激情啪啪啪| jul—619中文字幕在线| 日本阿v视频在线免费观看| 1区2区3区不卡视频| 57pao国产一区二区| 亚洲精品午夜久久久久| 欧美亚洲一二三区蜜臀| 亚洲国产免费av一区二区三区| av成人在线观看一区| 老司机免费视频网站在线看| 美女骚逼日出水来了| 91老师蜜桃臀大屁股| 国产剧情演绎系列丝袜高跟| 日韩中文字幕精品淫| 国产三级影院在线观看| 亚洲国产第一页在线观看| 日本福利午夜电影在线观看| 在线视频免费观看网| 国产女孩喷水在线观看| 亚洲中文字幕乱码区| 亚洲少妇人妻无码精品| brazzers欧熟精品系列| 久久久久久久亚洲午夜综合福利| 亚洲欧美激情国产综合久久久| 免费大片在线观看视频网站| 久久艹在线观看视频| 99精品免费久久久久久久久a| 精品老妇女久久9g国产| 日韩美女精品视频在线观看网站 | 国产精品视频一区在线播放| 黑人解禁人妻叶爱071| 黄色片黄色片wyaa| 天天操天天干天天日狠狠插| 亚洲乱码中文字幕在线| 五十路熟女人妻一区二区9933| 久久久久国产成人精品亚洲午夜| av老司机亚洲一区二区| 激情色图一区二区三区| 午夜精品一区二区三区福利视频| 黄页网视频在线免费观看 | 大尺度激情四射网站| 都市家庭人妻激情自拍视频| 91综合久久亚洲综合| 91免费福利网91麻豆国产精品| 亚洲欧美人精品高清| 亚洲一区二区三区久久午夜| 国产精品一二三不卡带免费视频| 韩国女主播精品视频网站| 久草视频在线一区二区三区资源站| 丝袜美腿欧美另类 中文字幕| 亚洲午夜在线视频福利| 欧美在线偷拍视频免费看| 日本免费一级黄色录像| av久久精品北条麻妃av观看| 欧美va亚洲va天堂va| 97人妻人人澡爽人人精品| 阴茎插到阴道里面的视频| 丰满少妇人妻xxxxx| 97超碰最新免费在线观看| 九色视频在线观看免费| 岛国青草视频在线观看| 人人妻人人爱人人草| 国产精品大陆在线2019不卡| av中文字幕福利网| 欧美黑人性暴力猛交喷水| 超级碰碰在线视频免费观看| 天天操天天爽天天干| 99国内小视频在现欢看| 91she九色精品国产| 女人精品内射国产99| 扒开腿挺进肉嫩小18禁视频| 成人动漫大肉棒插进去视频| 亚洲蜜臀av一区二区三区九色| 国产亚洲视频在线观看| 欧美亚洲中文字幕一区二区三区| 在线观看国产网站资源| 2017亚洲男人天堂| 亚洲成人av一区久久| 色花堂在线av中文字幕九九 | 欧美偷拍亚洲一区二区| 色伦色伦777国产精品| 最新激情中文字幕视频| 97人妻无码AV碰碰视频| 天天日天天干天天舔天天射| 中文字幕在线视频一区二区三区| 色偷偷伊人大杳蕉综合网| 狠狠的往里顶撞h百合| 日本少妇人妻xxxxx18| 粉嫩欧美美人妻小视频| 揄拍成人国产精品免费看视频| 精品91高清在线观看| 十八禁在线观看地址免费| 亚洲一级 片内射视正片| 欧美专区日韩专区国产专区| 欧美成人精品欧美一级黄色| 熟女人妻在线观看视频| 懂色av之国产精品| 91高清成人在线视频| 精品一区二区三四区| 欧美成人精品在线观看| 可以免费看的www视频你懂的| 国产精品久久久黄网站| 亚洲国产欧美一区二区丝袜黑人| 亚洲va欧美va人人爽3p| 久久久麻豆精亚洲av麻花| 精品一区二区三四区| 亚洲av成人免费网站| 日日夜夜大香蕉伊人| 午夜美女少妇福利视频| 亚洲精品福利网站图片| 日本中文字幕一二区视频| 天天日天天天天天天天天天天| 欧美专区第八页一区在线播放| 欧美特色aaa大片| av天堂中文字幕最新| 欧美精产国品一二三产品区别大吗| 2020av天堂网在线观看| 亚洲国产在线精品国偷产拍| 国产视频网站一区二区三区 | 欧美日韩人妻久久精品高清国产| 国产大鸡巴大鸡巴操小骚逼小骚逼| 天天日天天日天天擦| 超级av免费观看一区二区三区| 岛国青草视频在线观看| 亚洲 清纯 国产com| 日本一区二区三区免费小视频| 啪啪啪啪啪啪啪免费视频| 一区二区三区的久久的蜜桃的视频| 免费大片在线观看视频网站| 99的爱精品免费视频| 69精品视频一区二区在线观看| 欧美色呦呦最新网址| 老司机你懂得福利视频| 亚洲中文字幕国产日韩| 亚洲粉嫩av一区二区三区| 日本性感美女视频网站| 人人妻人人爽人人澡人人精品| 亚洲精品三级av在线免费观看| 国产综合精品久久久久蜜臀| 欧美精品亚洲精品日韩在线| 毛片一级完整版免费| 无码精品一区二区三区人| 欧美成人综合视频一区二区| 五月天色婷婷在线观看视频免费| 精品视频中文字幕在线播放| 99久久超碰人妻国产| 欧美黄片精彩在线免费观看| 亚洲成高清a人片在线观看| 在线亚洲天堂色播av电影| 亚洲av黄色在线网站| 国产麻豆精品人妻av| 成熟丰满熟妇高潮xx×xx| 婷婷综合蜜桃av在线| 欧美性受xx黑人性猛交| 91福利在线视频免费观看| 99av国产精品欲麻豆| 福利片区一区二体验区| 三级等保密码要求条款| 免费岛国喷水视频在线观看| 天天操夜夜骑日日摸| 欧美aa一级一区三区四区 | 成人精品在线观看视频| 天天日天天添天天爽| 99精品国自产在线人| 一本久久精品一区二区| 精品首页在线观看视频| 护士小嫩嫩又紧又爽20p| 夜夜嗨av蜜臀av| 可以免费看的www视频你懂的| 亚洲区美熟妇久久久久| 老鸭窝在线观看一区| 亚洲欧美一区二区三区电影| 最新91精品视频在线| 青青社区2国产视频| 国产美女精品福利在线| 亚洲午夜精品小视频| 欧美精品伦理三区四区| 18禁美女无遮挡免费| 岛国免费大片在线观看| 国产精品人妻熟女毛片av久| 在线观看视频 你懂的| 黄片大全在线观看观看| 欧美视频中文一区二区三区| 日本美女性生活一级片| 欧美一级色视频美日韩| 久久农村老妇乱69系列| 亚洲无码一区在线影院| 中文字幕中文字幕人妻| 天天日天天日天天射天天干| 亚洲一区av中文字幕在线观看| 在线观看av2025| 久久久精品欧洲亚洲av| 99热色原网这里只有精品| 岛国免费大片在线观看| 国产亚州色婷婷久久99精品| 青青青青草手机在线视频免费看 | 天天日天天添天天爽| 亚洲av一妻不如妾| 成人av久久精品一区二区| 日日日日日日日日夜夜夜夜夜夜| 亚洲变态另类色图天堂网| 午夜久久香蕉电影网| 黄色资源视频网站日韩| 天天躁日日躁狠狠躁av麻豆| 99亚洲美女一区二区三区| 91国内精品久久久久精品一| 在线新三级黄伊人网| 黑人借宿ntr人妻的沦陷2| 91精品激情五月婷婷在线| 亚洲久久午夜av一区二区| 日本人妻欲求不满中文字幕| 日韩伦理短片在线观看| 日韩av大胆在线观看| 一本久久精品一区二区| 人妻最新视频在线免费观看| 99久久久无码国产精品性出奶水| heyzo蜜桃熟女人妻| 亚洲午夜伦理视频在线| 中文字幕最新久久久| 午夜精品一区二区三区福利视频| 黄页网视频在线免费观看| 少妇人妻久久久久视频黄片| 91色网站免费在线观看| 超污视频在线观看污污污| 色综合久久五月色婷婷综合| 40道精品招牌菜特色| 亚洲精品成人网久久久久久小说 | 欧美乱妇无乱码一区二区| 国产精品午夜国产小视频| av中文字幕在线观看第三页| 丰满少妇翘臀后进式| 91she九色精品国产| 国产福利小视频二区| 国产女人露脸高潮对白视频| 午夜91一区二区三区| 亚洲免费国产在线日韩| 亚洲国产精品美女在线观看 | 欧美亚洲自偷自拍 在线| 亚洲 中文 自拍 另类 欧美| 天堂av在线官网中文| 80电影天堂网官网| 中文亚洲欧美日韩无线码| 亚洲欧美一卡二卡三卡| 日本18禁久久久久久| 亚洲精品国产久久久久久| xxx日本hd高清| 欧美精品欧美极品欧美视频| 91精品啪在线免费| 欧美 亚洲 另类综合| 视频一区 视频二区 视频| 国产a级毛久久久久精品| 国产伦精品一区二区三区竹菊| 无码中文字幕波多野不卡| 欧美成人综合视频一区二区| 黑人性生活视频免费看| 国产欧美精品一区二区高清 | 成人综合亚洲欧美一区| 精品国产高潮中文字幕| 91人妻精品一区二区在线看 | 一区二区三区蜜臀在线| 夜色撩人久久7777| 日韩精品啪啪视频一道免费| 4个黑人操素人视频网站精品91| 亚洲综合色在线免费观看| 国产在线拍揄自揄视频网站| 久久永久免费精品人妻专区 | 九色视频在线观看免费| 老师让我插进去69AV| 中文字幕人妻一区二区视频| 2020久久躁狠狠躁夜夜躁 | 中文字幕综合一区二区| 中文字幕av第1页中文字幕| 欧美日韩亚洲国产无线码| 色吉吉影音天天干天天操| 岛国免费大片在线观看| 亚洲视频在线视频看视频在线| 日本性感美女写真视频| 免费看国产av网站| 天天日天天爽天天爽| 2020国产在线不卡视频| 特大黑人巨大xxxx| 欧美亚洲免费视频观看| 国产亚州色婷婷久久99精品| huangse网站在线观看| 美女福利写真在线观看视频| 99久久中文字幕一本人| 国产激情av网站在线观看| 一二三中文乱码亚洲乱码one| 青青在线视频性感少妇和隔壁黑丝| 亚洲av成人免费网站| 亚洲成人线上免费视频观看| 黄工厂精品视频在线观看| 日韩加勒比东京热二区| 亚洲精品久久视频婷婷| 淫秽激情视频免费观看| 国产欧美日韩第三页| 国产极品美女久久久久久| 日本啪啪啪啪啪啪啪| 精彩视频99免费在线| 人妻无码中文字幕专区| 亚洲自拍偷拍精品网| 日韩在线视频观看有码在线| 适合午夜一个人看的视频| 少妇高潮无套内谢麻豆| 久久h视频在线观看| 2018在线福利视频| 好了av中文字幕在线| 婷婷六月天中文字幕| av手机在线免费观看日韩av| 免费高清自慰一区二区三区网站| 91‖亚洲‖国产熟女| 在线观看911精品国产| 一区二区三区四区视频| 2020韩国午夜女主播在线| 中文字幕日韩精品日本| 韩国AV无码不卡在线播放| 五十路熟女人妻一区二| 人妻熟女在线一区二区| 水蜜桃一区二区三区在线观看视频| 亚洲av成人免费网站| 国产精品黄片免费在线观看| 75国产综合在线视频| 亚洲综合色在线免费观看| 在线免费观看日本伦理| 亚洲欧美综合在线探花| 亚洲一区制服丝袜美腿| 超级福利视频在线观看| 日本乱人一区二区三区| 中文 成人 在线 视频| 97欧洲一区二区精品免费| 日本一区精品视频在线观看| 日韩三级电影华丽的外出| 深田咏美亚洲一区二区| 护士特殊服务久久久久久久| 深田咏美亚洲一区二区| 在线观看操大逼视频| av在线免费资源站| 在线制服丝袜中文字幕| 天堂av在线最新版在线| 久久h视频在线观看| 亚洲1卡2卡三卡4卡在线观看| 成人久久精品一区二区三区| 青青伊人一精品视频| 亚洲精品亚洲人成在线导航| 在线免费观看黄页视频| av欧美网站在线观看| 亚洲高清一区二区三区视频在线| 在线不卡成人黄色精品| 日本五十路熟新垣里子| www天堂在线久久| 1000小视频在线| 久久久久久97三级| 91精品国产综合久久久蜜| 一区二区在线观看少妇| 天天做天天干天天操天天射| 青青青青青免费视频| 免费一级黄色av网站| 大骚逼91抽插出水视频| 午夜dv内射一区区| 青娱乐在线免费视频盛宴| 成熟丰满熟妇高潮xx×xx| 一区二区三区四区视频| 五十路人妻熟女av一区二区| 日韩人妻在线视频免费| 丁香花免费在线观看中文字幕| 亚洲欧美国产综合777| 老有所依在线观看完整版| 蜜桃精品久久久一区二区| 丝袜长腿第一页在线| 国产精品精品精品999| 五月天色婷婷在线观看视频免费| 久久美欧人妻少妇一区二区三区| 超级碰碰在线视频免费观看| 日韩精品一区二区三区在线播放| 天天干狠狠干天天操| 精品美女在线观看视频在线观看| 极品性荡少妇一区二区色欲| 69精品视频一区二区在线观看| 伊人综合免费在线视频| 91精品国产综合久久久蜜| 鸡巴操逼一级黄色气| 在线观看视频污一区| 亚洲国际青青操综合网站| 91快播视频在线观看| 一色桃子久久精品亚洲| 天天通天天透天天插| 亚洲精品久久综合久| 少妇人妻100系列| 日视频免费在线观看| 国产刺激激情美女网站| 欧美亚洲中文字幕一区二区三区| 老司机午夜精品视频资源| 91成人在线观看免费视频| www骚国产精品视频| 亚洲成人线上免费视频观看| 2020久久躁狠狠躁夜夜躁| 亚洲综合另类精品小说| 日本欧美视频在线观看三区| 国产一区二区三免费视频| 色97视频在线播放| 国产又粗又猛又爽又黄的视频在线| 亚洲人成精品久久久久久久| 亚洲精品国产综合久久久久久久久 | 一区二区久久成人网| 91福利在线视频免费观看| 91久久国产成人免费网站| 国产av国片精品一区二区| 青青草成人福利电影| 亚洲自拍偷拍精品网| 青青草精品在线视频观看| 国内资源最丰富的网站| 国产在线91观看免费观看| 做爰视频毛片下载蜜桃视频1| 污污小视频91在线观看| 中文字幕乱码av资源| 偷拍自拍亚洲美腿丝袜| 欧美日韩激情啪啪啪| 视频一区二区综合精品| 亚洲av日韩高清hd| 国产av国片精品一区二区| 黄色视频在线观看高清无码 | 亚洲 欧美 自拍 偷拍 在线| 我想看操逼黄色大片| 天天射,天天操,天天说| 国产麻豆91在线视频| 日本男女操逼视频免费看| 2020国产在线不卡视频| 黄工厂精品视频在线观看| 日本韩国在线观看一区二区| 秋霞午夜av福利经典影视| 亚洲av在线观看尤物| 亚洲中文精品人人免费| 久草视频在线看免费| 又粗又长 明星操逼小视频| 99热久久这里只有精品8| av天堂中文字幕最新| 欧美aa一级一区三区四区| 中文字幕人妻三级在线观看| 精品久久久久久久久久中文蒉| 男人的网址你懂的亚洲欧洲av| 精品人妻每日一部精品| 成熟熟女国产精品一区| 色婷婷精品大在线观看| 69精品视频一区二区在线观看| 日本少妇精品免费视频| 巨乳人妻日下部加奈被邻居中出| 日本高清在线不卡一区二区| 天天日天天爽天天干| 抽查舔水白紧大视频| 天天日天天干天天舔天天射| 国产在线一区二区三区麻酥酥| av俺也去在线播放| 在线观看视频 你懂的| 色呦呦视频在线观看视频| 青娱乐极品视频青青草| 国产精品三级三级三级| 97资源人妻免费在线视频| 成人高潮aa毛片免费| 青青青艹视频在线观看| 97色视频在线观看| 揄拍成人国产精品免费看视频| 久久久超爽一二三av| 日韩美av高清在线| 国产在线自在拍91国语自产精品| 青草亚洲视频在线观看| 色秀欧美视频第一页| 在线不卡成人黄色精品| 日韩午夜福利精品试看| 精品欧美一区二区vr在线观看| 红杏久久av人妻一区| 亚洲精品 欧美日韩| 美女视频福利免费看| 91亚洲手机在线视频播放| 经典av尤物一区二区| 欧美成人小视频在线免费看| 传媒在线播放国产精品一区| 在线免费观看日本伦理| 51国产偷自视频在线播放| 天天日夜夜干天天操| 国产精品人妻熟女毛片av久| 国产久久久精品毛片| 欧美精品欧美极品欧美视频 | 日韩精品中文字幕在线| 日日操综合成人av| 抽查舔水白紧大视频| 成人av久久精品一区二区| av老司机亚洲一区二区| 亚洲欧美日韩视频免费观看| 青青社区2国产视频| 成年午夜免费无码区| 欧美成人综合色在线噜噜| 欧美激情电影免费在线| 天天操天天干天天日狠狠插| av视屏免费在线播放| 天天日天天舔天天射进去| 国产精品一区二区久久久av| 熟女俱乐部一二三区| 中文字幕AV在线免费看 | 日本福利午夜电影在线观看| 日本一区二区三区免费小视频| 国产乱子伦一二三区| 密臀av一区在线观看| 蜜桃精品久久久一区二区| 天天射,天天操,天天说| 亚洲综合乱码一区二区| 国产精品入口麻豆啊啊啊| 2022中文字幕在线| 亚洲福利午夜久久久精品电影网| 亚洲成人av一区在线| 国产精品黄页网站视频| 天干天天天色天天日天天射| 欧美偷拍自拍色图片| 亚洲人妻视频在线网| 午夜在线观看岛国av,com| 日本一道二三区视频久久| 午夜激情高清在线观看| 中文字幕一区的人妻欧美日韩| 天天做天天干天天舔| 少妇人妻二三区视频| 欧洲国产成人精品91铁牛tv| 大香蕉伊人国产在线| 亚洲欧美久久久久久久久| 熟妇一区二区三区高清版| 91久久人澡人人添人人爽乱| 午夜精品福利一区二区三区p| 最新的中文字幕 亚洲| 91亚洲精品干熟女蜜桃频道| 青草久久视频在线观看| 人妻av无码专区久久绿巨人| 中文字幕高清在线免费播放| 中出中文字幕在线观看| 在线免费观看日本伦理| 亚洲天堂精品福利成人av| 亚洲av人人澡人人爽人人爱| 在线观看911精品国产| 欧美精产国品一二三区| 91 亚洲视频在线观看| 激情内射在线免费观看| 蜜桃久久久久久久人妻| 日比视频老公慢点好舒服啊| 亚洲国产最大av综合| 中文字幕一区二区三区蜜月| 黄色片黄色片wyaa| 538精品在线观看视频| 黄色视频成年人免费观看| 在线观看av2025| 日本真人性生活视频免费看| 午夜精品一区二区三区福利视频| 国产麻豆精品人妻av| 日韩精品中文字幕福利| 91www一区二区三区| 亚洲男人的天堂a在线| 黑人借宿ntr人妻的沦陷2| 亚洲伊人av天堂有码在线| 3337p日本欧洲大胆色噜噜| 久久精品美女免费视频| 在线免费观看99视频| av天堂资源最新版在线看| 在线观看911精品国产| 国产av欧美精品高潮网站| 精品国产在线手机在线| 国产女人露脸高潮对白视频| 狠狠鲁狠狠操天天晚上干干| 成人色综合中文字幕| 在线播放 日韩 av| 伊人情人综合成人久久网小说| 特级欧美插插插插插bbbbb| 日韩av有码一区二区三区4| 欧美伊人久久大香线蕉综合| 班长撕开乳罩揉我胸好爽| 9国产精品久久久久老师 | 亚洲美女高潮喷浆视频| 晚上一个人看操B片| av线天堂在线观看| av在线免费资源站| 国产污污污污网站在线| 老鸭窝日韩精品视频观看| 2020韩国午夜女主播在线| 国产熟妇乱妇熟色T区| 97超碰免费在线视频| 亚洲熟色妇av日韩熟色妇在线| 一级a看免费观看网站| 亚洲码av无色中文| 亚洲精品乱码久久久本| 国产欧美精品不卡在线| 久草极品美女视频在线观看| 日辽宁老肥女在线观看视频| 中文字幕在线观看国产片| 91国产资源在线视频| 亚洲图片偷拍自拍区| brazzers欧熟精品系列| 欧美爆乳肉感大码在线观看| 五月激情婷婷久久综合网| 中文字幕av一区在线观看| 超黄超污网站在线观看| 精品黑人一区二区三区久久国产| 青青青青青免费视频| 国产精品大陆在线2019不卡| 98精产国品一二三产区区别| 99久久超碰人妻国产| aiss午夜免费视频| 午夜场射精嗯嗯啊啊视频| 一区二区三区日本伦理| 国产精品探花熟女在线观看| 视频一区 视频二区 视频| 中文字幕一区二区三区蜜月| 五十路人妻熟女av一区二区| 自拍偷拍一区二区三区图片| 精品人妻伦一二三区久| 中文字幕人妻被公上司喝醉在线 | 93精品视频在线观看| 精品高潮呻吟久久av| 99精品视频之69精品视频| 国产精彩福利精品视频| 中文字幕国产专区欧美激情| 国产极品精品免费视频| 黄工厂精品视频在线观看| 久久久久只精品国产三级| 日本免费午夜视频网站| 美女福利视频网址导航| 日日夜夜狠狠干视频| 激情小视频国产在线| 天天日天天做天天日天天做| 蜜臀av久久久久蜜臀av麻豆| 日本一区美女福利视频| 丝袜国产专区在线观看| 久久这里只有精品热视频| 超碰公开大香蕉97| 亚洲一区二区三区精品乱码| 午夜精品福利一区二区三区p| 亚洲精品国产久久久久久| 成人乱码一区二区三区av| 久青青草视频手机在线免费观看| 日韩欧美国产精品91| 少妇系列一区二区三区视频| 午夜在线观看岛国av,com| 高清成人av一区三区| 大陆胖女人与丈夫操b国语高清 | 色婷婷精品大在线观看| 欧美伊人久久大香线蕉综合| 黄色视频在线观看高清无码| 狠狠躁夜夜躁人人爽天天久天啪| 免费看国产又粗又猛又爽又黄视频| 欧美日本在线观看一区二区| 玖玖一区二区在线观看| 一级黄色片夫妻性生活| 亚洲福利精品福利精品福利| 亚洲综合在线视频可播放| 开心 色 六月 婷婷| 干逼又爽又黄又免费的视频| 91桃色成人网络在线观看| 五月激情婷婷久久综合网| 亚洲日本一区二区三区| 国产性生活中老年人视频网站| 成人精品在线观看视频| 99av国产精品欲麻豆| 大学生A级毛片免费视频| 成人乱码一区二区三区av| 人人妻人人爽人人添夜| 国产精品日韩欧美一区二区| 91p0rny九色露脸熟女| 三级黄色亚洲成人av| tube69日本少妇| 搞黄色在线免费观看| 成人av亚洲一区二区| 欧美亚洲免费视频观看| mm131美女午夜爽爽爽| 好吊视频—区二区三区| 97超碰人人搞人人| 中文字幕第1页av一天堂网| 国产精品国色综合久久 | 午夜精品久久久久久99热| 欧美香蕉人妻精品一区二区| 久久久精品精品视频视频| 欧美日韩国产一区二区三区三州| 欧美日韩在线精品一区二区三| 黄色大片男人操女人逼| 亚洲图库另类图片区| 国产日韩av一区二区在线| 中文字幕在线观看极品视频| 2020中文字幕在线播放| 亚洲成人国产综合一区| 2021年国产精品自拍| 欧美日韩激情啪啪啪| 2018最新中文字幕在线观看| 黑人3p华裔熟女普通话| 在线亚洲天堂色播av电影| 久久久久久九九99精品| 11久久久久久久久久久| 红桃av成人在线观看| 国产精品国产三级麻豆| av日韩在线免费播放| 免费在线看的黄片视频| 欧美成人黄片一区二区三区| 人妻久久久精品69系列| 人妻爱爱 中文字幕| 亚洲午夜伦理视频在线| 欧美国品一二三产区区别| 岛国av高清在线成人在线| 免费福利av在线一区二区三区| 久久综合老鸭窝色综合久久| 涩涩的视频在线观看视频| 国产片免费观看在线观看| 另类av十亚洲av| 色吉吉影音天天干天天操| 99热久久这里只有精品| 韩国三级aaaaa高清视频| 91试看福利一分钟| 色哟哟国产精品入口| 亚洲乱码中文字幕在线| 一个人免费在线观看ww视频| 91香蕉成人app下载| 天堂资源网av中文字幕| 自拍偷拍一区二区三区图片| 果冻传媒av一区二区三区| 天码人妻一区二区三区在线看 | 天天操天天插天天色| 六月婷婷激情一区二区三区| 班长撕开乳罩揉我胸好爽| 自拍偷区二区三区麻豆| 日本脱亚入欧是指什么| 另类av十亚洲av| 亚洲综合在线观看免费| 天天日天天干天天搡| 伊人成人综合开心网| 亚洲欧美自拍另类图片| 不卡一区一区三区在线| 五月天中文字幕内射| 天天干夜夜操啊啊啊| 人妻丝袜榨强中文字幕| 极品性荡少妇一区二区色欲| 亚洲高清视频在线不卡| 97成人免费在线观看网站| 日本福利午夜电影在线观看| 国产密臀av一区二区三| aaa久久久久久久久| av视屏免费在线播放| 黄色无码鸡吧操逼视频| 午夜场射精嗯嗯啊啊视频| 国产丰满熟女成人视频| 很黄很污很色的午夜网站在线观看| 久久国产精品精品美女| 亚洲精品成人网久久久久久小说| 日本啪啪啪啪啪啪啪| 亚洲区欧美区另类最新章节| 国产日韩欧美美利坚蜜臀懂色| 我想看操逼黄色大片| 成年女人免费播放视频| 春色激情网欧美成人| 亚洲欧洲一区二区在线观看| 大香蕉伊人国产在线| 天天日天天摸天天爱| 亚洲的电影一区二区三区| 青青青青草手机在线视频免费看| 在线国产日韩欧美视频| 国产女人露脸高潮对白视频| 97黄网站在线观看| 国产亚洲国产av网站在线| 在线观看av亚洲情色| 人人妻人人爽人人添夜| 天天夜天天日天天日| 大香蕉伊人中文字幕| 人妻另类专区欧美制服| 成人动漫大肉棒插进去视频| 亚洲av午夜免费观看| 中国无遮挡白丝袜二区精品| 国产亚洲视频在线观看| 亚洲国产中文字幕啊啊啊不行了 | 久久精品国产999| 2022精品久久久久久中文字幕| 亚洲视频在线观看高清| 在线观看视频网站麻豆| 欧美美女人体视频一区| 青草亚洲视频在线观看| 亚洲精品午夜久久久久| 精品黑人巨大在线一区| 蜜桃久久久久久久人妻| 国产午夜激情福利小视频在线| 黄色的网站在线免费看| 黄工厂精品视频在线观看 | 3D动漫精品啪啪一区二区下载| 久久久久只精品国产三级| 小泽玛利亚视频在线观看| 91精品国产高清自在线看香蕉网| 999九九久久久精品| 视频 国产 精品 熟女 | 亚洲人人妻一区二区三区| 夜女神免费福利视频| 亚洲国产成人最新资源| 午夜精品九一唐人麻豆嫩草成人| 激情色图一区二区三区| 亚洲成人av一区久久| 欧美特色aaa大片| 午夜青青草原网在线观看| 国产一区二区视频观看| 亚洲一级美女啪啪啪| 日本www中文字幕| 淫秽激情视频免费观看| 中文字幕之无码色多多| 日美女屁股黄邑视频| 欧美专区日韩专区国产专区| 亚洲av成人网在线观看| 宅男噜噜噜666国产| 国产女人叫床高潮大片视频| 欧美精品国产综合久久| 天天躁日日躁狠狠躁av麻豆| 欧美第一页在线免费观看视频| 中文字幕第1页av一天堂网| 特大黑人巨大xxxx| 成人性爱在线看四区| 又粗又硬又猛又黄免费30| 国产黄网站在线观看播放| 99热这里只有国产精品6| 精品久久婷婷免费视频| 社区自拍揄拍尻屁你懂的| 99热99这里精品6国产| 91超碰青青中文字幕| 人人妻人人澡人人爽人人dvl| 99视频精品全部15| 色吉吉影音天天干天天操| 亚洲最大黄了色网站| 5528327男人天堂| 91人妻精品一区二区在线看| 国际av大片在线免费观看| 人妻在线精品录音叫床| 日韩欧美制服诱惑一区在线| eeuss鲁片一区二区三区| 中文字幕中文字幕人妻| 久久这里有免费精品| 偷拍自拍亚洲美腿丝袜| 国产内射中出在线观看| 日日爽天天干夜夜操| 中文字幕人妻一区二区视频| 97少妇精品在线观看| 在线观看的a站 最新| 日曰摸日日碰夜夜爽歪歪| 天天色天天爱天天爽| 护士小嫩嫩又紧又爽20p| 青青青青青青青青青青草青青 | 蜜臀av久久久久久久| 中文字幕在线乱码一区二区| 亚洲va国产va欧美精品88| 毛片一级完整版免费| 青青青青青青青在线播放视频| 国产视频一区在线观看| 免费无码人妻日韩精品一区二区 | 一区二区三区激情在线| 干逼又爽又黄又免费的视频| 免费一级黄色av网站| 粗大的内捧猛烈进出爽大牛汉子| 黄页网视频在线免费观看 | 亚洲 图片 欧美 图片| 午夜美女少妇福利视频| 日韩美女福利视频网| 天天草天天色天天干| 男人操女人逼逼视频网站| 亚洲高清自偷揄拍自拍| 激情人妻校园春色亚洲欧美 | 亚洲天堂精品福利成人av| 国产精品熟女久久久久浪潮| 免费手机黄页网址大全| 亚洲卡1卡2卡三卡四老狼| 亚洲成人av一区久久| 淫秽激情视频免费观看| 2020国产在线不卡视频| 人妻最新视频在线免费观看| 98视频精品在线观看| 3D动漫精品啪啪一区二区下载| 天天插天天狠天天操| 新97超碰在线观看| 亚洲综合在线视频可播放| 欧美老鸡巴日小嫩逼| 国产成人一区二区三区电影网站| 青青青青青免费视频| 人妻少妇亚洲一区二区| 中文字幕一区二区三区人妻大片 | 91精品国产麻豆国产| 精品黑人一区二区三区久久国产| 国产V亚洲V天堂无码欠欠| 久久美欧人妻少妇一区二区三区| 欧美一区二区三区激情啪啪啪 | 午夜青青草原网在线观看| 自拍偷拍日韩欧美一区二区| 亚洲精品三级av在线免费观看| 果冻传媒av一区二区三区| 岛国黄色大片在线观看| 女人精品内射国产99| 成年女人免费播放视频| 亚洲欧美综合另类13p| 日韩午夜福利精品试看| 日韩欧美高清免费在线| 人妻熟女中文字幕aⅴ在线| 中文乱理伦片在线观看| 欧美性受xx黑人性猛交| 欧美精品免费aaaaaa| 色狠狠av线不卡香蕉一区二区| 精品黑人一区二区三区久久国产| 中字幕人妻熟女人妻a62v网| 日本又色又爽又黄又粗| av男人天堂狠狠干| 亚洲人妻av毛片在线| 日韩剧情片电影在线收看| 亚洲av香蕉一区区二区三区犇| 最近的中文字幕在线mv视频| 日本裸体熟妇区二区欧美| 岛国一区二区三区视频在线| 国产美女一区在线观看| 超碰97人人做人人爱| 亚洲人妻视频在线网| 日韩a级精品一区二区| 伊人综合aⅴ在线网| a v欧美一区=区三区| 91麻豆精品传媒国产黄色片| 久久久久久国产精品| 国产麻豆剧传媒精品国产av蜜桃| 天天操天天操天天碰| 三上悠亚和黑人665番号| 3D动漫精品啪啪一区二区下载| 欧美专区第八页一区在线播放 | 99精品国自产在线人| 亚洲一级av无码一级久久精品| 女生自摸在线观看一区二区三区| 亚洲免费在线视频网站| 99热这里只有国产精品6| 一区二区三区av高清免费| 岛国一区二区三区视频在线| 亚洲av黄色在线网站| 男女啪啪啪啪啪的网站| 免费十精品十国产网站| 2020av天堂网在线观看| 一个色综合男人天堂| 中文字幕视频一区二区在线观看| 亚洲国产香蕉视频在线播放| 成人国产激情自拍三区| 天天艹天天干天天操| 成年人黄色片免费网站| 欧美精品中文字幕久久二区| 免费无毒热热热热热热久| 青青青视频手机在线观看| 亚洲最大免费在线观看| 久久热这里这里只有精品| 18禁美女黄网站色大片下载| 黑人3p华裔熟女普通话| 午夜大尺度无码福利视频| 中文字幕乱码人妻电影| 色婷婷综合激情五月免费观看| 成人免费做爰高潮视频| 国产成人无码精品久久久电影| 人妻3p真实偷拍一二区| 66久久久久久久久久久| 任你操视频免费在线观看| 天天操天天射天天操天天天| 青青草在观免费国产精品| 久久久精品999精品日本| 一级黄片久久久久久久久| 操操网操操伊剧情片中文字幕网| 蜜桃视频入口久久久| av中文字幕国产在线观看| 啪啪啪啪啪啪啪啪啪啪黄色| 91老熟女连续高潮对白| 93视频一区二区三区| 爱有来生高清在线中文字幕| 天堂av在线播放免费| 91国内精品自线在拍白富美| 久草视频中文字幕在线观看| 绯色av蜜臀vs少妇| 国产精品黄页网站视频| 国产精品亚洲在线观看| 欧美麻豆av在线播放| 1000部国产精品成人观看视频| 久碰精品少妇中文字幕av| 91大神福利视频网| 人妻丝袜诱惑我操她视频| 性欧美日本大妈母与子| yellow在线播放av啊啊啊| 男人天堂色男人av| 蜜桃视频在线欧美一区| 99热这里只有国产精品6| 人人妻人人爽人人澡人人精品| 欧美日韩高清午夜蜜桃大香蕉| 国产亚州色婷婷久久99精品| 中文字幕日韩91人妻在线| 午夜美女少妇福利视频| 日韩精品二区一区久久| 免费黄色成人午夜在线网站| 91大神福利视频网| 国产三级片久久久久久久| 日韩美女综合中文字幕pp| 亚洲精品中文字幕下载| 91在线视频在线精品3| 91九色porny国产蝌蚪视频| 端庄人妻堕落挣扎沉沦| 伊拉克及约旦宣布关闭领空| 久久尻中国美女视频| 日本韩国免费福利精品| 爆乳骚货内射骚货内射在线| 含骚鸡巴玩逼逼视频| 亚洲日本一区二区久久久精品| 中文字幕亚洲久久久| 亚洲精品一线二线在线观看 | 在线观看av亚洲情色| 天天操,天天干,天天射| 午夜蜜桃一区二区三区| 午夜久久久久久久精品熟女| caoporn蜜桃视频| 色偷偷伊人大杳蕉综合网| 男人天堂av天天操| 人妻丰满熟妇综合网| 激情综合治理六月婷婷| 亚洲图片欧美校园春色| av完全免费在线观看av| 91人妻精品久久久久久久网站 | 天天操天天干天天艹| 在线免费91激情四射| 国产精品久久久久久久女人18| 午夜成午夜成年片在线观看| 亚洲欧美国产综合777| 欧美成一区二区三区四区| 成人性爱在线看四区| 欧美色呦呦最新网址| 天天艹天天干天天操| 在线观看免费岛国av| 亚洲va国产va欧美va在线| 日本最新一二三区不卡在线| 欧美综合婷婷欧美综合| 成人乱码一区二区三区av| 女同久久精品秋霞网| 天天日天天添天天爽| 天美传媒mv视频在线观看| 在线观看av2025| 亚洲一级美女啪啪啪| 天天想要天天操天天干| 国产麻豆精品人妻av| 中国无遮挡白丝袜二区精品| 在线不卡成人黄色精品| 三级av中文字幕在线观看| 青青草成人福利电影| 成人动漫大肉棒插进去视频| xxx日本hd高清| 国产91精品拍在线观看| 大鸡巴操b视频在线| 伊人综合免费在线视频| 欧美专区第八页一区在线播放| 亚洲成人激情av在线| 欧美一区二区中文字幕电影| 天天爽夜夜爽人人爽QC| 噜噜色噜噜噜久色超碰| 香蕉aⅴ一区二区三区| 99视频精品全部15| 激情综合治理六月婷婷| 欧美日韩一区二区电影在线观看 | 99视频精品全部15| 人妻少妇亚洲一区二区| 青青青青青青青青青国产精品视频| 久久久久久97三级| 午夜激情高清在线观看| 大白屁股精品视频国产| 国产日本精品久久久久久久 | 天天做天天爽夜夜做少妇| 亚洲区美熟妇久久久久| 中文字幕日韩人妻在线三区| 亚洲视频在线观看高清| 中文字幕av第1页中文字幕| 99re国产在线精品| 最新的中文字幕 亚洲| 欧美综合婷婷欧美综合| 日日夜夜狠狠干视频| 日韩精品激情在线观看| 日本成人一区二区不卡免费在线| 亚洲狠狠婷婷综合久久app| 国产极品美女久久久久久| 国产高清精品一区二区三区| 国产一区av澳门在线观看| 青青青青草手机在线视频免费看 | 换爱交换乱高清大片| 欧美亚洲一二三区蜜臀| 亚洲欧美激情人妻偷拍| 激情五月婷婷免费视频| 天堂va蜜桃一区入口| av男人天堂狠狠干| 国内资源最丰富的网站| 亚洲一区二区激情在线| 美女小视频网站在线| 狠狠躁夜夜躁人人爽天天久天啪| 天天干天天日天天谢综合156| 欧美精品亚洲精品日韩在线| 日韩人妻丝袜中文字幕| 欧美在线偷拍视频免费看| 视频一区 二区 三区 综合| 日本免费视频午夜福利视频| 亚洲成人国产综合一区| 日韩欧美国产一区不卡| 老司机福利精品视频在线| 久久久久久久一区二区三| 青青青艹视频在线观看| 天堂v男人视频在线观看| 免费观看丰满少妇做受| 在线观看成人国产电影| 91在线视频在线精品3| 在线观看黄色成年人网站| 99一区二区在线观看| 精品久久久久久久久久中文蒉| 国产真实灌醉下药美女av福利| 沈阳熟妇28厘米大战黑人| 秋霞午夜av福利经典影视| av在线免费中文字幕| 久久这里有免费精品| 日本最新一二三区不卡在线 | 一区二区视频在线观看免费观看| heyzo蜜桃熟女人妻| 欧美亚洲偷拍自拍色图| 中文字幕欧美日韩射射一| 日韩精品激情在线观看| 成人动漫大肉棒插进去视频| 亚洲精品福利网站图片| 91久久国产成人免费网站| 亚洲福利午夜久久久精品电影网 | 麻豆精品成人免费视频| 精品亚洲在线免费观看| 大骚逼91抽插出水视频| 亚洲第17页国产精品| 狠狠躁夜夜躁人人爽天天天天97| 国产亚洲欧美45p| 国产高清精品一区二区三区| 久久久久久久亚洲午夜综合福利| 91国产资源在线视频| 亚洲1区2区3区精华液| 久久久久久久一区二区三| 天天日天天日天天擦| 亚洲欧美国产麻豆综合| 亚洲一区二区三区偷拍女厕91| 一区二区三区蜜臀在线| 久草视频 久草视频2| 国产又粗又猛又爽又黄的视频美国 | 欧美视频一区免费在线| 精品黑人巨大在线一区| 国产黄色片蝌蚪九色91| 亚洲国产第一页在线观看| 久久久久久久久久一区二区三区| 91av中文视频在线| 国产内射中出在线观看| 日韩精品啪啪视频一道免费| 久久www免费人成一看片| 伊人开心婷婷国产av| 91大神福利视频网| 天天日夜夜操天天摸| 青娱乐在线免费视频盛宴| 欧美aa一级一区三区四区| 国产真实乱子伦a视频| 中文字幕人妻熟女在线电影| av视网站在线观看| 亚洲男人让女人爽的视频| 午夜精品亚洲精品五月色| 精品人妻一二三区久久| 18禁美女黄网站色大片下载| av日韩在线免费播放| 精品久久久久久高潮| 午夜精品九一唐人麻豆嫩草成人| 性生活第二下硬不起来| 亚洲的电影一区二区三区| 一区二区三区四区中文| 日韩a级精品一区二区| 男人操女人的逼免费视频| 这里有精品成人国产99| 中文字幕人妻熟女在线电影| 欧美亚洲国产成人免费在线| 91she九色精品国产| 国产精品女邻居小骚货| 久草极品美女视频在线观看| 精品视频一区二区三区四区五区| 日本少妇在线视频大香蕉在线观看 | 亚洲一区二区人妻av| 瑟瑟视频在线观看免费视频| 国产之丝袜脚在线一区二区三区| 国产熟妇人妻ⅹxxxx麻豆| 又黄又刺激的午夜小视频| 国产黄网站在线观看播放| 男人的网址你懂的亚洲欧洲av| 中文字幕在线第一页成人| 美味人妻2在线播放| 大尺度激情四射网站| 亚洲va欧美va人人爽3p| 中文字幕国产专区欧美激情| 欧美日本在线视频一区| 成人综合亚洲欧美一区 | 91麻豆精品久久久久| 100%美女蜜桃视频| 在线免费观看日本片| 国产三级影院在线观看| 亚洲精品成人网久久久久久小说| 亚洲公开视频在线观看| 久久久久久久久久久免费女人| 国产高潮无码喷水AV片在线观看| 高潮喷水在线视频观看| 中文字幕免费在线免费| 国产精品熟女久久久久浪潮| 91www一区二区三区| 新97超碰在线观看| 密臀av一区在线观看| www骚国产精品视频| 亚洲高清视频在线不卡| 天天操天天插天天色| 亚洲高清自偷揄拍自拍| 日韩美av高清在线| 少妇人妻二三区视频| 国产不卡av在线免费| 久久久制服丝袜中文字幕| 99精品视频之69精品视频 | 丝袜长腿第一页在线| 国产视频精品资源网站| 熟女人妻一区二区精品视频| 青娱乐在线免费视频盛宴| av老司机亚洲一区二区| 91一区精品在线观看| 色97视频在线播放| 91精品视频在线观看免费| 天天干天天日天天谢综合156| 成人高清在线观看视频| 国产麻豆乱子伦午夜视频观看| 一区二区三区久久久91| 亚洲高清视频在线不卡| 日本午夜福利免费视频| 亚洲欧美精品综合图片小说| 一区二区三区国产精选在线播放| 在线成人日韩av电影| 黑人3p华裔熟女普通话| 亚洲伊人av天堂有码在线| 999九九久久久精品| 91精品高清一区二区三区| 国产伊人免费在线播放| 日韩欧美制服诱惑一区在线| 久草视频中文字幕在线观看| 真实国产乱子伦一区二区| 欧美成人综合色在线噜噜| 粗大的内捧猛烈进出爽大牛汉子| 国产精品自偷自拍啪啪啪| 玖玖一区二区在线观看| 98精产国品一二三产区区别| 中文亚洲欧美日韩无线码| 亚洲av第国产精品| 91精品一区二区三区站长推荐| 欧美日韩国产一区二区三区三州| 一区二区三区日本伦理| 国内自拍第一页在线观看| 在线 中文字幕 一区| 色秀欧美视频第一页| 9久在线视频只有精品| 快插进小逼里大鸡吧视频| 日韩av大胆在线观看| chinese国产盗摄一区二区| 2022精品久久久久久中文字幕| www骚国产精品视频| 成人综合亚洲欧美一区| 夜色撩人久久7777| 久久久久久国产精品| 黄色av网站免费在线| 久久精品亚洲成在人线a| 手机看片福利盒子日韩在线播放| 成年美女黄网站18禁久久| 97人妻无码AV碰碰视频| 人妻无码中文字幕专区| 一个色综合男人天堂| 不卡一不卡二不卡三| 亚洲国产欧美一区二区三区久久| 日本少妇精品免费视频| 一区二区三区毛片国产一区| 福利片区一区二体验区| 亚洲1卡2卡三卡4卡在线观看| 最新国产亚洲精品中文在线| 521精品视频在线观看| 久久丁香花五月天色婷婷| 亚洲高清国产自产av| 激情内射在线免费观看| 亚洲高清自偷揄拍自拍| 天天射夜夜操综合网| 好吊视频—区二区三区| 国产精品久久综合久久| 国产欧美精品免费观看视频| 亚洲av日韩av第一区二区三区| 亚洲一区二区三区五区| 日本一二三区不卡无| 亚洲中文精品人人免费| 日韩美女综合中文字幕pp| 久草视频在线免播放| 女警官打开双腿沦为性奴| 国产九色91在线观看精品| 亚洲成人线上免费视频观看| 日本啪啪啪啪啪啪啪| 夜夜嗨av一区二区三区中文字幕| 日本乱人一区二区三区| 男人的天堂av日韩亚洲| 天天做天天爽夜夜做少妇| 成人av天堂丝袜在线观看| 色婷婷久久久久swag精品| 青青草国内在线视频精选| 亚洲一级av大片免费观看| 91麻豆精品传媒国产黄色片| 天天射夜夜操狠狠干| av老司机精品在线观看| 国产精品国产三级国产午| 国产一级麻豆精品免费| 午夜国产免费福利av| 欧美viboss性丰满| 五色婷婷综合狠狠爱| 麻豆精品成人免费视频| 激情啪啪啪啪一区二区三区| 亚洲视频在线视频看视频在线| 不卡日韩av在线观看| 啊啊好慢点插舔我逼啊啊啊视频| 综合激情网激情五月天| 男女啪啪视频免费在线观看| 久久三久久三久久三久久| 一区二区三区四区五区性感视频| 2020久久躁狠狠躁夜夜躁| 成人av中文字幕一区| 精彩视频99免费在线| 日本熟女精品一区二区三区| 91福利视频免费在线观看| 久久艹在线观看视频| av成人在线观看一区| 亚洲欧美成人综合视频| 日韩精品中文字幕播放| 性色蜜臀av一区二区三区| 日韩国产乱码中文字幕| 亚洲精品国产在线电影| 毛片一级完整版免费| 日本女人一级免费片| 欧美成人综合色在线噜噜| 天天日天天爽天天爽| 亚洲欧美激情人妻偷拍| 一区二区在线视频中文字幕| 亚洲成高清a人片在线观看| 亚洲精品欧美日韩在线播放| 97国产福利小视频合集| 日韩欧美一级黄片亚洲| 久久久精品国产亚洲AV一| 日本一道二三区视频久久| 粉嫩欧美美人妻小视频| 久草视频首页在线观看| 97人人妻人人澡人人爽人人精品| 大胆亚洲av日韩av| 四川五十路熟女av| 9久在线视频只有精品| 日本熟妇喷水xxx| 中文字幕国产专区欧美激情| 精品日产卡一卡二卡国色天香 | 92福利视频午夜1000看| 熟女妇女老妇一二三区| 久久精品亚洲国产av香蕉| 亚洲精品乱码久久久久久密桃明| 欧洲亚洲欧美日韩综合| 午夜婷婷在线观看视频| 亚洲码av无色中文| 亚洲最大黄了色网站| 一区二区三区毛片国产一区| 巨乳人妻日下部加奈被邻居中出| 午夜在线一区二区免费| 日韩欧美亚洲熟女人妻| 77久久久久国产精产品| 成人国产激情自拍三区| 男生舔女生逼逼的视频| 天天插天天狠天天操| 精品少妇一二三视频在线| 日韩不卡中文在线视频网站| 日美女屁股黄邑视频| 最近中文2019年在线看| 北条麻妃av在线免费观看| 国产麻豆剧果冻传媒app| 亚洲色偷偷综合亚洲AV伊人| 亚洲蜜臀av一区二区三区九色| 久久这里只有精品热视频| 欧美一级片免费在线成人观看| 精品黑人巨大在线一区| av俺也去在线播放| 男人和女人激情视频| 午夜久久香蕉电影网| 色花堂在线av中文字幕九九| 一区二区三区四区视频在线播放| 日日日日日日日日夜夜夜夜夜夜| 亚洲最大黄了色网站| 亚洲av男人的天堂你懂的| 91国产在线视频免费观看| 天天艹天天干天天操| 成人av久久精品一区二区| av天堂资源最新版在线看| 人人爽亚洲av人人爽av| 99精品免费观看视频| 少妇一区二区三区久久久| 天天操天天操天天碰| 93视频一区二区三区| 中文字幕奴隷色的舞台50| ka0ri在线视频| 香蕉91一区二区三区| 日韩熟女av天堂系列| japanese五十路熟女熟妇| 在线免费观看欧美小视频| 成人av电影免费版| 国产片免费观看在线观看| 动漫精品视频在线观看| 欧美精产国品一二三区| 国产久久久精品毛片| 日本午夜爽爽爽爽爽视频在线观看 | 最新日韩av传媒在线| 日本男女操逼视频免费看| 国产白嫩美女一区二区| 任你操视频免费在线观看| 涩爱综合久久五月蜜臀| 狠狠躁狠狠爱网站视频| 国产自拍在线观看成人| 欧洲日韩亚洲一区二区三区| 国产精品黄页网站视频| 成人亚洲精品国产精品| 久久精品在线观看一区二区| 欧美国产亚洲中英文字幕| 国产精品自拍视频大全| 国产自拍在线观看成人| 国产欧美精品一区二区高清| 国内自拍第一页在线观看| 中英文字幕av一区| 国产使劲操在线播放| 午夜免费观看精品视频| 色爱av一区二区三区| 少妇被强干到高潮视频在线观看| 夜女神免费福利视频| 伊人开心婷婷国产av| 亚洲高清视频在线不卡| 在线新三级黄伊人网| 国产精彩对白一区二区三区| 99视频精品全部15| 97人妻无码AV碰碰视频| 少妇被强干到高潮视频在线观看| 喷水视频在线观看这里只有精品 | 男人插女人视频网站| 国产欧美精品一区二区高清| 狠狠的往里顶撞h百合| 精品美女久久久久久| 天天操天天操天天碰| 精品乱子伦一区二区三区免费播| 亚洲成人国产av在线| 精品日产卡一卡二卡国色天香 | 免费观看污视频网站| 姐姐的朋友2在线观看中文字幕| 亚洲欧美精品综合图片小说| 中英文字幕av一区| japanese日本熟妇另类| 丝袜亚洲另类欧美变态| 欧美久久久久久三级网| 国产亚洲精品视频合集| 成人av在线资源网站| 最新国产亚洲精品中文在线| 蜜桃精品久久久一区二区| 欧美精品伦理三区四区| 精品国产乱码一区二区三区乱| 97超碰最新免费在线观看| 在线观看黄色成年人网站| 骚货自慰被发现爆操| 国产精品黄片免费在线观看| 黑人性生活视频免费看| 日本熟妇喷水xxx| 91精品国产麻豆国产| 91大屁股国产一区二区| 亚洲伊人av天堂有码在线| 在线免费观看黄页视频| 中文字幕日本人妻中出| 红桃av成人在线观看| 99热久久这里只有精品| 伊人成人综合开心网| 内射久久久久综合网| 性色av一区二区三区久久久| 精品黑人巨大在线一区| 欧美日本在线观看一区二区| 欧美精品国产综合久久| 自拍偷拍亚洲精品第2页| 亚洲一区二区三区av网站| 大陆胖女人与丈夫操b国语高清| 亚洲日本一区二区三区| 国产变态另类在线观看| 中文字幕av一区在线观看| 清纯美女在线观看国产| 91色网站免费在线观看| 日韩精品一区二区三区在线播放| 91色网站免费在线观看| 亚洲欧美一卡二卡三卡| 日韩av免费观看一区| 91九色porny国产蝌蚪视频| 国产又粗又黄又硬又爽| 国产黑丝高跟鞋视频在线播放| 国产白嫩美女一区二区| 中文字幕在线视频一区二区三区| 亚洲精品在线资源站| 免费成人av中文字幕| 玩弄人妻熟妇性色av少妇| 2018在线福利视频| 青娱乐极品视频青青草| 淫秽激情视频免费观看| 最近中文2019年在线看| 免费高清自慰一区二区三区网站| 9l人妻人人爽人人爽| 粉嫩小穴流水视频在线观看| 久青青草视频手机在线免费观看| 午夜久久久久久久精品熟女| 日韩av中文在线免费观看| 北条麻妃av在线免费观看| 性感美女高潮视频久久久| 中文字日产幕乱六区蜜桃| av线天堂在线观看| 视频一区二区在线免费播放| 中文字日产幕乱六区蜜桃| 全国亚洲男人的天堂| 亚洲av香蕉一区区二区三区犇| 精品高跟鞋丝袜一区二区| 1000部国产精品成人观看视频| 少妇人妻100系列| 亚洲一区二区三区五区| 国产一级麻豆精品免费| 中文字幕一区二区三区蜜月| 国产又粗又黄又硬又爽| 日本午夜久久女同精女女| 国产美女午夜福利久久| 美日韩在线视频免费看| 欧美一区二区三区乱码在线播放| 人人人妻人人澡人人| 在线观看一区二区三级| 日本免费午夜视频网站| 一区二区在线视频中文字幕| 天堂资源网av中文字幕| 国产一区二区三免费视频| 99精品视频之69精品视频| 亚洲日产av一区二区在线| 亚洲精品无码久久久久不卡| 一个人免费在线观看ww视频| 午夜激情高清在线观看| 2022中文字幕在线| 在线观看av2025| 免费av岛国天堂网站| 日韩伦理短片在线观看| 最新黄色av网站在线观看| 青草久久视频在线观看| 亚洲国产欧美一区二区三区久久 | 免费成人va在线观看| 抽查舔水白紧大视频| 人妻素人精油按摩中出| 好吊操视频这里只有精品| brazzers欧熟精品系列| 开心 色 六月 婷婷| 日韩美女综合中文字幕pp| 无码国产精品一区二区高潮久久4| 51国产成人精品视频| 国产麻豆精品人妻av| 久久久久91精品推荐99| 亚洲 人妻 激情 中文| 国产精品视频欧美一区二区| 99re久久这里都是精品视频| 日韩美女精品视频在线观看网站| 日本又色又爽又黄又粗| 国产精品成人xxxx| 国产精品久久久久久久久福交| 第一福利视频在线观看| 中国视频一区二区三区| 亚洲护士一区二区三区| 91人妻人人做人人爽在线| 做爰视频毛片下载蜜桃视频1| 欧美男人大鸡吧插女人视频| 一本久久精品一区二区| 丝袜美腿视频诱惑亚洲无 | 91精品国产观看免费| 啊啊好大好爽啊啊操我啊啊视频| 黄色无码鸡吧操逼视频| 99久久99一区二区三区| 日韩特级黄片高清在线看| 在线观看视频一区麻豆| 日本免费一级黄色录像| 18禁污污污app下载| 成人sm视频在线观看| 亚洲一区二区三区五区| 日曰摸日日碰夜夜爽歪歪| 日本特级片中文字幕| 中文字幕一区二区三区人妻大片| 最新日韩av传媒在线| 国产自拍在线观看成人| 成年人啪啪视频在线观看| 国产日韩欧美美利坚蜜臀懂色| 国产成人一区二区三区电影网站 | 亚洲综合色在线免费观看| 亚洲福利午夜久久久精品电影网 | 免费无码人妻日韩精品一区二区| 国产一区二区欧美三区 | 国产乱弄免费视频观看| 热99re69精品8在线播放| 鸡巴操逼一级黄色气| 国产一区av澳门在线观看| 91人妻精品久久久久久久网站| 午夜成午夜成年片在线观看| 免费看高清av的网站| 久草极品美女视频在线观看| 中文字幕免费在线免费| 最新国产亚洲精品中文在线| 大香蕉福利在线观看| 亚洲熟女女同志女同| 婷婷久久一区二区字幕网址你懂得 | 亚洲女人的天堂av| 精品国产高潮中文字幕| 11久久久久久久久久久| 肏插流水妹子在线乐播下载| 2o22av在线视频| 国产精品久久久黄网站| 亚洲av日韩高清hd| 好了av中文字幕在线| 国产精品精品精品999| 一区二区三区蜜臀在线| 精品一区二区三区在线观看| 成人av在线资源网站| 做爰视频毛片下载蜜桃视频1| 风流唐伯虎电视剧在线观看| 亚洲欧美激情中文字幕| 99精品免费观看视频| 日本韩国免费福利精品| www日韩毛片av| 97精品人妻一区二区三区精品| 色婷婷综合激情五月免费观看 | 亚洲精品 欧美日韩| 自拍偷拍日韩欧美一区二区| 影音先锋女人av噜噜色| 少妇人妻久久久久视频黄片| 日本熟妇色熟妇在线观看| 成人av中文字幕一区| 中文字幕av男人天堂| 直接观看免费黄网站| 很黄很污很色的午夜网站在线观看 | 在线免费视频 自拍| 亚洲中文字幕国产日韩| 亚洲av黄色在线网站| 天堂资源网av中文字幕| 好吊操视频这里只有精品| 午夜久久久久久久99| 亚洲天堂第一页中文字幕| 国产一区二区欧美三区| 欧美国品一二三产区区别| 又色又爽又黄的美女裸体| av天堂加勒比在线| 国产精品sm调教视频| 端庄人妻堕落挣扎沉沦| 一区二区三区在线视频福利| jiuse91九色视频| 国产日韩一区二区在线看| 成人福利视频免费在线| av在线免费资源站| 午夜国产福利在线观看| 夏目彩春在线中文字幕| 婷婷综合蜜桃av在线| 直接观看免费黄网站| asmr福利视频在线观看| 国产精品久久久久国产三级试频| 中文亚洲欧美日韩无线码| 国产91嫩草久久成人在线视频| 婷婷激情四射在线观看视频| av手机免费在线观看高潮| 888亚洲欧美国产va在线播放| 日韩精品中文字幕福利| 成人综合亚洲欧美一区 | 少妇露脸深喉口爆吞精| xxx日本hd高清| 欧美黑人巨大性xxxxx猛交| 熟女人妻在线中出观看完整版| 亚洲天堂第一页中文字幕| 爆乳骚货内射骚货内射在线| 天干天天天色天天日天天射| 97超碰人人搞人人| 久久免看30视频口爆视频| 亚洲熟色妇av日韩熟色妇在线| 一区国内二区日韩三区欧美| 亚洲自拍偷拍精品网| 黄色片年轻人在线观看| 日韩熟女av天堂系列| 在线网站你懂得老司机| 日美女屁股黄邑视频| 风流唐伯虎电视剧在线观看| 91中文字幕最新合集| 插小穴高清无码中文字幕| 91国偷自产一区二区三区精品| 99视频精品全部15| 欧美日韩人妻久久精品高清国产| 成人色综合中文字幕| 欧美黑人巨大性xxxxx猛交| 中文字幕中文字幕人妻| 大鸡巴操b视频在线| 玩弄人妻熟妇性色av少妇| 欧美精品一二三视频| 一区二区三区 自拍偷拍| 亚洲成人午夜电影在线观看| 精品国产亚洲av一淫| 午夜精品在线视频一区| 免费在线观看污污视频网站| 欧洲黄页网免费观看| 久久这里有免费精品| av中文字幕国产在线观看| 丝袜美腿视频诱惑亚洲无 | 丝袜亚洲另类欧美变态| 亚洲av天堂在线播放| 巨乳人妻日下部加奈被邻居中出 | 在线免费观看视频一二区| caoporm超碰国产| 亚洲欧美激情人妻偷拍| 女同性ⅹxx女同h偷拍| 亚洲av色香蕉一区二区三区| 欧美专区日韩专区国产专区| 免费在线福利小视频| 天天日天天操天天摸天天舔| 欧美激情电影免费在线| 青草青永久在线视频18| 人妻av无码专区久久绿巨人| 免费大片在线观看视频网站| 天天日天天干天天爱| 亚洲午夜电影之麻豆| 岛国毛片视频免费在线观看| 粉嫩av蜜乳av蜜臀| 午夜激情精品福利视频| 亚洲嫩模一区二区三区| 日本一二三区不卡无| 欧美天堂av无线av欧美| 漂亮 人妻被中出中文| 91人妻人人做人人爽在线| wwwxxx一级黄色片| 成人精品在线观看视频| 日本性感美女视频网站| 成人影片高清在线观看| 天天日天天爽天天干| 亚洲青青操骚货在线视频| 91在线免费观看成人| 国产免费av一区二区凹凸四季| 欧美色呦呦最新网址| 无忧传媒在线观看视频| 亚洲精品久久视频婷婷| 日韩人妻xxxxx| 亚洲午夜高清在线观看| 国产剧情演绎系列丝袜高跟| 午夜毛片不卡免费观看视频| 最新日韩av传媒在线| 国产av福利网址大全| 蜜桃专区一区二区在线观看| 国产密臀av一区二区三| 91在线免费观看成人| 97精品成人一区二区三区 | 日日夜夜狠狠干视频| 成人午夜电影在线观看 久久| 免费观看丰满少妇做受| 视频一区 二区 三区 综合| okirakuhuhu在线观看| tube69日本少妇| 在线免费观看日本伦理| 粉嫩欧美美人妻小视频| 一区二区三区国产精选在线播放 | 国产九色91在线视频| 天天色天天操天天透| 欧美日韩激情啪啪啪| 视频一区 二区 三区 综合| 97人人模人人爽人人喊| 91九色porny蝌蚪国产成人| 天天干天天搞天天摸| 视频一区 视频二区 视频| 亚洲午夜福利中文乱码字幕| 少妇一区二区三区久久久| 亚洲人人妻一区二区三区| 日本黄在免费看视频| 国产精品人妻66p| 天天插天天狠天天操| 18禁免费av网站| 人妻最新视频在线免费观看| 亚洲无码一区在线影院| 偷拍自拍亚洲美腿丝袜| 亚洲午夜在线视频福利| 午夜国产福利在线观看| 伊人日日日草夜夜草| 亚洲精品乱码久久久久久密桃明| 亚洲高清免费在线观看视频| 熟女人妻在线中出观看完整版| 成人亚洲国产综合精品| 在线观看欧美黄片一区二区三区| 亚洲一区二区久久久人妻| 日本少妇在线视频大香蕉在线观看| 日本一二三区不卡无| 国产成人精品久久二区91| 亚洲在线免费h观看网站| 亚洲国产40页第21页| 男女第一次视频在线观看| 中文字幕一区二区三区人妻大片| 亚洲国产精品免费在线观看| 中文字幕,亚洲人妻| av在线免费中文字幕| 亚洲一级美女啪啪啪| av视网站在线观看| 一区二区视频视频视频| 精品欧美一区二区vr在线观看| 亚洲精品乱码久久久本| 99久久中文字幕一本人| 欧美少妇性一区二区三区| 2020av天堂网在线观看| 亚洲 国产 成人 在线| 手机看片福利盒子日韩在线播放| 成人乱码一区二区三区av| 国产精品一区二区久久久av| 韩国爱爱视频中文字幕| 高潮视频在线快速观看国家快速| 亚洲最大黄 嗯色 操 啊| 好吊操视频这里只有精品| 粗大的内捧猛烈进出爽大牛汉子| 午夜91一区二区三区| 91老熟女连续高潮对白| 91国偷自产一区二区三区精品| 不戴胸罩引我诱的隔壁的人妻| 少妇与子乱在线观看| 日韩成人性色生活片| 偷拍自拍 中文字幕| 人妻无码色噜噜狠狠狠狠色| 日本少妇在线视频大香蕉在线观看| 国产亚洲视频在线二区| 99久久久无码国产精品性出奶水| 日本一区二区三区免费小视频| 久久久久只精品国产三级| 久久这里有免费精品| 青青青青青操视频在线观看| 一区二区三区久久中文字幕| 国产麻豆剧传媒精品国产av蜜桃| 北条麻妃高跟丝袜啪啪| 极品丝袜一区二区三区| 中文字幕高清在线免费播放| 97青青青手机在线视频| 亚洲推理片免费看网站| 综合精品久久久久97| 日韩欧美高清免费在线| 国产一区自拍黄视频免费观看| 99热这里只有精品中文| 亚洲自拍偷拍综合色| 大陆av手机在线观看| 中文字幕综合一区二区| 大屁股熟女一区二区三区|