自然語言處理入門4——RNN

一般來說,提到自然語言處理,我們都會涉及到循環神經網絡(RNN),這是因為自然語言可以被看作是一個時間序列,這個時間序列中的元素是一個個的token。傳統的前饋神經網絡結構簡單,但是不能很好的處理時間序列數據,RNN便應運而生。

一、RNN概述

語言模型給出了單詞序列發生的概率,具體來說就是評估一個單詞發生的可能性。我們之前的CBOW模型就是這種(可以參考我的前兩篇文章《自然語言處理入門2》《自然語言處理入門3》),但是CBOW模型有個問題,就是長度限制,因為CBOW需要選擇一個窗口window來作為上下文,也就是說它只能根據前后一定窗口的大小來預測中間缺失的單詞。如果不斷加大窗口大小也會造成速度和性能的困擾,并且CBOW這種模型的目的其實主要是為了獲取單詞的分布式表示方法,基于此所以語言模型一般都使用RNN。

RNN有一個特點,就是不受上下文長度限制(其實也不是不受限制,只是很大程度上可以不受限制,如果長度過長,一樣會引起梯度消失等等無法訓練的問題,所以才有后面的截斷時序訓練和門控循環神經網絡LSTM等等)。RNN最大的特征就是模型中存在回路,所以才被叫做循環神經網絡,結構圖如下:

跟一般的前饋神經網絡的區別就是,RNN的輸出除了流向下一個節點的結果之外,還要把這個結果重新作為輸入傳到模型中,我們稱之為隱藏信息h。把循環網絡展開來后,就是上圖右邊的樣子了。每個節點的輸入都是原始輸入數據本身以及上一個節點傳過來的隱藏信息。

舉個實際的例子:對于"you say goodbye and i say hello."這句話,傳遞流程如下圖所示:

1. 第一個單詞you,先進行向量化也就是embedding操作,序列沒有上一個節點傳過來的信息,因此輸入向量直接經過RNN得到一個輸出,轉變為概率,可以看到下一個輸出概率最高的是say,同時,RNN的輸出傳遞到下一個節點;

2.第二個單詞say,先進行embedding得到向量化表示,這次RNN有上一個節點傳過來的隱藏信息了,所以要把這個隱藏信息傳遞到RNN,并且將say的embedding表示數據也一并傳入RNN,得到一個輸出,轉變為概率,得到概率最高的goodbye,同時再把RNN的輸出傳遞到下一個節點;

3.第三個單詞goodbye,先進行embedding得到向量化表示,再把上一個的節點的隱藏信息一起傳遞到RNN中得到輸出,轉變為概率得到概率最高的輸出and,同時再把RNN的輸出傳遞掉下一個節點,這里輸出的隱藏信息已經包括了前面的you say goodbye三個單詞的信息了,然后以此類推;

... ...

4.最終遍歷完時間序列中的所有單詞。

不過這里要注意,其實真正的RNN并不存在這樣的鋪開式結構,這里的示意圖只是為了便于理解把RNN在時間方向上展開了而已。

二、RNN的實現

下面我們來實現一下RNN。

有順序的序列數據訓練一般采用“按時間順序展開的神經網絡的誤差反向傳播法”,簡稱BPTT。處理長時序數據時,通常的做法是將網絡連接截成適當的長度。具體來說,就是將時間軸方向上過長的網絡在合適的位置進行截斷,從而創建多個小型網絡,然后對截出來的小型網絡執行誤差反向傳播法,稱為Truncated BPTT。

這是書中提供的方法,因為當序列長度太長的時候,梯度會變得不穩定,容易出現梯度消失問題,并且消耗的計算資源也會很大,所以對網絡進行了截斷訓練,后面的LSTM,GRU等等模型也是為了解決RNN時序過長等引起的問題的方法。

Truncated BPTT的特點就是前饋網絡中正常傳遞,但是反向傳播進行截斷,以“塊”為單位進行誤差反向傳播,其實也就是等于分塊訓練,結構如下:

RNN的正向傳播用公式表示就是:

ht-1是上一個節點傳入的隱藏信息,Wh是隱藏信息的權重矩陣,xt是當前節點輸入的數據,Wx是輸入數據的權重矩陣,b是偏置。這幾個元素進行線性組合后,再應用一次非線性的正切變換,得到的就是輸出ht。

