小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

教程 | 從頭開始了解PyTorch的簡(jiǎn)單實(shí)現(xiàn)

 長(zhǎng)沙7喜 2018-04-12

本教程展示了如何從了解張量開始到使用 PyTorch 訓(xùn)練簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò),是非常基礎(chǔ)的 PyTorch 入門資源。PyTorch 建立在 Python 和 Torch 庫(kù)之上,并提供了一種類似 Numpy 的抽象方法來表征張量(或多維數(shù)組),它還能利用 GPU 來提升性能。本教程的代碼并不完整,詳情請(qǐng)查看原 Jupyter Notebook 文檔。

PyTorch 使入門深度學(xué)習(xí)變得簡(jiǎn)單,即使你這方面的背景知識(shí)不太充足。至少,知道多層神經(jīng)網(wǎng)絡(luò)模型可視為由權(quán)重連接的節(jié)點(diǎn)圖就是有幫助的,你可以基于前向和反向傳播,利用優(yōu)化過程(如梯度計(jì)算)從數(shù)據(jù)中估計(jì)權(quán)重。

  • 必備知識(shí):該教程假設(shè)讀者熟悉 Python 和 NumPy。

  • 必備軟件:在運(yùn)行原 Jupyter Notebook 之前你需要安裝 PyTorch。原 Notebook 有代碼單元格可供驗(yàn)證你是否做好準(zhǔn)備。

  • 必備硬件:你需要安裝 NVIDIA GPU 和 CUDA SDK。據(jù)報(bào)告此舉可能實(shí)現(xiàn) 10-100 的加速。當(dāng)然,如果你沒有進(jìn)行此設(shè)置,那么你仍然可以在僅使用 CPU 的情況下運(yùn)行 PyTorch。但是,記住,在訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型時(shí),生命苦短!所以還是盡可能使用 GPU 吧!

項(xiàng)目地址:https://github.com/hpcgarage/accelerated_dl_pytorch

1. 必要的 PyTorch 背景

  • PyTorch 是一個(gè)建立在 Torch 庫(kù)之上的 Python 包,旨在加速深度學(xué)習(xí)應(yīng)用。

  • PyTorch 提供一種類似 NumPy 的抽象方法來表征張量(或多維數(shù)組),它可以利用 GPU 來加速訓(xùn)練。

教程 | 從頭開始了解PyTorch的簡(jiǎn)單實(shí)現(xiàn)

1.1 PyTorch 張量

PyTorch 的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)是張量,即多維數(shù)組。其功能與 NumPy 的 ndarray 對(duì)象類似,如下我們可以使用 torch.Tensor() 創(chuàng)建張量。

# Generate a 2-D pytorch tensor (i.e., a matrix)

pytorch_tensor = torch.Tensor(10, 20)

print("type: ", type(pytorch_tensor), " and size: ", pytorch_tensor.shape )

如果你需要一個(gè)兼容 NumPy 的表征,或者你想從現(xiàn)有的 NumPy 對(duì)象中創(chuàng)建一個(gè) PyTorch 張量,那么就很簡(jiǎn)單了。

# Convert the pytorch tensor to a numpy array:

numpy_tensor = pytorch_tensor.numpy()

print("type: ", type(numpy_tensor), " and size: ", numpy_tensor.shape)

# Convert the numpy array to Pytorch Tensor:

print("type: ", type(torch.Tensor(numpy_tensor)), " and size: ", torch.Tensor(numpy_tensor).shape)

1.2 PyTorch vs. NumPy

PyTorch 并不是 NumPy 的簡(jiǎn)單替代品,但它實(shí)現(xiàn)了很多 NumPy 功能。其中有一個(gè)不便之處是其命名規(guī)則,有時(shí)候它和 NumPy 的命名方法相當(dāng)不同。我們來舉幾個(gè)例子說明其中的區(qū)別:

1 張量創(chuàng)建

t = torch.rand(2, 4, 3, 5)

a = np.random.rand(2, 4, 3, 5)

2 張量分割

a = t.numpy()

pytorch_slice = t[0, 1:3, :, 4]

numpy_slice = a[0, 1:3, :, 4]

