深度學習-函數-tf.nn.embedding_lookup 與tf.keras.layers.Embedding

1. one_hot編碼

首先,瞭解下什麼是one_hot編碼,直接舉例子如下:
詞庫

我   從   哪   裏   來   要   到   何   處  去
0    1    2    3   4    5   6    7    8   9

__one_hot編碼__如下:

# 我從哪裏來,要到何處去
[
[1 0 0 0 0 0 0 0 0 0]
[0 1 0 0 0 0 0 0 0 0]
[0 0 1 0 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 0 0]
[0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 1 0 0 0 0]
[0 0 0 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 1 0 0]
[0 0 0 0 0 0 0 0 1 0]
[0 0 0 0 0 0 0 0 0 1]
]
 
# 我從何處來,要到哪裏去
[
[1 0 0 0 0 0 0 0 0 0]
[0 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0]
[0 0 0 0 0 0 0 0 1 0]
[0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 1 0 0 0 0]
[0 0 0 0 0 0 1 0 0 0]
[0 0 1 0 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 1]
]

one_hot編碼後,一個句子可以用一個矩陣表示,出現在詞庫中的詞對應在矩陣中位置爲1

1.1. 簡單對比

one_hot編碼之前使用列表(一維)表達一個句子
one_hot編碼之後使用矩陣(二維)表達一個句子

1.2.優勢分析:

1、稀疏矩陣做矩陣計算的時候,只需要把1對應位置的數相乘求和就行,
2、one-hot編碼的優勢就體現出來了,計算方便快捷、表達能力強

1.3. 缺點分析:

1、過於稀疏時,過度佔用資源
比如:中文大大小小簡體繁體常用不常用有十幾萬,然後一篇文章100W字,要表達所有句子,需要100W X 10W的矩陣

1.4. 延伸思考

1、如果我們的文章有100W字,99W是重複的,有1W是不重複的,我們是不是可以用1W X 10W的矩陣存儲空間?這就是embedding的用途

2. embedding的用途

2.1 embedding有兩個用途:

1、降維,如下圖:26矩陣乘上63矩陣,得到2*3矩陣,維數減少

2、升維,原理同上

在這裏插入圖片描述

3. embedding的原理

可以參考這篇文章介紹的特別清楚

one_hot編碼矩陣如下:

公主很漂亮:
公 [0 0 0 0 1][0 0 0 1 0][0 0 1 0 0][0 1 0 0 0][1 0 0 0 0]

擴大詞庫後:
公 [0 0 0 0 1 0 0 0 0 0][0 0 0 1 0 0 0 0 0 0][0 0 1 0 0 0 0 0 0 0][0 1 0 0 0 0 0 0 0 0][1 0 0 0 0 0 0 0 0 0]

在這基礎上,王妃很漂亮表示爲:
王 [0 0 0 0 0 0 0 0 0 1][0 0 0 0 0 0 0 0 1 0][0 0 1 0 0 0 0 0 0 0][0 1 0 0 0 0 0 0 0 0][1 0 0 0 0 0 0 0 0 0]

從中文表示來看,我們可以感覺到,王妃跟公主其實是有很大關係的,比如:公主是皇帝的女兒,王妃是皇帝的妃子,可以從“皇帝”這個詞進行關聯上;公主住在宮裏,王妃住在宮裏,可以從“宮裏”這個詞關聯上;公主是女的,王妃也是女的,可以從“女”這個字關聯上

公主王妃one_hot編碼
公 [0 0 0 0 1 0 0 0 0 0][0 0 0 1 0 0 0 0 0 0][0 0 0 0 0 0 0 0 0 1][0 0 0 0 0 0 0 0 1 0]

通過剛纔的假設關聯,我們關聯出了“皇帝”、“宮裏”和“女”三個詞,那我們嘗試這麼去定義公主和王妃

公主一定是皇帝的女兒,我們假設她跟皇帝的關係相似度爲1.0;公主從一出生就住在宮裏,直到20歲才嫁到府上,活了80歲,我們假設她跟宮裏的關係相似度爲0.25;公主一定是女的,跟女的關係相似度爲1.0;

