实例 :手把手教你用PyTorch快速准确地建立神经网络(附4个学习用例)-程序员宅基地

作者:Shivam Bansal;翻译:陈之炎;校对:丁楠雅;

本文约5600字,建议阅读30+分钟。

本文中,我们将探讨PyTorch的全部内容。我们将不止学习理论,还包括编写4个不同的用例,看看PyTorch的表现如何。

简介


你可能已经在社交媒体上看到过N次关于PyTorch和 TensorFlow的两极分化的争论。这些框架的普及推动了近年来深度学习的兴起。二者都不乏坚定的支持者,但在过去的一年里,一个明显的赢家已经开始出现。


PyTorch是2018年最流行的框架之一。它已迅速成为学术界和工业界研究人员的首选深度学习框架。在过去几周使用了PyTorch之后,我体会到它是一个非常灵活且易于使用的深度学习库。


在本文中,我们将探讨PyTorch的全部内容。我们将不止学习理论-还包括编写4个不同的用例,看看PyTorch的表现如何。建立深度学习模型从来没有这么有趣过!


注:本文假设你对深度学习概念已经有了基本的理解。如果没有,我建议阅读下文。


内容


  • 什么是PyTorch?

  • 利用PyTorch构建神经网络

  • 用例1:手写数字分类(数字数据,MLP)

  • 用例2:物体图像分类(图像数据,CNN)

  • 用例3:情感文本分类(文本数据,RNN)

  • 用例4:图像样式的迁移(迁移学习)


什么是PyTorch?


在深入研究PyTorch的实现之前,让我们先了解一下PyTorch是什么,以及为什么它最近会变得如此流行。


PyTorch是一个基于Python的科学计算包,类似于NumPy,它具备GPU附加功能。与此同时,它也是一个深度学习框架,为实现和构建深层神经网络体系结构提供了最大程度的灵活性和速度。


最近发布的PyTorch 1.0帮助研究人员应对以下四大挑战:


  • 大面积的返工

  • 耗时的训练

  • Python语言缺乏灵活性

  • 慢速扩展


从本质上讲,PyTorch与其他深度学习框架有两个不同点:


  • 命令式编程

  • 动态计算图


命令式编程:PyTorch在遍历每一行代码的同时执行计算,这与Python程序的执行方式非常类似,这一概念称为命令式编程,它的最大优点是可以动态地调试代码和编程逻辑。


动态计算图:PyTorch被称为“由运行定义的”框架,这意味着计算图结构(神经网络体系结构)是在运行时生成的。该属性的主要优点是:它提供了一个灵活的编程运行时接口,通过连接操作来方便系统的构建和修改。在PyTorch中,每个前向通路处定义一个新的计算图,这与使用静态图的TensorFlow形成了鲜明的对比。


PyTorch1.0附带了一个名为torch.jit的重要特性,它是一个高级编译器,允许用户分离模型和代码。此外,它还支持在定制硬件(如GPU或TPU)上进行有效的模型优化。


用PyTorch构建神经网络


让我们通过一个实际案例来理解PyTorch。学习理论固然好,但是如果你不把它付诸实践的话,它就没有多大用处了!


神经网络的PyTorch实现看起来与NumPy实现完全一样。本节的目标是展示PyTorch和NumPy的等效性质。为此,让我们创建一个简单的三层网络,在输入层中有5个节点,在隐藏层中有3个节点,在输出层中有1个节点。我们只使用一个带有五个特征和一个目标的单行训练示例。


import torch

n_input, n_hidden, n_output = 5, 3, 1


第一步是进行参数初始化。这里,每个层的权重和偏置参数被初始化为张量变量。张量是PyTorch的基本数据结构,用于建立不同类型的神经网络。可以将它们当作是数组和矩阵的推广,换句话说,张量是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


在参数初始化完成之后,可以通过以下四个关键步骤来定义和训练神经网络:


  • 前向传播

  • 损失计算

  • 反向传播

  • 更新参数


让我们更详细地了解每一个步骤。


前向传播:在这个步骤中,每个层都使用以下两个公式计算激活流。这些激活流从输入层流向输出层,以生成最终输出。


1. z = weight * input + bias

2. a = activation_function (z)


下面的代码块显示了如何用PyTorch编写这些步骤。请注意,大多数函数,如指数和矩阵乘法,均与NumPy中的函数相类似。


## 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)


损失计算:这一步在输出层中计算误差 (也称为损失)。一个简单的损失函数可以用来衡量实际值和预测值之间的差异。稍后,我们将查看PyTorch中可用的不同类型的损失函数。


loss = y - output

 

反向传播:这一步的目的是通过对偏差和权重进行边际变化,从而将输出层的误差降到最低,边际变化是利用误差项的导数计算出来的。


根据链规则的微积分原理,将增量变化返回到隐藏层,并对其权重和偏差进行相应的修正。通过对权重和偏差的调整,使得误差最小化。


## 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


