日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

60分钟快速入门 PyTorch

發布時間:2023/12/10 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 60分钟快速入门 PyTorch 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

PyTorch 是由 Facebook 開發,基于 Torch 開發,從并不常用的 Lua 語言轉為 Python 語言開發的深度學習框架,Torch 是 TensorFlow 開源前非常出名的一個深度學習框架,而 PyTorch 在開源后由于其使用簡單,動態計算圖的特性得到非常多的關注,并且成為了 TensorFlow 的 最大競爭對手。目前其 Github 也有 2w8+ 關注。
Github 地址: https://github.com/pytorch/pytorch
官網: https://pytorch.org/
論壇:https://discuss.pytorch.org/

本文是翻譯自官方版教程–DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ,一份 60 分鐘帶你快速入門 PyTorch 的教程。

本文目錄如下:


1. Pytorch 是什么

Pytorch 是一個基于 Python 的科學計算庫,它面向以下兩種人群:

  • 希望將其代替 Numpy 來利用 GPUs 的威力;
  • 一個可以提供更加靈活和快速的深度學習研究平臺。

1.1 安裝

pytorch 的安裝可以直接查看官網教程,如下所示,官網地址:https://pytorch.org/get-started/locally/

根據提示分別選擇系統(Linux、Mac 或者 Windows),安裝方式(Conda,Pip,LibTorch 或者源碼安裝)、使用的編程語言(Python 2.7 或者 Python 3.5,3.6,3.7 或者是 C++),如果是 GPU 版本,就需要選擇 CUDA 的 版本,所以,如果如上圖所示選擇,安裝的命令是:

conda install pytorch torchvision cudatoolkit=9.0 -c pytorch

這里推薦采用 Conda 安裝,即使用 Anaconda,主要是可以設置不同環境配置不同的設置,關于 Anaconda 可以查看我之前寫的 Python 基礎入門–簡介和環境配置 。

當然這里會安裝最新版本的 Pytorch,也就是 1.1 版本,如果希望安裝之前的版本,可以點擊下面的網址:

http://pytorch.org/get-started/previous-versions/

如下圖所示,安裝 0.4.1 版本的 pytorch,在不同版本的 CUDA 以及沒有 CUDA 的情況。

然后還有其他的安裝方式,具體可以自己點擊查看。

安裝后,輸入下列命令:

from __future__ import print_function import torch x = torch.rand(5, 3) print(x)

輸出結果類似下面的結果即安裝成功:

tensor([[0.3380, 0.3845, 0.3217],[0.8337, 0.9050, 0.2650],[0.2979, 0.7141, 0.9069],[0.1449, 0.1132, 0.1375],[0.4675, 0.3947, 0.1426]])

然后是驗證能否正確運行在 GPU 上,輸入下列代碼,這份代碼中 cuda.is_available() 主要是用于檢測是否可以使用當前的 GPU 顯卡,如果返回 True,當然就可以運行,否則就不能。

import torch torch.cuda.is_available()

1.2 張量(Tensors)

Pytorch 的一大作用就是可以代替 Numpy 庫,所以首先介紹 Tensors ,也就是張量,它相當于 Numpy 的多維數組(ndarrays)。兩者的區別就是 Tensors 可以應用到 GPU 上加快計算速度。

首先導入必須的庫,主要是 torch

from __future__ import print_function import torch
1.2.1 聲明和定義

首先是對 Tensors 的聲明和定義方法,分別有以下幾種:

  • torch.empty(): 聲明一個未初始化的矩陣。
# 創建一個 5*3 的矩陣 x = torch.empty(5, 3) print(x)

輸出結果如下:

tensor([[9.2737e-41, 8.9074e-01, 1.9286e-37],[1.7228e-34, 5.7064e+01, 9.2737e-41],[2.2803e+02, 1.9288e-37, 1.7228e-34],[1.4609e+04, 9.2737e-41, 5.8375e+04],[1.9290e-37, 1.7228e-34, 3.7402e+06]])
  • torch.rand():隨機初始化一個矩陣
# 創建一個隨機初始化的 5*3 矩陣 rand_x = torch.rand(5, 3) print(rand_x)

輸出結果:

tensor([[0.4311, 0.2798, 0.8444],[0.0829, 0.9029, 0.8463],[0.7139, 0.4225, 0.5623],[0.7642, 0.0329, 0.8816],[1.0000, 0.9830, 0.9256]])
  • torch.zeros():創建數值皆為 0 的矩陣
# 創建一個數值皆是 0,類型為 long 的矩陣 zero_x = torch.zeros(5, 3, dtype=torch.long) print(zero_x)

輸出結果如下:

tensor([[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0]])

類似的也可以創建數值都是 1 的矩陣,調用 torch.ones

  • torch.tensor():直接傳遞 tensor 數值來創建
# tensor 數值是 [5.5, 3] tensor1 = torch.tensor([5.5, 3]) print(tensor1)

輸出結果:

tensor([5.5000, 3.0000])

除了上述幾種方法,還可以根據已有的 tensor 變量創建新的 tensor 變量,這種做法的好處就是可以保留已有 tensor 的一些屬性,包括尺寸大小、數值屬性,除非是重新定義這些屬性。相應的實現方法如下:

  • tensor.new_ones():new_*() 方法需要輸入尺寸大小
# 顯示定義新的尺寸是 5*3,數值類型是 torch.double tensor2 = tensor1.new_ones(5, 3, dtype=torch.double) # new_* 方法需要輸入 tensor 大小 print(tensor2)

輸出結果:

tensor([[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]], dtype=torch.float64)
  • torch.randn_like(old_tensor):保留相同的尺寸大小
# 修改數值類型 tensor3 = torch.randn_like(tensor2, dtype=torch.float) print('tensor3: ', tensor3)

輸出結果,這里是根據上個方法聲明的 tensor2 變量來聲明新的變量,可以看出尺寸大小都是 5*3,但是數值類型是改變了的。

tensor3: tensor([[-0.4491, -0.2634, -0.0040],[-0.1624, 0.4475, -0.8407],[-0.6539, -1.2772, 0.6060],[ 0.2304, 0.0879, -0.3876],[ 1.2900, -0.7475, -1.8212]])

最后,對 tensors 的尺寸大小獲取可以采用 tensor.size() 方法:

print(tensor3.size()) # 輸出: torch.Size([5, 3])

注意: torch.Size 實際上是元組(tuple)類型,所以支持所有的元組操作

1.2.2 操作(Operations)

操作也包含了很多語法,但這里作為快速入門,僅僅以加法操作作為例子進行介紹,更多的操作介紹可以點擊下面網址查看官方文檔,包括轉置、索引、切片、數學計算、線性代數、隨機數等等:

https://pytorch.org/docs/stable/torch.html

對于加法的操作,有幾種實現方式:

  • + 運算符
  • torch.add(tensor1, tensor2, [out=tensor3])
  • tensor1.add_(tensor2):直接修改 tensor 變量
tensor4 = torch.rand(5, 3) print('tensor3 + tensor4= ', tensor3 + tensor4) print('tensor3 + tensor4= ', torch.add(tensor3, tensor4)) # 新聲明一個 tensor 變量保存加法操作的結果 result = torch.empty(5, 3) torch.add(tensor3, tensor4, out=result) print('add result= ', result) # 直接修改變量 tensor3.add_(tensor4) print('tensor3= ', tensor3)

輸出結果

tensor3 + tensor4= tensor([[ 0.1000, 0.1325, 0.0461],[ 0.4731, 0.4523, -0.7517],[ 0.2995, -0.9576, 1.4906],[ 1.0461, 0.7557, -0.0187],[ 2.2446, -0.3473, -1.0873]])tensor3 + tensor4= tensor([[ 0.1000, 0.1325, 0.0461],[ 0.4731, 0.4523, -0.7517],[ 0.2995, -0.9576, 1.4906],[ 1.0461, 0.7557, -0.0187],[ 2.2446, -0.3473, -1.0873]])add result= tensor([[ 0.1000, 0.1325, 0.0461],[ 0.4731, 0.4523, -0.7517],[ 0.2995, -0.9576, 1.4906],[ 1.0461, 0.7557, -0.0187],[ 2.2446, -0.3473, -1.0873]])tensor3= tensor([[ 0.1000, 0.1325, 0.0461],[ 0.4731, 0.4523, -0.7517],[ 0.2995, -0.9576, 1.4906],[ 1.0461, 0.7557, -0.0187],[ 2.2446, -0.3473, -1.0873]])

注意:可以改變 tensor 變量的操作都帶有一個后綴 _, 例如 x.copy_(y), x.t_() 都可以改變 x 變量

除了加法運算操作,對于 Tensor 的訪問,和 Numpy 對數組類似,可以使用索引來訪問某一維的數據,如下所示:

# 訪問 tensor3 第一列數據 print(tensor3[:, 0])

