# Deep Learning 2 筆記
## 計數手法
### 前處理
收集大量且與自然語言相關的文本資料,集成語料庫(corpus)。
文本要經過 **轉小寫** 和 **切割** 等前處理。
```python=
text = "You say goodbye and I say hello."
text = text.lower()
text = text.replace("."," ." )
text # 'you say goodbye and i say hello .'
words = text.split(" ")
words # ['you', 'say', 'goodbye', 'and', 'i', 'say', 'hello', '.']
```
再將處理過後的文本轉換成字詞ID
```python=
word_to_id = {}
id_to_word = {}
for word in words:
if word not in word_to_id:
new_id = len(word_to_id)
word_to_id[word] = new_id
id_to_word[new_id] = word
word_to_id # {'you': 0, 'say': 1, 'goodbye': 2, 'and': 3, 'i': 4, 'hello': 5, '.': 6}
id_to_word # {0: 'you', 1: 'say', 2: 'goodbye', 3: 'and', 4: 'i', 5: 'hello', 6: '.'}
```
最後將清單整理轉換成NumPy陣列
```python=
import numpy as np
corpus = [word_to_id[w] for w in words]
corpus = np.array(corpus)
corpus # array([0, 1, 2, 3, 4, 1, 5, 6])
```
如此一來語料庫的準備工作就完成了。
corpus, word_to_id, id_to_word 三個變數分別是 字詞ID清單,字轉ID字典,ID轉字字典。
---
### 分布假說與共生矩陣
詞意是由周圍的字詞所形成的,意思相同的字往往會有相同的上下文。
舉例:(I guzzle beer;We guzzle wine;I drink beer;We drink wine)

上下文是指某個字詞的周圍字詞。通常用window size來決定上下文的大小,此圖window size=2。
```python=
def create_co_matrix(corpus, vocab_size, window_size=1):
corpus_size = len(corpus)
co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32)
for idx, word_id in enumerate(corpus):
for i in range(1, window_size + 1):
left_idx = idx - i
right_idx = idx + i
if left_idx >= 0:
left_word_id = corpus[left_idx]
co_matrix[word_id, left_word_id] += 1
if right_idx < corpus_size:
right_word_id = corpus[right_idx]
co_matrix[word_id, right_word_id] += 1
return co_matrix
```

針對每個字詞,計算上下文包含的詞彙,整理成表格,也稱為**共生矩陣**。
---
### 向量間的相似度
計算餘弦相似度,x=(x1,x2,...,xn),y=(y1,y2,...,yn),此數值介於-1~1之間。

```python=
def cos_similarity(x, y, eps=1e-8):
nx = x / np.sqrt(np.sum(x**2) + eps)
ny = y / np.sqrt(np.sum(y**2) + eps)
return np.dot(nx, ny)
```
為了避免零向量導致除以零的情況發生,在分母加上極小的浮點數。
試著計算"you"和"i"之間的相似度
```python=
c0 = co_matrix[word_to_id["you"]]
c1 = co_matrix[word_to_id["i"]]
cos_similarity(c0, c1) # 0.7071067758832467
```
---
### 顯示相似詞排名
```python=
def most_similar(query, word_to_id, id_to_word, word_matrix, top):
if query not in word_to_id:
print("%s is not found" % query)
return
print("\n[query]" + query)
query_id = word_to_id[query]
query_vec = word_matrix[query_id]
vocab_size = len(id_to_word)
similarity = np.zeros(vocab_size)
for i in range(vocab_size):
similarity[i] = cos_similarity(word_matrix[i], query_vec)
count = 0
for i in (-1*similarity).argsort():
if id_to_word[i] == query:
continue
print("%s: %s" % (id_to_word[i], similarity[i]))
count += 1
if count >= top:
return
```
顯示"you"與其他字詞的相似度
```python=
most_similar("you", word_to_id, id_to_word, co_matrix, top=5)
# [query]you
# goodbye: 0.7071067758832467
# i: 0.7071067758832467
# hello: 0.7071067758832467
# say: 0.0
# and: 0.0
```
這裡可以看到,"you"和"goodbye"、"i"、"hello"有較高的相似度,不過因為語料庫過小,無法參考此次範例結果。
## 改善計數手法
由於單純的計數手法會被**高頻率單詞**影響,造成字詞間的關聯性降低。
舉例來說,我們經常會看到"...the car..."這類的句子,因此這兩個字詞的共生次數出現較大的數值,但是(the, car)和(car, drive)相比較,很明顯在詞意上後者的關聯性比前者來的強,但若單單只看出現次數,反而前者的關聯性會高於後者。換句話說,因為the這個**高頻率單詞**,真正關聯性強的詞被影響。
### 點間互資訊(Pointwise Mutual Information)

C=出現次數,N是語料庫大小
假設在10000個單詞所組成的語料庫中,字詞"the"出現1000次,"car"出現20次,同時出現10次

另外"drive"出現10次,(car, drive)共生出現5次

由此可知,使用PMI計算關聯度,比較符合我們要的結果。
此時也會產生一個問題,若兩個字的共生次數為0時,則log~2~ 0 = -∞,因此需要改寫算式。

```python=
def ppmi(C, verbose=False, eps=1e-8):
M = np.zeros_like(C, dtype=np.float32)
N = np.sum(C)
S = np.sum(C, axis=0)
total = C.shape[0] * C.shape[1]
cnt = 0
for i in range(C.shape[0]):
for j in range(C.shape[1]):
pmi = np.log2(C[i, j] * N / (S[j]*S[i]) + eps)
M[i, j] = max(0, pmi)
if verbose:
cnt += 1
if cnt % (total/100) == 0:
print('%.if%% done' % (100*cnt/total))
return M
```
### 降維
使用奇異值分解(Singular Value Decomposition:SVD)進行降維。
SVD是把任意矩陣分解成三個矩陣乘積。

```python=
U, S, V = np.linalg.svd(W)
for word, word_id in word_to_id.items():
plt.annotate(word, (U[word_id, 0], U[word_id, 1]))
plt.scatter(U[:,0], U[:,1], alpha=0.5)
plt.show()
```

### PTB資料集(Penn Treebank)
PTB語料庫是由word2vec的發明者Tomas Mikolov提供。在使用前需要經過前處理,將罕見字詞以<unk>取代,將數字以<N>取代。

此資料庫總共有929589個不同的單字。
```
[query]you
i: 0.7016294002532959
we: 0.6388039588928223
anybody: 0.5868046879768372
do: 0.5612815022468567
'll: 0.5126119256019592
[query]year
month: 0.6957003474235535
quarter: 0.6914835572242737
earlier: 0.6661210656166077
last: 0.632778525352478
third: 0.623047411441803
[query]car
luxury: 0.6767404675483704
auto: 0.6339929103851318
vehicle: 0.5972709655761719
cars: 0.5888376235961914
truck: 0.5693155527114868
[query]toyota
motor: 0.7481383085250854
nissan: 0.7147315144538879
motors: 0.6946359872817993
lexus: 0.6553667783737183
honda: 0.6343462467193604
```
## 推論手法

推論手法是以相鄰的字詞作為上下文,而後對中間的字詞進行推論。

模型是以上下文當作輸入,再輸出各個可能出現字詞的機率。使用語料庫進行深度學習,最後取得字詞的分散式表示,當作學習結果,這就是推論手法的整體概念。
### 類神經網路的字詞處理方法
one-hot 編碼

### CBOW(Continuous bag-of-words)模型

CBOW模型是從上下文推測出中間的**目標對象**的類神經網路。

從語料庫中擷取出來的上下文(contexts)當作輸入,而中間的目標字詞(target)則當作label。