print ('Tensor[0, 1:3, :, 4]:\n', pytorch_slice)

print ('NdArray[0, 1:3, :, 4]:\n', numpy_slice)

-------------------------------------------------------------------------

Tensor[0, 1:3, :, 4]:

0.2032 0.1594 0.3114

0.9073 0.6497 0.2826

[torch.FloatTensor of size 2x3]

NdArray[0, 1:3, :, 4]:

[[ 0.20322084 0.15935552 0.31143939]

[ 0.90726137 0.64966112 0.28259504]]

3 張量

Maskingt = t - 0.5

pytorch_masked = t[t > 0]

numpy_masked = a[a > 0]

4 張量重塑

pytorch_reshape = t.view([6, 5, 4])

numpy_reshape = a.reshape([6, 5, 4])

1.3 PyTorch 變量

  • PyTorch 張量的簡(jiǎn)單封裝

  • 幫助建立計(jì)算圖

  • Autograd(自動(dòng)微分庫(kù))的必要部分

  • 將關(guān)于這些變量的梯度保存在 .grad 中

教程 | 從頭開始了解PyTorch的簡(jiǎn)單實(shí)現(xiàn)

結(jié)構(gòu)圖:

教程 | 從頭開始了解PyTorch的簡(jiǎn)單實(shí)現(xiàn)

計(jì)算圖和變量:在 PyTorch 中,神經(jīng)網(wǎng)絡(luò)會(huì)使用相互連接的變量作為計(jì)算圖來表示。PyTorch 允許通過代碼構(gòu)建計(jì)算圖來構(gòu)建網(wǎng)絡(luò)模型;之后 PyTorch 會(huì)簡(jiǎn)化估計(jì)模型權(quán)重的流程,例如通過自動(dòng)計(jì)算梯度的方式。

舉例來說,假設(shè)我們想構(gòu)建兩層模型,那么首先要為輸入和輸出創(chuàng)建張量變量。我們可以將 PyTorch Tensor 包裝進(jìn) Variable 對(duì)象中:

from torch.autograd import Variable

import torch.nn.functional as F

x = Variable(torch.randn(4, 1), requires_grad=False)

y = Variable(torch.randn(3, 1), requires_grad=False)

我們把 requires_grad 設(shè)置為 True,表明我們想要自動(dòng)計(jì)算梯度,這將用于反向傳播中以優(yōu)化權(quán)重。

現(xiàn)在我們來定義權(quán)重:

w1 = Variable(torch.randn(5, 4), requires_grad=True)

w2 = Variable(torch.randn(3, 5), requires_grad=True)

訓(xùn)練模型:

def model_forward(x):

return F.sigmoid(w2 @ F.sigmoid(w1 @ x))

print (w1)

print (w1.data.shape)

print (w1.grad) # Initially, non-existent

Variable containing:

1.6068 -1.3304 -0.6717 -0.6097

-0.3414 -0.5062 -0.2533 1.0260

-0.0341 -1.2144 -1.5983 -0.1392

-0.5473 0.0084 0.4054 0.0970

0.3596 0.5987 -0.0324 0.6116

[torch.FloatTensor of size 5x4]

torch.Size([5, 4])

None

1.4 PyTorch 反向傳播

這樣我們有了輸入和目標(biāo)、模型權(quán)重,那么是時(shí)候訓(xùn)練模型了。我們需要三個(gè)組件:

損失函數(shù):描述我們模型的預(yù)測(cè)距離目標(biāo)還有多遠(yuǎn);

import torch.nn as nncriterion = nn.MSELoss()

優(yōu)化算法:用于更新權(quán)重;

import torch.optim as optimoptimizer = optim.SGD([w1, w2], lr=0.001)

反向傳播步驟:

for epoch in range(10):

loss = criterion(model_forward(x), y)

optimizer.zero_grad() # Zero-out previous gradients

loss.backward() # Compute new gradients

optimizer.step() # Apply these gradients

1.6067 -1.3303 -0.6717 -0.6095

-0.3414 -0.5062 -0.2533 1.0259

-0.0340 -1.2145 -1.5983 -0.1396

-0.5476 0.0085 0.4055 0.0976