輸出結果:

tensor([0.1000, 0.4731, 0.2995, 1.0461, 2.2446])

對 Tensor 的尺寸修改,可以采用 torch.view() ,如下所示:

x = torch.randn(4, 4) y = x.view(16) # -1 表示除給定維度外的其余維度的乘積 z = x.view(-1, 8) print(x.size(), y.size(), z.size())

輸出結果:

torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])

如果 tensor 僅有一個元素,可以采用 .item() 來獲取類似 Python 中整數類型的數值:

x = torch.randn(1) print(x) print(x.item())

輸出結果:

tensor([0.4549]) 0.4549027979373932

更多的運算操作可以查看官方文檔的介紹:

https://pytorch.org/docs/stable/torch.html

1.3 和 Numpy 數組的轉換

Tensor 和 Numpy 的數組可以相互轉換,并且兩者轉換后共享在 CPU 下的內存空間,即改變其中一個的數值,另一個變量也會隨之改變。

1.3.1 Tensor 轉換為 Numpy 數組

實現 Tensor 轉換為 Numpy 數組的例子如下所示,調用 tensor.numpy() 可以實現這個轉換操作。

a = torch.ones(5) print(a) b = a.numpy() print(b)

輸出結果:

tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]

此外,剛剛說了兩者是共享同個內存空間的,例子如下所示,修改 tensor 變量 a,看看從 a 轉換得到的 Numpy 數組變量 b 是否發生變化。

a.add_(1) print(a) print(b)

輸出結果如下,很明顯,b 也隨著 a 的改變而改變。

tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
1.3.2 Numpy 數組轉換為 Tensor

轉換的操作是調用 torch.from_numpy(numpy_array) 方法。例子如下所示:

import numpy as np a = np.ones(5) b = torch.from_numpy(a) np.add(a, 1, out=a) print(a) print(b)

輸出結果:

[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

在 CPU 上,除了 CharTensor 外的所有 Tensor 類型變量,都支持和 Numpy 數組的相互轉換操作。

1.4. CUDA 張量

Tensors 可以通過 .to 方法轉換到不同的設備上,即 CPU 或者 GPU 上。例子如下所示:

# 當 CUDA 可用的時候,可用運行下方這段代碼,采用 torch.device() 方法來改變 tensors 是否在 GPU 上進行計算操作 if torch.cuda.is_available():device = torch.device("cuda") # 定義一個 CUDA 設備對象y = torch.ones_like(x, device=device) # 顯示創建在 GPU 上的一個 tensorx = x.to(device) # 也可以采用 .to("cuda") z = x + yprint(z)print(z.to("cpu", torch.double)) # .to() 方法也可以改變數值類型

輸出結果,第一個結果就是在 GPU 上的結果,打印變量的時候會帶有 device='cuda:0',而第二個是在 CPU 上的變量。

tensor([1.4549], device='cuda:0')tensor([1.4549], dtype=torch.float64)

本小節教程:

https://pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html

本小節的代碼:

https://github.com/ccc013/DeepLearning_Notes/blob/master/Pytorch/practise/basic_practise.ipynb

2. autograd

對于 Pytorch 的神經網絡來說,非常關鍵的一個庫就是 autograd ,它主要是提供了對 Tensors 上所有運算操作的自動微分功能,也就是計算梯度的功能。它屬于 define-by-run 類型框架,即反向傳播操作的定義是根據代碼的運行方式,因此每次迭代都可以是不同的。

接下來會簡單介紹一些例子來說明這個庫的作用。

2.1 張量

torch.Tensor 是 Pytorch 最主要的庫,當設置它的屬性 .requires_grad=True,那么就會開始追蹤在該變量上的所有操作,而完成計算后,可以調用 .backward() 并自動計算所有的梯度,得到的梯度都保存在屬性 .grad 中。

調用 .detach() 方法分離出計算的歷史,可以停止一個 tensor 變量繼續追蹤其歷史信息 ,同時也防止未來的計算會被追蹤。

而如果是希望防止跟蹤歷史(以及使用內存),可以將代碼塊放在 with torch.no_grad(): 內,這個做法在使用一個模型進行評估的時候非常有用,因為模型會包含一些帶有 requires_grad=True 的訓練參數,但實際上并不需要它們的梯度信息。

對于 autograd 的實現,還有一個類也是非常重要-- Function 。

Tensor 和 Function 兩個類是有關聯并建立了一個非循環的圖,可以編碼一個完整的計算記錄。每個 tensor 變量都帶有屬性 .grad_fn ,該屬性引用了創建了這個變量的 Function (除了由用戶創建的 Tensors,它們的 grad_fn=None )。

如果要進行求導運算,可以調用一個 Tensor 變量的方法 .backward() 。如果該變量是一個標量,即僅有一個元素,那么不需要傳遞任何參數給方法 .backward() ,當包含多個元素的時候,就必須指定一個 gradient 參數,表示匹配尺寸大小的 tensor,這部分見第二小節介紹梯度的內容。

接下來就開始用代碼來進一步介紹。

首先導入必須的庫:

import torch

開始創建一個 tensor, 并讓 requires_grad=True 來追蹤該變量相關的計算操作:

x = torch.ones(2, 2, requires_grad=True) print(x)

輸出結果:

tensor([[1., 1.],[1., 1.]], requires_grad=True)

執行任意計算操作,這里進行簡單的加法運算:

y = x + 2 print(y)

輸出結果:

tensor([[3., 3.],[3., 3.]], grad_fn=<AddBackward>)

y 是一個操作的結果,所以它帶有屬性 grad_fn:

print(y.grad_fn)

輸出結果:

<AddBackward object at 0x00000216D25DCC88>

繼續對變量 y 進行操作:

z = y * y * 3 out = z.mean()print('z=', z) print('out=', out)

輸出結果:

z= tensor([[27., 27.],[27., 27.]], grad_fn=<MulBackward>)out= tensor(27., grad_fn=<MeanBackward1>)

實際上,一個 Tensor 變量的默認 requires_grad 是 False ,可以像上述定義一個變量時候指定該屬性是 True,當然也可以定義變量后,調用 .requires_grad_(True) 設置為 True ,這里帶有后綴 _ 是會改變變量本身的屬性,在上一節介紹加法操作 add_() 說明過,下面是一個代碼例子:

a = torch.randn(2, 2) a = ((a * 3) / (a - 1)) print(a.requires_grad) a.requires_grad_(True) print(a.requires_grad) b = (a * a).sum() print(b.grad_fn)

輸出結果如下,第一行是為設置 requires_grad 的結果,接著顯示調用 .requires_grad_(True),輸出結果就是 True 。

FalseTrue<SumBackward0 object at 0x00000216D25ED710>

2.2 梯度

接下來就是開始計算梯度,進行反向傳播的操作。out 變量是上一小節中定義的,它是一個標量,因此 out.backward() 相當于 out.backward(torch.tensor(1.)) ,代碼如下:

out.backward() # 輸出梯度 d(out)/dx print(x.grad)

輸出結果:

tensor([[4.5000, 4.5000],[4.5000, 4.5000]])

結果應該就是得到數值都是 4.5 的矩陣。這里我們用 o 表示 out 變量,那么根據之前的定義會有:
o=14∑izi,zi=3(xi+2)2,zi∣xi=1=27o = \frac{1}{4}\sum_iz_i,\\ z_i = 3(x_i + 2)^2, \\ z_i|_{x_i=1} = 27 o=41?i?zi?,zi?=3(xi?+2)2,zi?xi?=1?=27
詳細來說,初始定義的 x 是一個全為 1 的矩陣,然后加法操作 x+2 得到 y ,接著 y*y*3, 得到 z ,并且此時 z 是一個 2*2 的矩陣,所以整體求平均得到 out 變量應該是除以 4,所以得到上述三條公式。

因此,計算梯度:
?o?xi=32(xi+2),?o?xi∣xi=1=92=4.5\frac{\partial o}{\partial x_i} = \frac{3}{2}(x_i+2),\\ \frac{\partial o}{\partial x_i}|_{x_i=1} = \frac{9}{2} = 4.5 ?xi??o?=23?(xi?+2),?xi??o?xi?=1?=29?=4.5
從數學上來說,如果你有一個向量值函數:
y?=f(x?)\vec{y}=f(\vec{x}) y?=f(x)
那么對應的梯度是一個雅克比矩陣(Jacobian matrix):
KaTeX parse error: No such environment: split at position 8: \begin{?s?p?l?i?t?}?J=\left(\begin{…
一般來說,torch.autograd 就是用于計算雅克比向量(vector-Jacobian)乘積的工具。這里略過數學公式,直接上代碼例子介紹:

x = torch.randn(3, requires_grad=True)y = x * 2 while y.data.norm() < 1000:y = y * 2print(y)

輸出結果:

tensor([ 237.5009, 1774.2396, 274.0625], grad_fn=<MulBackward>)

這里得到的變量 y 不再是一個標量,torch.autograd 不能直接計算完整的雅克比行列式,但我們可以通過簡單的傳遞向量給 backward() 方法作為參數得到雅克比向量的乘積,例子如下所示:

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float) y.backward(v)print(x.grad)

輸出結果:

tensor([ 102.4000, 1024.0000, 0.1024])

最后,加上 with torch.no_grad() 就可以停止追蹤變量歷史進行自動梯度計算:

print(x.requires_grad) print((x ** 2).requires_grad)with torch.no_grad():print((x ** 2).requires_grad)

輸出結果:

TrueTrueFalse

更多有關 autograd 和 Function 的介紹:

https://pytorch.org/docs/autograd

本小節教程:

https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html

本小節的代碼:

https://github.com/ccc013/DeepLearning_Notes/blob/master/Pytorch/practise/autograd.ipynb

3. 神經網絡

在 PyTorch 中 torch.nn 專門用于實現神經網絡。其中 nn.Module 包含了網絡層的搭建,以及一個方法-- forward(input) ,并返回網絡的輸出 outptu .

下面是一個經典的 LeNet 網絡,用于對字符進行分類。

對于神經網絡來說,一個標準的訓練流程是這樣的:

  • 定義一個多層的神經網絡
  • 對數據集的預處理并準備作為網絡的輸入
  • 將數據輸入到網絡
  • 計算網絡的損失
  • 反向傳播,計算梯度
  • 更新網絡的梯度,一個簡單的更新規則是 weight = weight - learning_rate * gradient

3.1 定義網絡

首先定義一個神經網絡,下面是一個 5 層的卷積神經網絡,包含兩層卷積層和三層全連接層:

import torch import torch.nn as nn import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net, self).__init__()# 輸入圖像是單通道,conv1 kenrnel size=5*5,輸出通道 6self.conv1 = nn.Conv2d(1, 6, 5)# conv2 kernel size=5*5, 輸出通道 16self.conv2 = nn.Conv2d(6, 16, 5)# 全連接層self.fc1 = nn.Linear(16*5*5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):# max-pooling 采用一個 (2,2) 的滑動窗口x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))# 核(kernel)大小是方形的話,可僅定義一個數字,如 (2,2) 用 2 即可x = F.max_pool2d(F.relu(self.conv2(x)), 2)x = x.view(-1, self.num_flat_features(x))x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xdef num_flat_features(self, x):# 除了 batch 維度外的所有維度size = x.size()[1:]num_features = 1for s in size:num_features *= sreturn num_featuresnet = Net() print(net)

打印網絡結構:

Net((conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))(fc1): Linear(in_features=400, out_features=120, bias=True)(fc2): Linear(in_features=120, out_features=84, bias=True)(fc3): Linear(in_features=84, out_features=10, bias=True) )

