捷徑

模組

PyTorch 使用模組來表示神經網路。模組是

  • 有狀態計算的建構塊。 PyTorch 提供了一個強大的模組庫,並且可以輕鬆定義新的自定義模組,從而可以輕鬆構建複雜的多層神經網路。

  • 與 PyTorch 的 autograd 系統緊密整合。 模組使 PyTorch 的 Optimizers 可以輕鬆指定可學習的參數以進行更新。

  • 易於使用和轉換。 模組可以輕鬆保存和還原、在 CPU / GPU / TPU 裝置之間傳輸、修剪、量化等等。

本筆記描述了模組,適用於所有 PyTorch 使用者。由於模組是 PyTorch 的基礎,本筆記中的許多主題在其他筆記或教學文件中都有詳細說明,此處也提供了許多這些文件的連結。

一個簡單的自定義模組

首先,讓我們看一下 PyTorch 的 Linear 模組的一個更簡單的自定義版本。此模組將仿射轉換應用於其輸入。

import torch
from torch import nn

class MyLinear(nn.Module):
  def __init__(self, in_features, out_features):
    super().__init__()
    self.weight = nn.Parameter(torch.randn(in_features, out_features))
    self.bias = nn.Parameter(torch.randn(out_features))

  def forward(self, input):
    return (input @ self.weight) + self.bias

這個簡單的模組具有以下模組的基本特徵

  • 它繼承自基礎 Module 類別。 所有模組都應該子類化 Module,以便與其他模組組合。

  • 它定義了一些用於計算的「狀態」。 在這裡,狀態包含隨機初始化的 weightbias 張量,它們定義了仿射轉換。由於它們中的每一個都被定義為 Parameter,因此它們會被註冊到模組中,並會自動追蹤並從呼叫 parameters() 返回。參數可以被認為是模組計算的「可學習」方面(稍後會詳細介紹)。請注意,模組不一定需要有狀態,也可以是無狀態的。

  • 它定義了一個執行計算的 forward() 函數。 對於這個仿射轉換模組,輸入與 weight 參數進行矩陣相乘(使用 @ 簡寫符號),並添加到 bias 參數以產生輸出。更一般地說,模組的 forward() 實作可以執行涉及任意數量的輸入和輸出的任意計算。

這個簡單的模組演示了模組如何將狀態和計算封裝在一起。可以建構並呼叫此模組的實例

m = MyLinear(4, 3)
sample_input = torch.randn(4)
m(sample_input)
: tensor([-0.3037, -1.0413, -4.2057], grad_fn=<AddBackward0>)

請注意,模組本身是可呼叫的,並且呼叫它會調用其 forward() 函數。這個名稱是指「前向傳遞」和「反向傳遞」的概念,它們適用於每個模組。「前向傳遞」負責將模組表示的計算應用於給定的輸入(如上面的程式碼片段所示)。「反向傳遞」計算模組輸出相對於其輸入的梯度,這些梯度可用於通過梯度下降方法「訓練」參數。PyTorch 的 autograd 系統會自動處理這種反向傳遞計算,因此無需為每個模組手動實作 backward() 函數。透過連續的前向/反向傳遞訓練模組參數的過程在 使用模組進行神經網路訓練 中有詳細介紹。

可以透過呼叫 parameters()named_parameters() 來迭代模組註冊的完整參數集,後者包括每個參數的名稱

for parameter in m.named_parameters():
  print(parameter)
: ('weight', Parameter containing:
tensor([[ 1.0597,  1.1796,  0.8247],
        [-0.5080, -1.2635, -1.1045],
        [ 0.0593,  0.2469, -1.4299],
        [-0.4926, -0.5457,  0.4793]], requires_grad=True))
('bias', Parameter containing:
tensor([ 0.3634,  0.2015, -0.8525], requires_grad=True))

