色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

PyTorch教程-9.5. 從零開始的遞歸神經網絡實現

jf_pJlTbmA9 ? 來源:PyTorch ? 作者:PyTorch ? 2023-06-05 15:44 ? 次閱讀

我們現在準備好從頭開始實施 RNN。特別是,我們將訓練此 RNN 作為字符級語言模型(參見 第 9.4 節),并按照第 9.2 節中概述的數據處理步驟,在由 HG Wells 的《時間機器》的整個文本組成的語料庫上對其進行訓練. 我們首先加載數據集。

%matplotlib inline
import math
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l

%matplotlib inline
import math
from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()

%matplotlib inline
import math
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l

%matplotlib inline
import math
import tensorflow as tf
from d2l import tensorflow as d2l

9.5.1. 循環神經網絡模型

我們首先定義一個類來實現 RNN 模型(第 9.4.2 節)。請注意,隱藏單元的數量num_hiddens是一個可調的超參數。

class RNNScratch(d2l.Module): #@save
  """The RNN model implemented from scratch."""
  def __init__(self, num_inputs, num_hiddens, sigma=0.01):
    super().__init__()
    self.save_hyperparameters()
    self.W_xh = nn.Parameter(
      torch.randn(num_inputs, num_hiddens) * sigma)
    self.W_hh = nn.Parameter(
      torch.randn(num_hiddens, num_hiddens) * sigma)
    self.b_h = nn.Parameter(torch.zeros(num_hiddens))

class RNNScratch(d2l.Module): #@save
  """The RNN model implemented from scratch."""
  def __init__(self, num_inputs, num_hiddens, sigma=0.01):
    super().__init__()
    self.save_hyperparameters()
    self.W_xh = np.random.randn(num_inputs, num_hiddens) * sigma
    self.W_hh = np.random.randn(
      num_hiddens, num_hiddens) * sigma
    self.b_h = np.zeros(num_hiddens)

class RNNScratch(nn.Module): #@save
  """The RNN model implemented from scratch."""
  num_inputs: int
  num_hiddens: int
  sigma: float = 0.01

  def setup(self):
    self.W_xh = self.param('W_xh', nn.initializers.normal(self.sigma),
                (self.num_inputs, self.num_hiddens))
    self.W_hh = self.param('W_hh', nn.initializers.normal(self.sigma),
                (self.num_hiddens, self.num_hiddens))
    self.b_h = self.param('b_h', nn.initializers.zeros, (self.num_hiddens))

class RNNScratch(d2l.Module): #@save
  """The RNN model implemented from scratch."""
  def __init__(self, num_inputs, num_hiddens, sigma=0.01):
    super().__init__()
    self.save_hyperparameters()
    self.W_xh = tf.Variable(tf.random.normal(
      (num_inputs, num_hiddens)) * sigma)
    self.W_hh = tf.Variable(tf.random.normal(
      (num_hiddens, num_hiddens)) * sigma)
    self.b_h = tf.Variable(tf.zeros(num_hiddens))

下面的方法forward定義了如何計算任何時間步的輸出和隱藏狀態,給定當前輸入和模型在前一個時間步的狀態。請注意,RNN 模型循環遍歷 的最外層維度inputs,一次更新隱藏狀態。這里的模型使用了tanh激活函數(第 5.1.2.3 節)。

@d2l.add_to_class(RNNScratch) #@save
def forward(self, inputs, state=None):
  if state is None:
    # Initial state with shape: (batch_size, num_hiddens)
    state = torch.zeros((inputs.shape[1], self.num_hiddens),
             device=inputs.device)
  else:
    state, = state
  outputs = []
  for X in inputs: # Shape of inputs: (num_steps, batch_size, num_inputs)
    state = torch.tanh(torch.matmul(X, self.W_xh) +
             torch.matmul(state, self.W_hh) + self.b_h)
    outputs.append(state)
  return outputs, state

@d2l.add_to_class(RNNScratch) #@save
def forward(self, inputs, state=None):
  if state is None:
    # Initial state with shape: (batch_size, num_hiddens)
    state = np.zeros((inputs.shape[1], self.num_hiddens),
             ctx=inputs.ctx)
  else:
    state, = state
  outputs = []
  for X in inputs: # Shape of inputs: (num_steps, batch_size, num_inputs)
    state = np.tanh(np.dot(X, self.W_xh) +
             np.dot(state, self.W_hh) + self.b_h)
    outputs.append(state)
  return outputs, state

@d2l.add_to_class(RNNScratch) #@save
def __call__(self, inputs, state=None):
  if state is not None:
    state, = state
  outputs = []
  for X in inputs: # Shape of inputs: (num_steps, batch_size, num_inputs)
    state = jnp.tanh(jnp.matmul(X, self.W_xh) + (
      jnp.matmul(state, self.W_hh) if state is not None else 0)
             + self.b_h)
    outputs.append(state)
  return outputs, state