更新参数:最后一步,利用从上述反向传播中接收到的增量变化来对权重和偏差进行更新。


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


当使用大量训练示例对多个历元执行这些步骤时,损失将降至最小值。得到最终的权重和偏差值之后,用它对未知数据进行预测。


用例1:手写数字分类


在上一节中,我们看到了用PyTorch编写神经网络的简单用例。在本节中,我们将利用PyTorch提供的不同的实用程序包(nn、autograd、Optimm、torchvision、torchtext等)来建立和训练神经网络。


利用这些包可以方便地定义和管理神经网络。在这个用例中,我们将创建一个多层感知器(MLP)网络,用于构建手写数字分类器。我们将使用torchvision包中的MNIST数据集。


与你将要从事的任何项目一样,第一步是数据预处理首先需要将原始数据集转换为张量,并在固定范围内将其归一化。torchvision包提供了一个名为 transforms的实用程序,利用它可以将不同的转换组合在一起。


from torchvision import transforms

_tasks = transforms.Compose([

    transforms.ToTensor(),

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

    ])


第一个转换是将原始数据转换为张量,第二个转换是通过以下操作执行归一化:


x_normalized = x-mean / std


数值为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迭代器,它为多个处理器之间并行地批处理、搬移和加载数据提供了实现的可能。为了评估这个模型,我们将数据集划分为训练集和验证集。


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中的神经网络架构可以定义为一个类,这个类继承了称为Modulenn包的基础类的所有属性。来自nn.Module类的继承使得我们可以轻松地实现、访问和调用多个方法,还可以定义类的构造函数中的各个层,以及前向传播步骤中的前向函数。


我们将定义一个具有以下层配置的网络:[784,128,10]。此配置表示输入层中有784个节点(28*28像素)、隐藏层中有128个节点,输出层中有10个节点。在前向函数中,我们将在隐藏层(可以通过nn模块访问)中使用Sigmoid激活函数。


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包定义损失函数和优化器:


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)


现在已经准备好,可以开始训练模型了,其核心步骤与前一节相同:前向传播、损失计算、反向传播和更新参数。


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


完成了模型的训练之后,即可在验证数据基础上进行预测。


## 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:物体图像分类

 

现在让我们更进一步。


在这个用例中,我们将在PyTorch中创建卷积神经网络(CNN)架构,利用流行的CIFAR-10数据集进行物体图像分类,此数据集也包含在torchvision包中。定义和训练模型的整个过程将与以前的用例相同,唯一的区别只是在网络中引入了额外的层。


加载并转换数据集:


## 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)


我们将创建三个用于低层特征提取的卷积层、三个用于最大信息量提取的池化层和两个用于线性分类的线性层。


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()


定义损失函数和优化器:


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())


完成了模型的训练之后,即可在验证数据基础上进行预测。


## 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:情感文本分类


我们将从计算机视觉用例转向自然语言处理,目的是展示PyTorch在不同领域的不同应用。


在本节中,我们将利用基于RNN(递归神经网络)和LSTM(长短期记忆)层的Pyotch来完成文本分类任务。首先,加载包含两个字段(文本和目标)的数据集。目标包含两个类:class1和class2,我们的任务是将每个文本分为其中一个类。


可以在下面的链接中下载数据集。


https://s3-ap-south-1.amazonaws.com/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


强烈建议在编码之前先设置种子,它可以保证你看到的结果与我的相同-这是在学习新概念时非常有用(也很有益)的特征。


np.random.seed(123)

torch.manual_seed(123)

torch.cuda.manual_seed(123)

torch.backends.cudnn.deterministic = True


在预处理步骤中,首先将文本数据转换为tokens序列,之后便可以将其传递到嵌入层。我将利用Keras包中提供的实用程序来进行预处理,利用torchtext包也同样可以实现。


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转换成向量。为此,利用预先训练过的GloVe词嵌入。我们将加载这些单词嵌入,并创建一个包含单词向量的嵌入矩阵。


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()


创建训练和验证集:


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)


定义损失和优化器:


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())


最后得到预测结果:


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:图像样式迁移


让我们来看最后一个用例,在这里我们将执行图形样式的迁移。这是我经历过的最有创意的项目之一,希望你也能玩得开心。样式迁移概念背后的基本理念是:


  • 从一幅图像中获取对象/内容

  • 从另一幅图像中获取样式/纹理

  • 生成二者混合的最终图像


“利用卷积网络进行图像样式迁移”这篇论文中对这一概念做了介绍,样式迁移的一个例子如下:


太棒了,对吧?让我们看看它在PyTorch中是如何实现的。这一进程包括六个步骤:


  • 从两个输入图像中提取低层特征。这可以使用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中获取特征。另外,也可以应用以下转换:调整张量的大小,以及值的归一化。


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)


  • 现在,我们需要获得这两幅图像的相关特征。从第一个图像中,我们需要提取内容或与存在的对象相关的特征;从第二张图像中,我们需要提取与样式和纹理相关的特征。