通常,模組註冊的參數是模組計算中應該「學習」的方面。本筆記的後續章節將展示如何使用 PyTorch 的其中一個 Optimizers 來更新這些參數。不過,在我們開始之前,讓我們先檢查一下模組如何彼此組合。

模組作為建構區塊

模組可以包含其他模組,使其成為開發更精細功能的有用建構區塊。最簡單的方法是使用 Sequential 模組。它允許我們將多個模組串聯在一起

net = nn.Sequential(
  MyLinear(4, 3),
  nn.ReLU(),
  MyLinear(3, 1)
)

sample_input = torch.randn(4)
net(sample_input)
: tensor([-0.6749], grad_fn=<AddBackward0>)

請注意,Sequential 會自動將第一個 MyLinear 模組的輸出作為輸入饋送到 ReLU 中,並將該輸出作為輸入饋送到第二個 MyLinear 模組中。如圖所示,它僅限於具有單個輸入和輸出的模組的依序鏈接。

通常,建議為超出最簡單用例的任何內容定義自定義模組,因為這可以完全靈活地控制子模組如何用於模組的計算。

例如,這是一個實現為自定義模組的簡單神經網路

import torch.nn.functional as F

class Net(nn.Module):
  def __init__(self):
    super().__init__()
    self.l0 = MyLinear(4, 3)
    self.l1 = MyLinear(3, 1)
  def forward(self, x):
    x = self.l0(x)
    x = F.relu(x)
    x = self.l1(x)
    return x

此模組由兩個「子元件」或「子模組」(l0l1)組成,它們定義了神經網路的層,並用於模組的 forward() 方法中的計算。可以透過呼叫 children()named_children() 來迭代模組的直接子元件

net = Net()
for child in net.named_children():
  print(child)
: ('l0', MyLinear())
('l1', MyLinear())

要深入到僅僅是直接子元件之外,modules()named_modules()遞迴地迭代模組及其子模組

class BigNet(nn.Module):
  def __init__(self):
    super().__init__()
    self.l1 = MyLinear(5, 4)
    self.net = Net()
  def forward(self, x):
    return self.net(self.l1(x))

big_net = BigNet()
for module in big_net.named_modules():
  print(module)
: ('', BigNet(
  (l1): MyLinear()
  (net): Net(
    (l0): MyLinear()
    (l1): MyLinear()
  )
))
('l1', MyLinear())
('net', Net(
  (l0): MyLinear()
  (l1): MyLinear()
))
('net.l0', MyLinear())
('net.l1', MyLinear())

有時,模組需要動態定義子模組。ModuleListModuleDict 模組在這裡很有用;它們從列表或字典註冊子模組

class DynamicNet(nn.Module):
  def __init__(self, num_layers):
    super().__init__()
    self.linears = nn.ModuleList(
      [MyLinear(4, 4) for _ in range(num_layers)])
    self.activations = nn.ModuleDict({
      'relu': nn.ReLU(),
      'lrelu': nn.LeakyReLU()
    })
    self.final = MyLinear(4, 1)
  def forward(self, x, act):
    for linear in self.linears:
      x = linear(x)
      x = self.activations[act](x)
    x = self.final(x)
    return x

dynamic_net = DynamicNet(3)
sample_input = torch.randn(4)
output = dynamic_net(sample_input, 'relu')

對於任何給定的模組,其參數包含其直接參數以及所有子模組的參數。這意味著呼叫 parameters()named_parameters() 將會遞迴地包含子參數,以便方便地優化網路中的所有參數。

for parameter in dynamic_net.named_parameters():
  print(parameter)
: ('linears.0.weight', Parameter containing:
tensor([[-1.2051,  0.7601,  1.1065,  0.1963],
        [ 3.0592,  0.4354,  1.6598,  0.9828],
        [-0.4446,  0.4628,  0.8774,  1.6848],
        [-0.1222,  1.5458,  1.1729,  1.4647]], requires_grad=True))