@d2l.add_to_class(RNNScratch) #@save
def forward(self, inputs, state=None):
  if state is None:
    # Initial state with shape: (batch_size, num_hiddens)
    state = tf.zeros((inputs.shape[1], self.num_hiddens))
  else:
    state, = state
    state = tf.reshape(state, (-1, self.num_hiddens))
  outputs = []
  for X in inputs: # Shape of inputs: (num_steps, batch_size, num_inputs)
    state = tf.tanh(tf.matmul(X, self.W_xh) +
             tf.matmul(state, self.W_hh) + self.b_h)
    outputs.append(state)
  return outputs, state

我們可以將一小批輸入序列輸入 RNN 模型,如下所示。

batch_size, num_inputs, num_hiddens, num_steps = 2, 16, 32, 100
rnn = RNNScratch(num_inputs, num_hiddens)
X = torch.ones((num_steps, batch_size, num_inputs))
outputs, state = rnn(X)

batch_size, num_inputs, num_hiddens, num_steps = 2, 16, 32, 100
rnn = RNNScratch(num_inputs, num_hiddens)
X = np.ones((num_steps, batch_size, num_inputs))
outputs, state = rnn(X)

batch_size, num_inputs, num_hiddens, num_steps = 2, 16, 32, 100
rnn = RNNScratch(num_inputs, num_hiddens)
X = jnp.ones((num_steps, batch_size, num_inputs))
(outputs, state), _ = rnn.init_with_output(d2l.get_key(), X)

batch_size, num_inputs, num_hiddens, num_steps = 2, 16, 32, 100
rnn = RNNScratch(num_inputs, num_hiddens)
X = tf.ones((num_steps, batch_size, num_inputs))
outputs, state = rnn(X)

讓我們檢查一下 RNN 模型是否產生了正確形狀的結果,以確保隱藏狀態的維數保持不變。

def check_len(a, n): #@save
  """Check the length of a list."""
  assert len(a) == n, f'list's length {len(a)} != expected length {n}'

def check_shape(a, shape): #@save
  """Check the shape of a tensor."""
  assert a.shape == shape, 
      f'tensor's shape {a.shape} != expected shape {shape}'

check_len(outputs, num_steps)
check_shape(outputs[0], (batch_size, num_hiddens))
check_shape(state, (batch_size, num_hiddens))

9.5.2. 基于循環神經網絡的語言模型

下面的類定義了一個基于 RNN 的語言模型,我們通過方法的參數 RNNLMScratch傳入我們的 RNN 。在訓練語言模型時,輸入和輸出來自相同的詞匯表。因此,它們具有相同的維度,即詞匯量大小。請注意,我們使用困惑來評估模型。正如 第 9.3.2 節中所討論的,這確保了不同長度的序列是可比較的。rnn__init__

class RNNLMScratch(d2l.Classifier): #@save
  """The RNN-based language model implemented from scratch."""
  def __init__(self, rnn, vocab_size, lr=0.01):
    super().__init__()
    self.save_hyperparameters()
    self.init_params()

  def init_params(self):
    self.W_hq = nn.Parameter(
      torch.randn(
        self.rnn.num_hiddens, self.vocab_size) * self.rnn.sigma)
    self.b_q = nn.Parameter(torch.zeros(self.vocab_size))

  def training_step(self, batch):
    l = self.loss(self(*batch[:-1]), batch[-1])
    self.plot('ppl', torch.exp(l), train=True)
    return l

  def validation_step(self, batch):
    l = self.loss(self(*batch[:-1]), batch[-1])
    self.plot('ppl', torch.exp(l), train=False)

class RNNLMScratch(d2l.Classifier): #@save
  """The RNN-based language model implemented from scratch."""
  def __init__(self, rnn, vocab_size, lr=0.01):
    super().__init__()
    self.save_hyperparameters()
    self.init_params()

  def init_params(self):
    self.W_hq = np.random.randn(
      self.rnn.num_hiddens, self.vocab_size) * self.rnn.sigma
    self.b_q = np.zeros(self.vocab_size)
    for param in self.get_scratch_params():
      param.attach_grad()
  def training_step(self, batch):
    l = self.loss(self(*batch[:-1]), batch[-1])
    self.plot('ppl', np.exp(l), train=True)
    return l

  def validation_step(self, batch):
    l = self.loss(self(*batch[:-1]), batch[-1])
    self.plot('ppl', np.exp(l), train=False)

class RNNLMScratch(d2l.Classifier): #@save
  """The RNN-based language model implemented from scratch."""
  rnn: nn.Module
  vocab_size: int
  lr: float = 0.01

  def setup(self):
    self.W_hq = self.param('W_hq', nn.initializers.normal(self.rnn.sigma),
                (self.rnn.num_hiddens, self.vocab_size))
    self.b_q = self.param('b_q', nn.initializers.zeros, (self.vocab_size))

  def training_step(self, params, batch, state):
    value, grads = jax.value_and_grad(
      self.loss, has_aux=True)(params, batch[:-1], batch[-1], state)
    l, _ = value
    self.plot('ppl', jnp.exp(l), train=True)
    return value, grads

  def validation_step(self, params, batch, state):
    l, _ = self.loss(params, batch[:-1], batch[-1], state)
    self.plot('ppl', jnp.exp(l), train=False)

class RNNLMScratch(d2l.Classifier): #@save
  """The RNN-based language model implemented from scratch."""
  def __init__(self, rnn, vocab_size, lr=0.01):
    super().__init__()
    self.save_hyperparameters()
    self.init_params()

  def init_params(self):
    self.W_hq = tf.Variable(tf.random.normal(
      (self.rnn.num_hiddens, self.vocab_size)) * self.rnn.sigma)
    self.b_q = tf.Variable(tf.zeros(self.vocab_size))

  def training_step(self, batch):
    l = self.loss(self(*batch[:-1]), batch[-1])
    self.plot('ppl', tf.exp(l), train=True)
    return l

  def validation_step(self, batch):
    l = self.loss(self(*batch[:-1]), batch[-1])
    self.plot('ppl', tf.exp(l), train=False)

9.5.2.1. 一次性編碼

回想一下,每個標記都由一個數字索引表示,該數字索引指示相應單詞/字符/單詞片段在詞匯表中的位置。您可能想構建一個具有單個輸入節點(在每個時間步長)的神經網絡,其中索引可以作為標量值輸入。當我們處理價格或溫度等數值輸入時,這是有效的,其中任何兩個足夠接近的值都應該被類似地對待。但這并不完全合理。這45th和 46th我們詞匯表中的詞恰好是“他們的”和“說的”,它們的含義并不相似。

處理此類分類數據時,最常見的策略是用單熱編碼表示每個項目(回憶 4.1.1 節)。one-hot 編碼是一個向量,其長度由詞匯表的大小給出N,其中所有條目都設置為0,除了與我們的令牌對應的條目,它被設置為1. 例如,如果詞匯表有 5 個元素,那么索引 0 和 2 對應的單熱向量如下。

F.one_hot(torch.tensor([0, 2]), 5)

tensor([[1, 0, 0, 0, 0],
    [0, 0, 1, 0, 0]])

npx.one_hot(np.array([0, 2]), 5)

array([[1., 0., 0., 0., 0.],
    [0., 0., 1., 0., 0.]])

jax.nn.one_hot(jnp.array([0, 2]), 5)

Array([[1., 0., 0., 0., 0.],
    [0., 0., 1., 0., 0.]], dtype=float32)

tf.one_hot(tf.constant([0, 2]), 5)


我們在每次迭代中采樣的小批量將采用形狀(批量大小、時間步數)。一旦將每個輸入表示為一個單熱向量,我們就可以將每個小批量視為一個三維張量,其中沿第三軸的長度由詞匯表大小 ( ) 給出len(vocab)。我們經常轉置輸入,以便獲得形狀的輸出(時間步數、批量大小、詞匯量大小)。這將允許我們更方便地循環遍歷最外層維度以更新小批量的隱藏狀態,時間步長(例如,在上述方法中forward)。

@d2l.add_to_class(RNNLMScratch) #@save
def one_hot(self, X):
  # Output shape: (num_steps, batch_size, vocab_size)
  return F.one_hot(X.T, self.vocab_size).type(torch.float32)

@d2l.add_to_class(RNNLMScratch) #@save
def one_hot(self, X):
  # Output shape: (num_steps, batch_size, vocab_size)
  return npx.one_hot(X.T, self.vocab_size)

@d2l.add_to_class(RNNLMScratch) #@save
def one_hot(self, X):
  # Output shape: (num_steps, batch_size, vocab_size)
  return jax.nn.one_hot(X.T, self.vocab_size)

@d2l.add_to_class(RNNLMScratch) #@save
def one_hot(self, X):
  # Output shape: (num_steps, batch_size, vocab_size)
  return tf.one_hot(tf.transpose(X), self.vocab_size)

9.5.2.2. 轉換 RNN 輸出

語言模型使用全連接輸出層將 RNN 輸出轉換為每個時間步的標記預測。

@d2l.add_to_class(RNNLMScratch) #@save
def output_layer(self, rnn_outputs):
  outputs = [torch.matmul(H, self.W_hq) + self.b_q for H in rnn_outputs]
  return torch.stack(outputs, 1)