王妃是皇帝的妃子,沒有親緣關係,但是有存在着某種關係,我們就假設她跟皇帝的關係相似度爲0.6吧;妃子從20歲就住在宮裏,活了80歲,我們假設她跟宮裏的關係相似度爲0.75;王妃一定是女的,跟女的關係相似度爲1.0;

於是,

       皇    宮  
       帝    裏    女
公主 [ 1.0  0.25  1.0]
王妃 [ 0.6  0.75  1.0]

這樣我們就把公主和王妃兩個詞,跟皇帝、宮裏、女這幾個字(特徵)關聯起來了,我們可以認爲:
公主=1.0 皇帝 +0.25宮裏 +1.0
王妃=0.6 皇帝 +0.75宮裏 +1.0

或者如下表示,

      皇     宮  
       帝     裏     女
公   [ 0.5  0.125   0.5][ 0.5  0.125   0.5][ 0.3  0.375   0.5][ 0.3  0.375   0.5]

我們把皇帝叫做特徵(1),宮裏叫做特徵(2),女叫做特徵(3),於是乎,我們就得出了公主和王妃的隱含特徵關係:

王妃=公主的特徵(1)* 0.6 +公主的特徵(2)* 3 +公主的特徵(3)* 1

於是,我們把文字的one-hot編碼,從稀疏態變成了密集態,並且讓相互獨立向量變成了有內在聯繫的關係向量

4. embedding的作用

就是把稀疏矩陣變成一個密集矩陣,也稱爲查表,因爲他們之間是一個一一映射關係。
這種關係在反向傳播的過程中,是一直在更新的,因此能在多次epoch後,使得這個關係變成相對成熟

5. embedding的生成

TF1.X 是函數 tf.nn.embedding_lookup
TF2.X 是函數 layers.Embedding(input_dim=**, output_dim=, input_length=),

6. embedding的使用

6.1. tf.nn.embedding_lookup 函數在TF1.x

關於np.random.RandomState、np.random.rand、np.random.random、np.random_sample參考https://blog.csdn.net/lanchunhui/article/details/50405670

tf.nn.embedding_lookup函數的用法主要是選取一個張量裏面索引對應的元素。tf.nn.embedding_lookup(params, ids):params可以是張量也可以是數組等,id就是對應的索引,其他的參數不介紹。

例如:

6.1.1 ids只有一行

import tensorflow as tf
#c = np.random.random([10, 1])  # 隨機生成一個10*1的數組
#b = tf.nn.embedding_lookup(c, [1, 3])#查找數組中的序號爲1和3的
p=tf.Variable(tf.random_normal([10,1]))#生成10*1的張量
b = tf.nn.embedding_lookup(p, [1, 3])#查找張量中的序號爲1和3的
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(b))
    #print(c)
    print(sess.run(p))
    print(p)
    print(type(p))

輸出:

[[0.15791859]
 [0.6468804 ]]
[[-0.2737084 ]
 [ 0.15791859]
 [-0.01315552]
 [ 0.6468804 ]
 [-1.4090979 ]
 [ 2.1583703 ]
 [ 1.4137447 ]
 [ 0.20688428]
 [-0.32815856]
 [-1.0601649 ]]
<tf.Variable 'Variable:0' shape=(10, 1) dtype=float32_ref>
<class 'tensorflow.python.ops.variables.Variable'>

分析:輸出爲張量的第一和第三個元素。

6.1.2 如果ids是多行

import tensorflow as tf
import numpy as np

a = [[0.1, 0.2, 0.3], [1.1, 1.2, 1.3], [2.1, 2.2, 2.3], [3.1, 3.2, 3.3], [4.1, 4.2, 4.3]]
a = np.asarray(a)
idx1 = tf.Variable([0, 2, 3, 1], tf.int32)
idx2 = tf.Variable([[0, 2, 3, 1], [4, 0, 2, 2]], tf.int32)
out1 = tf.nn.embedding_lookup(a, idx1)
out2 = tf.nn.embedding_lookup(a, idx2)
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    print sess.run(out1)
    print out1
    print '=================='
    print sess.run(out2)
    print out2