這里必須實現 forward 函數,而 backward 函數在采用 autograd 時就自動定義好了,在 forward 方法可以采用任何的張量操作。

net.parameters() 可以返回網絡的訓練參數,使用例子如下:

params = list(net.parameters()) print('參數數量: ', len(params)) # conv1.weight print('第一個參數大小: ', params[0].size())

輸出:

參數數量: 10 第一個參數大小: torch.Size([6, 1, 5, 5])

然后簡單測試下這個網絡,隨機生成一個 32*32 的輸入:

# 隨機定義一個變量輸入網絡 input = torch.randn(1, 1, 32, 32) out = net(input) print(out)

輸出結果:

tensor([[ 0.1005, 0.0263, 0.0013, -0.1157, -0.1197, -0.0141, 0.1425, -0.0521,0.0689, 0.0220]], grad_fn=<ThAddmmBackward>)

接著反向傳播需要先清空梯度緩存,并反向傳播隨機梯度:

# 清空所有參數的梯度緩存,然后計算隨機梯度進行反向傳播 net.zero_grad() out.backward(torch.randn(1, 10))

注意

torch.nn 只支持**小批量(mini-batches)**數據,也就是輸入不能是單個樣本,比如對于 nn.Conv2d 接收的輸入是一個 4 維張量–nSamples * nChannels * Height * Width 。

所以,如果你輸入的是單個樣本,需要采用 input.unsqueeze(0) 來擴充一個假的 batch 維度,即從 3 維變為 4 維

3.2 損失函數

損失函數的輸入是 (output, target) ,即網絡輸出和真實標簽對的數據,然后返回一個數值表示網絡輸出和真實標簽的差距。

PyTorch 中其實已經定義了不少的損失函數,這里僅采用簡單的均方誤差:nn.MSELoss ,例子如下:

output = net(input) # 定義偽標簽 target = torch.randn(10) # 調整大小,使得和 output 一樣的 size target = target.view(1, -1) criterion = nn.MSELoss()loss = criterion(output, target) print(loss)

輸出如下:

tensor(0.6524, grad_fn=<MseLossBackward>)

這里,整個網絡的數據輸入到輸出經歷的計算圖如下所示,其實也就是數據從輸入層到輸出層,計算 loss 的過程。

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d-> view -> linear -> relu -> linear -> relu -> linear-> MSELoss-> loss

如果調用 loss.backward() ,那么整個圖都是可微分的,也就是說包括 loss ,圖中的所有張量變量,只要其屬性 requires_grad=True ,那么其梯度 .grad 張量都會隨著梯度一直累計。

用代碼來說明:

# MSELoss print(loss.grad_fn) # Linear layer print(loss.grad_fn.next_functions[0][0]) # Relu print(loss.grad_fn.next_functions[0][0].next_functions[0][0])

輸出:

<MseLossBackward object at 0x0000019C0C349908><ThAddmmBackward object at 0x0000019C0C365A58><ExpandBackward object at 0x0000019C0C3659E8>

3.3 反向傳播

反向傳播的實現只需要調用 loss.backward() 即可,當然首先需要清空當前梯度緩存,即.zero_grad() 方法,否則之前的梯度會累加到當前的梯度,這樣會影響權值參數的更新。

下面是一個簡單的例子,以 conv1 層的偏置參數 bias 在反向傳播前后的結果為例:

# 清空所有參數的梯度緩存 net.zero_grad() print('conv1.bias.grad before backward') print(net.conv1.bias.grad)loss.backward()print('conv1.bias.grad after backward') print(net.conv1.bias.grad)

輸出結果:

conv1.bias.grad before backward tensor([0., 0., 0., 0., 0., 0.])conv1.bias.grad after backward tensor([ 0.0069, 0.0021, 0.0090, -0.0060, -0.0008, -0.0073])

了解更多有關 torch.nn 庫,可以查看官方文檔:

https://pytorch.org/docs/stable/nn.html

3.4 更新權重

采用隨機梯度下降(Stochastic Gradient Descent, SGD)方法的最簡單的更新權重規則如下:

weight = weight - learning_rate * gradient

按照這個規則,代碼實現如下所示:

# 簡單實現權重的更新例子 learning_rate = 0.01 for f in net.parameters():f.data.sub_(f.grad.data * learning_rate)

但是這只是最簡單的規則,深度學習有很多的優化算法,不僅僅是 SGD,還有 Nesterov-SGD, Adam, RMSProp 等等,為了采用這些不同的方法,這里采用 torch.optim 庫,使用例子如下所示:

import torch.optim as optim # 創建優化器 optimizer = optim.SGD(net.parameters(), lr=0.01)# 在訓練過程中執行下列操作 optimizer.zero_grad() # 清空梯度緩存 output = net(input) loss = criterion(output, target) loss.backward() # 更新權重 optimizer.step()

注意,同樣需要調用 optimizer.zero_grad() 方法清空梯度緩存。

本小節教程:

https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html

本小節的代碼:

https://github.com/ccc013/DeepLearning_Notes/blob/master/Pytorch/practise/neural_network.ipynb

4. 訓練分類器

上一節介紹了如何構建神經網絡、計算 loss 和更新網絡的權值參數,接下來需要做的就是實現一個圖片分類器。

4.1 訓練數據

在訓練分類器前,當然需要考慮數據的問題。通常在處理如圖片、文本、語音或者視頻數據的時候,一般都采用標準的 Python 庫將其加載并轉成 Numpy 數組,然后再轉回為 PyTorch 的張量。

  • 對于圖像,可以采用 Pillow, OpenCV 庫;
  • 對于語音,有 scipy 和 librosa;
  • 對于文本,可以選擇原生 Python 或者 Cython 進行加載數據,或者使用 NLTK 和 SpaCy 。

PyTorch 對于計算機視覺,特別創建了一個 torchvision 的庫,它包含一個數據加載器(data loader),可以加載比較常見的數據集,比如 Imagenet, CIFAR10, MNIST 等等,然后還有一個用于圖像的數據轉換器(data transformers),調用的庫是 torchvision.datasets 和 torch.utils.data.DataLoader 。