@d2l.add_to_class(RNNLMScratch) #@save
def forward(self, X, state=None):
  embs = self.one_hot(X)
  rnn_outputs, _ = self.rnn(embs, state)
  return self.output_layer(rnn_outputs)

@d2l.add_to_class(RNNLMScratch) #@save
def output_layer(self, rnn_outputs):
  outputs = [np.dot(H, self.W_hq) + self.b_q for H in rnn_outputs]
  return np.stack(outputs, 1)

@d2l.add_to_class(RNNLMScratch) #@save
def forward(self, X, state=None):
  embs = self.one_hot(X)
  rnn_outputs, _ = self.rnn(embs, state)
  return self.output_layer(rnn_outputs)

@d2l.add_to_class(RNNLMScratch) #@save
def output_layer(self, rnn_outputs):
  outputs = [jnp.matmul(H, self.W_hq) + self.b_q for H in rnn_outputs]
  return jnp.stack(outputs, 1)

@d2l.add_to_class(RNNLMScratch) #@save
def forward(self, X, state=None):
  embs = self.one_hot(X)
  rnn_outputs, _ = self.rnn(embs, state)
  return self.output_layer(rnn_outputs)

@d2l.add_to_class(RNNLMScratch) #@save
def output_layer(self, rnn_outputs):
  outputs = [tf.matmul(H, self.W_hq) + self.b_q for H in rnn_outputs]
  return tf.stack(outputs, 1)

@d2l.add_to_class(RNNLMScratch) #@save
def forward(self, X, state=None):
  embs = self.one_hot(X)
  rnn_outputs, _ = self.rnn(embs, state)
  return self.output_layer(rnn_outputs)

讓我們檢查前向計算是否產生具有正確形狀的輸出。

model = RNNLMScratch(rnn, num_inputs)
outputs = model(torch.ones((batch_size, num_steps), dtype=torch.int64))
check_shape(outputs, (batch_size, num_steps, num_inputs))

model = RNNLMScratch(rnn, num_inputs)
outputs = model(np.ones((batch_size, num_steps), dtype=np.int64))
check_shape(outputs, (batch_size, num_steps, num_inputs))

model = RNNLMScratch(rnn, num_inputs)
outputs, _ = model.init_with_output(d2l.get_key(),
                  jnp.ones((batch_size, num_steps),
                       dtype=jnp.int32))
check_shape(outputs, (batch_size, num_steps, num_inputs))

model = RNNLMScratch(rnn, num_inputs)
outputs = model(tf.ones((batch_size, num_steps), dtype=tf.int64))
check_shape(outputs, (batch_size, num_steps, num_inputs))

9.5.3. 漸變剪裁

雖然您已經習慣于將神經網絡視為“深度”網絡,即許多層甚至在單個時間步內將輸入和輸出分開,但序列的長度引入了新的深度概念。除了在輸入到輸出方向上通過網絡之外,第一個時間步的輸入必須通過一系列T沿著時間步長分層,以影響模型在最后時間步長的輸出。從后向的角度來看,在每次迭代中,我們通過時間反向傳播梯度,從而產生一系列具有長度的矩陣積 O(T). 如第 5.4 節所述 ,這會導致數值不穩定,導致梯度根據權重矩陣的屬性爆炸或消失。

處理梯度消失和爆炸是設計 RNN 時的一個基本問題,并激發了現代神經網絡架構中一些最大的進步。在下一章中,我們將討論旨在緩解梯度消失問題的專門架構。然而,即使是現代 RNN 仍然經常遭受梯度爆炸的困擾。一種不優雅但普遍存在的解決方案是簡單地裁剪梯度,強制生成的“裁剪”梯度采用較小的值。

一般來說,當通過梯度下降優化一些目標時,我們迭代地更新感興趣的參數,比如一個向量 x, 但將它推向負梯度方向g(在隨機梯度下降中,我們在隨機采樣的小批量上計算這個梯度)。例如,學習率η>0, 每次更新都采用以下形式 x←x?ηg. 讓我們進一步假設目標函數f足夠光滑。形式上,我們說目標是Lipschitz 連續的L,意味著對于任何x和 y, 我們有

(9.5.1)|f(x)?f(y)|≤L‖x?y‖.

如您所見,當我們通過減去更新參數向量時 ηg,目標值的變化取決于學習率,梯度的范數和L如下:

(9.5.2)|f(x)?f(x?ηg)|≤Lη‖g‖.

換句話說,目標的變化不能超過 Lη‖g‖. 此上限值較小可能被視為好事或壞事。不利的一面是,我們限制了降低目標價值的速度。從好的方面來說,這限制了我們在任何一個梯度步驟中可能出錯的程度。

當我們說梯度爆炸時,我們的意思是‖g‖ 變得過大。在這種最壞的情況下,我們可能會在單個梯度步驟中造成如此大的破壞,以至于我們可以撤消在數千次訓練迭代過程中取得的所有進展。當梯度如此之大時,神經網絡訓練通常會發散,無法降低目標值。在其他時候,訓練最終會收斂,但由于損失的巨大峰值而變得不穩定。