对象相关特征:在最初的文章中,作者建议可以从网络的初始层中提取更有价值的对象和内容,这是因为在较高层上,信息空间变得更为复杂,像素信息细节在高层往往会丢失。


样式相关特征:为了从第二幅图像中获取样式和纹理信息,作者在不同层次上使用了不同特征之间的相关性,下文第4点对此作了详细解释。


在实现这一目标之前,让我们来看看一个典型的VGG 19模型的结构:


对象信息提取用到的是CONV42层,它位于第4个卷积块中,深度为512。对于样式的表达,用到的层是网络中每个卷积块的第一卷积层,即CONV11、CONV21、CONV31、CONV41和CONV51,这些层的选取纯粹是根据作者的经验来做出选择,我仅在本文中复制它们的结果。


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之间的内积。


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}


  • 最终,可以利用这些特征和相关性进行样式转换。现在,为了将样式从一个图像转换到另一个图像,需要设置用于获取样式特征的每一层的权重。如上所述,由于初始层提供了更多的信息,因此可以为初始层设置更高的权重。此外,定义优化器函数和目标图像,也即是图像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)


  • 启动损失最小化处理过程:即在循环中运行大量步骤,来计算与对象特征提取和样式特征提取相关的损失。利用最小化后的损失,更新网络参数,进一步修正目标图像。经过一些迭代之后,将生成更新后的图像。


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()


最后,我们可以看到预测的结果,在这里我只运行了一小部分迭代,还可以运行多达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还可以实现大量的其他用例,它很快成为全球研究人员的宠儿。绝大多数PyTorch实现的开源库和开发应用可以在Github上看到。

 

在本文中,我阐述了什么是PyTorch,以及如何用PyTorch实现不同的用例,当然,这个指南只是一个出发点。如果能提供更多的数据,或进行更多的网络参数微调,那么每个用例的性能都可以得到大幅度提高,最重要的是如果在构建网络体系架构时应用创新技能,也能提高用例的性能。感谢你的阅读,并请在下面的评论部分留下你的反馈。


参考文献


1. 官方PyTorch指南:

https://pytorch.org/tutorials/


2. 用PyTorch进行深度学习

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


3. Faizan在 Analytics Vidhya上发表的文章:

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


4. 使用Pytorch的Udacity深度学习: 

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


5. 图片样式迁移原始论文:

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


你还可以在Analytics Vidhya的安卓APP上阅读本文。


原本标题:Get Started with PyTorch – Learn How to Build Quick & Accurate Neural Networks (with 4 Case Studies!)

原文链接:https://www.analyticsvidhya.com/blog/2019/01/guide-pytorch-neural-networks-case-studies/

译者简介:陈之炎,北京交通大学通信与控制工程专业毕业,获得工学硕士学位,历任长城计算机软件与系统公司工程师,大唐微电子公司工程师,现任北京吾译超群科技有限公司技术支持。目前从事智能化翻译教学系统的运营和维护,在人工智能深度学习和自然语言处理(NLP)方面积累有一定的经验。

「完」


转自:数据派THU ;

版权声明:本号内容部分来自互联网,转载请注明原文链接和作者,如有侵权或出处有误请和我们联系。

关联阅读

原创系列文章:

1:从0开始搭建自己的数据运营指标体系(概括篇)

2 :从0开始搭建自己的数据运营指标体系(定位篇)

3 :从0开始搭建自己的数据运营体系(业务理解篇)

4 :数据指标的构建流程与逻辑

5 :系列 :从数据指标到数据运营指标体系

6:   实战 :为自己的公号搭建一个数据运营指标体系

7:  从0开始搭建自己的数据运营指标体系(运营活动分析)

数据运营 关联文章阅读:  

运营入门,从0到1搭建数据分析知识体系    

推荐 :数据分析师与运营协作的9个好习惯

干货 :手把手教你搭建数据化用户运营体系

推荐 :最用心的运营数据指标解读

干货 : 如何构建数据运营指标体系

从零开始,构建数据化运营体系

干货 :解读产品、运营和数据三个基友关系

干货 :从0到1搭建数据运营体系

数据分析、数据产品 关联文章阅读:

干货 :数据分析团队的搭建和思考

关于用户画像那些事,看这一文章就够了

数据分析师必需具备的10种分析思维。

如何构建大数据层级体系,看这一文章就够了

干货 : 聚焦于用户行为分析的数据产品

80%的运营注定了打杂?因为你没有搭建出一套有效的用户运营体系

从底层到应用,那些数据人的必备技能

读懂用户运营体系:用户分层和分群

做运营必须掌握的数据分析思维,你还敢说不会做数据分析

合作请加qq:365242293  


更多相关知识请回复:“ 月光宝盒 ”;

数据分析(ID : ecshujufenxi )互联网科技与数据圈自己的微信,也是WeMedia自媒体联盟成员之一,WeMedia联盟覆盖5000万人群。

640?wx_fmt=png

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Tw6cy6uKyDea86Z/article/details/86684648

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan