Kaggle 官方教程:嵌入

原文:Embeddings

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

P.S...

本課程仍處于測試階段诗芜,因此我很樂意收到你的反饋意見褐缠。 如果你有時間填寫本課程的超短期調(diào)查海雪,我將非常感激锋叨。 你也可以在下面的評論中或在學習論壇上留下公開反饋含鳞。

一、嵌入層

歡迎閱讀嵌入主題的第一課儒搭。 在本課程中吠架,我將展示如何使用tf.keras API 實現(xiàn)帶嵌入層的模型。 嵌入是一種技術(shù)搂鲫,使深度神經(jīng)網(wǎng)絡(luò)能夠處理稀疏的類別變量傍药。

稀疏類別變量

我的意思是一個具有許多可能值(高基數(shù))的類別變量,其中少數(shù)(通常只有 1)存在于任何給定的觀察中魂仍。 一個很好的例子是詞匯拐辽。 英語中的詞匯是成千上萬的,但一條推文可能只有十幾個詞擦酌。 詞嵌入是將深度學習應(yīng)用于自然語言的關(guān)鍵技術(shù)俱诸。 但其他例子還有很多。

例如赊舶,洛杉磯餐館檢查的這個數(shù)據(jù)集有幾個稀疏的分類變量睁搭,包括:

  • employee_id:衛(wèi)生部門的哪些員工進行了這次檢查? (約 250 個不同的值)
  • facility_zip:餐廳的郵政編碼是什么笼平? (約 3,000 個不同的值)
  • owner_name:誰擁有餐廳园骆? (約 35,000 個不同的值)

對于將任何這些變量用作網(wǎng)絡(luò)的輸入,嵌入層是個好主意寓调。

在本課程中锌唾,我將使用 MovieLens 數(shù)據(jù)集作為示例。

MovieLens

MovieLens 數(shù)據(jù)集由用戶給電影的評分組成。這是一個示例:

userId movieId rating y title year
12904240 85731 1883 4.5 0.974498 Labyrinth 1986
6089380 45008 1221 4.5 0.974498 Femme Nikita, La (Nikita) 1990
17901393 125144 3948 4.0 0.474498 The Alamo 1960
9024816 122230 3027 3.5 -0.025502 Toy Story 2 1999
11655659 21156 5202 3.0 -0.525502 My Big Fat Greek Wedding

評分范圍是 0.5 到 5晌涕。我們的目標是預(yù)測由給定用戶ui給出的滋捶,特定電影mj的評分。 (列y只是評分列的副本余黎,減去了平均值 - 這在以后會有用重窟。)

userIdmovieId都是稀疏分類變量。 它們有許多可能的值:

138,493 個獨立用戶評分了 26,744 個不同的電影(總評分是 20,000,263 個)

在 Keras 中創(chuàng)建評分預(yù)測模型

我們想要構(gòu)建一個模型惧财,它接受用戶ui和電影mj亲族,并輸出 0.5-5 的數(shù)字,表示我們認為該用戶將為該電影評分多少星可缚。

注:你可能已經(jīng)注意到MovieLens數(shù)據(jù)集包含每部電影的信息,例如標題斋枢,發(fā)行年份帘靡,一組流派和用戶指定的標簽。 但就目前而言瓤帚,我們不會試圖利用任何額外的信息描姚。

我說我們需要一個嵌入層來處理這些輸入。 為什么戈次? 讓我們回顧一些替代方案轩勘,看看為什么它們不起作用。

壞主意 #1:使用用戶和電影 ID 作為數(shù)值輸入

為什么不將用戶 ID 和電影 ID 作為數(shù)值來輸入怯邪,然后添加一些密集層绊寻?即:

model = keras.Sequential([
    # 2 個輸入值:用戶 ID 和電影 ID
    keras.layers.Dense(256, input_dim=2, activation='relu'),
    keras.layers.Dense(32, activation='relu'),
    # 單個輸出節(jié)點,包含預(yù)測的評分
    keras.layers.Dense(1)
])

用最簡單的術(shù)語來說悬秉,神經(jīng)網(wǎng)絡(luò)的原理是對輸入進行數(shù)學運算澄步。 但分配給用戶和電影的 ID 的實際數(shù)值是沒有意義的『兔冢《辛德勒的名單》的 id 為 527村缸,而《非常嫌疑犯》的 id 為 50,但這并不意味著《辛德勒的名單》比《非常嫌疑犯》大十倍武氓。

壞主意 #2:獨熱編碼的用戶和電影輸入

如果你不熟悉單熱編碼梯皿,可能需要查看我們的課程“使用獨熱編碼處理類別數(shù)據(jù)”

在該課程中县恕,我們說獨熱編碼是“類別數(shù)據(jù)的標準方法”东羹。 那么為什么這是一個壞主意呢? 讓我們看看模型是什么樣子弱睦,它接受獨熱編碼的用戶和電影百姓。

input_size = n_movies + n_users
print("Input size = {:,} ({:,} movies + {:,} users)".format(
    input_size, n_movies, n_users,
))
model = keras.Sequential([
    # 一個帶有 128 個單元的隱藏層
    keras.layers.Dense(128, input_dim=input_size, activation='relu'),
    # 單個輸出節(jié)點,包含預(yù)測的評分
    keras.layers.Dense(1)
])
model.summary()
'''
Input size = 165,237 (26,744 movies + 138,493 users)
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_3 (Dense)              (None, 128)               21150464  
_________________________________________________________________
dense_4 (Dense)              (None, 1)                 129       
=================================================================
Total params: 21,150,593
Trainable params: 21,150,593
Non-trainable params: 0
_________________________________________________________________
'''

這里的一個基本問題是擴展和效率况木。 我們模型的單個輸入是包含 165,237 個數(shù)字的向量(其中我們知道 165,235 是零)垒拢。 我們整個 2000 萬個評分實例數(shù)據(jù)集的特征數(shù)據(jù)旬迹,將需要一個大小為 20,000,000 x 165,237 或大約 3 萬億個數(shù)字的二維數(shù)組。 但愿你能把這一切都放進內(nèi)存中求类!

此外奔垦,在我們的模型上進行訓練和推斷將是低效的。 為了計算我們的第一個隱藏層的激活尸疆,我們需要將我們的 165k 輸入乘以大約 2100 萬個權(quán)重 - 但是這些乘積的絕大多數(shù)都將為零椿猎。