0.3597 0.5986 -0.0324 0.6113

1.5 PyTorch CUDA 接口

PyTorch 的優(yōu)勢(shì)之一是為張量和 autograd 庫(kù)提供 CUDA 接口。使用 CUDA GPU,你不僅可以加速神經(jīng)網(wǎng)絡(luò)訓(xùn)練和推斷,還可以加速任何映射至 PyTorch 張量的工作負(fù)載。

你可以調(diào)用 torch.cuda.is_available() 函數(shù),檢查 PyTorch 中是否有可用 CUDA。

cuda_gpu = torch.cuda.is_available()

if (cuda_gpu):

print("Great, you have a GPU!")

else:

print("Life is short -- consider a GPU!")

很好,現(xiàn)在你有 GPU 了。

.cuda()

之后,使用 cuda 加速代碼就和調(diào)用一樣簡(jiǎn)單。如果你在張量上調(diào)用 .cuda(),則它將執(zhí)行從 CPU 到 CUDA GPU 的數(shù)據(jù)遷移。如果你在模型上調(diào)用 .cuda(),則它不僅將所有內(nèi)部?jī)?chǔ)存移到 GPU,還將整個(gè)計(jì)算圖映射至 GPU。

要想將張量或模型復(fù)制回 CPU,比如想和 NumPy 交互,你可以調(diào)用 .cpu()。

if cuda_gpu:

x = x.cuda()

print(type(x.data))

x = x.cpu()

print(type(x.data))

<class 'torch.cuda.FloatTensor'>

<class 'torch.FloatTensor'>

我們來定義兩個(gè)函數(shù)(訓(xùn)練函數(shù)和測(cè)試函數(shù))來使用我們的模型執(zhí)行訓(xùn)練和推斷任務(wù)。該代碼同樣來自 PyTorch 官方教程,我們摘選了所有訓(xùn)練/推斷的必要步驟。

對(duì)于訓(xùn)練和測(cè)試網(wǎng)絡(luò),我們需要執(zhí)行一系列動(dòng)作,這些動(dòng)作可直接映射至 PyTorch 代碼:

1. 我們將模型轉(zhuǎn)換到訓(xùn)練/推斷模式;

2. 我們通過在數(shù)據(jù)集上成批獲取圖像,以迭代訓(xùn)練模型;

3. 對(duì)于每一個(gè)批量的圖像,我們都要加載數(shù)據(jù)和標(biāo)注,運(yùn)行網(wǎng)絡(luò)的前向步驟來獲取模型輸出;

4. 我們定義損失函數(shù),計(jì)算每一個(gè)批量的模型輸出和目標(biāo)之間的損失;

5. 訓(xùn)練時(shí),我們初始化梯度為零,使用上一步定義的優(yōu)化器和反向傳播,來計(jì)算所有與損失有關(guān)的層級(jí)梯度;

6. 訓(xùn)練時(shí),我們執(zhí)行權(quán)重更新步驟。

def train(model, epoch, criterion, optimizer, data_loader):

model.train()

for batch_idx, (data, target) in enumerate(data_loader):

if cuda_gpu:

data, target = data.cuda(), target.cuda()

model.cuda()

data, target = Variable(data), Variable(target)

output = model(data)

optimizer.zero_grad()

loss = criterion(output, target)

loss.backward()

optimizer.step()

if (batch_idx+1) % 400 == 0:

print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(

epoch, (batch_idx+1) * len(data), len(data_loader.dataset),

100. * (batch_idx+1) / len(data_loader), loss.data[0]))

def test(model, epoch, criterion, data_loader):

model.eval()

test_loss = 0

correct = 0

for data, target in data_loader:

test_loss += criterion(output, target).data[0]

pred = output.data.max(1)[1] # get the index of the max log-probability

correct += pred.eq(target.data).cpu().sum()

test_loss /= len(data_loader) # loss function already averages over batch size

acc = correct / len(data_loader.dataset)

print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(

test_loss, correct, len(data_loader.dataset), 100. * acc))

return (acc, test_loss)

現(xiàn)在介紹完畢,讓我們開始這次數(shù)據(jù)科學(xué)之旅吧!

