乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      手把手教你用 PyTorch 快速準確地建立神經(jīng)網(wǎng)絡

       鷹兔牛熊眼 2019-02-03

      (給數(shù)據(jù)分析與開發(fā)加星標,提升數(shù)據(jù)技能


      英文:Shivam Bansal,轉(zhuǎn)自:數(shù)據(jù)派(ID:datapi),翻譯:陳之炎


      簡介


      你可能已經(jīng)在社交媒體上看到過N次關于PyTorch和 TensorFlow的兩極分化的爭論。這些框架的普及推動了近年來深度學習的興起。二者都不乏堅定的支持者,但在過去的一年里,一個明顯的贏家已經(jīng)開始出現(xiàn)。


      PyTorch是2018年最流行的框架之一。它已迅速成為學術界和工業(yè)界研究人員的首選深度學習框架。在過去幾周使用了PyTorch之后,我體會到它是一個非常靈活且易于使用的深度學習庫。


      在本文中,我們將探討PyTorch的全部內(nèi)容。我們將不止學習理論-還包括編寫4個不同的用例,看看PyTorch的表現(xiàn)如何。建立深度學習模型從來沒有這么有趣過!


      內(nèi)容


      • 什么是PyTorch?

      • 利用PyTorch構建神經(jīng)網(wǎng)絡

      • 用例1:手寫數(shù)字分類(數(shù)字數(shù)據(jù),MLP)

      • 用例2:物體圖像分類(圖像數(shù)據(jù),CNN)

      • 用例3:情感文本分類(文本數(shù)據(jù),RNN)

      • 用例4:圖像樣式的遷移(遷移學習)


      什么是PyTorch?


      在深入研究PyTorch的實現(xiàn)之前,讓我們先了解一下PyTorch是什么,以及為什么它最近會變得如此流行。


      PyTorch是一個基于Python的科學計算包,類似于NumPy,它具備GPU附加功能。與此同時,它也是一個深度學習框架,為實現(xiàn)和構建深層神經(jīng)網(wǎng)絡體系結(jié)構提供了最大程度的靈活性和速度。


      最近發(fā)布的PyTorch 1.0幫助研究人員應對以下四大挑戰(zhàn):


      • 大面積的返工

      • 耗時的訓練

      • Python語言缺乏靈活性

      • 慢速擴展


      從本質(zhì)上講,PyTorch與其他深度學習框架有兩個不同點:


      • 命令式編程

      • 動態(tài)計算圖


      命令式編程:PyTorch在遍歷每一行代碼的同時執(zhí)行計算,這與Python程序的執(zhí)行方式非常類似,這一概念稱為命令式編程,它的最大優(yōu)點是可以動態(tài)地調(diào)試代碼和編程邏輯。


      動態(tài)計算圖:PyTorch被稱為“由運行定義的”框架,這意味著計算圖結(jié)構(神經(jīng)網(wǎng)絡體系結(jié)構)是在運行時生成的。該屬性的主要優(yōu)點是:它提供了一個靈活的編程運行時接口,通過連接操作來方便系統(tǒng)的構建和修改。在PyTorch中,每個前向通路處定義一個新的計算圖,這與使用靜態(tài)圖的TensorFlow形成了鮮明的對比。


      PyTorch1.0附帶了一個名為torch.jit的重要特性,它是一個高級編譯器,允許用戶分離模型和代碼。此外,它還支持在定制硬件(如GPU或TPU)上進行有效的模型優(yōu)化。


      用PyTorch構建神經(jīng)網(wǎng)絡


      讓我們通過一個實際案例來理解PyTorch。學習理論固然好,但是如果你不把它付諸實踐的話,它就沒有多大用處了!


      神經(jīng)網(wǎng)絡的PyTorch實現(xiàn)看起來與NumPy實現(xiàn)完全一樣。本節(jié)的目標是展示PyTorch和NumPy的等效性質(zhì)。為此,讓我們創(chuàng)建一個簡單的三層網(wǎng)絡,在輸入層中有5個節(jié)點,在隱藏層中有3個節(jié)點,在輸出層中有1個節(jié)點。我們只使用一個帶有五個特征和一個目標的單行訓練示例。


      import torch

      n_input, n_hidden, n_output = 5, 3, 1


      第一步是進行參數(shù)初始化。這里,每個層的權重和偏置參數(shù)被初始化為張量變量。張量是PyTorch的基本數(shù)據(jù)結(jié)構,用于建立不同類型的神經(jīng)網(wǎng)絡。可以將它們當作是數(shù)組和矩陣的推廣,換句話說,張量是N維矩陣。


      ## initialize tensor for inputs, and outputs

      x = torch.randn((1, n_input))

      y = torch.randn((1, n_output))

      ## initialize tensor variables for weights

      w1 = torch.randn(n_input, n_hidden) # weight for hidden layer

      w2 = torch.randn(n_hidden, n_output) # weight for output layer

      ## initialize tensor variables for bias terms

      b1 = torch.randn((1, n_hidden)) # bias for hidden layer

      b2 = torch.randn((1, n_output)) # bias for output layer


      在參數(shù)初始化完成之后,可以通過以下四個關鍵步驟來定義和訓練神經(jīng)網(wǎng)絡:


      • 前向傳播

      • 損失計算

      • 反向傳播

      • 更新參數(shù)


      讓我們更詳細地了解每一個步驟。


      前向傳播:在這個步驟中,每個層都使用以下兩個公式計算激活流。這些激活流從輸入層流向輸出層,以生成最終輸出。


      1. z = weight * input + bias

      2. a = activation_function (z)


      下面的代碼塊顯示了如何用PyTorch編寫這些步驟。請注意,大多數(shù)函數(shù),如指數(shù)和矩陣乘法,均與NumPy中的函數(shù)相類似。


      ## sigmoid activation function using pytorch

      def sigmoid_activation(z):

         return 1 / (1 + torch.exp(-z))

      ## activation of hidden layer

      z1 = torch.mm(x, w1) + b1

      a1 = sigmoid_activation(z1)

      ## activation (output) of final layer

      z2 = torch.mm(a1, w2) + b2

      output = sigmoid_activation(z2)


      損失計算:這一步在輸出層中計算誤差 (也稱為損失)。一個簡單的損失函數(shù)可以用來衡量實際值和預測值之間的差異。稍后,我們將查看PyTorch中可用的不同類型的損失函數(shù)。

       

      loss = y - output


      反向傳播:這一步的目的是通過對偏差和權重進行邊際變化,從而將輸出層的誤差降到最低,邊際變化是利用誤差項的導數(shù)計算出來的。


      根據(jù)鏈規(guī)則的微積分原理,將增量變化返回到隱藏層,并對其權重和偏差進行相應的修正。通過對權重和偏差的調(diào)整,使得誤差最小化。


      ## function to calculate the derivative of activation

      def sigmoid_delta(x):

       return x * (1 - x)

      ## compute derivative of error terms

      delta_output = sigmoid_delta(output)

      delta_hidden = sigmoid_delta(a1)

      ## backpass the changes to previous layers

      d_outp = loss * delta_output

      loss_h = torch.mm(d_outp, w2.t())

      d_hidn = loss_h * delta_hidden


      更新參數(shù):最后一步,利用從上述反向傳播中接收到的增量變化來對權重和偏差進行更新。


      learning_rate = 0.1

      w2 += torch.mm(a1.t(), d_outp) * learning_rate

      w1 += torch.mm(x.t(), d_hidn) * learning_rate

      b2 += d_outp.sum() * learning_rate

      b1 += d_hidn.sum() * learning_rate


      當使用大量訓練示例對多個歷元執(zhí)行這些步驟時,損失將降至最小值。得到最終的權重和偏差值之后,用它對未知數(shù)據(jù)進行預測。


      用例1:手寫數(shù)字分類


      在上一節(jié)中,我們看到了用PyTorch編寫神經(jīng)網(wǎng)絡的簡單用例。在本節(jié)中,我們將利用PyTorch提供的不同的實用程序包(nn、autograd、Optimm、torchvision、torchtext等)來建立和訓練神經(jīng)網(wǎng)絡。


      利用這些包可以方便地定義和管理神經(jīng)網(wǎng)絡。在這個用例中,我們將創(chuàng)建一個多層感知器(MLP)網(wǎng)絡,用于構建手寫數(shù)字分類器。我們將使用torchvision包中的MNIST數(shù)據(jù)集。


      與你將要從事的任何項目一樣,第一步是數(shù)據(jù)預處理:首先需要將原始數(shù)據(jù)集轉(zhuǎn)換為張量,并在固定范圍內(nèi)將其歸一化。torchvision包提供了一個名為 transforms的實用程序,利用它可以將不同的轉(zhuǎn)換組合在一起。


      from torchvision import transforms

      _tasks = transforms.Compose([

         transforms.ToTensor(),

         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))

         ])


      第一個轉(zhuǎn)換是將原始數(shù)據(jù)轉(zhuǎn)換為張量,第二個轉(zhuǎn)換是通過以下操作執(zhí)行歸一化:


      x_normalized = x-mean / std


      數(shù)值為0.5,0.5表示紅色、綠色和藍色三個通道的均值和標準差。


      from torchvision.datasets import MNIST

      ## Load MNIST Dataset and apply transformations

      mnist = MNIST('data', download=True, train=True, transform=_tasks)


      PyTorch的另一個出色的實用工具是DataLoader迭代器,它為多個處理器之間并行地批處理、搬移和加載數(shù)據(jù)提供了實現(xiàn)的可能。為了評估這個模型,我們將數(shù)據(jù)集劃分為訓練集和驗證集。


      from torch.utils.data import DataLoader

      from torch.utils.data.sampler import SubsetRandomSampler

      ## create training and validation split

      split = int(0.8 * len(mnist))

      index_list = list(range(len(mnist)))

      train_idx, valid_idx = index_list[:split], index_list[split:]

      ## create sampler objects using SubsetRandomSampler

      tr_sampler = SubsetRandomSampler(train_idx)

      val_sampler = SubsetRandomSampler(valid_idx)

      ## create iterator objects for train and valid datasets

      trainloader = DataLoader(mnist, batch_size=256, sampler=tr_sampler)

      validloader = DataLoader(mnist, batch_size=256, sampler=val_sampler)


      PyTorch中的神經(jīng)網(wǎng)絡架構可以定義為一個類,這個類繼承了稱為Module的nn包的基礎類的所有屬性。來自nn.Module類的繼承使得我們可以輕松地實現(xiàn)、訪問和調(diào)用多個方法,還可以定義類的構造函數(shù)中的各個層,以及前向傳播步驟中的前向函數(shù)。


      我們將定義一個具有以下層配置的網(wǎng)絡:[784,128,10]。此配置表示輸入層中有784個節(jié)點(28*28像素)、隱藏層中有128個節(jié)點,輸出層中有10個節(jié)點。在前向函數(shù)中,我們將在隱藏層(可以通過nn模塊訪問)中使用Sigmoid激活函數(shù)。


      import torch.nn.functional as F

      class Model(nn.Module):

         def __init__(self):

             super().__init__()

             self.hidden = nn.Linear(784, 128)

             self.output = nn.Linear(128, 10)

       

        def forward(self, x):

             x = self.hidden(x)

             x = F.sigmoid(x)

             x = self.output(x)

             return x

      model = Model()


      利用nn和Optim包定義損失函數(shù)和優(yōu)化器:


      from torch import optim

      loss_function = nn.CrossEntropyLoss()

      optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay= 1e-6, momentum = 0.9, nesterov = True)


      現(xiàn)在已經(jīng)準備好,可以開始訓練模型了,其核心步驟與前一節(jié)相同:前向傳播、損失計算、反向傳播和更新參數(shù)。


      for epoch in range(1, 11): ## run the model for 10 epochs

         train_loss, valid_loss = [], []

         ## training part

         model.train()

         for data, target in trainloader:

             optimizer.zero_grad()

             ## 1. forward propagation

             output = model(data)

             

             ## 2. loss calculation

             loss = loss_function(output, target)

             

             ## 3. backward propagation

             loss.backward()

             

             ## 4. weight optimization

             optimizer.step()

             

             train_loss.append(loss.item())

             

         ## evaluation part

         model.eval()

         for data, target in validloader:

             output = model(data)

             loss = loss_function(output, target)

             valid_loss.append(loss.item())

         print ('Epoch:', epoch, 'Training Loss: ', np.mean(train_loss), 'Valid Loss: ', np.mean(valid_loss))



      >> Epoch: 1  Training Loss:  0.645777 Valid Loss:  0.344971

      >> Epoch: 2  Training Loss:  0.320241 Valid Loss:  0.299313

      >> Epoch: 3  Training Loss:  0.278429 Valid Loss:  0.269018

      >> Epoch: 4  Training Loss:  0.246289 Valid Loss:  0.237785

      >> Epoch: 5  Training Loss:  0.217010 Valid Loss:  0.217133

      >> Epoch: 6  Training Loss:  0.193017 Valid Loss:  0.206074

      >> Epoch: 7  Training Loss:  0.174385 Valid Loss:  0.180163

      >> Epoch: 8  Training Loss:  0.157574 Valid Loss:  0.170064

      >> Epoch: 9  Training Loss:  0.144316 Valid Loss:  0.162660

      >> Epoch: 10 Training Loss:  0.133053 Valid Loss:  0.152957


      完成了模型的訓練之后,即可在驗證數(shù)據(jù)基礎上進行預測。


      ## dataloader for validation dataset

      dataiter = iter(validloader)

      data, labels = dataiter.next()

      output = model(data)

      _, preds_tensor = torch.max(output, 1)

      preds = np.squeeze(preds_tensor.numpy())

      print ('Actual:', labels[:10])

      print ('Predicted:', preds[:10])



      >>> Actual: [0 1 1 1 2 2 8 8 2 8]

      >>> Predicted: [0 1 1 1 2 2 8 8 2 8]


      用例2:物體圖像分類

       

      現(xiàn)在讓我們更進一步。


      在這個用例中,我們將在PyTorch中創(chuàng)建卷積神經(jīng)網(wǎng)絡(CNN)架構,利用流行的CIFAR-10數(shù)據(jù)集進行物體圖像分類,此數(shù)據(jù)集也包含在torchvision包中。定義和訓練模型的整個過程將與以前的用例相同,唯一的區(qū)別只是在網(wǎng)絡中引入了額外的層。


      加載并轉(zhuǎn)換數(shù)據(jù)集:


      ## load the dataset

      from torchvision.datasets import CIFAR10

      cifar = CIFAR10('data', train=True, download=True, transform=_tasks)

      ## create training and validation split

      split = int(0.8 * len(cifar))

      index_list = list(range(len(cifar)))

      train_idx, valid_idx = index_list[:split], index_list[split:]

      ## create training and validation sampler objects

      tr_sampler = SubsetRandomSampler(train_idx)

      val_sampler = SubsetRandomSampler(valid_idx)

      ## create iterator objects for train and valid datasets

      trainloader = DataLoader(cifar, batch_size=256, sampler=tr_sampler)

      validloader = DataLoader(cifar, batch_size=256, sampler=val_sampler)


      我們將創(chuàng)建三個用于低層特征提取的卷積層、三個用于最大信息量提取的池化層和兩個用于線性分類的線性層。


      class Model(nn.Module):

         def __init__(self):

             super(Model, self).__init__()

             

             ## define the layers

             self.conv1 = nn.Conv2d(3, 16, 3, padding=1)

             self.conv2 = nn.Conv2d(16, 32, 3, padding=1)

             self.conv3 = nn.Conv2d(32, 64, 3, padding=1)

             self.pool = nn.MaxPool2d(2, 2)

             self.linear1 = nn.Linear(1024, 512)

             self.linear2 = nn.Linear(512, 10)

         

         def forward(self, x):

             x = self.pool(F.relu(self.conv1(x)))

             x = self.pool(F.relu(self.conv2(x)))

             x = self.pool(F.relu(self.conv3(x)))

             x = x.view(-1, 1024) ## reshaping

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

             x = self.linear2(x)

             return x

      model = Model()


      定義損失函數(shù)和優(yōu)化器:


      import torch.optim as optim

      loss_function = nn.CrossEntropyLoss()

      optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay= 1e-6, momentum = 0.9, nesterov = True)

      ## run for 30 Epochs

      for epoch in range(1, 31):

         train_loss, valid_loss = [], []

         ## training part

         model.train()

         for data, target in trainloader:

             optimizer.zero_grad()

             output = model(data)

             loss = loss_function(output, target)

             loss.backward()

             optimizer.step()

             train_loss.append(loss.item())

             

         ## evaluation part

         model.eval()

         for data, target in validloader:

             output = model(data)

             loss = loss_function(output, target)

             valid_loss.append(loss.item())


      完成了模型的訓練之后,即可在驗證數(shù)據(jù)基礎上進行預測。


      ## dataloader for validation dataset

      dataiter = iter(validloader)

      data, labels = dataiter.next()

      output = model(data)

      _, preds_tensor = torch.max(output, 1)

      preds = np.squeeze(preds_tensor.numpy())

      print ('Actual:', labels[:10])

      print ('Predicted:', preds[:10])

      Actual: ['truck', 'truck', 'truck', 'horse', 'bird', 'truck', 'ship', 'bird', 'deer', 'bird']

      Pred:   ['truck', 'automobile', 'automobile', 'horse', 'bird', 'airplane', 'ship', 'bird', 'deer', 'bird']


      用例3:情感文本分類


      我們將從計算機視覺用例轉(zhuǎn)向自然語言處理,目的是展示PyTorch在不同領域的不同應用。


      在本節(jié)中,我們將利用基于RNN(遞歸神經(jīng)網(wǎng)絡)和LSTM(長短期記憶)層的Pyotch來完成文本分類任務。首先,加載包含兩個字段(文本和目標)的數(shù)據(jù)集。目標包含兩個類:class1和class2,我們的任務是將每個文本分為其中一個類。


      可以在下面的鏈接中下載數(shù)據(jù)集。


      https://s3-ap-south-1./av-blog-media/wp-content/uploads/2019/01/train.csv


      train = pd.read_csv('train.csv')

      x_train = train['text'].values

      y_train = train['target'].values


      強烈建議在編碼之前先設置種子,它可以保證你看到的結(jié)果與我的相同-這是在學習新概念時非常有用(也很有益)的特征。


      np.random.seed(123)

      torch.manual_seed(123)

      torch.cuda.manual_seed(123)

      torch.backends.cudnn.deterministic = True


      在預處理步驟中,首先將文本數(shù)據(jù)轉(zhuǎn)換為tokens序列,之后便可以將其傳遞到嵌入層。我將利用Keras包中提供的實用程序來進行預處理,利用torchtext包也同樣可以實現(xiàn)。


      from keras.preprocessing import text, sequence

      ## create tokens

      tokenizer = Tokenizer(num_words = 1000)

      tokenizer.fit_on_texts(x_train)

      word_index = tokenizer.word_index

      ## convert texts to padded sequences

      x_train = tokenizer.texts_to_sequences(x_train)

      x_train = pad_sequences(x_train, maxlen = 70)


      接下來,需要將tokens轉(zhuǎn)換成向量。為此,利用預先訓練過的GloVe詞嵌入。我們將加載這些單詞嵌入,并創(chuàng)建一個包含單詞向量的嵌入矩陣。


      GloVe:

      https://github.com/stanfordnlp/GloVe


      EMBEDDING_FILE = 'glove.840B.300d.txt'

      embeddings_index = {}

      for i, line in enumerate(open(EMBEDDING_FILE)):

         val = line.split()

         embeddings_index[val[0]] = np.asarray(val[1:], dtype='float32')

      embedding_matrix = np.zeros((len(word_index) + 1, 300))

      for word, i in word_index.items():

         embedding_vector = embeddings_index.get(word)

         if embedding_vector is not None:

             embedding_matrix[i] = embedding_vector


      使用嵌入層和LSTM層定義模型架構:


      class Model(nn.Module):

         def __init__(self):

             super(Model, self).__init__()

             

             ## Embedding Layer, Add parameter

             self.embedding = nn.Embedding(max_features, embed_size)

             et = torch.tensor(embedding_matrix, dtype=torch.float32)

             self.embedding.weight = nn.Parameter(et)

             self.embedding.weight.requires_grad = False

             self.embedding_dropout = nn.Dropout2d(0.1)

             self.lstm = nn.LSTM(300, 40)        

             self.linear = nn.Linear(40, 16)

             self.out = nn.Linear(16, 1)

             self.relu = nn.ReLU()

        def forward(self, x):

             h_embedding = self.embedding(x)        

             h_lstm, _ = self.lstm(h_embedding)

             max_pool, _ = torch.max(h_lstm, 1)        

             linear = self.relu(self.linear(max_pool))

             out = self.out(linear)

             return out

      model = Model()


      創(chuàng)建訓練和驗證集:


      from torch.utils.data import TensorDataset

      ## create training and validation split

      split_size = int(0.8 * len(train_df))

      index_list = list(range(len(train_df)))

      train_idx, valid_idx = index_list[:split], index_list[split:]

      ## create iterator objects for train and valid datasets

      x_tr = torch.tensor(x_train[train_idx], dtype=torch.long)

      y_tr = torch.tensor(y_train[train_idx], dtype=torch.float32)

      train = TensorDataset(x_tr, y_tr)

      trainloader = DataLoader(train, batch_size=128)

      x_val = torch.tensor(x_train[valid_idx], dtype=torch.long)

      y_val = torch.tensor(y_train[valid_idx], dtype=torch.float32)

      valid = TensorDataset(x_val, y_val)

      validloader = DataLoader(valid, batch_size=128)


      定義損失和優(yōu)化器:


      loss_function = nn.BCEWithLogitsLoss(reduction='mean')

      optimizer = optim.Adam(model.parameters())


      訓練模型:


      ## run for 10 Epochs

      for epoch in range(1, 11):

         train_loss, valid_loss = [], []

      ## training part

         model.train()

         for data, target in trainloader:

             optimizer.zero_grad()

             output = model(data)

             loss = loss_function(output, target.view(-1,1))

             loss.backward()

             optimizer.step()

             train_loss.append(loss.item())

             

         ## evaluation part

         model.eval()

         for data, target in validloader:

             output = model(data)

             loss = loss_function(output, target.view(-1,1))

             valid_loss.append(loss.item())


      最后得到預測結(jié)果:


      dataiter = iter(validloader)

      data, labels = dataiter.next()

      output = model(data)

      _, preds_tensor = torch.max(output, 1)

      preds = np.squeeze(preds_tensor.numpy())

      Actual: [0 1 1 1 1 0 0 0 0]

      Predicted: [0 1 1 1 1 1 1 1 0 0]


      用例4:圖像樣式遷移


      讓我們來看最后一個用例,在這里我們將執(zhí)行圖形樣式的遷移。這是我經(jīng)歷過的最有創(chuàng)意的項目之一,希望你也能玩得開心。樣式遷移概念背后的基本理念是:


      • 從一幅圖像中獲取對象/內(nèi)容

      • 從另一幅圖像中獲取樣式/紋理

      • 生成二者混合的最終圖像


      “利用卷積網(wǎng)絡進行圖像樣式遷移”這篇論文中對這一概念做了介紹,樣式遷移的一個例子如下:


      太棒了,對吧?讓我們看看它在PyTorch中是如何實現(xiàn)的。這一進程包括六個步驟:


      • 從兩個輸入圖像中提取低層特征。這可以使用VGG 19這樣的預訓練的深度學習模型。


      from torchvision import models

      # get the features portion from VGG19

      vgg = models.vgg19(pretrained=True).features



      # freeze all VGG parameters

      for param in vgg.parameters():

         param.requires_grad_(False)

      # check if GPU is available

      device = torch.device('cpu')

      if torch.cuda.is_available():

         device = torch.device('cuda')

      vgg.to(device)


      • 將這兩幅圖像加載到設備上,并從VGG中獲取特征。另外,也可以應用以下轉(zhuǎn)換:調(diào)整張量的大小,以及值的歸一化。


      from torchvision import transforms as tf

      def transformation(img):

         tasks = tf.Compose([tf.Resize(400), tf.ToTensor(),

                    tf.Normalize((0.44,0.44,0.44),(0.22,0.22,0.22))])

         img = tasks(img)[:3,:,:].unsqueeze(0)    

         return img

      img1 = Image.open('image1.jpg').convert('RGB')

      img2 = Image.open('image2.jpg').convert('RGB')

      img1 = transformation(img1).to(device)

      img2 = transformation(img2).to(device)


      • 現(xiàn)在,我們需要獲得這兩幅圖像的相關特征。從第一個圖像中,我們需要提取內(nèi)容或與存在的對象相關的特征;從第二張圖像中,我們需要提取與樣式和紋理相關的特征。


      對象相關特征:在最初的文章中,作者建議可以從網(wǎng)絡的初始層中提取更有價值的對象和內(nèi)容,這是因為在較高層上,信息空間變得更為復雜,像素信息細節(jié)在高層往往會丟失。


      樣式相關特征:為了從第二幅圖像中獲取樣式和紋理信息,作者在不同層次上使用了不同特征之間的相關性,下文第4點對此作了詳細解釋。


      在實現(xiàn)這一目標之前,讓我們來看看一個典型的VGG 19模型的結(jié)構:


      對象信息提取用到的是CONV42層,它位于第4個卷積塊中,深度為512。對于樣式的表達,用到的層是網(wǎng)絡中每個卷積塊的第一卷積層,即CONV11、CONV21、CONV31、CONV41和CONV51,這些層的選取純粹是根據(jù)作者的經(jīng)驗來做出選擇,我僅在本文中復制它們的結(jié)果。


      def get_features(image, model):

         layers = {'0': 'conv1_1', '5': 'conv2_1',  '10': 'conv3_1',

                   '19': 'conv4_1', '21': 'conv4_2', '28': 'conv5_1'}

         x = image

         features = {}

         for name, layer in model._modules.items():

             x = layer(x)

             if name in layers:

                 features[layers[name]] = x    

         return features

      img1_features = get_features(img1, vgg)

      img2_features = get_features(img2, vgg)


      • 正如前面提到的,作者使用不同層次的相關性來獲得與樣式相關的特征。這些特征的相關性由Gram矩陣G給出,其中G中的每個單元(i,j)都是層中向量特征映射i和j之間的內(nèi)積。


      def correlation_matrix(tensor):

         _, d, h, w = tensor.size()    

         tensor = tensor.view(d, h * w)    

         correlation = torch.mm(tensor, tensor.t())

         return correlation

      correlations = {l: correlation_matrix(img2_features[l]) for l in

                                                         img2_features}


      • 最終,可以利用這些特征和相關性進行樣式轉(zhuǎn)換?,F(xiàn)在,為了將樣式從一個圖像轉(zhuǎn)換到另一個圖像,需要設置用于獲取樣式特征的每一層的權重。如上所述,由于初始層提供了更多的信息,因此可以為初始層設置更高的權重。此外,定義優(yōu)化器函數(shù)和目標圖像,也即是圖像1的副本。


      weights = {'conv1_1': 1.0, 'conv2_1': 0.8, 'conv3_1': 0.25,

                'conv4_1': 0.21, 'conv5_1': 0.18}



      target = img1.clone().requires_grad_(True).to(device)

      optimizer = optim.Adam([target], lr=0.003)


      • 啟動損失最小化處理過程:即在循環(huán)中運行大量步驟,來計算與對象特征提取和樣式特征提取相關的損失。利用最小化后的損失,更新網(wǎng)絡參數(shù),進一步修正目標圖像。經(jīng)過一些迭代之后,將生成更新后的圖像。


      for ii in range(1, 2001):

         

         ## calculate the content loss (from image 1 and target)

         target_features = get_features(target, vgg)

         loss = target_features['conv4_2'] - img1_features['conv4_2']

         content_loss = torch.mean((loss)**2)

         

         ## calculate the style loss (from image 2 and target)

         style_loss = 0

         for layer in weights:

             

             target_feature = target_features[layer]

             target_corr = correlation_matrix(target_feature)

             style_corr = correlations[layer]

             

             layer_loss = torch.mean((target_corr - style_corr)**2)

             layer_loss *= weights[layer]

             

             _, d, h, w = target_feature.shape

             style_loss += layer_loss / (d * h * w)  

         

         total_loss = 1e6 * style_loss + content_loss

         

         optimizer.zero_grad()

         total_loss.backward()

         optimizer.step()


      最后,我們可以看到預測的結(jié)果,在這里我只運行了一小部分迭代,還可以運行多達3000次迭代(如果計算資源足夠多的話!)。


      def tensor_to_image(tensor):

         image = tensor.to('cpu').clone().detach()

         image = image.numpy().squeeze()

         image = image.transpose(1, 2, 0)

         image *= np.array((0.22, 0.22, 0.22))

                            + np.array((0.44, 0.44, 0.44))

         image = image.clip(0, 1)

         return image

      fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))

      ax1.imshow(tensor_to_image(img1))

      ax2.imshow(tensor_to_image(target))


      后記


      PyTorch還可以實現(xiàn)大量的其他用例,它很快成為全球研究人員的寵兒。絕大多數(shù)PyTorch實現(xiàn)的開源庫和開發(fā)應用可以在Github上看到。

       

      在本文中,我闡述了什么是PyTorch,以及如何用PyTorch實現(xiàn)不同的用例,當然,這個指南只是一個出發(fā)點。如果能提供更多的數(shù)據(jù),或進行更多的網(wǎng)絡參數(shù)微調(diào),那么每個用例的性能都可以得到大幅度提高,最重要的是如果在構建網(wǎng)絡體系架構時應用創(chuàng)新技能,也能提高用例的性能。感謝你的閱讀,并請在下面的評論部分留下你的反饋。


      參考文獻


      1. 官方PyTorch指南:

      https://pytorch.org/tutorials/


      2. 用PyTorch進行深度學習

      https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html


      3. Faizan在 Analytics Vidhya上發(fā)表的文章:

      https://www./blog/2018/02/pytorch-tutorial/


      4. 使用Pytorch的Udacity深度學習: 

      https://github.com/udacity/deep-learning-v2-pytorch


      5. 圖片樣式遷移原始論文:

      https://www./openaccess/content_cvpr_2016/papers/Gatys_Image_Style_Transfer_CVPR_2016_paper.pdf

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多