神經風格遷移它包括使用基於深度神經網絡的人工系統設計圖像。 在設計過程中,算法會操縱內容圖像以生成具有另一圖像藝術風格的新圖像。
由 Leon A. Gatys、Alexander S. Ecker 和 Matthias Bethge 開發,機器學習的實際應用見於 2015 年。根據 Leon A. Gatys 的研究文章“A Neural Algorithm of Artistic Style”,內容和風格使用神經渲染將圖像的一部分分離並重新組合,以通過神經算法生成藝術效果。
優化技術使用兩個圖像:內容圖像和样式參考圖像。 風格參考圖像是畫家設計的任何藝術圖像。 圖像經過優化以匹配內容的內容和样式統計信息以及使用卷積網絡提取的樣式參考圖像。 生成的優化輸出圖像類似於內容圖像,但打印參考圖像的樣式。
在教程中,我們將了解VGG-19 神經風格方法並執行神經風格遷移在用戶圖像穿著Python3 和 PyTorch在Windows操作系統.
1. VGG-19梳理過程
在本教程中,您需要一個預訓練網絡和VGG-19網絡行為神經風格遷移 (NST). 在這裡,您將凍結 VGG-19 網絡,以便網絡中的權重保持不變。
VGG-19是一種圖像識別技術,將圖像推到19層的深度。
NST 過程使用三個圖像:內容圖像和样式參考圖像作為輸入,生成的圖像作為輸出。 通過訓練過程,生成的輸出圖像類似於結合了參考圖像風格的內容圖像。
三張圖片分別通過 VGG 網絡。 在提取輸出圖像時,您只需要指定複雜的圖層。 根據研究論文,有五個複雜的層次。 這些是 conv 1-1、conv 2-1、conv 3-1、conv 4-1 和 conv 5-1,其中第一個數字在圖像層經過最大池層。
由於 NST 使用三幅圖像,VGG 網絡將輸出 3x 5 個複雜層。 您應該通過具有三個組成部分的損失函數來優化圖層:總損失、內容損失和样式損失。
- 總變體損失是內容損失和風格損失之間的線性組合。 它由超參數 alpha 乘以內容損失和 beta 樣式損失時間表示。
- 內容損失比較內容圖像和通過對每一層取範數生成的圖像的特徵。
在上面的等式中,
a = 五個卷積層之一的輸出
l = 表示要從中提取輸出的捲積層數
C=內容圖片
G=生成的圖像
- 當深度學習發揮作用時,捕捉風格的喪失並不容易。 您需要為生成的和样式化的圖像構建 Gram 矩陣。 本質上,在 Gram 矩陣中,輸出乘以它的轉置。
2.需求和依賴
2.1 先決條件
要繼續本教程,您需要一台安裝了以下軟件的計算機系統:
- conda 包和環境管理系統。
創建一個預加載了所有必要包及其依賴項的 python 虛擬環境。 最新版本蟒蛇分佈它附帶 Python 3.9.13,對於安裝 PyTorch 庫必不可少。
- 火炬
基於Python的軟件包只兼容特定版本的Python 3。
conda 包管理器預裝了 Python 3.9,允許無縫安裝 PyTorch 及其庫。 遵循官方文檔火炬通過 conda 包系統安裝庫。
- 代碼編輯器
用於運行 NST 代碼的 Visual Studio Code 或 Jupyter Notebook。
2.2 導入包
使用conda環境安裝PyTorch庫後,使用Jupyter Notebook或VS Code等代碼編輯器完成教程。
-
torch
和torch.nn
這些是在 PyTorch 中使用神經網絡的必備包 -
torch.optim
表示有效的梯度下降 -
PIL
用於加載和顯示圖像 -
torchvision.transforms
將 PIL 圖像轉換為張量 -
torchvision.models
訓練或加載預訓練的 VGG-19 模型 -
torchvision.utils
傳輸完成後存儲生成的圖像import torch import torch.nn as nn import torch.optim as optim from PIL import Image import torchvision.transforms as transforms import torchvision.models as models from torchvision.utils import save_image
3. 如何使用 Jupyter Notebook 進行神經風格遷移實驗?
安裝所有包,然後顯示卷積層。 要獲取所有捲積層,請使用命令 models.vgg19
model = models.vgg19(weights=True).features
要檢查卷積層,請打印變量:
print(model)
關於 VGG-19 架構,以下輸出表示分別經過 VGG 網絡後的所有復雜層。
計算表示在 maxpool 之後拉出的 conv1-1、conv2-1、conv3-1、conv4-1 和 conv5-1 的層。
所以取0、5、10、19、28層,分別對應conv1-1、conv2-1、conv3-1、conv4-1、conv5-1。
但是28之後的層呢?
這些層是不必要的,因為它們在損失函數中沒有價值。
Sequential(
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace=True)
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU(inplace=True)
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(6): ReLU(inplace=True)
(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): ReLU(inplace=True)
(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(13): ReLU(inplace=True)
(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): ReLU(inplace=True)
(16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(17): ReLU(inplace=True)
(18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): ReLU(inplace=True)
(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(22): ReLU(inplace=True)
(23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(24): ReLU(inplace=True)
(25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(26): ReLU(inplace=True)
(27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(29): ReLU(inplace=True)
(30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(31): ReLU(inplace=True)
(32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(33): ReLU(inplace=True)
(34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(35): ReLU(inplace=True)
(36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
4. 使用 PyTorch 和 Python3 轉換用戶圖像
4.1 訓練週期設置
現在您知道要提取哪些轉換層以繼續本教程。
創建一個類 VGG'and inherit from the
nn.Module`
定義函數 _init_
self 並調用重寫的方法 VGG,自用 super
現在使用選擇的功能['0', '5', '10', '19', '28']表示完成神經式傳輸後提取的輸出的 A。
通過構建模型直至特徵 28 並排除其餘部分來完成該功能。
class VGG(nn.Module):
def __init__(self):
super(VGG,self).__init__()
self.chosen_features = ['0', '5', '10', '19', '28']
self.model = models.vgg19(weights=True).features[:29]
定義另一個函數調用 forward
帶有參數 self, x。
將所有函數存儲在構建中,因此定義一個空數組或列表。
對於所有層自己的模特,通過這些層發送 x,然後使用 x 調用輸出。
如果他層數它在選擇的特徵列表,然後將其添加到空數組中。
通過返回完成功能特徵.
def forward(self,x):
features =[]
for layer_num, layer in enumerate(self.model):
x = layer(x)
if str(layer_num) in self.chosen_features:
features.append(x)
return feature
設備或充電器尚未定義。 選擇一個設備來導入內容和样式圖像並運行 VGG-19 網絡。 在大圖像上運行神經風格遷移算法通常需要很長時間。 但是 GPU 加速了這個過程。 使用 torch.cuda.is_available()
檢查系統中是否有可用的 GPU。 確定設備後,設置 torch.device
始終使用同一設備。
.to(device) 方法用於將張量或模塊移動到所需的設備。
指定圖片大小,對於 CPU,使用較小的數字,如 356,這是一個合適的大小。 如果沒有,請使用顯卡在更大的圖像上訓練算法。 但需要更長的時間。
使用內容和样式參考圖像時,請確保大小相同。 如果它們不相同,則在計算損失時不能減去它們。
transforms.ToTensor
將兩個圖像轉換為張量。
device = torch.device("cuda" if torch.cuda.is_available else "cpu"
#device = torch.device("cpu")
image_size =500
4.2 加載圖片
導入樣式內容和圖像。 最初,PIL 圖像的值在 0 到 255 之間,將其轉換為火炬張量後,轉換並在 0 到 1 的範圍內。
調整圖像大小以匹配它們的尺寸。 請注意,PyTorch 庫的神經網絡的訓練僅使用從 0 到 1 的張量值完成。如果您為網絡提供 0 到 255 之間的張量圖像,激活的特徵圖將不會檢測到它們的內容和样式。 .
要加載圖像,定義一個函數 load_image
並使用一個參數圖片名稱.
初始化圖像變量為 Image
. 這是 PIL
圖書館開始發揮作用。
使用加載圖像 loader
unsqueeze(0)
它用於為批量大小添加維度。
在使用樣式參考內容和圖像時,將兩者放在同一個文件夾中。 將它們加載到程序中。
輸出生成的圖像可能表現為噪聲。 在這種情況下,我們將復制內容的圖像。 您可以使用創建原始圖像的副本 original_img.clone().
使它比使用噪音更快。
reguires_grad_(True)
這是必不可少的,因為您需要凍結網絡。 您唯一可以更改的是生成的圖像。
loader = transforms.Compose(
[
transforms.Resize((image_size, image_size)), # scale imported images
transforms.ToTensor(), # transform it into a torch tensor
]
)
def load_image(image_name):
image = Image.open(image_name)
image = loader(image).unsqueeze(0)
return image.to(device)
original_img = load_image("content_image.jpg")
style_img = load_image("style_image.jpg")
model = VGG().to(device).eval()
generated = original_img.clone().requires_grad_(True)
4.3 配置超參數
您必須選擇超參數。
total_steps
, learning_rate
, alpha
和 beta
total_steps = 6000
learning_rate = 0.001
alpha = 1
beta = 0.01
optimizer = optim.Adam([generated], lr= learning_rate)
運行 for 循環以確定圖像被修改的次數。
它通過 VGG-19 網絡發送三個圖像中的每一個。
在運行五個不同轉換層的輸出列表時,通過將它們初始化為 0 來預先找到樣式丟失和內容丟失。
for step in range(total_steps):
generated_features = model(generated)
original_img_features = model(original_img)
style_features = model(style_img)
style_loss = original_loss = 0
4.4 損失函數的計算
遍歷所選層的所有特徵。 運行一個在循環中對於轉換層的三個圖像中的方面。 考慮生成圖像、內容圖像和样式參考圖像的 conv1_1。 但是,您必須遍歷所有五個層。
計算內容損失 torch.mean
它返回從輸入張量中生成的方面減去原始特徵後所有值的平均值。
根據第 1 節中提到的理論計算生成的圖像和样式的 gram 矩陣。將每個通道的像素值乘以其他通道的像素值以獲得新生成的特徵。 以channel-by-channel形式總結,生成的gram矩陣減去style gram矩陣。
Gram 矩陣計算一種相關矩陣。 如果生成圖像和風格圖像的通道中的像素顏色相似,則兩幅圖像具有相似的風格。
當您擁有生成圖像和風格圖像的克矩陣時,計算風格損失和總損失。
完全損失執行 total_loss.backward()
和 optimizer.step()
for gen_feature, orig_feature, style_features in zip(
generated_features, original_img_features, style_features):
batch_size, channel, height, width = gen_feature.shape
original_loss += torch.mean((gen_feature - orig_feature) **2 )
G = gen_feature.view(channel, height*width).mm(
gen_feature.view(channel, height*width).t()
)
A = style_features.view(channel, height*width).mm(
style_features.view(channel, height*width).t()
)
style_loss +=torch.mean((G - A)**2)
total_loss = alpha*original_loss + beta * style_loss
optimizer.zero_grad()
total_loss.backward()
optimizer.step()
通過打印算法匹配的總損失並保存生成的圖像來完成程序。
if step % 200 == 0:
print(total_loss)
save_image(generated, "generated_image.png")
4.5 輸出
輸出控制台顯示每 200 步後的總損失。 訓練模型和使用超參數的次數越多,生成的圖像就越好。
tensor(5365698., grad_fn=<AddBackward0>)
tensor(100573.4922, grad_fn=<AddBackward0>)
tensor(40841.7070, grad_fn=<AddBackward0>)
tensor(23182.7207, grad_fn=<AddBackward0>)
tensor(15629.9502, grad_fn=<AddBackward0>)
tensor(11835.2373, grad_fn=<AddBackward0>)
tensor(9588.9961, grad_fn=<AddBackward0>)
tensor(8060.4053, grad_fn=<AddBackward0>)
tensor(6925.2471, grad_fn=<AddBackward0>)
tensor(6039.4619, grad_fn=<AddBackward0>)
tensor(5327.7583, grad_fn=<AddBackward0>)
tensor(4743.5991, grad_fn=<AddBackward0>)
tensor(4255.8604, grad_fn=<AddBackward0>)
tensor(3845.0798, grad_fn=<AddBackward0>)
tensor(3493.4805, grad_fn=<AddBackward0>)
tensor(3190.8813, grad_fn=<AddBackward0>)
tensor(2926.9409, grad_fn=<AddBackward0>)
tensor(2694.3345, grad_fn=<AddBackward0>)
tensor(2488.2522, grad_fn=<AddBackward0>)
tensor(2304.4019, grad_fn=<AddBackward0>)
tensor(2139.8572, grad_fn=<AddBackward0>)
tensor(1991.9841, grad_fn=<AddBackward0>)
tensor(1858.3828, grad_fn=<AddBackward0>)
tensor(1737.2626, grad_fn=<AddBackward0>)
tensor(1627.4678, grad_fn=<AddBackward0>)
tensor(1527.8431, grad_fn=<AddBackward0>)
tensor(1436.7794, grad_fn=<AddBackward0>)
tensor(1352.9731, grad_fn=<AddBackward0>)
tensor(1275.8182, grad_fn=<AddBackward0>)
tensor(1204.6921, grad_fn=<AddBackward0>)
結論和要點
在本教程中,您在 Windows 操作系統上實現了神經式傳遞。 分步指南使用 Python3 和 PyTorch 將樣式從參考圖像轉移到原始圖像。 NST 是一種使用深度神經網絡生成具有不同藝術風格的圖像的過程。 該教程涵蓋了 VGG-19 神經風格過程,他在其中使用了三個圖像和五個卷積層。
機器學習和人工智能有各種各樣的應用,神經風格的遷移就是其中之一。 Vultur 收集了大量值得探索的技術文檔:
-
以下是各種作者通過各種技術發表的文章列表。
-
嘗試使用 Python 和 Scikit Learn 創建機器學習分類器。
-
了解稱為穩定擴散的開源深度學習模型,並通過短信生成圖像。
文章標題 名稱(可選) 電子郵件(可選) 描述
發送建議