一種限制大小的方法Lη‖g‖是縮小學習率η到微小的值。這里的一個優勢是我們不會對更新產生偏見。但是,如果我們很少獲得大梯度怎么辦?這種激烈的舉動減慢了我們在所有步驟中的進度,只是為了應對罕見的梯度爆炸事件。一種流行的替代方法是采用梯度裁剪啟發式投影梯度 g到某個給定半徑的球上θ如下:

(9.5.3)g←min(1,θ‖g‖)g.

這確保梯度范數永遠不會超過θ并且更新后的梯度完全與原始方向對齊g. 它還具有理想的副作用,即限制任何給定的小批量(以及其中任何給定的樣本)對參數向量施加的影響。這賦予了模型一定程度的魯棒性。需要明確的是,這是一個 hack。梯度裁剪意味著我們并不總是遵循真正的梯度,并且很難對可能的副作用進行分析推理。然而,它是一個非常有用的 hack,并且在大多數深度學習框架的 RNN 實現中被廣泛采用。

fit_epoch下面我們定義了一個方法來裁剪漸變,該方法由類的方法調用 d2l.Trainer(參見 第 3.4 節)。請注意,在計算梯度范數時,我們將所有模型參數連接起來,將它們視為一個巨大的參數向量。

@d2l.add_to_class(d2l.Trainer) #@save
def clip_gradients(self, grad_clip_val, model):
  params = [p for p in model.parameters() if p.requires_grad]
  norm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))
  if norm > grad_clip_val:
    for param in params:
      param.grad[:] *= grad_clip_val / norm

@d2l.add_to_class(d2l.Trainer) #@save
def clip_gradients(self, grad_clip_val, model):
  params = model.parameters()
  if not isinstance(params, list):
    params = [p.data() for p in params.values()]
  norm = math.sqrt(sum((p.grad ** 2).sum() for p in params))
  if norm > grad_clip_val:
    for param in params:
      param.grad[:] *= grad_clip_val / norm

@d2l.add_to_class(d2l.Trainer) #@save
def clip_gradients(self, grad_clip_val, grads):
  grad_leaves, _ = jax.tree_util.tree_flatten(grads)
  norm = jnp.sqrt(sum(jnp.vdot(x, x) for x in grad_leaves))
  clip = lambda grad: jnp.where(norm < grad_clip_val,
                 grad, grad * (grad_clip_val / norm))
  return jax.tree_util.tree_map(clip, grads)

@d2l.add_to_class(d2l.Trainer) #@save
def clip_gradients(self, grad_clip_val, grads):
  grad_clip_val = tf.constant(grad_clip_val, dtype=tf.float32)
  new_grads = [tf.convert_to_tensor(grad) if isinstance(
    grad, tf.IndexedSlices) else grad for grad in grads]
  norm = tf.math.sqrt(sum((tf.reduce_sum(grad ** 2)) for grad in new_grads))
  if tf.greater(norm, grad_clip_val):
    for i, grad in enumerate(new_grads):
      new_grads[i] = grad * grad_clip_val / norm
    return new_grads
  return grads

9.5.4. 訓練

使用時間機器數據集 ( ),我們基于從頭開始實施的 RNN ()data訓練字符級語言模型 ( )。請注意,我們首先計算梯度,然后裁剪它們,最后使用裁剪的梯度更新模型參數。modelrnn

data = d2l.TimeMachine(batch_size=1024, num_steps=32)
rnn = RNNScratch(num_inputs=len(data.vocab), num_hiddens=32)
model = RNNLMScratch(rnn, vocab_size=len(data.vocab), lr=1)
trainer = d2l.Trainer(max_epochs=100, gradient_clip_val=1, num_gpus=1)
trainer.fit(model, data)

pYYBAGR9NoiALI-bABFzwQfkpjk208.svg

data = d2l.TimeMachine(batch_size=1024, num_steps=32)
rnn = RNNScratch(num_inputs=len(data.vocab), num_hiddens=32)
model = RNNLMScratch(rnn, vocab_size=len(data.vocab), lr=1)
trainer = d2l.Trainer(max_epochs=100, gradient_clip_val=1, num_gpus=1)
trainer.fit(model, data)

poYBAGR9No-AMPvcABELR2NiCVM073.svg

data = d2l.TimeMachine(batch_size=1024, num_steps=32)
rnn = RNNScratch(num_inputs=len(data.vocab), num_hiddens=32)
model = RNNLMScratch(rnn, vocab_size=len(data.vocab), lr=1)
trainer = d2l.Trainer(max_epochs=100, gradient_clip_val=1, num_gpus=1)
trainer.fit(model, data)

