日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

“让Keras更酷一些!”:层中层与mask

發布時間:2024/10/8 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 “让Keras更酷一些!”:层中层与mask 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


這一篇“讓 Keras 更酷一些!”將和讀者分享兩部分內容:第一部分是“層中層”,顧名思義,是在 Keras 中自定義層的時候,重用已有的層,這將大大減少自定義層的代碼量;另外一部分就是應讀者所求,介紹一下序列模型中的 mask 原理和方法。


作者丨蘇劍林

單位丨追一科技

研究方向丨NLP,神經網絡

個人主頁丨kexue.fm


層中層


在《“讓Keras更酷一些!”:精巧的層與花式的回調》[1]?一文中我們已經介紹過 Keras 自定義層的基本方法,其核心步驟是定義 build 和 call 兩個函數,其中 build 負責創建可訓練的權重,而 call 則定義具體的運算。


拒絕重復勞動


經常用到自定義層的讀者可能會感覺到,在自定義層的時候我們經常在重復勞動,比如我們想要增加一個線性變換,那就要在 build 中增加一個 kernel 和 bias 變量(還要自定義變量的初始化、正則化等),然后在 call 里邊用 K.dot 來執行,有時候還需要考慮維度對齊的問題,步驟比較繁瑣。


但事實上,一個線性變換其實就是一個不加激活函數的 Dense 層罷了,如果在自定義層時能重用已有的層,那顯然就可以大大節省代碼量了。?


事實上,只要你對 Python 面向對象編程比較熟悉,然后仔細研究 Keras 的 Layer 的源代碼,就不難發現重用已有層的方法了。下面將它整理成比較規范的流程,供讀者參考調用。


OurLayer


首先,我們定義一個新的 OurLayer 類:


class?OurLayer(Layer):
????"""定義新的Layer,增加reuse方法,允許在定義Layer時調用現成的層
????"""

????def?reuse(self,?layer,?*args,?**kwargs):
????????if?not?layer.built:
????????????if?len(args)?>?0:
????????????????inputs?=?args[0]
????????????else:
????????????????inputs?=?kwargs['inputs']
????????????if?isinstance(inputs,?list):
????????????????input_shape?=?[K.int_shape(x)?for?x?in?inputs]
????????????else:
????????????????input_shape?=?K.int_shape(inputs)
????????????layer.build(input_shape)
????????outputs?=?layer.call(*args,?**kwargs)
????????for?w?in?layer.trainable_weights:
????????????if?w?not?in?self._trainable_weights:
????????????????self._trainable_weights.append(w)
????????for?w?in?layer.non_trainable_weights:
????????????if?w?not?in?self._non_trainable_weights:
????????????????self._non_trainable_weights.append(w)
????????return?outputs


這個 OurLayer 類繼承了原來的 Layer 類,為它增加了 reuse 方法,就是通過它我們可以重用已有的層。


下面是一個簡單的例子,定義一個層,運算如下:



這里?f,g 是激活函數,其實就是兩個 Dense 層的復合,如果按照標準的寫法,我們需要在 build 那里定義好幾個權重,定義權重的時候還需要根據輸入來定義 shape,還要定義初始化等,步驟很多,但事實上這些在 Dense 層不都寫好了嗎,直接調用就可以了,參考調用代碼如下:


class?OurDense(OurLayer):
????"""原來是繼承Layer類,現在繼承OurLayer類
????"""

????def?__init__(self,?hidden_dimdim,?output_dim,
?????????????????hidden_activation='linear',
?????????????????output_activation='linear',?**kwargs)
:

????????super(OurDense,?self).__init__(**kwargs)
????????self.hidden_dim?=?hidden_dim
????????self.output_dim?=?output_dim
????????self.hidden_activation?=?hidden_activation
????????self.output_activation?=?output_activation
????def?build(self,?input_shape):
????????"""在build方法里邊添加需要重用的層,
????????當然也可以像標準寫法一樣條件可訓練的權重。
????????"""

????????super(OurDense,?self).build(input_shape)
????????self.h_dense?=?Dense(self.hidden_dimdim,
?????????????????????????????activation=self.hidden_activation)
????????self.o_dense?=?Dense(self.output_dim,
?????????????????????????????activation=self.output_activation)
????def?call(self,?inputs):
????????"""直接reuse一下層,等價于o_dense(h_dense(inputs))
????????"""

????????h?=?self.reuse(self.h_dense,?inputs)
????????o?=?self.reuse(self.o_dense,?h)
????????return?o
????def?compute_output_shape(self,?input_shape):
????????return?input_shape[:-1]?+?(self.output_dim,)