輸出:

[[ 0.1  0.2  0.3]
 [ 2.1  2.2  2.3]
 [ 3.1  3.2  3.3]
 [ 1.1  1.2  1.3]]
Tensor("embedding_lookup:0", shape=(4, 3), dtype=float64)
==================
[[[ 0.1  0.2  0.3]
  [ 2.1  2.2  2.3]
  [ 3.1  3.2  3.3]
  [ 1.1  1.2  1.3]]

 [[ 4.1  4.2  4.3]
  [ 0.1  0.2  0.3]
  [ 2.1  2.2  2.3]
  [ 2.1  2.2  2.3]]]
Tensor("embedding_lookup_1:0", shape=(2, 4, 3), dtype=float64)

6.1.3 例子

在這裏插入圖片描述
從id(索引)找到對應的One-hot encoding,然後紅色的weight就直接對應了輸出節點的值
在這裏插入圖片描述
從one_hot到矩陣編碼的轉換過程需要在embedding進行查找:

one_hot * embedding_weights = embedding_code
import tensorflow as tf
import numpy as np
input_ids = tf.placeholder(dtype=tf.int32, shape=[None])
_input_ids = tf.placeholder(dtype=tf.int32, shape=[3, 2])

embedding_param = tf.Variable(np.identity(8, dtype=np.int32))  # 生成一個8x8的單位矩陣
input_embedding = tf.nn.embedding_lookup(embedding_param, input_ids)
_input_embedding = tf.nn.embedding_lookup(embedding_param, _input_ids)

sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())

print('embedding:')
print(embedding_param.eval())

var1 = [1, 2, 6, 4, 2, 5, 7]
print('\n var1:')
print(var1)

print('\nprojecting result:')
print(sess.run(input_embedding, feed_dict={input_ids: var1}))

var2 = [[1, 4], [6, 3], [2, 5]]
print('\n _var2:')
print(var2)

print('\n _projecting result:')
print(sess.run(_input_embedding, feed_dict={_input_ids: var2}))

執行結果

embedding:
[[1 0 0 0 0 0 0 0]
 [0 1 0 0 0 0 0 0]
 [0 0 1 0 0 0 0 0]
 [0 0 0 1 0 0 0 0]
 [0 0 0 0 1 0 0 0]
 [0 0 0 0 0 1 0 0]
 [0 0 0 0 0 0 1 0]
 [0 0 0 0 0 0 0 1]]

 var1:
[1, 2, 6, 4, 2, 5, 7]

projecting result:
[[0 1 0 0 0 0 0 0]
 [0 0 1 0 0 0 0 0]
 [0 0 0 0 0 0 1 0]
 [0 0 0 0 1 0 0 0]
 [0 0 1 0 0 0 0 0]
 [0 0 0 0 0 1 0 0]
 [0 0 0 0 0 0 0 1]]

 _var2:
[[1, 4], [6, 3], [2, 5]]

 _projecting result:
[[[0 1 0 0 0 0 0 0]
  [0 0 0 0 1 0 0 0]]

 [[0 0 0 0 0 0 1 0]
  [0 0 0 1 0 0 0 0]]

 [[0 0 1 0 0 0 0 0]
  [0 0 0 0 0 1 0 0]]]

Process finished with exit code 0

6.2. tf.keras.layers.Embedding 函數在TF2.x 中

tf.keras.layers.Embedding
Arguments:
input_dim: int > 0. Size of the vocabulary,
i.e. maximum integer index + 1.
output_dim: int >= 0. Dimension of the dense embedding.

例子 -