2. 使用 PyTorch 進(jìn)行數(shù)據(jù)分析

使用 torch.nn 庫(kù)構(gòu)建模型

使用 torch.autograd 庫(kù)訓(xùn)練模型

將數(shù)據(jù)封裝進(jìn) torch.utils.data.Dataset 庫(kù)

使用 NumPy interface 連接你的模型、數(shù)據(jù)和你最喜歡的工具

在查看復(fù)雜模型之前,我們先來看個(gè)簡(jiǎn)單的:簡(jiǎn)單合成數(shù)據(jù)集上的線性回歸,我們可以使用 sklearn 工具生成這樣的合成數(shù)據(jù)集。

from sklearn.datasets import make_regression

import seaborn as sns

import pandas as pd

import matplotlib.pyplot as plt

sns.set()

x_train, y_train, W_target = make_regression(n_samples=100, n_features=1, noise=10, coef = True)

df = pd.DataFrame(data = {'X':x_train.ravel(), 'Y':y_train.ravel()})

sns.lmplot(x='X', y='Y', data=df, fit_reg=True)

plt.show()

x_torch = torch.FloatTensor(x_train)

y_torch = torch.FloatTensor(y_train)

y_torch = y_torch.view(y_torch.size()[0], 1)

教程 | 從頭開始了解PyTorch的簡(jiǎn)單實(shí)現(xiàn)

PyTorch 的 nn 庫(kù)中有大量有用的模塊,其中一個(gè)就是線性模塊。如名字所示,它對(duì)輸入執(zhí)行線性變換,即線性回歸。

class LinearRegression(torch.nn.Module):

def __init__(self, input_size, output_size):

super(LinearRegression, self).__init__()

self.linear = torch.nn.Linear(input_size, output_size)

def forward(self, x):

return self.linear(x)

model = LinearRegression(1, 1)

要訓(xùn)練線性回歸,我們需要從 nn 庫(kù)中添加合適的損失函數(shù)。對(duì)于線性回歸,我們將使用 MSELoss()——均方差損失函數(shù)。

我們還需要使用優(yōu)化函數(shù)(SGD),并運(yùn)行與之前示例類似的反向傳播。本質(zhì)上,我們重復(fù)上文定義的 train() 函數(shù)中的步驟。不能直接使用該函數(shù)的原因是我們實(shí)現(xiàn)它的目的是分類而不是回歸,以及我們使用交叉熵?fù)p失和最大元素的索引作為模型預(yù)測(cè)。而對(duì)于線性回歸,我們使用線性層的輸出作為預(yù)測(cè)。

criterion = torch.nn.MSELoss()

optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

for epoch in range(50):

data, target = Variable(x_torch), Variable(y_torch)

output = model(data)

optimizer.zero_grad()

loss = criterion(output, target)

loss.backward()

optimizer.step()

predicted = model(Variable(x_torch)).data.numpy()

現(xiàn)在我們可以打印出原始數(shù)據(jù)和適合 PyTorch 的線性回歸。

plt.plot(x_train, y_train, 'o', label='Original data')

plt.plot(x_train, predicted, label='Fitted line')

plt.legend()

plt.show()

教程 | 從頭開始了解PyTorch的簡(jiǎn)單實(shí)現(xiàn)

為了轉(zhuǎn)向更復(fù)雜的模型,我們下載了 MNIST 數(shù)據(jù)集至「datasets」文件夾中,并測(cè)試一些 PyTorch 中可用的初始預(yù)處理。PyTorch 具備數(shù)據(jù)加載器和處理器,可用于不同的數(shù)據(jù)集。數(shù)據(jù)集下載好后,你可以隨時(shí)使用。你還可以將數(shù)據(jù)包裝進(jìn) PyTorch 張量,創(chuàng)建自己的數(shù)據(jù)加載器類別。

批大?。╞atch size)是機(jī)器學(xué)習(xí)中的術(shù)語,指一次迭代中使用的訓(xùn)練樣本數(shù)量。批大小可以是以下三種之一:

batch 模式:批大小等于整個(gè)數(shù)據(jù)集,因此迭代和 epoch 值一致;