是不是特別清爽?


Mask


這一節我們來討論一下處理變長序列時的 padding 和 mask 問題。?


證明你思考過


近來筆者開源的幾個模型中大量地用到了 mask,不少讀者似乎以前從未遇到過這個東西,各種疑問紛至沓來。本來,對一樣新東西有所疑問是無可厚非的事情,但問題是不經思考的提問就顯得很不負責任了。


我一直認為,在向別人提問的時候,需要同時去“證明”自己是思考過的,比如如果你要去解釋關于 mask 的問題,我會先請你回答:mask 之前的序列大概是怎樣的?mask 之后序列的哪些位置發生了變化?變成了怎么樣??


這三個問題跟 mask 的原理沒有關系,只是要你看懂 mask 做了什么運算,在此基礎上,我們才能去討論為什么要這樣運算。如果你連運算本身都看不懂,那只有兩條路可選了,一是放棄這個問題的理解,二是好好學幾個月 Keras 咱們再來討論。?


下面假設讀者已經看懂了 mask 的運算,然后我們來簡單討論一下 mask 的基本原理。


排除padding


mask 是伴隨著 padding 出現的,因為神經網絡的輸入需要一個規整的張量,而文本通常都是不定長的,這樣一來就需要裁剪或者填充的方式來使得它們變成定長,按照常規習慣,我們會使用 0 作為 padding 符號。?


這里用簡單的向量來描述 padding 的原理。假設有一個長度為 5 的向量:



經過 padding 變成長度為 8:



當你將這個長度為 8 的向量輸入到模型中時,模型并不知道你這個向量究竟是“長度為 8 的向量”還是“長度為 5 的向量,填充了 3 個無意義的 0”。為了表示出哪些是有意義的,哪些是 padding 的,我們還需要一個 mask 向量(矩陣):



這是一個 0/1 向量(矩陣),用 1 表示有意義的部分,用 0 表示無意義的 padding 部分。


所謂 mask,就是 x 和 m 的運算,來排除 padding 帶來的效應。比如我們要求 x 的均值,本來期望的結果是:



但是由于向量已經經過 padding,直接算的話就得到:



會帶來偏差。更嚴重的是,對于同一個輸入,每次 padding 的零的數目可能是不固定的,因此同一個樣本每次可能得到不同的均值,這是很不合理的。有了 mask 向量 m 之后,我們可以重寫求均值的運算:



這里的 ? 是逐位對應相乘的意思。這樣一來,分子只對非 padding 部分求和,分母則是對非 padding 部分計數,不管你 padding 多少個零,最終算出來的結果都是一樣的。


如果要求 x 的最大值呢?我們有 max([1,0,3,4,5])=max([1,0,3,4,5,0,0,0])=5,似乎不用排除 padding 效應了?在這個例子中是這樣,但還有可能是:



經過 padding 后變成了:



如果直接對 padding 后的 x 求 max,那么得到的是 0,而 0 不在原來的范圍內。這時候解決的方法是:讓 padding 部分足夠小,以至于 max(幾乎)不能取到 padding 部分,比如:



正常來說,神經網絡的輸入輸出的數量級不會很大,所以經過后,padding 部分在這個數量級中上,可以保證取 max 的話不會取到 padding 部分了。


處理 softmax 的 padding 也是如此。在 Attention 或者指針網絡時,我們就有可能遇到對變長的向量做 softmax,如果直接對 padding 后的向量做 softmax,那么 padding 部分也會平攤一部分概率,導致實際有意義的部分概率之和都不等于 1 了。解決辦法跟 max 時一樣,讓 padding 部分足夠小足夠小,使得足夠接近于 0,以至于可以忽略:



上面幾個算子的 mask 處理算是比較特殊的,其余運算的 mask 處理(除了雙向 RNN),基本上只需要輸出:



就行了,也就是讓 padding 部分保持為 0。


Keras實現要點


Keras 自帶了 mask 功能,但是不建議用,因為自帶的 mask 不夠清晰靈活,而且也不支持所有的層,強烈建議讀者自己實現 mask。?


近來開源的好幾個模型都已經給出了足夠多的 mask 案例,我相信讀者只要認真去閱讀源碼,一定很容易理解 mask 的實現方式的,這里簡單提一下幾個要點。


一般來說 NLP 模型的輸入是詞 ID 矩陣,形狀為 [batch_size, seq_len],其中我會用 0 作為 padding 的 ID,而 1 作為 UNK 的 ID,剩下的就隨意了,然后我就用一個 Lambda 層生成 mask 矩陣:


#?x是詞ID矩陣
mask?=?Lambda(lambda?x:?K.cast(K.greater(K.expand_dims(x,?2),?0),?'float32'))(x)


這樣生成的 mask 矩陣大小是 [batch_size, seq_len, 1],然后詞 ID 矩陣經過 Embedding 層后的大小為 [batch_size, seq_len, word_size],這樣一來就可以用 mask 矩陣對輸出結果就行處理了。這種寫法只是我的習慣,并非就是唯一的標準。


結合:雙向RNN


剛才我們的討論排除了雙向 RNN,這是因為 RNN 是遞歸模型,沒辦法簡單地 mask(主要是逆向 RNN 這部分)。所謂雙向 RNN,就是正反各做一次 RNN 然后拼接或者相加之類的。


假如我們要對 [1,0,3,4,5,0,0,0] 做逆向 RNN 運算時,最后輸出的結果都會包含 padding 部分的 0(因為 padding 部分在一開始就參與了運算)。因此事后是沒法排除的,只有在事前排除。


排除的方案是:要做逆向 RNN,先將 [1,0,3,4,5,0,0,0] 反轉為 [5,4,3,0,1,0,0,0],然后做一個正向 RNN,然后再把結果反轉回去,要注意反轉的時候只反轉非 padding 部分(這樣才能保證遞歸運算時 padding 部分始終不參與,并且保證跟正向 RNN 的結果對齊),這個 tensorflow 提供了現成的函數 tf.reverse_sequence()。


遺憾的是,Keras 自帶的 Bidirectional 并沒有這個功能,所以我重寫了它,供讀者參考:


class?OurBidirectional(OurLayer):
????"""自己封裝雙向RNN,允許傳入mask,保證對齊
????"""

????def?__init__(self,?layer,?**args):
????????super(OurBidirectional,?self).__init__(**args)
????????self.forward_layer?=?copy.deepcopy(layer)
????????self.backward_layer?=?copy.deepcopy(layer)
????????self.forward_layer.name?=?'forward_'?+?self.forward_layer.name
????????self.backward_layer.name?=?'backward_'?+?self.backward_layer.name
????def?reverse_sequence(self,?x,?mask):
????????"""這里的mask.shape是[batch_size,?seq_len,?1]
????????"""

????????seq_len?=?K.round(K.sum(mask,?1)[:,?0])
????????seq_len?=?K.cast(seq_len,?'int32')
????????return?K.tf.reverse_sequence(x,?seq_len,?seq_dim=1)
????def?call(self,?inputs):
????????x,?mask?=?inputs
????????x_forward?=?self.reuse(self.forward_layer,?x)
????????x_backward?=?self.reverse_sequence(x,?mask)
????????x_backward?=?self.reuse(self.backward_layer,?x_backward)
????????x_backward?=?self.reverse_sequence(x_backward,?mask)
????????x?=?K.concatenate([x_forward,?x_backward],?2)
????????return?x?*?mask
????def?compute_output_shape(self,?input_shape):
????????return?(None,?input_shape[0][1],?self.forward_layer.units?*?2)


使用方法跟自帶的 Bidirectional 基本一樣的,只不過要多傳入 mask 矩陣,比如:


x?=?OurBidirectional(LSTM(128))([x,?x_mask])


小結


Keras 是一個極其友好、極其靈活的高層深度學習 API 封裝,千萬不要聽信網上流傳的“Keras 對新手很友好,但是欠缺靈活性”的謠言。Keras 對新手很友好,對老手更友好,對需要頻繁自定義模塊的用戶更更友好。


相關鏈接


[1]?https://kexue.fm/archives/5765




點擊以下標題查看作者其他文章:?


  • 當Bert遇上Keras:這可能是Bert最簡單的打開姿勢

  • 玩轉Keras之Seq2Seq自動生成標題 | 附開源代碼

  • Keras之小眾需求:自定義優化器

  • 讓Keras更酷一些:中間變量、權重滑動和安全生成器

  • 讓Keras更酷一些:分層的學習率和自由的梯度

  • 全新視角:用變分推斷統一理解生成模型



#投 稿 通 道#

?讓你的論文被更多人看到?



如何才能讓更多的優質內容以更短路徑到達讀者群體,縮短讀者尋找優質內容的成本呢?答案就是:你不認識的人。


總有一些你不認識的人,知道你想知道的東西。PaperWeekly 或許可以成為一座橋梁,促使不同背景、不同方向的學者和學術靈感相互碰撞,迸發出更多的可能性。