('linears.0.bias', Parameter containing:
tensor([ 1.5310,  1.0609, -2.0940,  1.1266], requires_grad=True))
('linears.1.weight', Parameter containing:
tensor([[ 2.1113, -0.0623, -1.0806,  0.3508],
        [-0.0550,  1.5317,  1.1064, -0.5562],
        [-0.4028, -0.6942,  1.5793, -1.0140],
        [-0.0329,  0.1160, -1.7183, -1.0434]], requires_grad=True))
('linears.1.bias', Parameter containing:
tensor([ 0.0361, -0.9768, -0.3889,  1.1613], requires_grad=True))
('linears.2.weight', Parameter containing:
tensor([[-2.6340, -0.3887, -0.9979,  0.0767],
        [-0.3526,  0.8756, -1.5847, -0.6016],
        [-0.3269, -0.1608,  0.2897, -2.0829],
        [ 2.6338,  0.9239,  0.6943, -1.5034]], requires_grad=True))
('linears.2.bias', Parameter containing:
tensor([ 1.0268,  0.4489, -0.9403,  0.1571], requires_grad=True))
('final.weight', Parameter containing:
tensor([[ 0.2509], [-0.5052], [ 0.3088], [-1.4951]], requires_grad=True))
('final.bias', Parameter containing:
tensor([0.3381], requires_grad=True))

使用 to() 也可以輕鬆地將所有參數移動到不同的設備或更改其精度。

# Move all parameters to a CUDA device
dynamic_net.to(device='cuda')

# Change precision of all parameters
dynamic_net.to(dtype=torch.float64)

dynamic_net(torch.randn(5, device='cuda', dtype=torch.float64))
: tensor([6.5166], device='cuda:0', dtype=torch.float64, grad_fn=<AddBackward0>)

更廣泛地說,可以使用 apply() 函數將任意函數遞迴地應用於模組及其子模組。 例如,將自定義初始化應用於模組及其子模組的參數。

# Define a function to initialize Linear weights.
# Note that no_grad() is used here to avoid tracking this computation in the autograd graph.
@torch.no_grad()
def init_weights(m):
  if isinstance(m, nn.Linear):
    nn.init.xavier_normal_(m.weight)
    m.bias.fill_(0.0)

# Apply the function recursively on the module and its submodules.
dynamic_net.apply(init_weights)

這些範例展示了如何通過模組組合形成精密的類神經網路,並方便地進行操作。 為了能夠以最少的樣板程式碼快速輕鬆地構建類神經網路,PyTorch 在 torch.nn 命名空間中提供了大量效能良好的模組,這些模組執行常見的類神經網路操作,如池化 (pooling)、卷積 (convolutions)、損失函數 (loss functions) 等。

在下一節中,我們將提供一個訓練類神經網路的完整範例。

如需更多資訊,請參閱:

使用模組進行類神經網路訓練

一旦構建了網路,就必須對其進行訓練,並且可以使用 torch.optim 中的 PyTorch 優化器輕鬆地優化其參數。

# Create the network (from previous section) and optimizer
net = Net()
optimizer = torch.optim.SGD(net.parameters(), lr=1e-4, weight_decay=1e-2, momentum=0.9)

# Run a sample training loop that "teaches" the network
# to output the constant zero function
for _ in range(10000):
  input = torch.randn(4)
  output = net(input)
  loss = torch.abs(output)
  net.zero_grad()
  loss.backward()
  optimizer.step()

# After training, switch the module to eval mode to do inference, compute performance metrics, etc.
# (see discussion below for a description of training and evaluation modes)
...
net.eval()
...

在這個簡化的範例中,網路學習簡單地輸出零,因為任何非零輸出都會根據其絕對值通過使用 torch.abs() 作為損失函數來「懲罰」。雖然這不是一個非常有趣的任務,但訓練的關鍵部分都存在。

  • 建立一個網路。

  • 建立一個優化器(在本例中,是一個隨機梯度下降優化器),並將網路的參數與之關聯。

  • 一個訓練迴圈…
    • 取得一個輸入,

    • 執行網路,

    • 計算一個損失,

    • 將網路參數的梯度歸零,

    • 呼叫 loss.backward() 來更新參數的梯度,

    • 呼叫 optimizer.step() 將梯度應用於參數。