對于具有少量可能值的分類變量,例如{Red, Yellow, Green}{Monday, Tuesday, Wednesday, Friday, Saturday, Sunday}寿弱,獨熱編碼是合適的犯眠。 但在像我們的電影推薦問題的情況下,它并不是那么好症革,其中變量有數(shù)十或數(shù)十萬個可能的值筐咧。

好主意:嵌入層

簡而言之,嵌入層將一組離散對象(如單詞噪矛,用戶或電影)中的每個元素映射到實數(shù)的密集(嵌入)向量量蕊。

注:一個關(guān)鍵的實現(xiàn)細節(jié)是嵌入層接受被嵌入實體的索引作為輸入(即我們可以將userIdmovieId作為輸入)。 你可以將其視為一種“查找表”艇挨。 這比采用獨熱向量并進行巨大的矩陣乘法要有效得多残炮!

例如,如果我們?yōu)殡娪皩W習大小為 8 的嵌入缩滨,則《律政俏佳人》(index = 4352)的嵌入可能如下所示:

[1.624,?0.612,?0.528,?1.073,0.865,?2.302,1.745,?0.761]

它們來自哪里势就? 我們使用隨機噪聲為每個用戶和電影初始化嵌入,然后我們將它們訓練脉漏,作為整體評分預(yù)測模型訓練過程的一部分蛋勺。

他們的意思是什么? 如果對象的嵌入有任何好處鸠删,它應(yīng)該捕獲該對象的一些有用的潛在屬性抱完。 但這里的關(guān)鍵詞是潛在,也就是隱藏的刃泡。 由模型來發(fā)現(xiàn)實體的任何屬性巧娱,并在嵌入空間中對它們編碼,對預(yù)測任務(wù)有用烘贴。 聽起來很神秘禁添? 在后面的課程中,我將展示一些解釋習得的嵌入的技術(shù)桨踪,例如使用 t-SNE 算法將它們可視化老翘。

實現(xiàn)它

我希望我的模型是這樣:

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-1.png

需要注意的一個關(guān)鍵點是,這個網(wǎng)絡(luò)不僅僅是從輸入到輸出的一堆層級。 我們將用戶和電影視為單獨的輸入铺峭,只有在每個輸入經(jīng)過自己的嵌入層之后才會聚集在一起墓怀。

這意味著keras.Sequential類(你可能從我們的圖像數(shù)據(jù)深度學習課程中熟悉它)將無法工作。 我們需要使用keras.Model類轉(zhuǎn)向更強大的“函數(shù)式 API”卫键。 函數(shù)式 API 的更多詳細信息傀履,請查看 Keras 的指南

這是代碼:

hidden_units = (32,4)
movie_embedding_size = 8
user_embedding_size = 8

# 每個實例將包含兩個輸入:單個用戶 ID 和單個電影 ID
user_id_input = keras.Input(shape=(1,), name='user_id')
movie_id_input = keras.Input(shape=(1,), name='movie_id')
user_embedded = keras.layers.Embedding(df.userId.max()+1, user_embedding_size, 
                                       input_length=1, name='user_embedding')(user_id_input)
movie_embedded = keras.layers.Embedding(df.movieId.max()+1, movie_embedding_size, 
                                        input_length=1, name='movie_embedding')(movie_id_input)
# 連接嵌入(并刪除無用的額外維度)
concatenated = keras.layers.Concatenate()([user_embedded, movie_embedded])
out = keras.layers.Flatten()(concatenated)

# 添加一個或多個隱層
for n_hidden in hidden_units:
    out = keras.layers.Dense(n_hidden, activation='relu')(out)

# 單一輸出:我們的預(yù)測評分
out = keras.layers.Dense(1, activation='linear', name='prediction')(out)

model = keras.Model(
    inputs = [user_id_input, movie_id_input],
    outputs = out,
)
model.summary(line_length=88)
'''
________________________________________________________________________________________
Layer (type)                 Output Shape       Param #   Connected to                  
========================================================================================
user_id (InputLayer)         (None, 1)          0                                       
________________________________________________________________________________________
movie_id (InputLayer)        (None, 1)          0                                       
________________________________________________________________________________________
user_embedding (Embedding)   (None, 1, 8)       1107952   user_id[0][0]                 
________________________________________________________________________________________
movie_embedding (Embedding)  (None, 1, 8)       213952    movie_id[0][0]                
________________________________________________________________________________________
concatenate (Concatenate)    (None, 1, 16)      0         user_embedding[0][0]          
                                                          movie_embedding[0][0]         
________________________________________________________________________________________
flatten (Flatten)            (None, 16)         0         concatenate[0][0]             
________________________________________________________________________________________
dense_5 (Dense)              (None, 32)         544       flatten[0][0]                 
________________________________________________________________________________________
dense_6 (Dense)              (None, 4)          132       dense_5[0][0]                 
________________________________________________________________________________________
prediction (Dense)           (None, 1)          5         dense_6[0][0]                 
========================================================================================
Total params: 1,322,585
Trainable params: 1,322,585
Non-trainable params: 0
________________________________________________________________________________________
'''

訓練

我們將編譯我們的模型莉炉,來最小化平方誤差('MSE')钓账。 我們還將絕對值誤差('MAE')作為在訓練期間報告的度量標準,因為它更容易解釋絮宁。

需要考慮的事情:我們知道評分只能取值{0.5,1,1.5,2,2.5,3,3.5,4,4.5,5} - 所以為什么不將其視為 10 類的多類分類問題 梆暮,每個可能的星級評分一個?

model.compile(
    # 技術(shù)說明:使用嵌入層時绍昂,我強烈建議使用
    # tf.train 中發(fā)現(xiàn)的優(yōu)化器之一:
    # https://www.tensorflow.org/api_guides/python/train#Optimizers
    # 傳入像 'adam' 或 'SGD' 這樣的字符串惕蹄,會加載一個 keras 優(yōu)化器 
    # (在 tf.keras.optimizers 下尋找)。 對于像這樣的問題治专,它們似乎要慢得多,
    # 因為它們無法有效處理稀疏梯度更新遭顶。
    tf.train.AdamOptimizer(0.005),
    loss='MSE',
    metrics=['MAE'],
)

讓我們訓練模型:

注:我傳入df.y而不是df.rating张峰,作為我的目標變量。y列只是評分的“中心”版本 - 即評分列減去其在訓練集上的平均值棒旗。 例如喘批,如果訓練集中的總體平均評分是 3 星,那么我們將 3 星評分翻譯為 0, 5星評分為 2.0 等等您旁,來獲得y们陆。 這是深度學習中的常見做法奔浅,并且往往有助于在更少的時期內(nèi)獲得更好的結(jié)果。 對于更多詳細信息敌厘,請隨意使用我在 MovieLens 數(shù)據(jù)集上執(zhí)行的所有預(yù)處理來檢查這個內(nèi)核

history = model.fit(
    [df.userId, df.movieId],
    df.y,
    batch_size=5000,
    epochs=20,
    verbose=0,
    validation_split=.05,
);

為了判斷我們的模型是否良好朽合,有一個基線是有幫助的俱两。 在下面的單元格中,我們計算了幾個虛擬基線的誤差:始終預(yù)測全局平均評分曹步,以及預(yù)測每部電影的平均評分:

  • 訓練集的平均評分:3.53 星
  • 總是預(yù)測全局平均評分宪彩,結(jié)果為 MAE=0.84,MSE=1.10
  • 預(yù)測每部電影的平均評分讲婚,結(jié)果為 MAE=0.73尿孔,MSE=0.88

這是我們的嵌入模型的絕對誤差隨時間的繪圖。 為了進行比較,我們的最佳基線(預(yù)測每部電影的平均評分)用虛線標出:

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-2.png