mini-batch 模式:批大小大于 1 但小于整個(gè)數(shù)據(jù)集的大小。通常,數(shù)量可以是能被整個(gè)數(shù)據(jù)集整除的值。

隨機(jī)模式:批大小等于 1。因此梯度和神經(jīng)網(wǎng)絡(luò)參數(shù)在每個(gè)樣本之后都要更新。

from torchvision import datasets, transforms

batch_num_size = 64

train_loader = torch.utils.data.DataLoader(

datasets.MNIST('data',train=True, download=True, transform=transforms.Compose([

transforms.ToTensor(),

transforms.Normalize((0.1307,), (0.3081,))

])),

batch_size=batch_num_size, shuffle=True)

test_loader = torch.utils.data.DataLoader(

datasets.MNIST('data',train=False, transform=transforms.Compose([

3. PyTorch 中的 LeNet 卷積神經(jīng)網(wǎng)絡(luò)(CNN)

現(xiàn)在我們從頭開始創(chuàng)建第一個(gè)簡(jiǎn)單神經(jīng)網(wǎng)絡(luò)。該網(wǎng)絡(luò)要執(zhí)行圖像分類,識(shí)別 MNIST 數(shù)據(jù)集中的手寫數(shù)字。這是一個(gè)四層的卷積神經(jīng)網(wǎng)絡(luò)(CNN),一種分析 MNIST 數(shù)據(jù)集的常見架構(gòu)。該代碼來自 PyTorch 官方教程,你可以在這里(http://pytorch.org/tutorials/)找到更多示例。

我們將使用 torch.nn 庫(kù)中的多個(gè)模塊:

1. 線性層:使用層的權(quán)重對(duì)輸入張量執(zhí)行線性變換;

2. Conv1 和 Conv2:卷積層,每個(gè)層輸出在卷積核(小尺寸的權(quán)重張量)和同樣尺寸輸入?yún)^(qū)域之間的點(diǎn)積;

3. Relu:修正線性單元函數(shù),使用逐元素的激活函數(shù) max(0,x);

4. 池化層:使用 max 運(yùn)算執(zhí)行特定區(qū)域的下采樣(通常 2x2 像素);

5. Dropout2D:隨機(jī)將輸入張量的所有通道設(shè)為零。當(dāng)特征圖具備強(qiáng)相關(guān)時(shí),dropout2D 提升特征圖之間的獨(dú)立性;

6. Softmax:將 Log(Softmax(x)) 函數(shù)應(yīng)用到 n 維輸入張量,以使輸出在 0 到 1 之間。

class LeNet(nn.Module):

def __init__(self):

super(LeNet,self).__init__()

self.conv1 = nn.Conv2d(1,10,kernel_size=5)

self.conv2 = nn.Conv2d(10,20,kernel_size=5)

self.conv2_drop = nn.Dropout2d()

self.fc1 = nn.Linear(320,50)

self.fc2 = nn.Linear(50,10)

def forward(self,x):

x = F.relu(F.max_pool2d(self.conv1(x),2))

x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)),2))

x = x.view(-1, 320)

x = F.relu(self.fc1(x))

x = F.dropout(x, training=self.training)

x = self.fc2(x)

return F.log_softmax(x, dim=1)

創(chuàng)建 LeNet 類后,創(chuàng)建對(duì)象并移至 GPU:

model = LeNet()

model.cuda()

print ('MNIST_net model:\n')

print (model)

MNIST_net model:

LeNet(

(conv1): Conv2d(1, 10, kernel_size=(5, 5), stride=(1, 1))

(conv2): Conv2d(10, 20, kernel_size=(5, 5), stride=(1, 1))

(conv2_drop): Dropout2d(p=0.5)

(fc1): Linear(in_features=320, out_features=50, bias=True)

(fc2): Linear(in_features=50, out_features=10, bias=True)

)

要訓(xùn)練該模型,我們需要使用帶動(dòng)量的 SGD,學(xué)習(xí)率為 0.01,momentum 為 0.5。

criterion = nn.CrossEntropyLoss()

optimizer = optim.SGD(model.parameters(),lr = 0.005, momentum = 0.9)