反向傳播示意圖:

反向傳播流程:

上一個節點傳入的dhnext代表傳遞過來的梯度信息,要對ht-1(也就是hprev),Wh,xt,Wx和b分別求偏導數,以得到他們各自的梯度(反向傳播算法里面有說明,可以參考深度學習教科書)。

假設ht-1Wh + xtWx + b為Z,正向傳播公式:

那么他們各自的梯度如下(由于tanh(z)對z的導數是1-(tanh(z))^2):

基于以上的推斷,我們可以寫出RNN的實現程序:

import numpy as npclass RNN:def __init__(self, Wx, Wh, b):self.params = [Wx, Wh, b]self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]self.cache = Nonedef forward(self, x, h_prev):Wx, Wh, b = self.paramst = np.dot(h_prev, Wh) + np.dot(x, Wx) + bh_next = np.tanh(t)# 暫存self.cache = (x, h_prev, h_next) return h_next # 返回正向隱藏信息def backward(self, dh_next):Wx, Wh, b = self.paramsx, h_prev, h_next = self.cachedt = dh_next*(1-h_next**2)db = np.sum(dt, axis=0)dWh = np.dot(h_prev.T, dt)dh_prev = np.dot(dt, Wh.T)dWx = np.dot(x.T, dt)dx = np.dot(dt, Wx.T)self.grads[0][...] = dWxself.grads[1][...] = dWhself.grads[2][...] = dbreturn dx, dh_prev # 返回上一個隱藏信息的梯度和輸入的梯度

根據之前說的截斷網絡訓練方法,我們在RNN的基礎上構建TimeRNN。Time RNN是T個RNN層連起來的網絡。其中有一個成員變量layers,保存T個RNN層,另一個成員變量h保存調用forward方法時的最后一個RNN層隱藏狀態。stateful=True表示繼承Time RNN層的狀態,stateful=False表示不繼承Time RNN層的狀態。

class TimeRNN:def __init__(self, Wx, Wh, b, stateful=False):self.params = [Wx, Wh, b]self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]self.layers = Noneself.h, self.dh = None, Noneself.stateful = statefuldef set_state(self, h):self.h = hdef reset_state(self):self.h = Nonedef forward(self, xs):Wx, Wh, b = self.params # 傳入權重矩陣和偏置# N表示batch_size,T是xs包括的時序數據個數,D是輸入向量的維度N, T, D = xs.shape # H表示隱藏狀態的向量維數D, H = Wx.shapeself.layers = []# 定義輸出隱藏信息hs = np.empty((N,T,H), dtype='f')# 如果是第一個節點或者不繼承隱藏狀態if not self.stateful or self.h is None:# 則輸入的隱藏信息設置為0self.h = np.zeros((N,H), dtype='f')for t in range(T):# 循環遍歷T個節點,記錄隱藏信息layer = RNN(*self.params)self.h = layer.forward(xs[:,t,:],self.h)hs[:,t,:] = self.hself.layers.append(layer)return hsdef backward(self, dhs):Wx, Wh, b = self.paramsN, T, D = dhs.shapeD, H = Wx.shapedxs = np.empty((N,T,D), dtype='f')dh = 0grads = [0,0,0]# 這里是反序遍歷T個節點for t in reversed(range(T)):layer = self.layers[t]# 每個節點內部做反向傳播dx,dh = layer.backward(dhs[:,t,:]+dh) # 求和后的梯度dxs[:,t,:] = dx# 獲取Wx,Wh和b的梯度,并進行累加for i, grad in enumerate(layer.grads):grads[i] += gradfor i,grad in enumerate(grads):self.grads[i][...] = gradself.dh = dhreturn dxs