poYBAGR9Np6APOEFABE1J_Oeyvk737.svg

data = d2l.TimeMachine(batch_size=1024, num_steps=32)
with d2l.try_gpu():
  rnn = RNNScratch(num_inputs=len(data.vocab), num_hiddens=32)
  model = RNNLMScratch(rnn, vocab_size=len(data.vocab), lr=1)
trainer = d2l.Trainer(max_epochs=100, gradient_clip_val=1)
trainer.fit(model, data)

pYYBAGR9NqeAaG6uABFMS9jcCR4776.svg

9.5.5. 解碼

一旦學習了語言模型,我們不僅可以使用它來預測下一個標記,還可以繼續預測每個后續標記,將先前預測的標記視為輸入中的下一個標記。有時我們只想生成文本,就好像我們從文檔的開頭開始一樣。但是,根據用戶提供的前綴來調節語言模型通常很有用。例如,如果我們正在為搜索引擎開發自動完成功能或幫助用戶編寫電子郵件,我們會希望輸入他們到目前為止所寫的內容(前綴),然后生成可能的延續。

以下predict方法生成一個延續,一次一個字符,在攝取用戶提供的字符后,prefix循環遍歷 中的字符時prefix,我們不斷將隱藏狀態傳遞到下一個時間步,但不生成任何輸出。這稱為 預熱期。攝取前綴后,我們現在準備開始發出后續字符,每個字符都將作為后續時間步的輸入反饋回模型。

@d2l.add_to_class(RNNLMScratch) #@save
def predict(self, prefix, num_preds, vocab, device=None):
  state, outputs = None, [vocab[prefix[0]]]
  for i in range(len(prefix) + num_preds - 1):
    X = torch.tensor([[outputs[-1]]], device=device)
    embs = self.one_hot(X)
    rnn_outputs, state = self.rnn(embs, state)
    if i < len(prefix) - 1: # Warm-up period
      outputs.append(vocab[prefix[i + 1]])
    else: # Predict num_preds steps
      Y = self.output_layer(rnn_outputs)
      outputs.append(int(Y.argmax(axis=2).reshape(1)))
  return ''.join([vocab.idx_to_token[i] for i in outputs])

@d2l.add_to_class(RNNLMScratch) #@save
def predict(self, prefix, num_preds, vocab, device=None):
  state, outputs = None, [vocab[prefix[0]]]
  for i in range(len(prefix) + num_preds - 1):
    X = np.array([[outputs[-1]]], ctx=device)
    embs = self.one_hot(X)
    rnn_outputs, state = self.rnn(embs, state)
    if i < len(prefix) - 1: # Warm-up period
      outputs.append(vocab[prefix[i + 1]])
    else: # Predict num_preds steps
      Y = self.output_layer(rnn_outputs)
      outputs.append(int(Y.argmax(axis=2).reshape(1)))
  return ''.join([vocab.idx_to_token[i] for i in outputs])

@d2l.add_to_class(RNNLMScratch) #@save
def predict(self, prefix, num_preds, vocab, params):
  state, outputs = None, [vocab[prefix[0]]]
  for i in range(len(prefix) + num_preds - 1):
    X = jnp.array([[outputs[-1]]])
    embs = self.one_hot(X)
    rnn_outputs, state = self.rnn.apply({'params': params['rnn']},
                      embs, state)
    if i < len(prefix) - 1: # Warm-up period
      outputs.append(vocab[prefix[i + 1]])
    else: # Predict num_preds steps
      Y = self.apply({'params': params}, rnn_outputs,
              method=self.output_layer)
      outputs.append(int(Y.argmax(axis=2).reshape(1)))
  return ''.join([vocab.idx_to_token[i] for i in outputs])

@d2l.add_to_class(RNNLMScratch) #@save
def predict(self, prefix, num_preds, vocab, device=None):
  state, outputs = None, [vocab[prefix[0]]]
  for i in range(len(prefix) + num_preds - 1):
    X = tf.constant([[outputs[-1]]])
    embs = self.one_hot(X)
    rnn_outputs, state = self.rnn(embs, state)
    if i < len(prefix) - 1: # Warm-up period
      outputs.append(vocab[prefix[i + 1]])
    else: # Predict num_preds steps
      Y = self.output_layer(rnn_outputs)
      outputs.append(int(tf.reshape(tf.argmax(Y, axis=2), 1)))
  return ''.join([vocab.idx_to_token[i] for i in outputs])

在下文中,我們指定前綴并讓它生成 20 個額外的字符。

model.predict('it has', 20, data.vocab, d2l.try_gpu())

'it has of the the the the '

model.predict('it has', 20, data.vocab, d2l.try_gpu())

'it has in the the the the '

model.predict('it has', 20, data.vocab, trainer.state.params)