與基線相比活合,我們能夠?qū)⑵骄`差降低超過 0.1 星(或約 15%)雏婶。不錯!

示例預(yù)測

讓我們嘗試一些示例預(yù)測作為健全性檢查芜辕。 我們首先從數(shù)據(jù)集中隨機挑選一個特定用戶尚骄。

用戶 #26556 評分了 21 個電影(平均評分為 3.7)
userId movieId rating title year
4421455 26556 2705 5.0 Airplane! 1980
14722970 26556 2706 5.0 Airplane II: The Sequel 1982
7435440 26556 2286 4.5 Fletch 1985
16621016 26556 2216 4.5 History of the World: Part I 1981
11648630 26556 534 4.5 Six Degrees of Separation 1993
14805184 26556 937 4.5 Mr. Smith Goes to Washington 1939
14313285 26556 2102 4.5 Strangers on a Train 1951
13671173 26556 2863 4.5 Dr. No 1962
13661434 26556 913 4.0 Notorious 1946
11938282 26556 916 4.0 To Catch a Thief 1955
2354167 26556 3890 4.0 Diamonds Are Forever 1971
16095891 26556 730 4.0 Spy Hard 1996
16265128 26556 3414 3.5 Network 1976
13050537 26556 1414 3.5 Waiting for Guffman 1996
9891416 26556 2907 3.5 Thunderball 1965
3496223 26556 4917 3.5 Gosford Park 2001
1996728 26556 1861 3.0 On the Waterfront 1954
15893218 26556 1082 2.5 A Streetcar Named Desire 1951
13875921 26556 3445 2.5 Keeping the Faith 2000
13163853 26556 1225 2.0 The Day the Earth Stood Still 1951
7262983 26556 2348 0.5 A Civil Action 1998

用戶 26556 給電影《空前絕后滿天飛》和《空前絕后滿天飛 II》打了兩個完美的評分。很棒的選擇侵续! 也許他們也會喜歡《白頭神探》系列 - 另一系列由 Leslie Nielsen 主演的惡搞電影倔丈。

我們沒有那么多關(guān)于這個用戶討厭什么的證據(jù)。 我們不根據(jù)他們的少數(shù)低評分做推斷状蜗,用戶不喜歡什么的更好推斷是需五,他們甚至沒有評價的電影類型。 讓我們再舉幾個電影的例子轧坎,根據(jù)用戶的評分歷史記錄宏邮,他們似乎不太可能看過。

candidate_movies = movies[
    movies.title.str.contains('Naked Gun')
    | (movies.title == 'The Sisterhood of the Traveling Pants')
    | (movies.title == 'Lilo & Stitch')
].copy()

preds = model.predict([
    [uid] * len(candidate_movies), # 用戶 ID
    candidate_movies.index, # 電影 ID
])
# 注意:記住我們在 'y' 上訓練缸血,這是評分列的中心為 0 的版本蜜氨。
# 要將我們模型的輸出值轉(zhuǎn)換為 [0.5, 5] 原始的星級評分范圍, 
# 我們需要通過添加均值來對值“去中心化”
row = df.iloc[0] # rating 和 y 之間的差對于所有行都是相同的捎泻,所以我們可以使用第一行
y_delta = row.rating - row.y
candidate_movies['predicted_rating'] = preds + y_delta
# 添加一列飒炎,帶有我們的預(yù)測評分(對于此用戶)
# 和電影對于數(shù)據(jù)集中所有用戶的總體平均評分之間的差 
candidate_movies['delta'] = candidate_movies['predicted_rating'] - candidate_movies['mean_rating']
candidate_movies.sort_values(by='delta', ascending=False)
title year mean_rating n_ratings predicted_rating delta
movieId
366 Naked Gun 33 1/3: The Final Insult 1994 2.954226 13534.0 3.816926 0.862699
3776 The Naked Gun 2 1/2: The Smell of Fear 1991 3.132616 4415.0 3.946124 0.813508
3775 The Naked Gun: From the Files of Police Squad! 1988 3.580381 6973.0 4.236419 0.656037
5347 Lilo & Stitch 2002 3.489323 4402.0 3.971318 0.481995
10138 The Sisterhood of the Traveling Pants 2005 3.369987 773.0 2.041227 -1.328760

看起來很合理! 對于《白頭神探》系列中的每部電影笆豁,我們對此用戶的預(yù)測評分郎汪,大約比數(shù)據(jù)集中平均評分高一星,而我們的“out of left field”使它們的預(yù)測評分低于平均值闯狱。

你的回合

前往練習筆記本煞赢,進行嵌入層的實踐練習。

二哄孤、用于推薦問題的矩陣分解

在上一課中照筑,我們訓練了一個模型來預(yù)測在 MovieLens 數(shù)據(jù)集中,用戶給電影的評分瘦陈。 提醒一下朦肘,模型看起來像這樣:

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-1.png

我們?yōu)殡娪昂陀脩舨檎仪度胂蛄浚瑢⑺鼈冞B接在一起双饥。 然后我們添加一些隱層媒抠。 最后,這些在一個輸出節(jié)點匯集在一起來預(yù)測評分咏花。

在本節(jié)課中趴生,我將展示一個更簡單的架構(gòu)阀趴,來解決同樣的問題:矩陣分解。 更簡單可以是一件非常好的事情苍匆! 有時刘急,簡單的模型會快速收斂到適當?shù)慕鉀Q方案,一個更復(fù)雜的模型可能會過擬合或無法收斂浸踩。

這是我們的矩陣分解模型的樣子:

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-3.png

點積

讓我們回顧一下數(shù)學叔汁。 如果你是線性代數(shù)專家,請?zhí)^本節(jié)检碗。

兩個長度為n的向量ab的點積定義為:

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-4.png

結(jié)果是單個標量(不是向量)据块。

點積僅為相同長度的矢量而定義。 這意味著我們需要為電影嵌入和用戶嵌入使用相同的大小折剃。

例如另假,假設(shè)我們已經(jīng)訓練了大小為 4 的嵌入,并且電影 Twister 由向量表示:

m_Twister=[ 1.0 ?0.5 0.3 ?0.1 ]

用戶 Stanley 表示為:

u_Stanley=[ ?0.2 1.5 ?0.1 0.9 ]

我們認為 Stanley 會給 Twister 什么評分怕犁? 我們可以將模型的輸出計算為:

m_Twister · u_Stanley 
= (1.0·?0.2)+(?0.5·1.5)+(0.3·?0.1)+(?0.1·0.9)
= ?1.07

因為我們正在在評分列的中心版本上訓練边篮,所以我們的模型輸出的比例為 0 等于訓練集中的總體平均評分(約 3.5)。 因此我們預(yù)測 Stanley 將給 Twister 3.5+(?1.07)=2.43星奏甫。

為什么

有一個直觀的解釋戈轿,支持了以這種方式組合我們的嵌入向量的決定。 假設(shè)我們的電影嵌入空間的維度對應(yīng)于以下變化的軸:

維度 1:多么令人激動阵子?
維度 2:多么浪漫思杯?
維度 3:目標受眾有多成熟?
維度 4:多么好笑款筑?

因此,Twister 是一部令人激動的災(zāi)難電影腾么,m1的正值為 1.0奈梳。

簡單來說,u1告訴我們“這個用戶對動作片的看法如何解虱?”攘须。 他們喜歡它嗎?討厭它殴泰?還是不喜歡也不討厭于宙?

Stanley 的向量告訴,我們他是浪漫和喜劇的忠實粉絲悍汛,并且略微不喜歡動作和成熟的內(nèi)容捞魁。 如果我們給他一部類似于最后一部的電影,除了它有很多浪漫元素离咐,會怎么樣谱俭?

m_Titanic=[ 1.0 1.1 0.3 ?0.1 ]

不難預(yù)測這會如何影響我們的評分輸出奉件。 我們給 Stanley 更多他喜歡的東西,所以他的預(yù)測評分會增加昆著。

predicted_rating(Stanley,Titanic)
= m_Titanic·u_Stanley+3.5
=(1.0·?0.2)+(1.1·1.5)+(0.3·?0.1)+(?0.1·0.9)+3.5
=4.83 stars

注:在實踐中县貌,我們的電影嵌入的維度的含義不會那么明確,但我們的電影嵌入空間和用戶嵌入空間的含義從根本上聯(lián)系在一起凑懂,這仍然是正確的:ui總是代表“這個用戶多么喜歡某個電影煤痕,其質(zhì)量由mi代表?“ (希望這也提供了一些直覺接谨,為什么電影嵌入空間和用戶嵌入空間在這個技巧中必須大小相同摆碉。)

實現(xiàn)它

創(chuàng)建此模型的代碼,類似于我們在上一課中編寫的代碼疤坝,除了我使用點積層來組合用戶和電影嵌入層的輸出(而不是連接它們兆解,并輸入到密集層)。

movie_embedding_size = user_embedding_size = 8

# 每個實例由兩個輸入組成:單個用戶 ID 和單個電影 ID
user_id_input = keras.Input(shape=(1,), name='user_id')
movie_id_input = keras.Input(shape=(1,), name='movie_id')
user_embedded = keras.layers.Embedding(df.userId.max()+1, user_embedding_size, 
                                       input_length=1, name='user_embedding')(user_id_input)
movie_embedded = keras.layers.Embedding(df.movieId.max()+1, movie_embedding_size, 
                                        input_length=1, name='movie_embedding')(movie_id_input)

dotted = keras.layers.Dot(2)([user_embedded, movie_embedded])
out = keras.layers.Flatten()(dotted)

model = keras.Model(
    inputs = [user_id_input, movie_id_input],
    outputs = out,
)
model.compile(
    tf.train.AdamOptimizer(0.001),
    loss='MSE',
    metrics=['MAE'],
)
model.summary(line_length=88)
'''
________________________________________________________________________________________
Layer (type)                 Output Shape       Param #   Connected to                  
========================================================================================
user_id (InputLayer)         (None, 1)          0                                       
________________________________________________________________________________________
movie_id (InputLayer)        (None, 1)          0                                       
________________________________________________________________________________________
user_embedding (Embedding)   (None, 1, 8)       1107952   user_id[0][0]                 
________________________________________________________________________________________
movie_embedding (Embedding)  (None, 1, 8)       213952    movie_id[0][0]                
________________________________________________________________________________________
dot (Dot)                    (None, 1, 1)       0         user_embedding[0][0]          
                                                          movie_embedding[0][0]         
________________________________________________________________________________________
flatten (Flatten)            (None, 1)          0         dot[0][0]                     
========================================================================================
Total params: 1,321,904
Trainable params: 1,321,904
Non-trainable params: 0
________________________________________________________________________________________
'''

讓我們訓練它跑揉。

history = model.fit(
    [df.userId, df.movieId],
    df.y,
    batch_size=5000,
    epochs=20,
    verbose=0,
    validation_split=.05,
);

讓我們將這個模型隨時間的誤差锅睛,與我們在上一課中訓練的深度神經(jīng)網(wǎng)絡(luò)進行比較:

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-5.png

我們新的,更簡單的模型(藍色)看起來非常好历谍。

然而现拒,即使我們的嵌入相當小,兩種模型都會產(chǎn)生一些明顯的過擬合望侈。 也就是說印蔬,訓練集上的誤差 - 實線 - 明顯好于看不見的數(shù)據(jù)。 我們將在練習中盡快解決這個問題脱衙。

你的回合

前往練習筆記本侥猬,進行矩陣分解的實踐練習。

三捐韩、使用 Gensim 探索嵌入

早些時候退唠,我們訓練了一個模型,使用一個網(wǎng)絡(luò)荤胁,它帶有為每個電影和用戶學習的嵌入瞧预,來預(yù)測用戶為電影提供的評分。 嵌入是強大的仅政!但他們實際如何工作垢油?

以前,我說嵌入捕獲了它們所代表的對象的“含義”圆丹,并發(fā)現(xiàn)了有用的潛在結(jié)構(gòu)滩愁。 讓我們來測試吧!

查詢嵌入

讓我們加載我們之前訓練過的模型辫封,這樣我們就可以研究它學到的嵌入權(quán)重惊楼。

import os

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import tensorflow as tf
from tensorflow import keras

input_dir = '../input/movielens-preprocessing'
model_dir = '../input/movielens-spiffy-model'
model_path = os.path.join(model_dir, 'movie_svd_model_32.h5')
model = keras.models.load_model(model_path)

嵌入權(quán)重是模型內(nèi)部的一部分玖瘸,因此我們必須進行一些挖掘才能訪問它們。 我們將獲取負責嵌入電影的層檀咙,并使用get_weights()方法獲取其學習的權(quán)重雅倒。

emb_layer = model.get_layer('movie_embedding')
(w,) = emb_layer.get_weights()
w.shape
# (26744, 32)

對于那么多電影,我們的權(quán)重矩陣有 26,744 行弧可。 每行是 32 個數(shù)字 - 我們的電影嵌入的大小蔑匣。

我們來看一個示例電影向量:

w[0]
'''
array([-0.08716497, -0.25286013, -0.52679837, -0.2602235 , -0.4349191 ,
       -0.48805636, -0.30346015, -0.1416321 ,  0.08305884, -0.17578898,
       -0.36220485,  0.14578693,  0.37118354, -0.02961254, -0.063666  ,
       -0.5223456 ,  0.0526049 ,  0.47991064, -0.19034313, -0.3271599 ,
        0.32792446, -0.3794548 , -0.55778086, -0.42602876,  0.14532137,
        0.21002969, -0.32203963, -0.46950188, -0.22500233, -0.08298543,
       -0.00373308, -0.3885791 ], dtype=float32)
'''

這是什么電影的嵌入? 讓我們加載我們的電影元數(shù)據(jù)的數(shù)據(jù)幀棕诵。

movies_path = os.path.join(input_dir, 'movie.csv')
movies_df = pd.read_csv(movies_path, index_col=0)
movies_df.head()
movieId title genres key year n_ratings mean_rating
0 0 Toy Story Adventure Animation Children Comedy Fantasy Toy Story 1995 49695 3.921240
1 1 Jumanji Adventure Children Fantasy Jumanji 1995 22243 3.211977
2 2 Grumpier Old Men Comedy Romance Grumpier Old Men 1995 12735 3.151040
3 3 Waiting to Exhale Comedy Drama Romance Waiting to Exhale 1995 2756 2.861393
4 4 Father of the Bride Part II Comedy Father of the Bride Part II 1995 12161 3.064592

當然裁良,這是《玩具總動員》! 我應(yīng)該在任何地方認出這個向量校套。

好吧价脾,我很滑稽。此時很難利用這些向量笛匙。 我們從未告訴模型如何使用任何特定嵌入維度侨把。 我們只讓它學習它認為有用的任何表示。

那么我們?nèi)绾螜z查這些表示是否合理且連貫妹孙?

向量相似度

測試它的一種簡單方法是秋柄,查看嵌入空間中電影對有多么接近或遠離。 嵌入可以被認為是智能的距離度量蠢正。 如果我們的嵌入矩陣是良好的骇笔,它應(yīng)該將類似的電影(如《玩具總動員》和《怪物史萊克》)映射到類似的向量。

i_toy_story = 0
i_shrek = movies_df.loc[
    movies_df.title == 'Shrek',
    'movieId'
].iloc[0]

toy_story_vec = w[i_toy_story]
shrek_vec = w[i_shrek]

print(
    toy_story_vec,
    shrek_vec,
    sep='\n',
)
'''
[-0.08716497 -0.25286013 -0.52679837 -0.2602235  -0.4349191  -0.48805636
 -0.30346015 -0.1416321   0.08305884 -0.17578898 -0.36220485  0.14578693
  0.37118354 -0.02961254 -0.063666   -0.5223456   0.0526049   0.47991064
 -0.19034313 -0.3271599   0.32792446 -0.3794548  -0.55778086 -0.42602876
  0.14532137  0.21002969 -0.32203963 -0.46950188 -0.22500233 -0.08298543
 -0.00373308 -0.3885791 ]
[ 0.0570179   0.5991162  -0.71662885  0.22245468 -0.40536046 -0.33602375
 -0.24281627  0.08997302  0.03362623 -0.12569055 -0.2764452  -0.12710975
  0.48197436  0.2724923   0.01551001 -0.20889504 -0.04863157  0.39106563
 -0.24811408 -0.05642252  0.24475795 -0.53363544 -0.2281187  -0.17529544
  0.21050802 -0.37807122  0.03861505 -0.27024794 -0.24332719 -0.17732081
  0.07961234 -0.39079434]
'''

逐個維度地比較嚣崭,這些看起來大致相似笨触。 如果我們想為它們的相似度分配一個數(shù)字,我們可以計算這兩個向量之間的歐氏距離雹舀。 (這是我們傳統(tǒng)的“烏鴉飛過的”兩點之間的距離的概念芦劣。容易在 1,2 或 3 維上進行研究。在數(shù)學上葱跋,我們也可以將它擴展到 32 維持寄,雖然需要好運來可視化它源梭。)

from scipy.spatial import distance

distance.euclidean(toy_story_vec, shrek_vec)
# 1.4916094541549683

這與我們認為非常不同的一對電影相比如何娱俺?

i_exorcist = movies_df.loc[
    movies_df.title == 'The Exorcist',
    'movieId'
].iloc[0]

exorcist_vec = w[i_exorcist]

distance.euclidean(toy_story_vec, exorcist_vec)
# 2.356588363647461

更遠了,和我們期待的一樣废麻。

余弦距離

如果你看看scipy.spatial模塊的文檔荠卷,你會發(fā)現(xiàn)人們用于不同任務(wù)的距離,實際上有很多不同的衡量標準烛愧。

在判斷嵌入的相似性時油宜,使用余弦相似性更為常見掂碱。

簡而言之,兩個向量的余弦相似度范圍從 -1 到 1慎冤,并且是向量之間的角度的函數(shù)疼燥。 如果兩個向量指向同一方向,則它們的余弦相似度為 1蚁堤。如果它們指向相反的方向醉者,它為 -1。 如果它們是正交的(即成直角)披诗,則它們的余弦相似度為 0撬即。

余弦距離定義為 1 減去余弦相似度(因此范圍從 0 到 2)。

讓我們計算電影向量之間的幾個余弦距離:

print(
    distance.cosine(toy_story_vec, shrek_vec),
    distance.cosine(toy_story_vec, exorcist_vec),
    sep='\n'
)
'''
0.3593705892562866
0.811933159828186
'''

注:為什么在使用嵌入時常用余弦距離呈队? 與許多深度學習技巧一樣剥槐,簡短的答案是“憑經(jīng)驗,它能用”宪摧。 在即將進行的練習中粒竖,你將進行一些實踐調(diào)查,更深入地探討這個問題绍刮。

哪部電影與《玩具總動員》最相似温圆? 在嵌入空間中哪些電影落在 Psycho 和 Scream 之間? 我們可以編寫一堆代碼來解決這樣的問題孩革,但這樣做非常繁瑣岁歉。 幸運的是,已經(jīng)有一個庫可以完成這類工作:Gensim膝蜈。

使用 Gensim 探索嵌入

我將使用我們的模型的電影嵌入和相應(yīng)電影的標題锅移,來實例化WordEmbeddingsKeyedVectors

注:你可能會注意到饱搏,Gensim 的文檔及其許多類和方法名稱都指的是詞嵌入非剃。 雖然庫最常用于文本領(lǐng)域,但我們可以使用它來探索任何類型的嵌入推沸。

from gensim.models.keyedvectors import WordEmbeddingsKeyedVectors

# 將數(shù)據(jù)集中的電影限制為至少具有這么多評分
threshold = 100
mainstream_movies = movies_df[movies_df.n_ratings >= threshold].reset_index(drop=True)

movie_embedding_size = w.shape[1]
kv = WordEmbeddingsKeyedVectors(movie_embedding_size)
kv.add(
    mainstream_movies['key'].values,
    w[mainstream_movies.movieId]
)

好的备绽,哪個電影與《玩具總動員》最相似?

kv.most_similar('Toy Story')
'''
/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
  if np.issubdtype(vec.dtype, np.int):
[('Toy Story 2', 0.9583659172058105),
 ('Toy Story 3', 0.9159570932388306),
 ('Finding Nemo', 0.882755696773529),
 ('Monsters, Inc.', 0.8684015870094299),
 ("A Bug's Life", 0.8322919607162476),
 ('The Incredibles', 0.8271597623825073),
 ('Ratatouille', 0.8149864673614502),
 ('Up', 0.802034318447113),
 ('WALL·E', 0.7794805765151978),
 ('The Iron Giant', 0.7664535641670227)]
'''

哇鬓催,這些都很棒肺素! 《玩具總動員 2》是與玩具總動員最相似的電影,這是完全合理的宇驾。 其余大多數(shù)都是具有類似計算機動畫風格的動畫兒童電影倍靡。

所以它學到了關(guān)于三維動畫兒童電影的一些東西,但也許這只是一個僥幸课舍。 讓我們來看看幾個不同類型的電影的最近鄰居:

/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
  if np.issubdtype(vec.dtype, np.int):

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-6.png

小眾的性愛劇塌西,風騷的半吊子喜劇他挎,老派音樂劇,超級英雄電影......我們的嵌入能夠支持各種各樣的電影類型捡需!

語義向量數(shù)學

most_similar方法接受可選的第二個參數(shù)negative办桨。 如果我們調(diào)用kv.most_similar(a, b),那么它將找到最接近a-b的向量站辉,而不是找到最接近a的向量崔挖。

你為什么想這么做? 事實證明庵寞,對嵌入向量進行加法和減法通常會產(chǎn)生令人驚訝的有意義的結(jié)果狸相。 例如,你將如何填寫以下等式捐川?

Scream = Psycho + ________

Scream 和 Psycho 的相似之處在于它們是恐怖片和驚悚片之間的某個地方的暴力恐怖電影脓鹃。 最大的區(qū)別是 Scream 有喜劇元素。 因此古沥,如果你將 Psycho 與喜劇結(jié)合起來瘸右,我會說 Scream 就是你所得到的。

但我們實際上可以通過向量數(shù)學(在重新排列之后)讓 Gensim 為我們填補空白:

________ = Scream - Psycho
kv.most_similar(
    positive = ['Scream'],
    negative = ['Psycho (1960)']
)
'''
/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
  if np.issubdtype(vec.dtype, np.int):
[('Scream 3', 0.6535503268241882),
 ('Scream 2', 0.6417772769927979),
 ('Piranha (Piranha 3D)', 0.6411199569702148),
 ('Freddy vs. Jason', 0.6275623440742493),
 ('Final Destination 5', 0.6264907121658325),
 ('Booty Call', 0.6207411289215088),
 ("Charlie's Angels", 0.6146069765090942),
 ('Mortal Kombat', 0.6145076155662537),
 ('Deuce Bigalow: Male Gigolo', 0.6140967607498169),
 ('Final Destination 2', 0.612423300743103)]
'''

如果你熟悉這些電影岩齿,你會發(fā)現(xiàn)太颤,從 Psycho 到 Scream 的缺失成分是喜劇(也是 90 年代后期的青少年電影)盹沈。

類比解決

用于進入美國大學和學院的 SAT 考試提出了類似的問題:

shower : deluge :: _____ : stare

(意思是“shower”(淋粤湔隆)對于“deluge”(洪水),相當于“_____”對于“stare”(凝視))

為了解決這個問題乞封,我們找到了“deluge”和“shower”之間的關(guān)系做裙,并將其應(yīng)用于“stare”。 “shower”是一種溫和的“deluge”形式肃晚。 什么是溫和的“stare”的形式锚贱? 這里一個好的答案是“glance”(一瞥)或“l(fā)ook”(看)。

令人驚訝的是关串,這種方法很有效拧廊,但人們發(fā)現(xiàn)這些通常可以通過單詞嵌入的簡單向量數(shù)學來有效地解決晋修。 我們可以通過嵌入來解決電影類比問題嗎吧碾? 我們試試吧。這樣如何:

Brave : Cars 2 :: Pocahontas : _____

答案不明確飞蚓。 一種解釋是滤港,《勇敢傳說》(Brave)就像《賽車總動員 2》(Cars 2)廊蜒,除了后者主要針對男孩趴拧,而前者可能對女孩更具吸引力溅漾,因為它是女性主角。 所以也許答案應(yīng)該像《風中奇緣》(Pocahontas)一樣著榴,90 年代中期的傳統(tǒng)動畫兒童電影添履,但更像是一部“男孩電影”∧杂郑《大力士》暮胧?《獅子王》?

讓我們問一下他們的想法问麸。

在向量數(shù)學方面往衷,我們可以將其構(gòu)建為......

Cars 2 = Brave + X
_____  = Pocahontas + X

重新排列之后,我們得到:

____ = Pocahontas + (Cars 2 - Brave)

我們可以通過將兩部電影(《風中奇緣》和《賽車總動員 2》)傳遞給most_similarpositive严卖,將《勇敢傳說》作為negative參數(shù)席舍,來解決這個問題:

kv.most_similar(
    ['Pocahontas', 'Cars 2'],
    negative = ['Brave']
)
'''
/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
  if np.issubdtype(vec.dtype, np.int):
[("A Kid in King Arthur's Court", 0.8660464882850647),
 ('Land Before Time III: The Time of the Great Giving', 0.8655920624732971),
 ('Free Willy 2: The Adventure Home', 0.8606677651405334),
 ('3 Ninjas Knuckle Up', 0.8496973514556885),
 ('3 Ninjas Kick Back', 0.8479241132736206),
 ('The Return of Jafar', 0.8474882245063782),
 ("Beethoven's 2nd", 0.8443870544433594),
 ('Air Bud: Golden Receiver', 0.84358811378479),
 ('Meet the Deedles', 0.8370730876922607),
 ('All Dogs Go to Heaven 2', 0.8368842601776123)]
'''

這與我們的預(yù)測無關(guān):4 部最接近的電影確實是 90 年代的兒童動畫電影。 在那之后哮笆,結(jié)果有點令人困惑来颤。

我們的模型是錯的,還是我們是錯的稠肘? 在《賽車總動員 2》和《勇敢傳說》之間福铅,我們未能解釋的另一個區(qū)別是前者是續(xù)集,而后者則不是项阴。 我們的結(jié)果中有 7/10 也是續(xù)集滑黔。 這告訴我們關(guān)于我們學習的嵌入的一些有趣內(nèi)容(最終,關(guān)于預(yù)測電影偏好的問題)环揽。 “Sequelness”是我們模型的一個重要特性 - 這表明我們數(shù)據(jù)中的一些變化拷沸,是因為有些人傾向于比其他人更喜歡續(xù)集。

你的回合

前往練習筆記本薯演,進行一些動手實踐撞芍,使用 gensim 探索嵌入。

四跨扮、將 t-SNE 用于可視化

在上一課中序无,我們查看了我們學習的電影嵌入的一些示例,測量了電影對之間的距離衡创,查找了與某些電影最相似的電影帝嗡,并且通過向量數(shù)學組合了電影語義。 這些是調(diào)試嵌入模型或理解嵌入模型的好方法璃氢。 但它也非常耗時哟玷。

在本課程中,你將學習如何使用 t-SNE 算法可視化嵌入。 這是一種很好的廉價技術(shù)巢寡,用于理解嵌入的本質(zhì)喉脖。

t-SNE

可視化 1 維或 2 維的數(shù)據(jù)很容易 - 但目前尚不清楚如何可視化 8 維或 32 維的嵌入。 t-SNE 是一種降維算法抑月,通常用于可視化树叽。 它學習從一組高維向量到較小維數(shù)(通常為 2)的空間映射,這有望很好地表示高維空間谦絮。

是什么讓映射成為“良好的表示”题诵? 簡而言之,t-SNE 試圖確保如果高維向量uv靠近在一起层皱,則map(u)map(v)在 2d 映射空間中靠近在一起性锭。

代碼

首先,我們將加載我們的預(yù)訓練嵌入叫胖,就像之前一樣篷店。

%matplotlib inline
import random
import os

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import tensorflow as tf
from tensorflow import keras

input_dir = '../input/movielens-preprocessing'
model_dir = '../input/movielens-spiffy-model'
model_path = os.path.join(model_dir, 'movie_svd_model_32.h5')

model = keras.models.load_model(model_path)
emb_layer = model.get_layer('movie_embedding')
(w,) = emb_layer.get_weights()

movies_path = os.path.join(input_dir, 'movie.csv')
movies_df = pd.read_csv(movies_path, index_col=0)

正如我們在前面的課程中看到的那樣,我們的數(shù)據(jù)集中有很多不起眼的電影臭家,評分很少(有時只有一個)疲陕。 我們對這些電影知之甚少,因為它們的嵌入效果和隨機一樣钉赁。 我們可以通過僅僅選擇滿足一定流行度閾值的電影蹄殃,來弄清楚我們的可視化。

threshold = 100
mainstream_movies = movies_df[movies_df.n_ratings >= threshold].reset_index(drop=True)
print("Went from {} to {} movies after applying threshold".format(
    len(movies_df), len(mainstream_movies),
))
w_full = w
w = w[mainstream_movies.movieId]
df = mainstream_movies
# 在應(yīng)用閾值后你踩,電影從 26744 變?yōu)?8546 部

我們將使用 scikit-learn 的 t-SNE 實現(xiàn)诅岩。

我提到 t-SNE 在特征空間中試圖保持實體之間的“接近度”。 我們在之前的課程中看到带膜,有許多競爭性的距離概念吩谦。 默認情況下,t-SNE 使用歐氏距離膝藕。 但是因為已知余弦距離適用于嵌入式廷,我們將在創(chuàng)建模型時傳遞metric ="cosine"

from sklearn.manifold import TSNE

# 1,000 次迭代的默認值可以得到很好的結(jié)果芭挽,
# 但是我的訓練時間更長滑废,只是為了一些微小的改進。 
# 注意:這需要近一個小時袜爪!
tsne = TSNE(random_state=1, n_iter=15000, metric="cosine")

embs = tsne.fit_transform(w)
# 為方便起見蠕趁,添加到數(shù)據(jù)幀
df['x'] = embs[:, 0]
df['y'] = embs[:, 1]

這是我們將電影映射到的二維向量樣本:

embs[:5]
'''
array([[ -93.78184  ,   74.296936 ],
       [ -78.09159  , -107.294334 ],
       [  27.506392 ,  -73.33844  ],
       [  -7.8512335,  -82.217896 ],
       [ -10.345706 ,  -71.288704 ]], dtype=float32)
'''

這種降維的全部意義在于可視化,所以讓我們使用 matplotlib 繪制我們電影的散點圖辛馆,使用我們新的二維映射俺陋。

FS = (10, 8)
fig, ax = plt.subplots(figsize=FS)
# 使點變得半透明,以便我們可以直觀地識別具有高密度重疊點的區(qū)域
ax.scatter(df.x, df.y, alpha=.1);

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-7.png

它有效嘛

單憑形狀很難判斷。 良好的理智檢查是識別腊状,我們強烈認為應(yīng)該靠近的一些電影分組诱咏,看看它們是否在二維空間中接近。

例如寿酌,所有的哈利波特電影都應(yīng)該互相接近,對吧硕蛹?

# 這個和其他幾個輔助函數(shù)在上面的代碼單元中定義醇疼。
# 如果你對它們的實現(xiàn)方式感到好奇,請點擊上面的“代碼”按鈕法焰。
plot_by_title_pattern('Harry Potter', figsize=(15, 9), bg_alpha=.05, text=False);

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-8.png

上面的繪圖中秧荆,8 個哈利波特電影中的每一個都有一個綠點 - 但它們是如此接近,它們無法在這個刻度上區(qū)分埃仪。 是個好的標志乙濒!

讓我們放大一下,仔細看看卵蛉。

plot_region_around('Harry Potter and the Order of the Phoenix', 4);

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-9.png

哈利波特的電影不僅緊密聚集在一起颁股,而且大致按發(fā)布順序排列!

局部和全局結(jié)構(gòu)

t-SNE 的一個關(guān)鍵特性使它非常適合可視化傻丝,它擅長在多個尺度上捕獲簇甘有。 我們已經(jīng)看到,我們的映射成功捕獲了小而緊湊的局部結(jié)構(gòu)葡缰。 那些包含更多松散的相關(guān)電影的大型結(jié)構(gòu)呢亏掀?

我們在上面已經(jīng)看到了這方面的一個小例子:與哈利波特電影最接近的鄰居是饑餓游戲系列的電影 - 另一組基于一系列青年幻想小說的電影。這說得通泛释!

小眾流派如何滤愕? 紀錄片落在哪里?

docs = df[ (df.genres == 'Documentary') ]
plot_with_annotations(docs.index, text=False, alpha=.4, figsize=(15, 8));

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-10.png

太好了怜校! 它不是一個緊密的簇间影,但這里肯定有較強的規(guī)律。

并且重申一下:我們從未真正將類型展示給模型作為特征茄茁。 它無法讀取標題宇智,并看到《哈利波特和魔法石》和《哈利波特和密室》屬于同一系列。 它設(shè)法獲取這些潛在的模式并將它們合并到嵌入空間中胰丁,只需看到數(shù)據(jù)點随橘,例如“用戶 5299 給電影 806 評分為 4.5”。 非常好锦庸!

這是另一個稍微復(fù)雜的類型實驗:可視化所有電影机蔗,其類型是{喜劇,戲劇,浪漫}的一部分(即喜劇萝嘁,戲劇梆掸,浪漫,戲劇牙言,浪漫劇酸钦,romcoms 和......我猜是“dromcoms”?)

https://github.com/apachecn/kaggle/blob/dev/learn/img/emb-11.png

這是最大規(guī)模的結(jié)構(gòu)的一個很棒的例子咱枉。 戲劇主要在上半部分卑硫,而喜劇主要在另一半(浪漫片的分布更加分散)。

你的回合

前往練習筆記本進行一些實踐練習,使用 t-SNE 可視化嵌入。

擴展閱讀

我們使用 t-SNE 模型的開箱即用的默認參數(shù)取得了良好的效果幽污,但根據(jù)你的數(shù)據(jù)特征诉探,你可能不會那么幸運。

t-SNE 不是簡單的閉式數(shù)學運算。 你正在訓練模型,使用隨機梯度下降來最小化一些非凸損失函數(shù)。 可能需要一段時間障陶,需要一點折騰。 你甚至可以在使用相同參數(shù)訓練的兩個 t-SNE 模型之間看到非常不同的結(jié)果(如果你想要可重復(fù)性聊训,則設(shè)置固定的random_state)咸这。

如果你在嘗試訓練 t-SNE 模型時得到的結(jié)果不令人滿意,或者你只是想了解更多數(shù)學基礎(chǔ)和實現(xiàn)魔眨,那么下面的鏈接會提供一些你可能會覺得有用的信息媳维。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末墓毒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子亲怠,更是在濱河造成了極大的恐慌所计,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件团秽,死亡現(xiàn)場離奇詭異主胧,居然都是意外死亡叭首,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門踪栋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焙格,“玉大人,你說我怎么就攤上這事夷都【彀Γ” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵囤官,是天一觀的道長冬阳。 經(jīng)常有香客問我,道長治拿,這世上最難降的妖魔是什么摩泪? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任笆焰,我火速辦了婚禮劫谅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嚷掠。我一直安慰自己捏检,他們只是感情好,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布不皆。 她就那樣靜靜地躺著贯城,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霹娄。 梳的紋絲不亂的頭發(fā)上能犯,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音犬耻,去河邊找鬼踩晶。 笑死,一個胖子當著我的面吹牛枕磁,可吹牛的內(nèi)容都是我干的渡蜻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼计济,長吁一口氣:“原來是場噩夢啊……” “哼茸苇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沦寂,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤学密,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后传藏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體则果,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡幔翰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了西壮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遗增。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖款青,靈堂內(nèi)的尸體忽然破棺而出做修,到底是詐尸還是另有隱情,我是刑警寧澤抡草,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布饰及,位于F島的核電站,受9級特大地震影響康震,放射性物質(zhì)發(fā)生泄漏燎含。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一腿短、第九天 我趴在偏房一處隱蔽的房頂上張望屏箍。 院中可真熱鬧,春花似錦橘忱、人聲如沸赴魁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颖御。三九已至,卻和暖如春凝颇,著一層夾襖步出監(jiān)牢的瞬間潘拱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工拧略, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芦岂,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓辑鲤,卻偏偏與公主長得像盔腔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子月褥,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容