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