PaperWeekly 鼓勵高校實驗室或個人,在我們的平臺上分享各類優質內容,可以是最新論文解讀,也可以是學習心得技術干貨。我們的目的只有一個,讓知識真正流動起來。


??來稿標準:

? 稿件確系個人原創作品,來稿需注明作者個人信息(姓名+學校/工作單位+學歷/職位+研究方向)?

? 如果文章并非首發,請在投稿時提醒并附上所有已發布鏈接?

? PaperWeekly 默認每篇文章都是首發,均會添加“原創”標志


? 投稿郵箱:

? 投稿郵箱:hr@paperweekly.site?

? 所有文章配圖,請單獨在附件中發送?

? 請留下即時聯系方式(微信或手機),以便我們在編輯發布時和作者溝通




?


現在,在「知乎」也能找到我們了

進入知乎首頁搜索「PaperWeekly」

點擊「關注」訂閱我們的專欄吧



關于PaperWeekly


PaperWeekly 是一個推薦、解讀、討論、報道人工智能前沿論文成果的學術平臺。如果你研究或從事 AI 領域,歡迎在公眾號后臺點擊「交流群」,小助手將把你帶入 PaperWeekly 的交流群里。


▽ 點擊 |?閱讀原文?| 查看作者博客

總結

以上是生活随笔為你收集整理的“让Keras更酷一些!”:层中层与mask的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 精品国产乱码久久久人妻 | 日韩精品免费播放 | 污污视频在线看 | 亚洲精品中文字幕成人片 | 奇米成人影视 | 久久国产日韩 | 精品国产aⅴ麻豆 | 中国字幕一色哟哟 | 日本人视频69式jzzij | 狠狠躁18三区二区一区传媒剧情 | 无码h黄肉3d动漫在线观看 | 在线网站黄 | 色爽爽一区二区三区 | 亚洲综合成人网 | 人妻久久一区二区三区 | 无码播放一区二区三区 | 在线播放视频高清在线观看 | 色香蕉网站 | 97伊人网 | 美女露出粉嫩尿囗让男人桶 | 久久精品视频一区 | 精品在线免费视频 | 中文日韩欧美 | 黄色一极毛片 | 欧美专区在线播放 | 中文字幕欧美一区 | 五级 黄 色 片 | 在线观看免费国产 | 你懂的91| 久久久久久久久久久久国产精品 | 日韩欧美亚洲综合 | 国产片淫乱18一级毛片动态图 | 午夜电影天堂 | 91麻豆产精品久久久久久夏晴子 | 男生和女生操操 | 亚洲av永久无码精品一区二区国产 | 69视频网 | 中文字幕一区二区人妻痴汉电车 | 制服丝袜av一区二区三区下载 | 国产人与zoxxxx另类 | 日韩日日日 | 欧美videossex极品 | 久色视频在线观看 | 大牛影视剧免费播放在线 | 欧美zozo | 五月开心网| 日韩精品极品视频免费观看 | 玩日本老头很兴奋xxxx | 日韩欧美卡一卡二 | 国产专区在线播放 | 综合国产在线 | jlzzzjlzzz国产免费观看 | 已满十八岁免费观看全集动漫 | 91色视频在线观看 | 性xxxxx大片免费视频 | 青青草视频在线观看免费 | 色妞网站| 欧美极品三级 | 又色又爽又黄 | 成人乱人乱一区二区三区一级视频 | 小sao货水好多真紧h无码视频 | 黑色丝袜吻戏亲胸摸腿 | 国产午夜一区二区三区 | 一级片av | 国内露脸中年夫妇交换 | 美日韩精品 | 日韩五月| 欧美精品一区二区成人 | 蜜臀视频一区二区三区 | 秋霞电影网一区二区 | 国产一区二区三区久久 | 麻豆chinese极品少妇 | 亚洲第八页 | 日本一本视频 | 国产精品国产精品国产专区不卡 | 麻豆免费在线观看 | 在线日韩三级 | 亚洲一区二区三区久久久 | 国产高清免费在线观看 | 青青草久久伊人 | 麻豆日产六区 | 人人爱超碰 | 亚洲中文字幕久久无码 | 无码一区二区三区在线观看 | 豆花在线视频 | 天天做天天摸天天爽天天爱 | 97精品久久| 国产夫妻在线视频 | 青青草在线免费观看 | 俄罗斯女人裸体性做爰 | 午夜影院日本 | 国产在线导航 | 黄色录像片子 | 亚洲情区| 国产乱人伦 | 国产中文欧美日韩在线 | 免费久久久 | jizz中国女人高潮 | 色图18p|