'it has in the time tree th'

model.predict('it has', 20, data.vocab)

'it has it the the prount o'

雖然從頭開始實施上述 RNN 模型具有指導意義,但并不方便。在下一節中,我們將了解如何利用深度學習框架來使用標準架構啟動 RNN,并通過依賴高度優化的庫函數來獲得性能提升。

9.5.6. 概括

我們可以訓練基于 RNN 的語言模型來生成遵循用戶提供的文本前綴的文本。一個簡單的 RNN 語言模型由輸入編碼、RNN 建模和輸出生成組成。在訓練過程中,梯度裁剪可以減輕梯度爆炸的問題,但不能解決梯度消失的問題。在實驗中,我們實現了一個簡單的 RNN 語言模型,并在文本序列上使用梯度裁剪對其進行訓練,并在字符級別進行標記化。通過以前綴為條件,我們可以使用語言模型來生成可能的延續,這在許多應用程序中被證明是有用的,例如,自動完成功能。

9.5.7. 練習

實施的語言模型是否根據時間機器中的第一個標記之前的所有過去標記預測下一個標記?

哪個超參數控制用于預測的歷史長度?

證明 one-hot 編碼等同于為每個對象選擇不同的嵌入。

調整超參數(例如,epoch 數、隱藏單元數、minibatch 中的時間步數和學習率)以提高困惑度。堅持使用這個簡單的架構,你能做到多低?

用可學習的嵌入替換單熱編碼。這會帶來更好的性能嗎?

進行實驗以確定在時間機器上訓練的這種語言模型在 HG Wells 的其他書籍(例如世界大戰)中的效果如何。

進行另一項實驗以評估此模型對其他作者所寫書籍的困惑度。

修改預測方法,例如使用采樣而不是選擇最有可能的下一個字符。

會發生什么?

將模型偏向更可能的輸出,例如,通過從 q(xt∣xt?1,…,x1)∝P(xt∣xt?1,…,x1)α 為了α>1.

在不剪切漸變的情況下運行本節中的代碼。會發生什么?

將本節中使用的激活函數替換為 ReLU,并重復本節中的實驗。我們還需要梯度裁剪嗎?為什么?

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 神經網絡
    +關注

    關注

    42

    文章

    4771

    瀏覽量

    100720
  • pytorch
    +關注

    關注

    2

    文章

    808

    瀏覽量

    13202