在TimeRNN的基礎上構建了RNNLM,RNNLM是指基于RNN的語言模型(language model)。這個模型就是把我們之前的信息都合并在一起,輸入的一串時序數據,每串時序數據都要先進行Embedding操作(每串時序數據包含T個單獨的時序數據,或者叫token),然后傳入TimeRNN層,最后把輸出的隱藏信息傳入到Affine層,Affine就是一個簡單的神經網絡,進行計算得到輸出結果。(《深度學習入門:基于Python的理論與實現》有詳細論述),把這三個操作串聯起來形成一個layer。輸出的分類結果進行softmax操作,并計算出損失值,傳遞到Affine層,得到輸入的梯度dx,再輸入到TimeRNN,這里進行分塊,塊內反向傳播,得到的梯度相加,得到總的梯度,再傳遞到Emebedding,進行反向傳播,最后用優化器optimizer進行梯度更新,完成訓練。

class SimpleRnnlm:def __init__(self, vocab_size, wordvec_size, hidden_size):V,D,H = vocab_size, wordvec_size, hidden_sizern = np.random.randn# 初始化權重embed_W = (rn(V,D)/100).astype('f')rnn_Wx = (rn(D,H)/np.sqrt(D)).astype('f')rnn_Wh = (rn(H,H)/np.sqrt(H)).astype('f')rnn_b = np.zeros(H).astype('f')affine_W = (rn(H,V)/np.sqrt(H)).astype('f')affine_b = np.zeros(V).astype('f')# 生成層self.layers = [TimeEmbedding(embed_W),TimeRNN(rnn_Wx, rnn_Wh, rnn_b, stateful=True),TimeAffine(affine_W, affine_b)]self.loss_layer = TimeSoftmaxWithLoss()self.rnn_layer = self.layers[1]# 將所有的權重和梯度整理到列表中self.params, self.grads = [],[]for layer in self.layers:self.params += layer.paramsself.grads += layer.gradsdef forward(self, xs, ts):for layer in self.layers:xs = layer.forward(xs)loss = self.loss_layer.forward(xs, ts)return lossdef backward(self, dout=1):dout = self.loss_layer.backward(dout)for layer in reversed(self.layers):dout = layer.backward(dout)return doutdef reset_state(self):self.rnn_layer.reset_state()

我們可以用之前用到的一個英文語料庫ptb進行訓練。語言模型是基于已經出現的單詞預測將要出現的單詞的概率分布。困惑度(perplexity)是一個比較常用的指標,它是概率的倒數,如果預測一個單詞出現的概率是0.2,則它的困惑度是5,如果預測一個單詞出現的概率是0.8,則它的困惑度是1.25,我們的模型訓練過程可視化指標選擇用困惑度來表示。困惑度自然是越低越好。

import numpy as np# 設定超參數
batch_size = 10
wordvec_size = 100
hidden_size = 100  # RNN的隱藏狀態向量的元素個數
time_size = 5  # RNN的展開大小
lr = 0.1
max_epoch = 100# 讀入訓練數據
corpus, word_to_id, id_to_word = load_data('train')
corpus_size = 1000  # 縮小測試用的數據集
corpus = corpus[:corpus_size]
vocab_size = int(max(corpus) + 1)
xs = corpus[:-1]  # 輸入
#print(xs.shape)
ts = corpus[1:]  # 輸出(監督標簽)# 生成模型
model = SimpleRnnlm(vocab_size, wordvec_size, hidden_size)
optimizer = SGD(lr)
trainer = RnnlmTrainer(model, optimizer)trainer.fit(xs, ts, max_epoch, batch_size, time_size)
trainer.plot()
# 輸出
| epoch 1 |  iter 1 / 19 | time 0[s] | perplexity 417.35
| epoch 2 |  iter 1 / 19 | time 0[s] | perplexity 387.39
| epoch 3 |  iter 1 / 19 | time 0[s] | perplexity 272.27
| epoch 4 |  iter 1 / 19 | time 0[s] | perplexity 224.16
| epoch 5 |  iter 1 / 19 | time 0[s] | perplexity 210.55
| epoch 6 |  iter 1 / 19 | time 0[s] | perplexity 208.73
| epoch 7 |  iter 1 / 19 | time 0[s] | perplexity 200.27
| epoch 8 |  iter 1 / 19 | time 0[s] | perplexity 200.94
| epoch 9 |  iter 1 / 19 | time 0[s] | perplexity 194.13
| epoch 10 |  iter 1 / 19 | time 0[s] | perplexity 189.88
... ...
| epoch 95 |  iter 1 / 19 | time 2[s] | perplexity 6.94
| epoch 96 |  iter 1 / 19 | time 2[s] | perplexity 6.83
| epoch 97 |  iter 1 / 19 | time 2[s] | perplexity 6.54
| epoch 98 |  iter 1 / 19 | time 2[s] | perplexity 6.41
| epoch 99 |  iter 1 / 19 | time 2[s] | perplexity 5.99
| epoch 100 |  iter 1 / 19 | time 2[s] | perplexity 5.89