在執行完上面的程式碼片段後,請注意網路的參數已更改。 特別是,檢查 l1weight 參數的值表明,其值現在更接近於 0(正如預期的那樣)。

print(net.l1.weight)
: Parameter containing:
tensor([[-0.0013],
        [ 0.0030],
        [-0.0008]], requires_grad=True)

請注意,上述過程完全是在網路模組處於「訓練模式」時完成的。 模組預設為訓練模式,可以使用 train()eval() 在訓練和評估模式之間切換。 根據它們所處的模式,它們的行為可能會有所不同。 例如,BatchNorm 模組在訓練期間維護一個運行平均值和變異數,當模組處於評估模式時,這些值不會更新。 一般來說,模組在訓練期間應處於訓練模式,並且僅在推論或評估時切換到評估模式。 以下是一個自定義模組的範例,該模組在兩種模式下的行為不同。

class ModalModule(nn.Module):
  def __init__(self):
    super().__init__()

  def forward(self, x):
    if self.training:
      # Add a constant only in training mode.
      return x + 1.
    else:
      return x


m = ModalModule()
x = torch.randn(4)

print('training mode output: {}'.format(m(x)))
: tensor([1.6614, 1.2669, 1.0617, 1.6213, 0.5481])

m.eval()
print('evaluation mode output: {}'.format(m(x)))
: tensor([ 0.6614,  0.2669,  0.0617,  0.6213, -0.4519])

訓練類神經網路通常很棘手。 如需更多資訊,請參閱:

模組狀態

在前一節中,我們演示了訓練模組的「參數」,即計算的可學習方面。 現在,如果我們要將訓練好的模型儲存到磁碟,我們可以通過儲存它的 state_dict(即「狀態字典」)來實現。

# Save the module
torch.save(net.state_dict(), 'net.pt')

...

# Load the module later on
new_net = Net()
new_net.load_state_dict(torch.load('net.pt'))
: <All keys matched successfully>

模組的 state_dict 包含影響其計算的狀態。 這包括但不限於模組的參數。 對於某些模組,擁有超出參數範圍的狀態可能是有用的,這些狀態會影響模組計算但不可學習。 對於這種情況,PyTorch 提供了「緩衝區」的概念,包括「持久性」和「非持久性」緩衝區。 以下是模組可以擁有的各種狀態類型的概述。

  • 參數:計算的可學習方面;包含在 state_dict 中。

  • 緩衝區:計算的不可學習方面。

    • 持久性緩衝區:包含在 state_dict 中(即,在儲存和載入時序列化)。

    • 非持久性緩衝區:不包含在 state_dict 中(即,從序列化中排除)。

作為使用緩衝區的動機範例,考慮一個維護運行平均值的簡單模組。 我們希望運行平均值的當前值被視為模組的 state_dict 的一部分,以便在載入模組的序列化形式時將其還原,但我們不希望它是可學習的。 這個程式碼片段展示了如何使用 register_buffer() 來完成此操作。

class RunningMean(nn.Module):
  def __init__(self, num_features, momentum=0.9):
    super().__init__()
    self.momentum = momentum
    self.register_buffer('mean', torch.zeros(num_features))
  def forward(self, x):
    self.mean = self.momentum * self.mean + (1.0 - self.momentum) * x
    return self.mean

現在,運行平均值的當前值被視為模組的 state_dict 的一部分,並且在從磁碟載入模組時將被正確還原。

m = RunningMean(4)
for _ in range(10):
  input = torch.randn(4)
  m(input)

