正文
你可以比较一下 while 循环语句的下两种定义——第一个是 TensorFlow 中,第二个是 PyTorch 中:
import tensorflow as tf
first_counter = tf.constant(0)
second_counter = tf.constant(10)
some_value = tf.Variable(15)
# condition should handle all args:
def cond(first_counter, second_counter, *args):
return first_counter < second_counter
def body(first_counter, second_counter, some_value):
first_counter = tf.add(first_counter, 2)
second_counter = tf.add(second_counter, 1)
return first_counter, second_counter, some_value
c1, c2, val = tf.while_loop(
cond, body, [first_counter, second_counter, some_value])
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
counter_1_res, counter_2_res = sess.run([c1, c2])
import torch
first_counter = torch.Tensor([0])
second_counter = torch.Tensor([10])
some_value = torch.Tensor(15)
while (first_counter < second_counter)[0]:
first_counter += 2
second_counter += 1
看起来第二种方法比第一个简单多了,你觉得呢?
模型定义
现在我们看到,想在 PyTorch 中创建 if/else/while 复杂语句非常容易。不过让我们先回到常见模型中,PyTorch 提供了非常类似于 Keras 的、即开即用的层构造函数:
神经网络包(nn)定义了一系列的模块,它可以粗略地等价于神经网络的层。模块接收输入变量并计算输出变量,但也可以保存内部状态,例如包含可学习参数的变量。nn 包还定义了一组在训练神经网络时常用的损失函数。
from collections import OrderedDict
import torch.nn as nn
# Example of using Sequential
model = nn.Sequential(
nn.Conv2d(1, 20, 5),
nn.ReLU(),
nn.Conv2d(20, 64, 5),
nn.ReLU()
)
# Example of using Sequential with OrderedDict
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1, 20, 5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20, 64, 5)),
('relu2', nn.ReLU())
]))
output = model(some_input)
如果你想要构建复杂的模型,我们可以将 nn.Module 类子类化。当然,这两种方式也可以互相结合。
from torch import nn
class Model(nn.Module):
def __init__(self):
super().__init__()
self.feature_extractor = nn.Sequential(
nn.Conv2d(3, 12, kernel_size=3, padding=1, stride=1),
nn.Conv2d(12, 24, kernel_size=3, padding=1, stride=1),
)
self.second_extractor = nn.Conv2d(
24, 36, kernel_size=3, padding=1, stride=1)
def forward(self, x):
x = self.feature_extractor(x)
x = self.second_extractor(x)
# note that we may call same layer twice or mode
x = self.second_extractor(x)
return x
在__init__方法中,我们需要定义之后需要使用的所有层。在正向方法中,我们需要提出如何使用已经定义的层的步骤。而在反向传播上,和往常一样,计算是自动进行的。
自定义层
如果我们想要定义一些非标准反向传播模型要怎么办?这里有一个例子——XNOR 网络:
在这里我们不会深入细节,如果你对它感兴趣,可以参考一下原始论文:
https://arxiv.org/abs/1603.05279
与我们问题相关的是反向传播需要权重必须介于-1 到 1 之间。在 PyTorch 中,这可以很容易实现:
import torch
class MyFunction(torch.autograd.Function):
@staticmethod