import tensorflow as tf
import numpy as np
model = tf.keras.Sequential()
model.add(tf.keras.layers.Embedding(1000, 64, input_length=10))
# The model will take as input an integer matrix of size (batch,
# input_length), and the largest integer (i.e. word index) in the input
# should be no larger than 999 (vocabulary size).
# Now model.output_shape is (None, 10, 64), where `None` is the batch
# dimension.
input_array = np.random.randint(1000, size=(32, 10))
print(input_array)
model.compile('rmsprop', 'mse')
output_array = model.predict(input_array)
print(output_array.shape)

執行結果

[[988 830 373 434 333 520 601 316 871 342]
 [241 351  83 855 512 374 687 192 910 995]
 [820 368 967 744 445  15 894 331 832 143]
 [648 120 239 108 575 853 644 985 469 185]
 [131 805 349 671 681 793 356  31  29 396]
 [462 433 587 180 529 618 676 567 695 612]
 [682 862 827 947 971 152 345  37 628 523]
 [464 709 267 910 836 245 750 578 187 526]
 [800 907 651 837 683 840 275 362 391 123]
 [860 161 912 305 234 612 917  32 162 457]
 [422 762 171 413  94 454 642  87 982 146]
 [740 597 544 900  56 707 914 192 911 563]
 [521 818 506 104 469 284 199 192 298 723]
 [418 207 418 385 974 641 367 768 539 701]
 [822 765 409 355 529  22 678  33 796 743]
 [238 804 746 592 714 141 419 370 116 675]
 [291  54 887 619 237  12  76  91 792 893]
 [199 821 862 800 392  73 585 287 491 704]
 [303  52  80 799 233 986 651 216 737 801]
 [  5 704 387 346 810 579 325 661 763 802]
 [520 231 421 182 102 511 819 531 243 726]
 [703 419 431 122 292 598 394 786 701 475]
 [630 724 302 541 568 814 401 990 498 875]
 [345 464 405 949  90 342 841 274 681 378]
 [401 590 670  52  33 308 929 131 292 402]
 [617 589  50 440  19 181 509 287 285  73]
 [976 636  57 529 368 745 553 709 229 650]
 [140 359 619 747 411 666 134 640 318 460]
 [758 910 285 935 955 104 757 708 349 209]
 [739 528 478 190 924 106  93 439 498 767]
 [758 712 734 681 860 435 230 850 530 848]
 [901  14 885 531  86 950 626 378 206 779]]
(32, 10, 64)

Process finished with exit code 0

6.2. tf.keras.layers.Embedding 函數傳入權重在TF2.x 中

weight : 如果你要已經訓練好的詞向量,可以在這裏傳入。比如現在大部分用Google的Word2Vector中詞向量。

import tensorflow as tf
import numpy as np
weight = np.arange(60).reshape(10, 6)
for i in range(10):
    weight[i] = i
print(weight)
model = tf.keras.Sequential()
model.add(tf.keras.layers.Embedding(10, 6, input_length=2, weights =[weight]))
input_array = np.random.randint(10, size=(3, 2))
print(input_array)
model.compile('rmsprop', 'mse')
output_array = model.predict(input_array)
print(output_array.shape)
print(output_array)

執行結果

10
[[0 0 0 0 0 0]
 [1 1 1 1 1 1]
 [2 2 2 2 2 2]
 [3 3 3 3 3 3]
 [4 4 4 4 4 4]
 [5 5 5 5 5 5]
 [6 6 6 6 6 6]
 [7 7 7 7 7 7]
 [8 8 8 8 8 8]
 [9 9 9 9 9 9]]
 
 [[7 8]
 [3 1]
 [2 0]]
(3, 2, 6)
[[[7. 7. 7. 7. 7. 7.]
  [8. 8. 8. 8. 8. 8.]]

 [[3. 3. 3. 3. 3. 3.]
  [1. 1. 1. 1. 1. 1.]]

 [[2. 2. 2. 2. 2. 2.]
  [0. 0. 0. 0. 0. 0.]]]

7. 參考資料

https://www.cnblogs.com/gaofighting/p/9625868.html
https://www.tensorflow.org/api_docs/python/tf/keras/layers/Embedding?version=nightly
https://blog.csdn.net/hit0803107/article/details/98377030

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章