print(m.state_dict())
: OrderedDict([('mean', tensor([ 0.1041, -0.1113, -0.0647,  0.1515]))]))

# Serialized form will contain the 'mean' tensor
torch.save(m.state_dict(), 'mean.pt')

m_loaded = RunningMean(4)
m_loaded.load_state_dict(torch.load('mean.pt'))
assert(torch.all(m.mean == m_loaded.mean))

如先前所述,緩衝區可以透過將它們標記為非持久性,從模組的 state_dict 中省略。

self.register_buffer('unserialized_thing', torch.randn(5), persistent=False)

持久性和非持久性緩衝區都會受到使用 to() 應用於整個模型的裝置/dtype 變更的影響。

# Moves all module parameters and buffers to the specified device / dtype
m.to(device='cuda', dtype=torch.float64)

可以使用 buffers()named_buffers() 迭代模組的緩衝區。

for buffer in m.named_buffers():
  print(buffer)

以下類別示範了在模組中註冊參數和緩衝區的各種方法。

class StatefulModule(nn.Module):
  def __init__(self):
    super().__init__()
    # Setting a nn.Parameter as an attribute of the module automatically registers the tensor
    # as a parameter of the module.
    self.param1 = nn.Parameter(torch.randn(2))

    # Alternative string-based way to register a parameter.
    self.register_parameter('param2', nn.Parameter(torch.randn(3)))

    # Reserves the "param3" attribute as a parameter, preventing it from being set to anything
    # except a parameter. "None" entries like this will not be present in the module's state_dict.
    self.register_parameter('param3', None)

    # Registers a list of parameters.
    self.param_list = nn.ParameterList([nn.Parameter(torch.randn(2)) for i in range(3)])

    # Registers a dictionary of parameters.
    self.param_dict = nn.ParameterDict({
      'foo': nn.Parameter(torch.randn(3)),
      'bar': nn.Parameter(torch.randn(4))
    })

    # Registers a persistent buffer (one that appears in the module's state_dict).
    self.register_buffer('buffer1', torch.randn(4), persistent=True)

    # Registers a non-persistent buffer (one that does not appear in the module's state_dict).
    self.register_buffer('buffer2', torch.randn(5), persistent=False)

    # Reserves the "buffer3" attribute as a buffer, preventing it from being set to anything
    # except a buffer. "None" entries like this will not be present in the module's state_dict.
    self.register_buffer('buffer3', None)

    # Adding a submodule registers its parameters as parameters of the module.
    self.linear = nn.Linear(2, 3)

m = StatefulModule()

# Save and load state_dict.
torch.save(m.state_dict(), 'state.pt')
m_loaded = StatefulModule()
m_loaded.load_state_dict(torch.load('state.pt'))

# Note that non-persistent buffer "buffer2" and reserved attributes "param3" and "buffer3" do
# not appear in the state_dict.
print(m_loaded.state_dict())
: OrderedDict([('param1', tensor([-0.0322,  0.9066])),
               ('param2', tensor([-0.4472,  0.1409,  0.4852])),
               ('buffer1', tensor([ 0.6949, -0.1944,  1.2911, -2.1044])),
               ('param_list.0', tensor([ 0.4202, -0.1953])),
               ('param_list.1', tensor([ 1.5299, -0.8747])),
               ('param_list.2', tensor([-1.6289,  1.4898])),
               ('param_dict.bar', tensor([-0.6434,  1.5187,  0.0346, -0.4077])),
               ('param_dict.foo', tensor([-0.0845, -1.4324,  0.7022])),
               ('linear.weight', tensor([[-0.3915, -0.6176],
                                         [ 0.6062, -0.5992],
                                         [ 0.4452, -0.2843]])),
               ('linear.bias', tensor([-0.3710, -0.0795, -0.3947]))])

如需更多資訊,請參閱:

模組初始化