僅僅需要 5 個(gè) epoch(一個(gè) epoch 意味著你使用整個(gè)訓(xùn)練數(shù)據(jù)集來更新訓(xùn)練模型的權(quán)重),我們就可以訓(xùn)練出一個(gè)相當(dāng)準(zhǔn)確的 LeNet 模型。這段代碼檢查可以確定文件中是否已有預(yù)訓(xùn)練好的模型。有則加載;無則訓(xùn)練一個(gè)并保存至磁盤。

import os

epochs = 5

if (os.path.isfile('pretrained/MNIST_net.t7')):

print ('Loading model')

model.load_state_dict(torch.load('pretrained/MNIST_net.t7', map_location=lambda storage, loc: storage))

acc, loss = test(model, 1, criterion, test_loader)

else:

print ('Training model')

for epoch in range(1, epochs + 1):

train(model, epoch, criterion, optimizer, train_loader)

acc, loss = test(model, 1, criterion, test_loader)

torch.save(model.state_dict(), 'pretrained/MNIST_net.t7')

Loading model

Test set: Average loss: 0.0471, Accuracy: 9859/10000 (99%)

現(xiàn)在我們來看下模型。首先,打印出該模型的信息。打印函數(shù)顯示所有層(如 Dropout 被實(shí)現(xiàn)為一個(gè)單獨(dú)的層)及其名稱和參數(shù)。同樣有一個(gè)迭代器在模型中所有已命名模塊之間運(yùn)行。當(dāng)你具備一個(gè)包含多個(gè)「內(nèi)部」模型的復(fù)雜 DNN 時(shí),這有所幫助。在所有已命名模塊之間的迭代允許我們創(chuàng)建模型解析器,可讀取模型參數(shù)、創(chuàng)建與該網(wǎng)絡(luò)類似的模塊。

print ('Internal models:')

for idx, m in enumerate(model.named_modules()):

print(idx, '->', m)

print ('-------------------------------------------------------------------------')

#輸出:

Internal models:

0 -> ('', LeNet(

))

1 -> ('conv1', Conv2d(1, 10, kernel_size=(5, 5), stride=(1, 1)))

2 -> ('conv2', Conv2d(10, 20, kernel_size=(5, 5), stride=(1, 1)))

3 -> ('conv2_drop', Dropout2d(p=0.5))

4 -> ('fc1', Linear(in_features=320, out_features=50, bias=True))

5 -> ('fc2', Linear(in_features=50, out_features=10, bias=True))

你可以使用 .cpu() 方法將張量移至 CPU(或確保它在那里)?;蛘?,當(dāng) GPU 可用時(shí)(torch.cuda. 可用),使用 .cuda() 方法將張量移至 GPU。你可以看到張量是否在 GPU 上,其類型為 torch.cuda.FloatTensor。如果張量在 CPU 上,則其類型為 torch.FloatTensor。

print (type(t.cpu().data))

if torch.cuda.is_available():

print ("Cuda is available")

print (type(t.cuda().data))

else:

print ("Cuda is NOT available")

Cuda is available

如果張量在 CPU 上,我們可以將其轉(zhuǎn)換成 NumPy 數(shù)組,其共享同樣的內(nèi)存位置,改變其中一個(gè)就會(huì)改變另一個(gè)。

try:

print(t.data.numpy())

except RuntimeError as e:

"you can't transform a GPU tensor to a numpy nd array, you have to copy your weight tendor to cpu and then get the numpy array"

print(type(t.cpu().data.numpy()))

print(t.cpu().data.numpy().shape)

print(t.cpu().data.numpy())

現(xiàn)在我們了解了如何將張量轉(zhuǎn)換成 NumPy 數(shù)組,我們可以利用該知識(shí)使用 matplotlib 進(jìn)行可視化!我們來打印出第一個(gè)卷積層的卷積濾波器。

data = model.conv1.weight.cpu().data.numpy()

print (data.shape)

print (data[:, 0].shape)

kernel_num = data.shape[0]

fig, axes = plt.subplots(ncols=kernel_num, figsize=(2*kernel_num, 2))

for col in range(kernel_num):

axes[col].imshow(data[col, 0, :, :], cmap=plt.cm.gray)

plt.show()

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多