經過100個世代的訓練,可以看到困惑度從訓練一開始的417.35多下降到5.89,說明預測的概率也在不斷提升,效果還是不錯的,當然5.89的困惑度還是比較高的,繼續訓練有望進一步降低困惑度。我測試了一下,當訓練200個世代后,困惑度下降到了1.15,這就是一個比較好的結果了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73872.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73872.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73872.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構之鏈表(雙鏈表)

目錄 一、雙向帶頭循環鏈表 概念 二、哨兵位的頭節點 優點: 頭節點的初始化 三、帶頭雙向鏈表的實現 1.雙鏈表的銷毀 2.雙鏈表的打印 3.雙鏈表的尾插和頭插 尾插: 頭插: 4.雙鏈表的尾刪和頭刪 尾刪: 頭刪: …

ASP3605同步降壓調節器——滿足汽車電子嚴苛要求的電源芯片方案

ASP3605高效同步降壓調節器,通過AEC-Q100 Grade1認證,輸入電壓4V至15V,輸出電流5A,峰值效率94%。車規級型號ASP3605A3U支持-40C至125C工作溫度,適用于ADAS、車載信息娛樂系統等場景。 面向汽車電子的核心功能設計 1. …

vue3+Ts+elementPlus二次封裝Table分頁表格,表格內展示圖片、switch開關、支持

目錄 一.項目文件結構 二.實現代碼 1.子組件(表格組件) 2.父組件(使用表格) 一.項目文件結構 1.表格組件(子組件)位置 2.使用表格組件的頁面文件(父組件)位置 3.演示圖片位置 ele…

[特殊字符]1.2.1 新型基礎設施建設

🚀 新型基礎設施建設全解析 🌟 核心概念與定義 維度詳細內容定義以新發展理念為引領,以技術創新為驅動,以信息網絡為基礎,提供數字轉型、智能升級、融合創新服務的基礎設施體系。提出背景2018年中央經濟工作會議首次提…

SQL Server數據庫慢SQL調優

SQL Server中慢SQL會顯著降低系統性能并引發級聯效應。首先,用戶直接體驗響應時間延長,核心業務操作(如交易處理、報表生成)效率下降,導致客戶滿意度降低甚至業務中斷。其次,資源利用率失衡,CPU…

【安全運營】安全運營關于告警降噪的一些梳理

目錄 前言一、智能技術層面1、機器學習和 AI 模型訓練2、攻擊成功判定 二、多源關聯分析1、多源設備關聯(跨設備日志整合)2、上下文信息增強 三、業務白名單和策略優化1、動態白名單機制2、閾值和規則調整 四、自動化和流程化1、告警歸并與去重2、同類型…

逆向中常見的加密算法識別

1、base64及換表 base64主要是將輸入的每3字節(共24bit)按照每六比特分成一組,變成4個小于64的索引值,然后通過一個索引表得到4個可見的字符。 索引表為一個64字節的字符串,如果在代碼中發現引用了這個索引表“ABCDEF…

《UNIX網絡編程卷1:套接字聯網API》第2章 傳輸層:TCP、UDP和SCTP

《UNIX網絡編程卷1:套接字聯網API》第2章 傳輸層:TCP、UDP和SCTP 2.1 傳輸層的核心作用與協議選型 傳輸層是網絡協議棧中承上啟下的核心層,直接決定應用的通信質量。其主要職責包括: 端到端通信:屏蔽底層網絡細節&am…

Eclipse 創建 Java 類

Eclipse 創建 Java 類 引言 Eclipse 是一款功能強大的集成開發環境(IDE),被廣泛用于 Java 開發。本文將詳細介紹如何在 Eclipse 中創建 Java 類,包括配置開發環境、創建新項目、添加類以及編寫類代碼等步驟。 配置 Eclipse 開發環境 1. 安裝 Eclipse 首先,您需要在您…