預設情況下,由 torch.nn 提供的模組的參數和浮點緩衝區,會在模組實例化期間,使用一種歷史上被認為對該模組類型表現良好的初始化方案,初始化為 CPU 上的 32 位元浮點數值。在某些使用案例中,可能希望使用不同的 dtype、裝置 (例如 GPU) 或初始化技術進行初始化。

範例

# Initialize module directly onto GPU.
m = nn.Linear(5, 3, device='cuda')

# Initialize module with 16-bit floating point parameters.
m = nn.Linear(5, 3, dtype=torch.half)

# Skip default parameter initialization and perform custom (e.g. orthogonal) initialization.
m = torch.nn.utils.skip_init(nn.Linear, 5, 3)
nn.init.orthogonal_(m.weight)

請注意,上面示範的裝置和 dtype 選項也適用於為模組註冊的任何浮點緩衝區。

m = nn.BatchNorm2d(3, dtype=torch.half)
print(m.running_mean)
: tensor([0., 0., 0.], dtype=torch.float16)

雖然模組編寫者可以使用任何裝置或 dtype 來初始化其自訂模組中的參數,但良好的做法是預設也使用 dtype=torch.floatdevice='cpu'。或者,您可以透過遵循上述慣例,為您的自訂模組提供這些領域的完全彈性,即所有 torch.nn 模組都遵循此慣例。

  • 提供一個 device 建構函式 kwarg,它適用於模組註冊的任何參數/緩衝區。

  • 提供一個 dtype 建構函式 kwarg,它適用於模組註冊的任何參數/浮點緩衝區。

  • 僅在模組的建構函式中使用初始化函數(即來自 torch.nn.init 的函數)來初始化參數和緩衝區。請注意,這僅在使用 skip_init() 時才需要;請參閱 此頁面 以獲得說明。

如需更多資訊,請參閱:

模組 Hook

使用模組進行神經網路訓練 中,我們示範了模組的訓練過程,該過程迭代地執行前向和後向傳遞,並在每次迭代中更新模組參數。為了更好地控制此過程,PyTorch 提供了 “hooks”,可以在前向或後向傳遞期間執行任意計算,甚至可以根據需要修改傳遞的執行方式。此功能的一些有用範例包括除錯、視覺化啟動、深入檢查梯度等。可以將 Hooks 新增到您自己尚未編寫的模組中,這意味著此功能可以應用於第三方或 PyTorch 提供的模組。

PyTorch 為模組提供兩種 hooks

所有的 Hook 都允許使用者回傳一個更新後的值,這個值將會用於後續的計算中。因此,這些 Hook 可以用來執行任意程式碼,在模組的前向/反向傳播過程中,或是修改輸入/輸出,而不需要更改模組的 forward() 函式。

下方範例展示了前向和反向 Hook 的用法

torch.manual_seed(1)

def forward_pre_hook(m, inputs):
  # Allows for examination and modification of the input before the forward pass.
  # Note that inputs are always wrapped in a tuple.
  input = inputs[0]
  return input + 1.

def forward_hook(m, inputs, output):
  # Allows for examination of inputs / outputs and modification of the outputs
  # after the forward pass. Note that inputs are always wrapped in a tuple while outputs
  # are passed as-is.

  # Residual computation a la ResNet.
  return output + inputs[0]

def backward_hook(m, grad_inputs, grad_outputs):
  # Allows for examination of grad_inputs / grad_outputs and modification of
  # grad_inputs used in the rest of the backwards pass. Note that grad_inputs and
  # grad_outputs are always wrapped in tuples.
  new_grad_inputs = [torch.ones_like(gi) * 42. for gi in grad_inputs]
  return new_grad_inputs

# Create sample module & input.
m = nn.Linear(3, 3)
x = torch.randn(2, 3, requires_grad=True)

# ==== Demonstrate forward hooks. ====
# Run input through module before and after adding hooks.
print('output with no forward hooks: {}'.format(m(x)))
: output with no forward hooks: tensor([[-0.5059, -0.8158,  0.2390],
                                        [-0.0043,  0.4724, -0.1714]], grad_fn=<AddmmBackward>)