在本教程中,將采用 CIFAR10 數據集,它包含 10 個類別,分別是飛機、汽車、鳥、貓、鹿、狗、青蛙、馬、船和卡車。數據集中的圖片都是 3x32x32。一些例子如下所示:

4.2 訓練圖片分類器

訓練流程如下:

  • 通過調用 torchvision 加載和歸一化 CIFAR10 訓練集和測試集;
  • 構建一個卷積神經網絡;
  • 定義一個損失函數;
  • 在訓練集上訓練網絡;
  • 在測試集上測試網絡性能。
  • 4.2.1 加載和歸一化 CIFAR10

    首先導入必須的包:

    import torch import torchvision import torchvision.transforms as transforms

    torchvision 的數據集輸出的圖片都是 PILImage ,即取值范圍是 [0, 1] ,這里需要做一個轉換,變成取值范圍是 [-1, 1] , 代碼如下所示:

    # 將圖片數據從 [0,1] 歸一化為 [-1, 1] 的取值范圍 transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=4,shuffle=False, num_workers=2)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')

    這里下載好數據后,可以可視化部分訓練圖片,代碼如下:

    import matplotlib.pyplot as plt import numpy as np# 展示圖片的函數 def imshow(img):img = img / 2 + 0.5 # 非歸一化npimg = img.numpy()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()# 隨機獲取訓練集圖片 dataiter = iter(trainloader) images, labels = dataiter.next()# 展示圖片 imshow(torchvision.utils.make_grid(images)) # 打印圖片類別標簽 print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

    展示圖片如下所示:

    其類別標簽為:

    frog plane dog ship
    4.2.2 構建一個卷積神經網絡

    這部分內容其實直接采用上一節定義的網絡即可,除了修改 conv1 的輸入通道,從 1 變為 3,因為這次接收的是 3 通道的彩色圖片。

    import torch.nn as nn import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = x.view(-1, 16 * 5 * 5)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xnet = Net()
    4.2.3 定義損失函數和優化器

    這里采用類別交叉熵函數和帶有動量的 SGD 優化方法:

    import torch.optim as optimcriterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
    4.2.4 訓練網絡

    第四步自然就是開始訓練網絡,指定需要迭代的 epoch,然后輸入數據,指定次數打印當前網絡的信息,比如 loss 或者準確率等性能評價標準。

    import time start = time.time() for epoch in range(2):running_loss = 0.0for i, data in enumerate(trainloader, 0):# 獲取輸入數據inputs, labels = data# 清空梯度緩存optimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 打印統計信息running_loss += loss.item()if i % 2000 == 1999:# 每 2000 次迭代打印一次信息print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))running_loss = 0.0 print('Finished Training! Total cost time: ', time.time()-start)

    這里定義訓練總共 2 個 epoch,訓練信息如下,大概耗時為 77s。

    [1, 2000] loss: 2.226 [1, 4000] loss: 1.897 [1, 6000] loss: 1.725 [1, 8000] loss: 1.617 [1, 10000] loss: 1.524 [1, 12000] loss: 1.489 [2, 2000] loss: 1.407 [2, 4000] loss: 1.376 [2, 6000] loss: 1.354 [2, 8000] loss: 1.347 [2, 10000] loss: 1.324 [2, 12000] loss: 1.311Finished Training! Total cost time: 77.24696755409241
    4.2.5 測試模型性能

    訓練好一個網絡模型后,就需要用測試集進行測試,檢驗網絡模型的泛化能力。對于圖像分類任務來說,一般就是用準確率作為評價標準。

    首先,我們先用一個 batch 的圖片進行小小測試,這里 batch=4 ,也就是 4 張圖片,代碼如下:

    dataiter = iter(testloader) images, labels = dataiter.next()# 打印圖片 imshow(torchvision.utils.make_grid(images)) print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

    圖片和標簽分別如下所示:

    GroundTruth: cat ship ship plane

    然后用這四張圖片輸入網絡,看看網絡的預測結果:

    # 網絡輸出 outputs = net(images)# 預測結果 _, predicted = torch.max(outputs, 1) print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

    輸出為:

    Predicted: cat ship ship ship

    前面三張圖片都預測正確了,第四張圖片錯誤預測飛機為船。

    接著,讓我們看看在整個測試集上的準確率可以達到多少吧!

    correct = 0 total = 0 with torch.no_grad():for data in testloader:images, labels = dataoutputs = net(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))

    輸出結果如下

    Accuracy of the network on the 10000 test images: 55 %

    這里可能準確率并不一定一樣,教程中的結果是 51% ,因為權重初始化問題,可能多少有些浮動,相比隨機猜測 10 個類別的準確率(即 10%),這個結果是不錯的,當然實際上是非常不好,不過我們僅僅采用 5 層網絡,而且僅僅作為教程的一個示例代碼。

    然后,還可以再進一步,查看每個類別的分類準確率,跟上述代碼有所不同的是,計算準確率部分是 c = (predicted == labels).squeeze(),這段代碼其實會根據預測和真實標簽是否相等,輸出 1 或者 0,表示真或者假,因此在計算當前類別正確預測數量時候直接相加,預測正確自然就是加 1,錯誤就是加 0,也就是沒有變化。

    class_correct = list(0. for i in range(10)) class_total = list(0. for i in range(10)) with torch.no_grad():for data in testloader:images, labels = dataoutputs = net(images)_, predicted = torch.max(outputs, 1)c = (predicted == labels).squeeze()for i in range(4):label = labels[i]class_correct[label] += c[i].item()class_total[label] += 1for i in range(10):print('Accuracy of %5s : %2d %%' % (classes[i], 100 * class_correct[i] / class_total[i]))

    輸出結果,可以看到貓、鳥、鹿是錯誤率前三,即預測最不準確的三個類別,反倒是船和卡車最準確。

    Accuracy of plane : 58 % Accuracy of car : 59 % Accuracy of bird : 40 % Accuracy of cat : 33 % Accuracy of deer : 39 % Accuracy of dog : 60 % Accuracy of frog : 54 % Accuracy of horse : 66 % Accuracy of ship : 70 % Accuracy of truck : 72 %

    4.3 在 GPU 上訓練

    深度學習自然需要 GPU 來加快訓練速度的。所以接下來介紹如果是在 GPU 上訓練,應該如何實現。

    首先,需要檢查是否有可用的 GPU 來訓練,代碼如下:

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print(device)

    輸出結果如下,這表明你的第一塊 GPU 顯卡或者唯一的 GPU 顯卡是空閑可用狀態,否則會打印 cpu 。

    cuda:0

    既然有可用的 GPU ,接下來就是在 GPU 上進行訓練了,其中需要修改的代碼如下,分別是需要將網絡參數和數據都轉移到 GPU 上:

    net.to(device) inputs, labels = inputs.to(device), labels.to(device)

    修改后的訓練部分代碼:

    import time # 在 GPU 上訓練注意需要將網絡和數據放到 GPU 上 net.to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)start = time.time() for epoch in range(2):running_loss = 0.0for i, data in enumerate(trainloader, 0):# 獲取輸入數據inputs, labels = datainputs, labels = inputs.to(device), labels.to(device)# 清空梯度緩存optimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 打印統計信息running_loss += loss.item()if i % 2000 == 1999:# 每 2000 次迭代打印一次信息print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))running_loss = 0.0 print('Finished Training! Total cost time: ', time.time() - start)

    注意,這里調用 net.to(device) 后,需要定義下優化器,即傳入的是 CUDA 張量的網絡參數。訓練結果和之前的類似,而且其實因為這個網絡非常小,轉移到 GPU 上并不會有多大的速度提升,而且我的訓練結果看來反而變慢了,也可能是因為我的筆記本的 GPU 顯卡問題。

    如果需要進一步提升速度,可以考慮采用多 GPUs,也就是下一節的內容。

    本小節教程:

    https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html

    本小節的代碼:

    https://github.com/ccc013/DeepLearning_Notes/blob/master/Pytorch/practise/train_classifier_example.ipynb

    5. 數據并行

    這部分教程將學習如何使用 DataParallel 來使用多個 GPUs 訓練網絡。

    首先,在 GPU 上訓練模型的做法很簡單,如下代碼所示,定義一個 device 對象,然后用 .to() 方法將網絡模型參數放到指定的 GPU 上。

    device = torch.device("cuda:0") model.to(device)

    接著就是將所有的張量變量放到 GPU 上:

    mytensor = my_tensor.to(device)

    注意,這里 my_tensor.to(device) 是返回一個 my_tensor 的新的拷貝對象,而不是直接修改 my_tensor 變量,因此你需要將其賦值給一個新的張量,然后使用這個張量。

    Pytorch 默認只會采用一個 GPU,因此需要使用多個 GPU,需要采用 DataParallel ,代碼如下所示:

    model = nn.DataParallel(model)

    這代碼也就是本節教程的關鍵,接下來會繼續詳細介紹。

    5.1 導入和參數

    首先導入必須的庫以及定義一些參數:

    import torch import torch.nn as nn from torch.utils.data import Dataset, DataLoader# Parameters and DataLoaders input_size = 5 output_size = 2batch_size = 30 data_size = 100device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    這里主要定義網絡輸入大小和輸出大小,batch 以及圖片的大小,并定義了一個 device 對象。

    5.2 構建一個假數據集

    接著就是構建一個假的(隨機)數據集。實現代碼如下:

    class RandomDataset(Dataset):def __init__(self, size, length):self.len = lengthself.data = torch.randn(length, size)def __getitem__(self, index):return self.data[index]def __len__(self):return self.lenrand_loader = DataLoader(dataset=RandomDataset(input_size, data_size),batch_size=batch_size, shuffle=True)

    5.3 簡單的模型

    接下來構建一個簡單的網絡模型,僅僅包含一層全連接層的神經網絡,加入 print() 函數用于監控網絡輸入和輸出 tensors 的大小:

    class Model(nn.Module):# Our modeldef __init__(self, input_size, output_size):super(Model, self).__init__()self.fc = nn.Linear(input_size, output_size)def forward(self, input):output = self.fc(input)print("\tIn Model: input size", input.size(),"output size", output.size())return output

    5.4 創建模型和數據平行

    這是本節的核心部分。首先需要定義一個模型實例,并且檢查是否擁有多個 GPUs,如果是就可以將模型包裹在 nn.DataParallel ,并調用 model.to(device) 。代碼如下:

    model = Model(input_size, output_size) if torch.cuda.device_count() > 1:print("Let's use", torch.cuda.device_count(), "GPUs!")# dim = 0 [30, xxx] -> [10, ...], [10, ...], [10, ...] on 3 GPUsmodel = nn.DataParallel(model)model.to(device)

    5.5 運行模型

    接著就可以運行模型,看看打印的信息:

    for data in rand_loader:input = data.to(device)output = model(input)print("Outside: input size", input.size(),"output_size", output.size())

    輸出如下:

    In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2]) Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])

    5.6 運行結果

    如果僅僅只有 1 個或者沒有 GPU ,那么 batch=30 的時候,模型會得到輸入輸出的大小都是 30。但如果有多個 GPUs,那么結果如下:

    2 GPUs
    # on 2 GPUs Let's use 2 GPUs!In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2]) Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])
    3 GPUs
    Let's use 3 GPUs!In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2]) Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])
    8 GPUs
    Let's use 8 GPUs!In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2]) Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2]) Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])

    5.7 總結

    DataParallel 會自動分割數據集并發送任務給多個 GPUs 上的多個模型。然后等待每個模型都完成各自的工作后,它又會收集并融合結果,然后返回。

    更詳細的數據并行教程:

    https://pytorch.org/tutorials/beginner/former_torchies/parallelism_tutorial.html

    本小節教程:

    https://pytorch.org/tutorials/beginner/blitz/data_parallel_tutorial.html


    小結

    教程從最基礎的張量開始介紹,然后介紹了非常重要的自動求梯度的 autograd ,接著介紹如何構建一個神經網絡,如何訓練圖像分類器,最后簡單介紹使用多 GPUs 加快訓練速度的方法。

    快速入門教程就介紹完了,接下來你可以選擇:

    • 訓練一個神經網絡來玩視頻游戲
    • 在 imagenet 上訓練 ResNet
    • 采用 GAN 訓練一個人臉生成器
    • 采用循環 LSTM 網絡訓練一個詞語級別的語言模型
    • 更多的例子
    • 更多的教程
    • 在 Forums 社區討論 PyTorch

    歡迎關注我的微信公眾號–機器學習與計算機視覺,或者掃描下方的二維碼,大家一起交流,學習和進步!

    往期精彩推薦

    機器學習系列
    • 初學者的機器學習入門實戰教程!
    • 模型評估、過擬合欠擬合以及超參數調優方法
    • 常用機器學習算法匯總比較(完)
    • 常用機器學習算法匯總比較(上)
    • 機器學習入門系列(2)–如何構建一個完整的機器學習項目(一)
    • 特征工程之數據預處理(上)
    • 來了解下計算機視覺的八大應用
    Github項目 & 資源教程推薦
    • [Github 項目推薦] 一個更好閱讀和查找論文的網站
    • [資源分享] TensorFlow 官方中文版教程來了
    • 必讀的AI和深度學習博客
    • [教程]一份簡單易懂的 TensorFlow 教程
    • [資源]推薦一些Python書籍和教程,入門和進階的都有!
    • [Github項目推薦] 機器學習& Python 知識點速查表
    • [Github項目推薦] 推薦三個助你更好利用Github的工具
    • Github上的各大高校資料以及國外公開課視頻
    • 這些單詞你都念對了嗎?順便推薦三份程序員專屬英語教程!

    總結

    以上是生活随笔為你收集整理的60分钟快速入门 PyTorch的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    又黄又爽又湿又无遮挡的在线视频 | 国产99久久九九精品免费 | 色网站黄 | 天天曰视频 | av在线免费观看黄 | 啪啪肉肉污av国网站 | 成人国产精品一区 | 91在线日韩 | 在线免费中文字幕 | 国产一级片免费视频 | 国产精品免费麻豆入口 | 久产久精国产品 | 激情五月婷婷综合网 | 99欧美视频 | 麻豆视频入口 | 精品一区二区在线免费观看 | 日韩高清片 | 韩日三级在线 | 99久久99久久精品国产片果冰 | 96亚洲精品久久久蜜桃 | 久久婷婷亚洲 | 亚洲在线日韩 | 日韩视频中文字幕在线观看 | www,黄视频 | 中文字幕在线乱 | 欧美一级片免费观看 | 在线免费视频你懂的 | 中文国产在线观看 | 一区在线观看 | av国产网站 | 激情电影影院 | 麻豆国产精品永久免费视频 | 婷婷六月天天 | 国产丝袜制服在线 | 亚洲欧美色婷婷 | 超碰97国产 | 久久亚洲综合国产精品99麻豆的功能介绍 | 99久久精品费精品 | 国产色一区 | 亚洲另类视频在线观看 | 国产h片在线观看 | 国产美女主播精品一区二区三区 | 国产美女网站视频 | 狠狠的干狠狠的操 | 国产一级黄色免费看 | 色偷偷88888欧美精品久久久 | 99精品国产一区二区三区不卡 | 国产小视频在线观看免费 | 国产 亚洲 欧美 在线 | 五月天婷亚洲天综合网鲁鲁鲁 | 亚洲免费激情 | 天天射日 | 日韩精品在线播放 | 欧美精品久久久久久久久久白贞 | 麻豆91在线播放 | 国产精品毛片一区二区在线 | 国产一区二区在线播放视频 | 93久久精品日日躁夜夜躁欧美 | 超碰97人人射妻 | 三级av在线免费观看 | 国产美女在线观看 | 久久看看| 免费黄av| 国产剧情亚洲 | 精精国产xxxx视频在线播放 | 免费在线观看av电影 | av综合 日韩| 99免在线观看免费视频高清 | 麻豆影视网站 | 成人h在线| 日日夜夜综合 | 亚洲精品国偷拍自产在线观看蜜桃 | 在线视频日韩一区 | 在线97| 狠狠色噜噜狠狠狠狠2021天天 | 国产精品成人一区二区三区吃奶 | 激情网色 | 成人久久18免费网站麻豆 | 午夜精品一区二区三区在线观看 | 免费看污的网站 | 综合在线亚洲 | 在线观看免费观看在线91 | 欧美一二三专区 | 99精品视频在线观看 | 综合国产在线 | 免费av高清 | 伊人网综合在线观看 | 日韩久久片 | 日韩免费在线一区 | 国产成人福利在线 | 中文在线字幕免费观 | 一本一本久久a久久精品综合妖精 | 国产免费视频一区二区裸体 | 久久精品这里都是精品 | 亚洲免费婷婷 | 99精品国产视频 | 一区二区三区四区五区在线 | a在线播放 | 欧美一区在线观看视频 | 亚洲资源在线 | 91福利视频一区 | 免费看黄在线观看 | a色视频 | 综合网色 | 日韩一区二区三区免费视频 | 久久精品99精品国产香蕉 | 久久久999免费视频 日韩网站在线 | 欧美精品免费在线 | 天天干视频在线 | 精品在线播放视频 | 91试看| 成人av网址大全 | 精品96久久久久久中文字幕无 | 一性一交视频 | 久香蕉 | 久草在线免费看视频 | 婷婷丁香在线观看 | 人人爽人人香蕉 | 丁香六月中文字幕 | 国产a国产a国产a | av网址aaa | 99精品久久久久久久久久综合 | 91久久精品一区二区二区 | 久久99国产视频 | 国产精品久久久区三区天天噜 | 久久久久久久久网站 | 国产精品美女在线 | 深夜免费福利在线 | 午夜av在线免费 | 精品国产视频一区 | 永久免费视频国产 | 在线观看视频在线 | 四虎成人网 | 99久久夜色精品国产亚洲96 | 波多野结衣一区二区三区中文字幕 | 成人久久18免费网站麻豆 | 香蕉在线影院 | 高清有码中文字幕 | 久久大片网站 | 久久综合狠狠综合 | 91精品麻豆 | 日韩精品中文字幕在线观看 | 夜夜看av | 国产精品成人在线 | 欧美日韩色婷婷 | 日韩一级片大全 | 日本中文在线观看 | 中文字幕日韩免费视频 | av电影在线不卡 | 亚洲国产精品视频 | 97色婷婷 | 91视频 - v11av| 久久夜靖品 | 四虎在线观看网址 | 精品国产一区二区三区四区在线观看 | 亚洲天天| 亚洲精品成人在线 | 久久视频 | 午夜在线观看影院 | 免费观看一级特黄欧美大片 | 亚洲深爱激情 | 国产精品资源 | 黄视频色网站 | 亚洲国产经典视频 | 亚洲无人区小视频 | 婷婷色在线播放 | 日韩欧美综合精品 | 欧美精品久久久 | 依人成人综合网 | 免费色网站| 少妇搡bbbb搡bbb搡69 | 亚洲在线网址 | 一本一本久久a久久精品综合 | 精品国产一区二区三区男人吃奶 | 在线观看亚洲国产 | 在线成人一区 | 亚洲粉嫩av | 91精品国产高清自在线观看 | 2018亚洲男人天堂 | www黄在线 | 免费看污网站 | 小草av在线播放 | 亚洲激情久久 | 最新亚洲视频 | 欧美午夜久久久 | 97超碰网| 日日夜日日干 | 在线播放国产精品 | 九九热在线精品 | 国产最新精品视频 | 免费看一及片 | 亚洲黄色在线免费观看 | 国产精品一区二区av影院萌芽 | 中文成人字幕 | 欧美日韩免费观看一区=区三区 | 中文字幕在线视频一区 | 伊人黄色网 | 97日日碰人人模人人澡分享吧 | 99久久久久久国产精品 | 久草在线免 | 在线播放91 | 97看片吧 | 天天综合视频在线观看 | 国产一级免费在线观看 | 国产免费观看高清完整版 | 久久字幕精品一区 | 国产精品久久久久久久久免费 | 国产免费观看av | 亚洲va欧洲va国产va不卡 | 国产成人久久av免费高清密臂 | 99精品在线视频观看 | 国产精品成人在线 | 日韩免费在线看 | 久久在现 | 在线观看精品黄av片免费 | 午夜视频一区二区三区 | adn—256中文在线观看 | 久久草在线视频国产 | 亚洲精品美女久久17c | 91麻豆精品国产自产在线游戏 | 99视频精品在线 | 国产亚洲成人精品 | 美女av免费| 久久精品中文字幕 | 色香蕉网 | 成人中心免费视频 | 久久爱影视i| 国产亚洲精品中文字幕 | 狠狠干狠狠艹 | 黄网站a | 中文字幕一区二区三区四区久久 | 色中色综合| 欧美精品一区二区三区四区在线 | 大胆欧美gogo免费视频一二区 | 中文伊人| 91九色视频在线播放 | 欧美巨乳波霸 | 人人爱人人做人人爽 | 一区二区电影在线观看 | 久久精品一区二区三区四区 | 成人91在线观看 | 日韩乱理| 精品国产91亚洲一区二区三区www | 天堂av在线| 久久av黄色 | 日韩美av在线| 国产精品原创视频 | 欧美日韩国产区 | 精品国产成人av在线免 | 亚洲欧美999| 中文字幕在线成人 | 国产一区精品在线 | 婷婷亚洲激情 | 久草资源免费 | 中文字幕乱在线伦视频中文字幕乱码在线 | 永久免费视频国产 | 国产成人精品综合久久久久99 | 一级黄色片在线免费看 | 天天操天天爱天天干 | 久久艹在线观看 | 在线观看一区视频 | 四虎亚洲精品 | 91天天操| bbbbb女女女女女bbbbb国产 | 在线视频日韩欧美 | 亚洲精品国产成人av在线 | 最近高清中文字幕在线国语5 | 射射射av| 91精品一 | 99免费精品 | 久青草视频| av性在线 | 九九视频免费观看视频精品 | 国产一区二区久久 | 成人国产精品电影 | 热久久这里只有精品 | 色操插| zzijzzij亚洲日本少妇熟睡 | 久久亚洲私人国产精品va | 精品国产亚洲日本 | 免费高清看电视网站 | 久久最新视频 | 欧美日韩性视频在线 | 9在线观看免费高清完整版在线观看明 | 免费成人av电影 | 米奇狠狠狠888| 中文字幕观看av | 99精品在线观看视频 | 久久久免费看视频 | www黄色av| 亚洲永久精品一区 | 在线不卡视频 | 日本久久电影 | 亚洲国产影院 | 成人亚洲免费 | 91av视频在线播放 | 午夜.dj高清免费观看视频 | 欧美国产日韩激情 | 国产成人免费观看久久久 | 久草免费资源 | 久久精品老司机 | 成人免费在线电影 | 日韩视频图片 | 中文字幕资源网在线观看 | 综合久久2023 | 久草在线视频首页 | 免费av在线网 | 天天操夜 | 成人在线播放免费观看 | av在线免费观看网站 | 香蕉在线视频播放网站 | 69亚洲乱 | 国产精品99久久久精品免费观看 | 亚洲 欧美 另类人妖 | 女人18片| 日韩欧美中文 | 亚洲视频精品在线 | 日韩精品观看 | 91桃色在线免费观看 | 2024国产精品视频 | 国产一区二区三区在线免费观看 | 亚洲国产视频网站 | 美女网站在线免费观看 | 五月花丁香婷婷 | 久久久免费观看 | 国产视频亚洲 | 亚洲免费在线播放视频 | 美女福利视频在线 | 国产精品免费久久久久久久久久中文 | 特级毛片在线免费观看 | 在线日韩亚洲 | 亚洲精品中文字幕视频 | 亚洲成人免费在线 | 亚洲视频六区 | 麻豆91在线看 | 制服丝袜一区二区 | 福利一区在线视频 | 日本三级不卡视频 | 黄a在线观看 | 国产又黄又爽无遮挡 | 激情综合一区 | 国产精品成人免费精品自在线观看 | 美女天天操 | 国产精品免费小视频 | 九九热99视频 | 国产精品v a免费视频 | 91久色蝌蚪 | 亚洲一级特黄 | 久久免费成人精品视频 | 久草在线视频首页 | 久久久久久久久久电影 | 99热在线国产 | 欧美性色综合网 | 天天看天天干 | 福利一区在线 | 天天狠狠| 网站免费黄色 | 国产91aaa| 国产黄视频在线观看 | 精品久久久久久一区二区里番 | 久久理论视频 | 欧美地下肉体性派对 | 日韩爱爱片 | 久久国产精品一国产精品 | 韩国在线一区 | 国产免费又粗又猛又爽 | 久久不卡国产精品一区二区 | 国产一级免费av | 99精品在线观看 | 欧美色图视频一区 | 国产一区播放 | 国产成人在线播放 | 国产不卡视频在线播放 | 成人免费观看电影 | 国产中文字幕一区 | 久久不卡av| 婷婷色视频 | 国产精品99久久久久久大便 | 黄色亚洲在线 | 中文国产字幕在线观看 | 人人干狠狠操 | 亚洲永久字幕 | 亚洲天天看| 成人av一区二区在线观看 | 精品99久久久久久 | 6080yy午夜一二三区久久 | 97在线精品视频 | 一级黄色在线视频 | 免费观看一区二区三区视频 | 久久精品5| 久久久精品国产免费观看一区二区 | 五月开心六月伊人色婷婷 | 久久久高清一区二区三区 | 91在线中字 | 高清国产在线一区 | 日韩免费一区二区在线观看 | 国产精品99久久久久久人免费 | 日韩免费观看高清 | 91久久人澡人人添人人爽欧美 | 激情综合色综合久久综合 | 国产一区私人高清影院 | 成人小视频在线免费观看 | 久久手机在线视频 | 最新中文字幕在线资源 | av网在线观看 | 久久久精品福利视频 | 伊人电影在线观看 | av免费网站观看 | 香蕉在线视频播放网站 | 久草在线视频免费资源观看 | 国产精品一区二区三区免费看 | 国产成人av在线 | 国产.精品.日韩.另类.中文.在线.播放 | 日韩艹| 成人黄色免费在线观看 | 国产精品久久久久一区二区 | 久草免费在线 | 国产成人在线精品 | 久久视频精品在线观看 | www麻豆视频 | 黄色三级网站 | 久久精品99久久久久久 | 免费在线激情视频 | 欧美日韩观看 | 久久久久久久网站 | 国产精品免费久久久久久久久久中文 | 操久在线 | 香蕉久久久久久av成人 | 国产视频一| 成人小视频在线 | 中文字幕在线日本 | 久久伊人操 | 91av资源在线 | 91污污视频在线观看 | 天天天干天天天操 | 91精品一区国产高清在线gif | 日韩欧美视频一区 | www日韩视频 | 亚洲欧美日韩中文在线 | 成年人电影免费在线观看 | 99久免费精品视频在线观看 | 亚洲视频一级 | 成人一级黄色片 | 九九热免费在线视频 | 九月婷婷人人澡人人添人人爽 | 国产免费资源 | 国产精品中文 | 91网址在线 | 91九色成人 | 7777精品伊人久久久大香线蕉 | 精品亚洲免费 | 18性欧美xxxⅹ性满足 | 奇米影视在线99精品 | 在线精品亚洲一区二区 | 日韩精品一区二区三区第95 | 久久99日韩 | 四虎成人免费观看 | av资源免费看 | 国产中文字幕在线免费观看 | 亚洲丝袜一区 | 亚洲精品久久久久久久蜜桃 | 亚洲精品观看 | 久久免费国产精品 | 国产精品一区二区无线 | www.色婷婷 | 五月婷婷六月丁香 | 999久久久久久久久久久 | 欧美性生活小视频 | 日韩动漫免费观看高清完整版在线观看 | 成年人国产视频 | 在线成人一区二区 | 91精品国自产在线观看欧美 | 偷拍视频一区 | 成人黄色片免费看 | 免费久草视频 | 久久手机视频 | 国产一区二区观看 | 99精彩视频在线观看免费 | 蜜桃视频成人在线观看 | av一区二区三区在线 | 国产精品久久久久影院日本 | 欧美色图p | 亚洲狠狠操 | 国产成人精品av久久 | 精品久久久国产 | 国产一线二线三线性视频 | 91传媒激情理伦片 | 国产小视频在线免费观看 | 香蕉91视频 | 久久久影片 | 欧美日韩精品在线观看视频 | 免费看一级 | 91av在线播放| 色橹橹欧美在线观看视频高清 | 日韩特级毛片 | 久草视频在线播放 | 日韩精品一卡 | 国产精品www | 午夜精品久久久久久久久久久久久久 | 亚洲国产影院av久久久久 | 亚洲伦理一区 | 五月天久久综合网 | 亚洲激情影院 | 亚洲人人网 | 天天操天天是 | 国产日产精品久久久久快鸭 | 欧美日韩中文在线观看 | 国产精品理论在线观看 | 五月在线视频 | 草久在线观看 | 色人久久 | 久草国产在线观看 | 777奇米四色 | 久久99精品久久久久久久久久久久 | 在线观看一区二区视频 | 欧美资源 | 久久精品视频4 | 亚洲一二三区精品 | 91人人射| 亚洲激情在线 | 久久久免费高清视频 | 久久综合狠狠综合久久狠狠色综合 | 国产午夜精品一区二区三区 | 日韩精品亚洲专区在线观看 | 婷婷去俺也去六月色 | 亚洲精品国精品久久99热一 | 欧美激情视频一区 | 国产裸体无遮挡 | www.国产在线观看 | 九色福利视频 | 免费网站在线观看成人 | 99国产精品久久久久久久久久 | 国产精品女同一区二区三区久久夜 | 久久色视频 | 午夜视频在线网站 | 午夜av不卡| 日批视频在线 | 国产精品手机在线 | 午夜av免费观看 | 黄色毛片在线 | 在线观看爱爱视频 | 最近中文字幕大全中文字幕免费 | 麻豆一区二区三区视频 | 中文资源在线播放 | 日韩欧美视频在线 | 97精品超碰一区二区三区 | 在线视频黄 | 久久久久久久久国产 | 综合婷婷久久 | 91av视频免费在线观看 | 免费黄色网址大全 | 久久九九九九 | 一区中文字幕电影 | 九九九免费视频 | 国产高清视频网 | 91人人爽人人爽人人精88v | 久久艹精品 | av中文字幕网站 | 亚洲黄色免费在线看 | 欧美性大战久久久久 | 色综合天天狠狠 | 日韩剧情| 久久久91精品国产一区二区精品 | 97品白浆高清久久久久久 | 韩国在线视频一区 | 激情综合网在线观看 | 麻豆国产精品永久免费视频 | 天天操综| 久久五月婷婷丁香社区 | 亚洲成人动漫在线观看 | 香蕉影视在线观看 | 亚洲一级电影在线观看 | 久久综合免费视频影院 | 久久久免费精品 | www.香蕉| 国产美女黄网站免费 | 国产精品69久久久久 | 蜜臀久久99精品久久久无需会员 | 色偷偷88欧美精品久久久 | 九九热av| 国产精品原创视频 | av 一区二区三区 | 最近高清中文在线字幕在线观看 | 午夜av在线播放 | 九九久久久久久久久激情 | 久久视了| 国内精品久久久久久久久久久 | 亚洲黄色a| 成人精品久久久 | 日韩在线观看你懂得 | 久久99精品国产 | 在线电影 一区 | 久久99国产综合精品免费 | 在线观看国产中文字幕 | 亚洲婷婷网 | 丰满少妇麻豆av | 九九爱免费视频 | 久久精品视频在线观看免费 | 日韩一区在线播放 | 有没有在线观看av | 在线观看黄污 | 久草在线视频在线 | 99免费在线观看视频 | 成人av高清在线 | 久久综合九色综合97婷婷女人 | 91丨九色丨高潮丰满 | 日韩美女久久 | 成人黄色在线电影 | 久久热亚洲 | 五月天久久久久久 | 99视频一区二区 | 91香蕉亚洲精品 | 日本中文字幕在线一区 | 国产1区在线观看 | 国产91全国探花系列在线播放 | 国产美女视频一区 | 色天天综合久久久久综合片 | 91麻豆传媒 | a在线视频v视频 | 国产一区成人 | 亚洲区另类春色综合小说 | 色999视频| www国产亚洲精品久久麻豆 | 免费a v在线 | 伊人丁香 | 欧美a级片免费看 | 最新国产视频 | 日韩免费成人av | 日本久久中文 | 国内精品99 | 九九99视频| 视频一区亚洲 | 成 人 黄 色 视频播放1 | 精品国偷自产国产一区 | 成 人 免费 黄 色 视频 | 99国产视频 | 久久激情综合网 | 美女露久久 | 色视频在线看 | 国产精品资源在线观看 | 天堂av在线网址 | 亚洲精品乱码久久久一二三 | 在线导航福利 | 国产黄色免费观看 | 中文区中文字幕免费看 | 99 精品 在线 | 久久精品国产免费看久久精品 | 午夜精品导航 | 亚州av成人 | 亚洲人人网 | 国产99久久久国产精品免费看 | 亚洲男模gay裸体gay | 91在线播 | 精品99免费 | 综合久久影院 | www.超碰 | 国产精品九九久久久久久久 | 中文字幕色婷婷在线视频 | 欧美在线一二区 | 81精品国产乱码久久久久久 | 亚洲电影一区二区 | 免费a网 | 久久综合成人 | 99久久久国产精品免费99 | 九九热精品视频在线观看 | 在线观看一级视频 | 91视频免费看片 | 99久久夜色精品国产亚洲 | 精品在线视频观看 | 亚洲国内精品 | 日韩精品大片 | 中文字幕网站视频在线 | 91视频观看免费 | 久久人人爽人人爽 | 国产亚洲人成网站在线观看 | 99精品在线视频播放 | 一区免费观看 | 欧美日韩二三区 | 91精品国产亚洲 | 免费国产黄线在线观看视频 | 欧美伊人网 | 免费日韩 精品中文字幕视频在线 | 久久久国产精品久久久 | 夜夜操天天操 | 国产黄大片 | 日韩免费一区二区在线观看 | 欧美日韩国产精品久久 | 特黄免费av | 国产亚洲永久域名 | 日韩在线视 | 麻豆免费精品视频 | 99 色 | 久久艹免费 | 国产精品岛国久久久久久久久红粉 | 成人教育av | 久久国产三级 | 亚洲国产中文在线观看 | 国产成人精品福利 | 中文字幕三区 | 国产一区视频在线 | 狠狠干天天 | 一区二区三区在线电影 | 国产手机视频精品 | 日日夜夜操av | 尤物一区二区三区 | 日韩欧美国产精品 | 天天干天天怕 | 国产综合香蕉五月婷在线 | 午夜婷婷综合 | 久久成人精品电影 | 久久久99精品免费观看app | 国产视频精选在线 | 久久爱导航 | 超碰97人人爱 | 久久午夜影视 | 国内精品99 | 国产精品1区2区在线观看 | 国产欧美精品一区二区三区四区 | 欧美日韩首页 | 91成人在线观看喷潮 | 精品久久一区 | 国产不卡在线播放 | 四虎影视精品永久在线观看 | 911免费视频 | 中文一区在线观看 | 成人欧美一区二区三区在线观看 | 午夜一级免费电影 | 黄色官网在线观看 | 久久精品com | 久久久久久国产精品999 | www.夜色.com | 中文字幕在线观看免费 | 免费av在线 | 97超碰免费在线观看 | 成人精品亚洲 | 91高清免费 | 在线天堂日本 | 久久美女精品 | 成人片在线播放 | 免费中文字幕视频 | 久久一级电影 | av免费网站 | 亚洲资源片 | 成人黄色av网站 | wwwww.国产 | 成人a大片 | 国产高清绿奴videos | 精品中文字幕在线观看 | 久久精品国产成人精品 | 97视频在线免费 | 视频三区在线 | 国产精品成久久久久三级 | 日本久久久久久科技有限公司 | 国产精品精品久久久久久 | 99精品视频在线 | 国产高清视频在线观看 | 亚洲欧美综合精品久久成人 | av丝袜美腿 | 韩国av永久免费 | 午夜av影院 | 88av视频 | 久久精品一区二区国产 | 日韩毛片久久久 | 国产高清视频在线播放 | 亚洲国产欧美在线人成大黄瓜 | 91在线观看欧美日韩 | 色激情在线 | 日韩av在线免费看 | 日韩av电影一区 | 精品国产一区二区三区免费 | 亚洲精品影视 | 色网站国产精品 | 精品伊人久久久 | 久久艹国产 | 天天操导航 | 国产精品久久久久久久久久久久久 | 激情喷水 | 免费亚洲精品视频 | 欧美大片www | 夜夜躁狠狠躁日日躁视频黑人 | 国产免费一区二区三区最新 | 亚洲成av人电影 | 日韩成人免费观看 | 日韩综合视频在线观看 | 久久精品网站免费观看 | 久久久免费精品 | 久久视频这里只有精品 | 美女网站免费福利视频 | 欧美一区二区免费在线观看 | 探花视频在线版播放免费观看 | 天天在线免费视频 | 亚洲欧洲在线视频 | 在线观看视频你懂的 | 日本在线精品视频 | 亚洲性少妇性猛交wwww乱大交 | 开心综合网 | 日韩中文在线播放 | 日韩精品久久久 | 欧美ⅹxxxxxx| 日韩精品久久久久久久电影竹菊 | 2019av在线视频 | 天堂网一区二区 | 成人小视频在线播放 | 天天射狠狠干 | 激情丁香5月 | 日韩免费一区 | 久草视频免费 | 99精品久久精品一区二区 | 1024久久 | 亚a在线| 日日摸日日 | 免费开视频 | 中文字幕在线观看第二页 | 国产亚洲精品美女 | 国产视频手机在线 | 天天综合网~永久入口 | 黄色网址中文字幕 | 曰本免费av | 探花视频免费在线观看 | 99精品在线观看视频 | 国产一区二区高清 | 日韩二区在线播放 | 91精品伦理| 国产一区二区在线免费观看 | 中文字幕影片免费在线观看 | 午夜资源站 | 午夜一级免费电影 | 三级视频片 | 久久综合婷婷综合 | 天天av在线播放 | 天天综合网久久综合网 | 国产99久久久精品视频 | 国产福利精品在线观看 | 81国产精品久久久久久久久久 | 五月婷婷一区二区三区 | 免费人成网ww44kk44 | www.久久色 | 国产一区二区久久久久 | 午夜精品久久久 | 青青草国产免费 | 国产伦理精品一区二区 | 国产毛片在线 | 一区 二区电影免费在线观看 | 999久久久久久久久久久 | 国产精品99久久久久久人免费 | 国产精品岛国久久久久久久久红粉 | 天天操欧美 | 五月天综合网站 | 国产伦理久久精品久久久久_ | 久久一区二区三区四区 | 99这里只有久久精品视频 | 国内精品亚洲 | 亚洲精品免费看 | 黄色91免费观看 | 91人人人 | 中文资源在线官网 | 在线观看91视频 | 91久久国产露脸精品国产闺蜜 | 国产成人中文字幕 | 国产免费黄视频在线观看 | 国产手机视频 | 国产精品视频最多的网站 | 日本电影黄色 | 国产一级在线 | 中文字幕不卡在线88 | 欧美日本国产在线观看 | 特级免费毛片 | 91视频88av| 99在线高清视频在线播放 | 亚洲欧美婷婷六月色综合 | 97在线精品视频 | 久久精品小视频 | 亚洲欧美婷婷六月色综合 | 伊人av综合 | 欧美一级片免费 | 国产精品美女久久久网av | 色婷久久 | 欧美在线a视频 | 00av视频 | 国产视频日本 | 91传媒在线看 | 亚洲天堂网在线视频 | 你操综合 | 超碰国产人人 | 玖玖视频国产 | 天天操天天操一操 | 粉嫩av一区二区三区入口 | 中文在线最新版天堂 | 婷婷激情站 | 久久免费观看视频 | 成人毛片在线视频 | 国产999精品久久久影片官网 | 在线播放视频一区 | 欧美激情精品久久久久久变态 | 一区二区三区电影大全 | 高清av中文在线字幕观看1 | 国产亚洲一区 | 国产xx在线| www.综合网.com | 久久免费av电影 | 91色综合| 欧美va天堂va视频va在线 | 日韩精品一区二区三区在线视频 | 在线综合色 | 黄色av免费看| 超碰国产在线 | 在线小视频你懂得 | av中文字幕在线观看网站 | 亚洲欧美日韩国产精品一区午夜 | 在线导航福利 | 国产欧美综合视频 | 操碰av| 六月色婷婷 | 一本色道久久精品 | 久久精品直播 | 成人国产电影在线观看 | 欧美日韩国产精品爽爽 | 中文电影网 | 国产区精品视频 | 中文字幕日韩一区二区三区不卡 | 亚洲精品国久久99热 | 亚洲免费在线观看视频 | 天天爱天天草 | 国产亚洲欧美日韩高清 | 亚洲乱码中文字幕综合 | 91c网站色版视频 | 最新亚洲视频 | 亚洲精选在线观看 | www.狠狠| 五月综合在线观看 | 91精品国自产在线偷拍蜜桃 | 日本在线观看中文字幕 | 麻豆成人网 | www.精选视频.com | 久草在在线视频 | 国产美女精品视频免费观看 | 国产精品久久久久久久久久ktv | 在线免费看黄色 | 人人草在线观看 | 正在播放 国产精品 | 中文字幕在线播放第一页 | 日韩欧美一区二区不卡 | 高清中文字幕 | 中文字幕在线字幕中文 | 91丨九色丨91啦蝌蚪老版 | 欧美一二三视频 | 久久这里只有精品23 | 麻豆传媒视频在线免费观看 | 国产精品毛片完整版 | 狠狠干中文字幕 | 欧美日韩免费观看一区=区三区 | 在线看黄网站 | 日韩精品免费一区 | 天天操天天色天天射 | 国产在线视频不卡 | 在线看片日韩 | 久草视频在线资源站 | 一区二区中文字幕在线播放 | 欧美日韩大片在线观看 | 亚洲精品在线观看网站 | 国产精品视频 | 成人av网站在线 | 在线播放日韩av | 人人射 | 视频在线精品 | 欧美a√大片 | 色视频成人在线观看免 | 免费a网站| 丁香六月在线观看 | 国产中文字幕一区二区三区 | 亚洲一级在线观看 | 久久视频中文字幕 | 99精品小视频 | 九九热免费在线视频 | 亚洲三级在线免费观看 | 黄色成人毛片 | 国产精品久久久久久久久久妇女 | 精精国产xxxx视频在线播放 | 亚洲欧美成人综合 | 国产精品国产亚洲精品看不卡 | 久久久福利视频 | 亚洲理论在线观看电影 | 97国产人人 | 久久精品香蕉 | av在线电影播放 | 在线观看亚洲精品视频 | 国产福利免费在线观看 | 午夜男人影院 | 中文字幕在线观看第一区 | 午夜天使 | 久草网在线视频 | 国产精品18久久久久久久 | 精品国产久 | 国产又粗又猛又爽 | 91porny九色91啦中文 | 久久久久久美女 | 亚洲国产成人精品久久 | 免费看三片 |