汽車安全確認等級-中國等保

1、概念解析 網絡安全保證等級(Cybersecurity Assurance Level)通常指在不同標準或框架下,根據系統或數據的敏感性、重要性以及潛在風險劃分的等級,用于指導組織采取相應的安全防護措施。以下是幾個常見的網絡安全保證等級體系及…

藍橋杯練習day2:執行操作后的變化量

題意 存在一種僅支持 4 種操作和 1 個變量 X 的編程語言: X 和 X 使變量 X 的值 加 1 –X 和 X-- 使變量 X 的值 減 1 最初,X 的值是 0 給你一個字符串數組 operations ,這是由操作組成的一個列表,返回執行所有操作后&#xff…

【機器學習chp14 — 2】生成式模型—變分自編碼器VAE(超詳細分析,易于理解,推導嚴謹,一文就夠了)

目錄 二、變分自編碼器 VAE 1、自編碼器 AE (1)自編碼器的基本結構與目標 1.1 編碼器-解碼器結構 1.2 目標函數:重構誤差最小化 (2)自編碼器與 PCA 的對比 2.1 PCA 與線性降維 2.2 非線性映射的優勢 &#xf…

Linux 一步部署DHCP服務

#!/bin/bash #腳本作者和日期 #author: PEI #date: 20250319 #檢查root權限 if [ "$USER" ! "root" ]; then echo "錯誤:非root用戶,權限不足!" exit 0 fi #防火墻與高級權限 systemctl stop firewa…

【RHCE】awk文本處理

目錄 基本介紹 命令格式 awk基本使用 命令行讀取程序腳本 數據字段變量 腳本中使用多個命令 文件中讀取程序 處理數據前運行腳本(BEGIN) 處理數據后運行腳本(END) awk高級用法 變量 內建變量 自定義變量 數組 定義…

Vue3 核心特性解析:Suspense 與 Teleport 原理深度剖析

Vue3 核心特性解析:Suspense 與 Teleport 原理深度剖析 一、Teleport:突破組件層級的時空傳送 1.1 實現原理圖解 #mermaid-svg-75dTmiektg1XNS13 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-s…

工業界處理 Atomic 操作的優化策略

在產業界,處理 atomic 操作 時,通常會根據具體情境選擇不同的策略,主要取決于以下三個因素: 內存一致性需求:是否需要確保 所有線程(threads) 都能看到最新的變量值。性能需求:是否…

Python功能完美的寶庫——內置的強大“武器庫”builtins

builtins模塊包含了Python大量的內置對象(函數、異常和類型等),她是Python的內置武器庫,堪稱功能完美的寶庫。 筆記模板由python腳本于2025-03-19 08:16:27創建,本篇筆記適合喜歡探究python的coder翻閱。 【學習的細節…

三分鐘掌握視頻分辨率修改 | 在 Rust 中優雅地使用 FFmpeg

前言 在視頻處理領域,調整視頻分辨率是一個繞不過去的需求。比如,你可能需要將一段視頻適配到手機、平板或大屏電視上,或者為了節省存儲空間和網絡帶寬而壓縮視頻尺寸。然而,傳統的FFmpeg命令行工具雖然功能強大,但復…

PyTorch 深度學習實戰(17):Asynchronous Advantage Actor-Critic (A3C) 算法與并行訓練

在上一篇文章中,我們深入探討了 Soft Actor-Critic (SAC) 算法及其在平衡探索與利用方面的優勢。本文將介紹強化學習領域的重要里程碑——Asynchronous Advantage Actor-Critic (A3C) 算法,并展示如何利用 PyTorch 實現并行化訓練來加速學習過程。 一、A…

【深度學習】多目標融合算法(五):定制門控網絡CGC(Customized Gate Control)

目錄 一、引言 二、CGC(Customized Gate Control,定制門控網絡) 2.1 技術原理 2.2 技術優缺點 2.3 業務代碼實踐 2.3.1 業務場景與建模 2.3.2 模型代碼實現 2.3.3 模型訓練與推理測試 2.3.4 打印模型結構 三、總結 一、引言 上一…