<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 6.5 循環神經網絡的簡潔實現 本節將使用PyTorch來更簡潔地實現基于循環神經網絡的語言模型。首先,我們讀取周杰倫專輯歌詞數據集。 ``` python import time import math import numpy as np import torch from torch import nn, optim import torch.nn.functional as F import sys sys.path.append("..") import d2lzh_pytorch as d2l device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') (corpus_indices, char_to_idx, idx_to_char, vocab_size) = d2l.load_data_jay_lyrics() ``` ## 6.5.1 定義模型 PyTorch中的`nn`模塊提供了循環神經網絡的實現。下面構造一個含單隱藏層、隱藏單元個數為256的循環神經網絡層`rnn_layer`。 ``` python num_hiddens = 256 # rnn_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens) # 已測試 rnn_layer = nn.RNN(input_size=vocab_size, hidden_size=num_hiddens) ``` 與上一節中實現的循環神經網絡不同,這里`rnn_layer`的輸入形狀為(時間步數, 批量大小, 輸入個數)。其中輸入個數即one-hot向量長度(詞典大小)。此外,`rnn_layer`作為`nn.RNN`實例,在前向計算后會分別返回輸出和隱藏狀態h,其中輸出指的是隱藏層在**各個時間步**上計算并輸出的隱藏狀態,它們通常作為后續輸出層的輸入。需要強調的是,該“輸出”本身并不涉及輸出層計算,形狀為(時間步數, 批量大小, 隱藏單元個數)。而`nn.RNN`實例在前向計算返回的隱藏狀態指的是隱藏層在**最后時間步**的隱藏狀態:當隱藏層有多層時,每一層的隱藏狀態都會記錄在該變量中;對于像長短期記憶(LSTM),隱藏狀態是一個元組(h, c),即hidden state和cell state。我們會在本章的后面介紹長短期記憶和深度循環神經網絡。關于循環神經網絡(以LSTM為例)的輸出,可以參考下圖([圖片來源](https://stackoverflow.com/questions/48302810/whats-the-difference-between-hidden-and-output-in-pytorch-lstm/48305882))。 <div align=center> <img width="500" src="images/6.5.png"/> </div> <div align=center>循環神經網絡(以LSTM為例)的輸出</div> 來看看我們的例子,輸出形狀為(時間步數, 批量大小, 輸入個數),隱藏狀態h的形狀為(層數, 批量大小, 隱藏單元個數)。 ``` python num_steps = 35 batch_size = 2 state = None X = torch.rand(num_steps, batch_size, vocab_size) Y, state_new = rnn_layer(X, state) print(Y.shape, len(state_new), state_new[0].shape) ``` 輸出: ``` torch.Size([35, 2, 256]) 1 torch.Size([2, 256]) ``` > 如果`rnn_layer`是`nn.LSTM`實例,那么上面的輸出是什么? 接下來我們繼承`Module`類來定義一個完整的循環神經網絡。它首先將輸入數據使用one-hot向量表示后輸入到`rnn_layer`中,然后使用全連接輸出層得到輸出。輸出個數等于詞典大小`vocab_size`。 ``` python # 本類已保存在d2lzh_pytorch包中方便以后使用 class RNNModel(nn.Module): def __init__(self, rnn_layer, vocab_size): super(RNNModel, self).__init__() self.rnn = rnn_layer self.hidden_size = rnn_layer.hidden_size * (2 if rnn_layer.bidirectional else 1) self.vocab_size = vocab_size self.dense = nn.Linear(self.hidden_size, vocab_size) self.state = None def forward(self, inputs, state): # inputs: (batch, seq_len) # 獲取one-hot向量表示 X = d2l.to_onehot(inputs, self.vocab_size) # X是個list Y, self.state = self.rnn(torch.stack(X), state) # 全連接層會首先將Y的形狀變成(num_steps * batch_size, num_hiddens),它的輸出 # 形狀為(num_steps * batch_size, vocab_size) output = self.dense(Y.view(-1, Y.shape[-1])) return output, self.state ``` ## 6.5.2 訓練模型 同上一節一樣,下面定義一個預測函數。這里的實現區別在于前向計算和初始化隱藏狀態的函數接口。 ``` python # 本函數已保存在d2lzh_pytorch包中方便以后使用 def predict_rnn_pytorch(prefix, num_chars, model, vocab_size, device, idx_to_char, char_to_idx): state = None output = [char_to_idx[prefix[0]]] # output會記錄prefix加上輸出 for t in range(num_chars + len(prefix) - 1): X = torch.tensor([output[-1]], device=device).view(1, 1) if state is not None: if isinstance(state, tuple): # LSTM, state:(h, c) state = (state[0].to(device), state[1].to(device)) else: state = state.to(device) (Y, state) = model(X, state) if t < len(prefix) - 1: output.append(char_to_idx[prefix[t + 1]]) else: output.append(int(Y.argmax(dim=1).item())) return ''.join([idx_to_char[i] for i in output]) ``` 讓我們使用權重為隨機值的模型來預測一次。 ``` python model = RNNModel(rnn_layer, vocab_size).to(device) predict_rnn_pytorch('分開', 10, model, vocab_size, device, idx_to_char, char_to_idx) ``` 輸出: ``` '分開戲想暖迎涼想征涼征征' ``` 接下來實現訓練函數。算法同上一節的一樣,但這里只使用了相鄰采樣來讀取數據。 ``` python # 本函數已保存在d2lzh_pytorch包中方便以后使用 def train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes): loss = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=lr) model.to(device) state = None for epoch in range(num_epochs): l_sum, n, start = 0.0, 0, time.time() data_iter = d2l.data_iter_consecutive(corpus_indices, batch_size, num_steps, device) # 相鄰采樣 for X, Y in data_iter: if state is not None: # 使用detach函數從計算圖分離隱藏狀態, 這是為了 # 使模型參數的梯度計算只依賴一次迭代讀取的小批量序列(防止梯度計算開銷太大) if isinstance (state, tuple): # LSTM, state:(h, c) state = (state[0].detach(), state[1].detach()) else: state = state.detach() (output, state) = model(X, state) # output: 形狀為(num_steps * batch_size, vocab_size) # Y的形狀是(batch_size, num_steps),轉置后再變成長度為 # batch * num_steps 的向量,這樣跟輸出的行一一對應 y = torch.transpose(Y, 0, 1).contiguous().view(-1) l = loss(output, y.long()) optimizer.zero_grad() l.backward() # 梯度裁剪 d2l.grad_clipping(model.parameters(), clipping_theta, device) optimizer.step() l_sum += l.item() * y.shape[0] n += y.shape[0] try: perplexity = math.exp(l_sum / n) except OverflowError: perplexity = float('inf') if (epoch + 1) % pred_period == 0: print('epoch %d, perplexity %f, time %.2f sec' % ( epoch + 1, perplexity, time.time() - start)) for prefix in prefixes: print(' -', predict_rnn_pytorch( prefix, pred_len, model, vocab_size, device, idx_to_char, char_to_idx)) ``` 使用和上一節實驗中一樣的超參數(除了學習率)來訓練模型。 ```python num_epochs, batch_size, lr, clipping_theta = 250, 32, 1e-3, 1e-2 # 注意這里的學習率設置 pred_period, pred_len, prefixes = 50, 50, ['分開', '不分開'] train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes) ``` 輸出: ``` epoch 50, perplexity 10.658418, time 0.05 sec - 分開始我媽 想要你 我不多 讓我心到的 我媽媽 我不能再想 我不多再想 我不要再想 我不多再想 我不要 - 不分開 我想要你不你 我 你不要 讓我心到的 我媽人 可愛女人 壞壞的讓我瘋狂的可愛女人 壞壞的讓我瘋狂的 epoch 100, perplexity 1.308539, time 0.05 sec - 分開不會痛 不要 你在黑色幽默 開始了美麗全臉的夢滴 閃爍成回憶 傷人的美麗 你的完美主義 太徹底 讓我 - 不分開不是我不要再想你 我不能這樣牽著你的手不放開 愛可不可以簡簡單單沒有傷害 你 靠著我的肩膀 你 在我 epoch 150, perplexity 1.070370, time 0.05 sec - 分開不能去河南嵩山 學少林跟武當 快使用雙截棍 哼哼哈兮 快使用雙截棍 哼哼哈兮 習武之人切記 仁者無敵 - 不分開 在我會想通 是誰開沒有全有開始 他心今天 一切人看 我 一口令秋軟語的姑娘緩緩走過外灘 消失的 舊 epoch 200, perplexity 1.034663, time 0.05 sec - 分開不能去嗎周杰倫 才離 沒要你在一場悲劇 我的完美主義 太徹底 分手的話像語言暴力 我已無能為力再提起 - 不分開 讓我面到你 愛情來的太快就像龍卷風 離不開暴風圈來不及逃 我不能再想 我不能再想 我不 我不 我不 epoch 250, perplexity 1.021437, time 0.05 sec - 分開 我我外的家邊 你知道這 我愛不看的太 我想一個又重來不以 迷已文一只剩下回憶 讓我叫帶你 你你的 - 不分開 我我想想和 是你聽沒不 我不能不想 不知不覺 你已經離開我 不知不覺 我跟了這節奏 后知后覺 ``` ## 小結 * PyTorch的`nn`模塊提供了循環神經網絡層的實現。 * PyTorch的`nn.RNN`實例在前向計算后會分別返回輸出和隱藏狀態。該前向計算并不涉及輸出層計算。 ----------- > 注:除代碼外本節與原書此節基本相同,[原書傳送門](https://zh.d2l.ai/chapter_recurrent-neural-networks/rnn-gluon.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看