# Note that the modified input results in a different output.
forward_pre_hook_handle = m.register_forward_pre_hook(forward_pre_hook)
print('output with forward pre hook: {}'.format(m(x)))
: output with forward pre hook: tensor([[-0.5752, -0.7421,  0.4942],
                                        [-0.0736,  0.5461,  0.0838]], grad_fn=<AddmmBackward>)

# Note the modified output.
forward_hook_handle = m.register_forward_hook(forward_hook)
print('output with both forward hooks: {}'.format(m(x)))
: output with both forward hooks: tensor([[-1.0980,  0.6396,  0.4666],
                                          [ 0.3634,  0.6538,  1.0256]], grad_fn=<AddBackward0>)

# Remove hooks; note that the output here matches the output before adding hooks.
forward_pre_hook_handle.remove()
forward_hook_handle.remove()
print('output after removing forward hooks: {}'.format(m(x)))
: output after removing forward hooks: tensor([[-0.5059, -0.8158,  0.2390],
                                               [-0.0043,  0.4724, -0.1714]], grad_fn=<AddmmBackward>)

# ==== Demonstrate backward hooks. ====
m(x).sum().backward()
print('x.grad with no backwards hook: {}'.format(x.grad))
: x.grad with no backwards hook: tensor([[ 0.4497, -0.5046,  0.3146],
                                         [ 0.4497, -0.5046,  0.3146]])

# Clear gradients before running backward pass again.
m.zero_grad()
x.grad.zero_()

m.register_full_backward_hook(backward_hook)
m(x).sum().backward()
print('x.grad with backwards hook: {}'.format(x.grad))
: x.grad with backwards hook: tensor([[42., 42., 42.],
                                      [42., 42., 42.]])

進階功能

PyTorch 也提供了一些設計用於模組的更進階功能。所有這些功能都適用於自定義編寫的模組,但需要注意的是,某些功能可能要求模組符合特定的約束才能被支援。關於這些功能及其對應需求的深入討論,請參閱以下連結。

分散式訓練

PyTorch 內有多種分散式訓練的方法,可用於擴展使用多個 GPU 的訓練,以及跨多個機器的訓練。 請查看分散式訓練概述頁面,以獲取關於如何使用它們的詳細資訊。

性能分析

PyTorch Profiler 可以幫助識別模型中的性能瓶頸。 它可以測量並輸出內存使用量和花費時間的性能特徵。

使用量化提升性能

將量化技術應用於模組,可以透過使用比浮點精度更低的位元寬度來提高性能和內存使用率。 查看 PyTorch 提供的各種量化機制 這裡

使用剪枝改善內存使用

大型深度學習模型通常過度參數化,導致高內存使用率。為了應對這個問題,PyTorch 提供了模型剪枝機制,有助於減少內存使用率,同時保持任務準確性。 剪枝教學 描述了如何使用 PyTorch 提供的剪枝技術,或在必要時定義自定義剪枝技術。

參數化

對於某些應用,在模型訓練期間約束參數空間可能是有益的。 例如,強制學習到的參數的正交性可以改善 RNN 的收斂性。 PyTorch 提供了一種應用 參數化 的機制,例如這種正交性約束,並進一步允許定義自定義約束。

使用 FX 轉換模組

PyTorch 的 FX 組件提供了一種靈活的方式,透過直接操作模組計算圖來轉換模組。 這可用於以程式化的方式生成或操作模組,以用於廣泛的用例。 若要探索 FX,請查看使用 FX 進行 卷積 + 批次正規化融合CPU 性能分析 的這些範例。

文件

存取 PyTorch 的完整開發者文件

檢視文件

教學

獲取初學者和高級開發人員的深入教學

檢視教學

資源

尋找開發資源並獲得問題解答

檢視資源