2
本文作者: Raey Raey Li | 2017-05-12 18:29 |
幾乎所有人都喜歡與家人、朋友一起觀看電影度過(guò)閑暇時(shí)光。大家可能都有過(guò)這樣的體驗(yàn):本想在接下來(lái)的兩個(gè)小時(shí)里看一個(gè)電影,卻坐在沙發(fā)上坐了20分鐘不知道看什么,選擇困難癥又犯了,結(jié)果好心情也變得沮喪。所以,我們很需要一個(gè)電腦代理,在做挑選電影的時(shí)候提供推薦。
現(xiàn)在,電影智能推薦系統(tǒng)已經(jīng)成為日常生活中的一部分。
Data Science Central 曾表示:
“雖然硬數(shù)據(jù)很難獲得,但知情人士估計(jì),對(duì)亞馬遜和Netflix這樣的大型電商平臺(tái),推薦系統(tǒng)為它們帶來(lái)高達(dá)10%至25%的收入增長(zhǎng)”。
在這個(gè)項(xiàng)目中,我研究了一些針對(duì)電影推薦的基本算法,并嘗試將深度學(xué)習(xí)融入到電影推薦系統(tǒng)中。
把娛樂(lè)與視覺(jué)藝術(shù)相結(jié)合,電影是一個(gè)很好的例子。電影海報(bào)可以直接、快速地把電影信息傳達(dá)給觀眾。Design Mantic表示:“不論上映前后,電影海報(bào)都是創(chuàng)造噱頭的主要因素。多半的人(目標(biāo)觀眾)都根據(jù)海報(bào)來(lái)決定買不買票,看不看電影。”我們甚至可以僅僅根據(jù)海報(bào)字體,來(lái)推測(cè)這個(gè)電影的情緒。
這聽(tīng)起來(lái)有點(diǎn)像魔術(shù)——但看一眼海報(bào)就預(yù)測(cè)出電影的類型,的確是可能的。就拿我來(lái)說(shuō),瞟一眼海報(bào)就知道我想不想看這個(gè)電影了。舉個(gè)例子,我不是卡通迷,一看到有卡通主題海報(bào),就知道不是我的菜。這個(gè)決策的過(guò)程很直接,并不需要閱讀電影評(píng)論(不確定誰(shuí)真的有時(shí)間讀那些評(píng)論)。因此,除了標(biāo)準(zhǔn)的電影推薦算法,我還用了深度學(xué)習(xí)來(lái)處理海報(bào),并將相似的電影推薦給用戶。最終目標(biāo)是模仿人類視覺(jué),并僅僅通過(guò)觀察海報(bào),就能用深度學(xué)習(xí)創(chuàng)建一個(gè)直觀的電影推薦系統(tǒng)。該項(xiàng)目是受到Ethan Rosenthal博客啟發(fā)。我對(duì)他博客里的代碼進(jìn)行了修改,以適應(yīng)這個(gè)項(xiàng)目的算法。
我們用的是從 MovieLens 下載的電影數(shù)據(jù)集。他包含9066個(gè)電影和671名用戶,分成了100000個(gè)打分和1300個(gè)標(biāo)簽。這個(gè)數(shù)據(jù)集最后更新于10/2016.
粗略地說(shuō),有三種類型的推薦系統(tǒng)(不包括簡(jiǎn)單的評(píng)級(jí)方法)
基于內(nèi)容的推薦
協(xié)同過(guò)濾
混合模型
“基于內(nèi)容的推薦”是一個(gè)回歸問(wèn)題,我們把電影內(nèi)容作為特征,對(duì)用戶對(duì)電影的評(píng)分做預(yù)測(cè)。
而在“協(xié)同過(guò)濾”推薦系統(tǒng)中,一般無(wú)法提前獲得內(nèi)容特征。是通過(guò)用戶之間的相似度(用戶們給了用一個(gè)電影相同的評(píng)級(jí))和電影之間的相似度(有相似用戶評(píng)級(jí)的電影),來(lái)學(xué)習(xí)潛在特征,同時(shí)預(yù)測(cè)用戶對(duì)電影的評(píng)分。此外,學(xué)習(xí)了電影的特征之后,我們便可以衡量電影之間的相似度,并根據(jù)用戶歷史觀影信息,向他/她推薦最相似的電影。
“基于內(nèi)容的推薦”和“協(xié)同過(guò)濾”是10多年前最先進(jìn)的技術(shù)。很顯然,現(xiàn)在有很多模型和算法可以提高預(yù)測(cè)效果。比如,針對(duì)事先缺乏用戶電影評(píng)分信息的情況,可以使用隱式矩陣分解,用偏好和置信度取代用戶電影打分——比如用戶對(duì)電影推薦有多少次點(diǎn)擊,以此進(jìn)行協(xié)同過(guò)濾。另外,我們還可以將“內(nèi)容推薦”與“協(xié)同過(guò)濾”的方法結(jié)合起來(lái),將內(nèi)容作為側(cè)面信息來(lái)提高預(yù)測(cè)精度。這種混合方法,可以用“學(xué)習(xí)進(jìn)行排序”("Learning to Rank" )算法來(lái)實(shí)現(xiàn)。
該項(xiàng)目中,我會(huì)聚焦于“協(xié)同過(guò)濾”方法。首先,我將討論如何不使用回歸,而是電影(用戶)相似度來(lái)預(yù)測(cè)評(píng)分,并基于相似度做電影推薦。然后,我將討論如何使用回歸同時(shí)學(xué)習(xí)潛在特征、做電影推薦。最后會(huì)談?wù)?strong>如何在推薦系統(tǒng)中使用深度學(xué)習(xí)。
對(duì)于基于協(xié)作過(guò)濾的推薦系統(tǒng),首先要建立評(píng)分矩陣。其中,每一行表示一個(gè)用戶,每一列對(duì)應(yīng)其對(duì)某一電影的打分。建立的評(píng)分矩陣如下:
df = pd.read_csv('ratings.csv', sep=',')
df_id = pd.read_csv('links.csv', sep=',')
df = pd.merge(df, df_id, on=['movieId'])
rating_matrix = np.zeros((df.userId.unique().shape[0], max(df.movieId)))
for row in df.itertuples():
rating_matrix[row[1]-1, row[2]-1] = row[3]
rating_matrix = rating_matrix[:,:9000]
這里“ratings.csv”包含用戶id,電影id, 評(píng)級(jí),和時(shí)間信息;"link.csv"包括電影id, IMDB id,和TMDB id。每一個(gè)電影利用 API 從 Movie Databasewebsite 獲得海報(bào),都需要 IMDB id——因此,我們將兩個(gè)表格結(jié)合到一起。我們檢驗(yàn)了評(píng)分矩陣的稀疏性,如下:
sparsity = float(len(ratings.nonzero()[0]))
sparsity /= (ratings.shape[0] * ratings.shape[1])
sparsity *= 100
當(dāng)非零項(xiàng)(entry)只有1.40%的時(shí)候評(píng)級(jí)矩陣是稀疏的?,F(xiàn)在,為了訓(xùn)練和測(cè)試,我們將評(píng)分矩陣分解成兩個(gè)較小的矩陣。我們從評(píng)分矩陣中刪除了10個(gè)評(píng)分,把它們放入測(cè)試集。
train_matrix = rating_matrix.copy()
test_matrix = np.zeros(ratings_matrix.shape)
for i in xrange(rating_matrix.shape[0]):
rating_idx = np.random.choice(
rating_matrix[i, :].nonzero()[0],
size=10,
replace=True)
train_matrix[i, rating_idx] = 0.0
test_matrix[i, rating_idx] = rating_matrix[i, rating_idx]
根據(jù)以下公式計(jì)算用戶/電影中的(余弦Cosine) 相似性
這里s(u,v)是用戶u和v之間的余弦相似度。
similarity_user = train_matrix.dot(train_matrix.T) + 1e-9
norms = np.array([np.sqrt(np.diagonal(similarity_user))])
similarity_user = ( similarity_user / (norms * norms.T) )
similarity_movie = train_matrix.T.dot(train_matrix) + 1e-9
norms = np.array([np.sqrt(np.diagonal(similarity_movie))])
similarity_movie = ( similarity_movie / (norms * norms.T) )
利用用戶之間的相似性,我們能預(yù)測(cè)每個(gè)用戶對(duì)電影的評(píng)級(jí),并計(jì)算出相應(yīng)的MSE。該預(yù)測(cè)基于相似用戶的評(píng)分。特別地,可以根據(jù)以下公式進(jìn)行打分預(yù)測(cè):
用戶u對(duì)電影i的預(yù)測(cè),是用戶v對(duì)電影的評(píng)分的(標(biāo)準(zhǔn)化的)加權(quán)和。權(quán)重為用戶u和v的相似度。
from sklearn.metrics import mean_squared_error
prediction = similarity_user.dot(train_matrix) / np.array([np.abs(similarity_user).sum(axis=1)]).T
prediction = prediction[test_matrix.nonzero()].flatten()
test_vector = test_matrix[test_matrix.nonzero()].flatten()
mse = mean_squared_error(prediction, test_vector)
print 'MSE = ' + str(mse)
預(yù)測(cè)的MSE為9.8252。這個(gè)數(shù)字意味著什么?這個(gè)推薦系統(tǒng)是好是壞??jī)H僅看著MSE結(jié)果來(lái)評(píng)估預(yù)測(cè)效果不是很符合直覺(jué)。因此,我們直接檢查電影推薦來(lái)評(píng)估。我們將搜索一個(gè)感興趣的電影,并讓電腦代理來(lái)推薦幾部電影。首先要得到相應(yīng)的電影海報(bào),這樣就能看到都有什么電影被推薦。我們使用IMDB id,使用它的API從Movie Database 網(wǎng)站獲取海報(bào)。
import requests
import json
from IPython.display import Image
from IPython.display import display
from IPython.display import HTML
idx_to_movie = {}
for row in df_id.itertuples():
idx_to_movie[row[1]-1] = row[2]
idx_to_movie
k = 6
idx = 0
movies = [ idx_to_movie[x] for x in np.argsort(similarity_movie[idx,:])[:-k-1:-1] ]
movies = filter(lambda imdb: len(str(imdb)) == 6, movies)
n_display = 5
URL = [0]*n_display
IMDB = [0]*n_display
i = 0
for movie in movies:
(URL[i], IMDB[i]) = get_poster(movie, base_url)
i += 1
images = ''
for i in range(n_display):
images += "<img style='width: 100px; margin: 0px; \
float: left; border: 1px solid black;' src='%s' />" \
% URL[i]
display(HTML(images))
好玩的來(lái)了!讓我們來(lái)搜索一個(gè)電影并看看四個(gè)最相似的推薦。讓我們?cè)囍阉鳌侗I火線》,在左手邊第一個(gè),后面是四部推薦的電影。
《盜火線》是1995年上映的一部美國(guó)犯罪電影,由羅伯特·德·尼羅、阿爾·帕西諾主演。搜索結(jié)果看起來(lái)不錯(cuò)。但《離開(kāi)拉斯維加斯》可能不是一個(gè)好的建議,我猜原因是因?yàn)殡娪啊队玛J奪命島》里有尼古拉斯·凱奇,《The Rock》,以及對(duì)喜歡 《盜火線》的觀眾而言,它是一個(gè)不錯(cuò)的推薦。這可能是相似性矩陣和協(xié)同過(guò)濾的缺點(diǎn)之一。讓我們?cè)囋嚫嗟睦印?/p>
這個(gè)看起還好。《玩具總動(dòng)員2》絕對(duì)是應(yīng)該推薦給喜歡《玩具總動(dòng)員》的觀眾。但是《阿甘正傳》在我看來(lái)不合適。顯然,因?yàn)闇贰h克斯的聲音出現(xiàn)在《玩具總動(dòng)員》里,所以《阿甘正傳》也被推薦了。值得注意的是,我們可以只看一眼海報(bào)就分辨出《玩具總動(dòng)員》與 《阿甘正傳》的區(qū)別,比如電影類型、情緒等。假設(shè)每一個(gè)小孩都喜歡《玩具總動(dòng)員》,他們可能會(huì)忽略《阿甘正傳》。
在前面的討論中,我們簡(jiǎn)單地計(jì)算了用戶和電影的余弦相似度,并以此來(lái)預(yù)測(cè)用戶對(duì)電影的評(píng)分,還根據(jù)某電影推薦其它電影?,F(xiàn)在,我們可以把問(wèn)題做為一個(gè)回歸問(wèn)題;對(duì)所有的電影加入潛在特征y,對(duì)所有用戶加入權(quán)重向量x。目標(biāo)是將評(píng)分預(yù)測(cè)的(在 2-norm 的正則化條件下)MSE最小化。
雷鋒網(wǎng)提醒:權(quán)重向量和特征向量都是決策變量。顯然,這不是一個(gè)凸函數(shù)問(wèn)題,現(xiàn)在也不需要過(guò)分擔(dān)心這個(gè)非凸函數(shù)的收斂性。有很多方法能解決非凸函數(shù)的優(yōu)化問(wèn)題。方法之一就是以交替方式()解決權(quán)重向量(對(duì)用戶)和特征向量(對(duì)電影)。處理權(quán)重向量時(shí),假設(shè)特征向量是常向量;處理特征向量時(shí),假設(shè)權(quán)重向量是常向量。解決這個(gè)回歸問(wèn)題的另一種方法,是將權(quán)重向量與特征向量的更新結(jié)合起來(lái),在同一個(gè)迭代中更新它們。另外,還可以借助隨機(jī)梯度下降來(lái)加速計(jì)算。這里,我用隨機(jī)梯度下降來(lái)解決這個(gè)回歸問(wèn)題,我們的MSE預(yù)測(cè)如下:
這個(gè)MSE比用相似性矩陣得到的,要小得多。當(dāng)然,我們也可以使用網(wǎng)格搜索和交叉驗(yàn)證對(duì)模型、算法調(diào)參。再看看電影搜索的推薦:
看起來(lái)并不是很好。我覺(jué)得這四部電影不應(yīng)該通過(guò)搜索《盜火線》推薦給我,他們看起來(lái)與《盜火線》完全不相關(guān),這四個(gè)電影是浪漫、戲劇類。如果我找的是一部有大明星的美國(guó)犯罪電影,我憑什么會(huì)想要看戲劇電影? 這讓我很困惑——一個(gè)好的MSE的結(jié)果可能會(huì)給我們一個(gè)風(fēng)馬牛不相及的推薦。
因此,我們討論一下基于協(xié)同過(guò)濾的推薦系統(tǒng)的弱點(diǎn)。
協(xié)同過(guò)濾方法通過(guò)使用數(shù)據(jù),來(lái)發(fā)現(xiàn)類似的用戶和電影,這將導(dǎo)致熱門(mén)電影比小眾電影更容易被推薦。
由于新上映的電影沒(méi)有太多的使用數(shù)據(jù),指望協(xié)同過(guò)濾向用戶推薦任何新電影很不現(xiàn)實(shí)。
接下來(lái),我們將考慮采用另一種方法來(lái)處理協(xié)同過(guò)濾問(wèn)題——用深度學(xué)習(xí)推薦電影。
我們將在Keras中用VGG16來(lái)訓(xùn)練神經(jīng)網(wǎng)絡(luò)。我們的數(shù)據(jù)集中沒(méi)有目標(biāo),只是將倒數(shù)第四層作為一個(gè)特征向量。我們用這個(gè)特征向量,來(lái)描述數(shù)據(jù)集中的每一個(gè)電影。雷鋒網(wǎng)提醒,在訓(xùn)練神經(jīng)網(wǎng)絡(luò)之前,還需要做一些預(yù)處理,訓(xùn)練過(guò)程如下。
df_id = pd.read_csv('links.csv', sep=',')
idx_to_movie = {}
for row in df_id.itertuples():
idx_to_movie[row[1]-1] = row[2]
total_movies = 9000
movies = [0]*total_movies
for i in range(len(movies)):
if i in idx_to_movie.keys() and len(str(idx_to_movie[i])) == 6:
movies[i] = (idx_to_movie[i])
movies = filter(lambda imdb: imdb != 0, movies)
total_movies = len(movies)
URL = [0]*total_movies
IMDB = [0]*total_movies
URL_IMDB = {"url":[],"imdb":[]}
i = 0
for movie in movies:
(URL[i], IMDB[i]) = get_poster(movie, base_url)
if URL[i] != base_url+"":
URL_IMDB["url"].append(URL[i])
URL_IMDB["imdb"].append(IMDB[i])
i += 1
# URL = filter(lambda url: url != base_url+"", URL)
df = pd.DataFrame(data=URL_IMDB)
total_movies = len(df)
import urllib
poster_path = "/Users/wannjiun/Desktop/nycdsa/project_5_recommender/posters/"
for i in range(total_movies):
urllib.urlretrieve(df.url[i], poster_path + str(i) + ".jpg")
from keras.applications import VGG16
from keras.applications.vgg16 import preprocess_input
from keras.preprocessing import image as kimage
image = [0]*total_movies
x = [0]*total_movies
for i in range(total_movies):
image[i] = kimage.load_img(poster_path + str(i) + ".jpg", target_size=(224, 224))
x[i] = kimage.img_to_array(image[i])
x[i] = np.expand_dims(x[i], axis=0)
x[i] = preprocess_input(x[i])
model = VGG16(include_top=False, weights='imagenet')
prediction = [0]*total_movies
matrix_res = np.zeros([total_movies,25088])
for i in range(total_movies):
prediction[i] = model.predict(x[i]).ravel()
matrix_res[i,:] = prediction[i]
similarity_deep = matrix_res.dot(matrix_res.T)
norms = np.array([np.sqrt(np.diagonal(similarity_deep))])
similarity_deep = similarity_deep / norms / norms.T
在代碼中,我們首先使用API和IMDB id,從TMDB網(wǎng)站獲取電影海報(bào)。然后向VGG16提供海報(bào)來(lái)訓(xùn)練神經(jīng)網(wǎng)絡(luò)。最后,用VGG16學(xué)習(xí)的特征來(lái)計(jì)算余弦相似性。獲得電影相似性之后,我們可以推薦相似度最高的電影。VGG16總共有25088個(gè)學(xué)來(lái)的特征,我們使用這些特征來(lái)描述數(shù)據(jù)集中的每個(gè)電影。
來(lái)看看使用深度學(xué)習(xí)的電影推薦系統(tǒng)。
《導(dǎo)火線》不再和愛(ài)情戲劇一起出現(xiàn)了!這些電影海報(bào)有一些相同的特點(diǎn):深藍(lán)色的、上面還有人物等等。讓我們?cè)賮?lái)試試《玩具總動(dòng)員》。
《阿甘正傳》不會(huì)再被推薦了!結(jié)果看起來(lái)不錯(cuò),朕心甚慰,再來(lái)試試別的!
注意,這些海報(bào)里都有一或兩個(gè)人,并有冷色系的主題風(fēng)格。
這些海報(bào)想讓觀眾知道相應(yīng)電影的氛圍歡樂(lè)、緊張,并有很多動(dòng)作鏡頭,所以海報(bào)的顏色也很強(qiáng)烈。
不同于上一組,這些海報(bào)想告訴觀眾:這些電影講述的是一個(gè)單身漢。
我們找到的與《功夫熊貓》類似的電影。
這一組很有趣。一群相似的怪獸以及湯姆·克魯斯!
所有這些海報(bào)里都有姿勢(shì)類似的女士。等等,那個(gè)是奧尼爾???
成功找到了蜘蛛俠!
這些海報(bào)的排版設(shè)計(jì)很接近。
結(jié)論
在推薦系統(tǒng)中有幾種使用深度學(xué)習(xí)的方法:
無(wú)監(jiān)督學(xué)習(xí)
從協(xié)同過(guò)濾中預(yù)測(cè)潛在特征
將深度學(xué)習(xí)生成的特征作為輔助信息
電影海報(bào)具有創(chuàng)造噱頭和興趣的視覺(jué)元素。這個(gè)項(xiàng)目中,我們使用了無(wú)監(jiān)督深度學(xué)習(xí),通過(guò)海報(bào)來(lái)學(xué)習(xí)電影的相似性。顯然,這只是在推薦系統(tǒng)中使用深度學(xué)習(xí)的第一步,我們還可以嘗試很多東西。例如,我們可以用深度學(xué)習(xí)來(lái)預(yù)測(cè)協(xié)同過(guò)濾生成的潛在特征。Spotify的音樂(lè)推薦也使用了類似的方法,區(qū)別于圖像處理,他們通過(guò)處理歌曲的聲音,來(lái)用深度學(xué)習(xí)來(lái)預(yù)測(cè)協(xié)同過(guò)濾中的潛在特征。還有一個(gè)可能的方向。是把深度學(xué)習(xí)學(xué)到的特征作為輔助信息,來(lái)提高預(yù)測(cè)的準(zhǔn)確性。
via nycdatascience,雷鋒網(wǎng)編譯
從初級(jí)到高級(jí),理論+實(shí)戰(zhàn),一站式深度了解 TensorFlow!
本課程面向深度學(xué)習(xí)開(kāi)發(fā)者,講授如何利用 TensorFlow 解決圖像識(shí)別、文本分析等具體問(wèn)題。課程跨度為 10 周,將從 TensorFlow 的原理與基礎(chǔ)實(shí)戰(zhàn)技巧開(kāi)始,一步步教授學(xué)員如何在 TensorFlow 上搭建 CNN、自編碼、RNN、GAN 等模型,并最終掌握一整套基于 TensorFlow 做深度學(xué)習(xí)開(kāi)發(fā)的專業(yè)技能。
兩名授課老師佟達(dá)、白發(fā)川身為 ThoughtWorks 的資深技術(shù)專家,具有豐富的大數(shù)據(jù)平臺(tái)搭建、深度學(xué)習(xí)系統(tǒng)開(kāi)發(fā)項(xiàng)目經(jīng)驗(yàn)。
時(shí)間:每周二、四晚 20:00-21:00
開(kāi)課時(shí)長(zhǎng):總學(xué)時(shí) 20 小時(shí),分 10 周完成,每周2次,每次 1 小時(shí)
相關(guān)文章:
從理論到實(shí)踐,一文詳解 AI 推薦系統(tǒng)的三大算法
雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見(jiàn)轉(zhuǎn)載須知。