收藏 人收藏

    評論

    相關推薦

    遞歸神經網絡(RNN)

    遞歸神經網絡(RNN)RNN是最強大的模型之一,它使我們能夠開發如分類、序列數據標注、生成文本序列(例如預測下一輸入詞的SwiftKey keyboard應用程序),以及將一個序列轉換為另一個序列
    發表于 07-20 09:27

    PyTorch教程之從零開始遞歸神經網絡實現

    電子發燒友網站提供《PyTorch教程之從零開始遞歸神經網絡實現.pdf》資料免費下載
    發表于 06-05 09:55 ?0次下載
    <b class='flag-5'>PyTorch</b>教程之<b class='flag-5'>從零開始</b>的<b class='flag-5'>遞歸</b><b class='flag-5'>神經網絡</b><b class='flag-5'>實現</b>

    PyTorch教程9.6之遞歸神經網絡的簡潔實現

    電子發燒友網站提供《PyTorch教程9.6之遞歸神經網絡的簡潔實現.pdf》資料免費下載
    發表于 06-05 09:56 ?0次下載
    <b class='flag-5'>PyTorch</b>教程9.6之<b class='flag-5'>遞歸</b><b class='flag-5'>神經網絡</b>的簡潔<b class='flag-5'>實現</b>

    PyTorch教程10.3之深度遞歸神經網絡

    電子發燒友網站提供《PyTorch教程10.3之深度遞歸神經網絡.pdf》資料免費下載
    發表于 06-05 15:12 ?0次下載
    <b class='flag-5'>PyTorch</b>教程10.3之深度<b class='flag-5'>遞歸</b><b class='flag-5'>神經網絡</b>

    PyTorch教程10.4之雙向遞歸神經網絡

    電子發燒友網站提供《PyTorch教程10.4之雙向遞歸神經網絡.pdf》資料免費下載
    發表于 06-05 15:13 ?0次下載
    <b class='flag-5'>PyTorch</b>教程10.4之雙向<b class='flag-5'>遞歸</b><b class='flag-5'>神經網絡</b>

    PyTorch教程16.2之情感分析:使用遞歸神經網絡

    電子發燒友網站提供《PyTorch教程16.2之情感分析:使用遞歸神經網絡.pdf》資料免費下載
    發表于 06-05 10:55 ?0次下載
    <b class='flag-5'>PyTorch</b>教程16.2之情感分析:使用<b class='flag-5'>遞歸</b><b class='flag-5'>神經網絡</b>

    使用PyTorch構建神經網絡

    PyTorch是一個流行的深度學習框架,它以其簡潔的API和強大的靈活性在學術界和工業界得到了廣泛應用。在本文中,我們將深入探討如何使用PyTorch構建神經網絡,包括從基礎概念到高級特性的全面解析。本文旨在為讀者提供一個完整的
    的頭像 發表于 07-02 11:31 ?705次閱讀

    遞歸神經網絡是循環神經網絡

    遞歸神經網絡(Recurrent Neural Network,簡稱RNN)和循環神經網絡(Recurrent Neural Network,簡稱RNN)實際上是同一個概念,只是不同的翻譯方式
    的頭像 發表于 07-04 14:54 ?739次閱讀

    遞歸神經網絡與循環神經網絡一樣嗎

    遞歸神經網絡(Recursive Neural Network,RvNN)和循環神經網絡(Recurrent Neural Network,RNN)是兩種不同類型的神經網絡結構,它們在
    的頭像 發表于 07-05 09:28 ?832次閱讀

    遞歸神經網絡結構形式主要分為

    結構形式。 Elman網絡 Elman網絡是一種基本的遞歸神經網絡結構,由Elman于1990年提出。其結構主要包括輸入層、隱藏層和輸出層,其中隱藏層具有時間延遲單元,可以存儲前一時刻
    的頭像 發表于 07-05 09:32 ?519次閱讀

    rnn是遞歸神經網絡還是循環神經網絡

    RNN(Recurrent Neural Network)是循環神經網絡,而非遞歸神經網絡。循環神經網絡是一種具有時間序列特性的神經網絡,能
    的頭像 發表于 07-05 09:52 ?560次閱讀

    PyTorch神經網絡模型構建過程

    PyTorch,作為一個廣泛使用的開源深度學習庫,提供了豐富的工具和模塊,幫助開發者構建、訓練和部署神經網絡模型。在神經網絡模型中,輸出層是尤為關鍵的部分,它負責將模型的預測結果以合適的形式輸出。以下將詳細解析
    的頭像 發表于 07-10 14:57 ?493次閱讀

    遞歸神經網絡實現方法

    (Recurrent Neural Network,通常也簡稱為RNN,但在此處為區分,我們將循環神經網絡稱為Recurrent RNN)不同,遞歸神經網絡更側重于處理樹狀或圖結構的數據,如句法分析樹、自然語言的語法結構等。以下
    的頭像 發表于 07-10 17:02 ?315次閱讀

    遞歸神經網絡和循環神經網絡的模型結構

    遞歸神經網絡是一種旨在處理分層結構的神經網絡,使其特別適合涉及樹狀或嵌套數據的任務。這些網絡明確地模擬了層次結構中的關系和依賴關系,例如語言中的句法結構或圖像中的層次表示。它使用
    的頭像 發表于 07-10 17:21 ?641次閱讀
    <b class='flag-5'>遞歸</b><b class='flag-5'>神經網絡</b>和循環<b class='flag-5'>神經網絡</b>的模型結構

    pytorch中有神經網絡模型嗎

    當然,PyTorch是一個廣泛使用的深度學習框架,它提供了許多預訓練的神經網絡模型。 PyTorch中的神經網絡模型 1. 引言 深度學習是一種基于人工
    的頭像 發表于 07-11 09:59 ?693次閱讀
    主站蜘蛛池模板: 牛牛免费视频| 国内精品久久久久影院亚洲| 久久内在线视频精品mp4| 无码爽死成人777在线观看网站| 99热精品在线视频观看| 久久极品视频| 亚洲精品无码AV中文字幕蜜桃| 大咪咪dvd| 青草视频久久| 97免费在线视频| 久久深夜视频| 一级淫片bbbxxx| 狠狠色狠色综合曰曰| 午夜特级毛片| 国产高清精品自在久久| 青柠在线观看免费全集| 99re久久热最新地址一| 美女医生深夜在家裸睡惨死| 中文视频在线| 久久只精品99品免费久| 影音先锋亚洲AV少妇熟女| 精品少妇爆AV无码专区| 亚洲国产中文字幕新在线| 国产婷婷色一区二区三区在线| 天天靠天天擦天天摸| 国产成人小视频在线观看| 日日摸天天添天天添无码蜜臀| 成人bt下载| 日韩亚洲欧美中文高清| 成人免费一区二区无码视频| 日韩精品 中文字幕 有码| 成人公开免费视频| 色多多污污在线播放免费| 国产3级在线观看| 无码AV免费精品一区二区三区| 国产精品久久久久久久久免费下载| 污污又黄又爽免费的网站 | 久久久久久久免费| 伦理79电影网在线观看| 综合久久久久久久综合网| 蜜桃成熟时2在线|