構(gòu)建基于深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)協(xié)同過濾模型(NCF)的視頻推薦系統(tǒng)(Python3.10/Tensorflow2.11)

毋庸諱言,和傳統(tǒng)架構(gòu)(BS開發(fā)/CS開發(fā))相比寞秃,人工智能技術(shù)確實(shí)有一定的基礎(chǔ)門檻瑰枫,它注定不是大眾化踱葛,普適化的東西。但也不能否認(rèn)光坝,人工智能技術(shù)也具備像傳統(tǒng)架構(gòu)一樣“套路化”的流程尸诽,也就是說,我們大可不必自己手動(dòng)構(gòu)建基于神經(jīng)網(wǎng)絡(luò)的機(jī)器學(xué)習(xí)系統(tǒng)盯另,直接使用深度學(xué)習(xí)框架反而更加簡單性含,深度學(xué)習(xí)可以幫助我們自動(dòng)地從原始數(shù)據(jù)中提取特征,不需要手動(dòng)選擇和提取特征鸳惯。

之前我們手動(dòng)構(gòu)建了一個(gè)小型的神經(jīng)網(wǎng)絡(luò)商蕴,解決了機(jī)器學(xué)習(xí)的分類問題,本次我們利用深度學(xué)習(xí)框架Tensorflow2.11構(gòu)建一套基于神經(jīng)網(wǎng)絡(luò)協(xié)同過濾模型(NCF)的視頻推薦系統(tǒng)芝发,解決預(yù)測問題绪商,完成一個(gè)真正可以落地的項(xiàng)目。

推薦系統(tǒng)發(fā)展歷程

“小伙子辅鲸,要光盤嗎格郁?新的到貨了惊科,內(nèi)容相當(dāng)精彩漏麦!”

大約20年前扇谣,在北京中關(guān)村的街頭攀隔,一位抱著嬰兒的中年大媽興奮地拽著筆者的胳臂,手舞足蹈地推薦著她的“產(chǎn)品”决采,大概這就是最原始的推薦系統(tǒng)雛形了自沧。

事實(shí)上,時(shí)至今日树瞭,依然有類似產(chǎn)品使用這樣的套路拇厢,不管三七二十一,弄個(gè)首頁大Banner移迫,直接懟用戶臉上旺嬉,且不論用戶感不感興趣管行,有沒有用戶點(diǎn)擊和轉(zhuǎn)化厨埋,這種強(qiáng)買強(qiáng)賣式的推薦,著實(shí)不怎么令人愉快捐顷。

所以推薦系統(tǒng)解決的痛點(diǎn)應(yīng)該是用戶的興趣需求荡陷,給用戶推薦喜歡的內(nèi)容,才是推薦系統(tǒng)的核心迅涮。

于是乎废赞,啟發(fā)式推薦算法(Memory-based algorithms)就應(yīng)運(yùn)而生了。

啟發(fā)式推薦算法易于實(shí)現(xiàn)叮姑,并且推薦結(jié)果的可解釋性強(qiáng)唉地。啟發(fā)式推薦算法又可以分為兩類:

基于用戶的協(xié)同過濾(User-based collaborative filtering):主要考慮的是用戶和用戶之間的相似度,只要找出相似用戶喜歡的物品传透,并預(yù)測目標(biāo)用戶對對應(yīng)物品的評分耘沼,就可以找到評分最高的若干個(gè)物品推薦給用戶。舉個(gè)例子朱盐,李老師和閆老師擁有相似的電影喜好群嗤,當(dāng)新電影上映后,李老師對其表示喜歡兵琳,那么就能將這部電影推薦給閆老師狂秘。

基于物品的協(xié)同過濾(Item-based collaborative filtering):主要考慮的是物品和物品之間的相似度,只有找到了目標(biāo)用戶對某些物品的評分躯肌,那么就可以對相似度高的類似物品進(jìn)行預(yù)測者春,將評分最高的若干個(gè)相似物品推薦給用戶。舉個(gè)例子清女,如果用戶A碧查、B、C給書籍X,Y的評分都是5分,當(dāng)用戶D想要買Y書籍的時(shí)候忠售,系統(tǒng)會為他推薦X書籍传惠,因?yàn)榛谟脩鬉、B稻扬、C的評分卦方,系統(tǒng)會認(rèn)為喜歡Y書籍的人在很大程度上會喜歡X書籍。

啟發(fā)式協(xié)同過濾算法是一種結(jié)合了基于用戶的協(xié)同過濾和基于項(xiàng)目的協(xié)同過濾的算法泰佳,它通過啟發(fā)式規(guī)則來預(yù)測用戶對物品的評分盼砍。

然而,啟發(fā)式協(xié)同過濾算法也存在一些缺陷:

難以處理冷啟動(dòng)問題:當(dāng)一個(gè)用戶或一個(gè)物品沒有足夠的評分?jǐn)?shù)據(jù)時(shí)逝她,啟發(fā)式協(xié)同過濾算法無法對其進(jìn)行有效的預(yù)測浇坐,因?yàn)樗枰蕾囉谝延械脑u分?jǐn)?shù)據(jù)。

對數(shù)據(jù)稀疏性敏感:如果數(shù)據(jù)集中存在大量的缺失值黔宛,啟發(fā)式協(xié)同過濾算法的預(yù)測準(zhǔn)確率會受到影響近刘,因?yàn)樗枰蕾囉谕暾脑u分?jǐn)?shù)據(jù)來進(jìn)行預(yù)測。

算法的可解釋性較差:啟發(fā)式協(xié)同過濾算法的預(yù)測結(jié)果是通過啟發(fā)式規(guī)則得出的臀晃,這些規(guī)則可能很難被解釋和理解觉渴。

受限于啟發(fā)式規(guī)則的質(zhì)量:啟發(fā)式協(xié)同過濾算法的預(yù)測準(zhǔn)確率受到啟發(fā)式規(guī)則的質(zhì)量影響,如果啟發(fā)式規(guī)則得不到有效的優(yōu)化和更新徽惋,算法的性能可能會受到影響案淋。

說白了,這種基于啟發(fā)式的協(xié)同過濾算法险绘,很容易陷入一個(gè)小范圍的困境踢京,就是如果某個(gè)用戶特別喜歡體育的視頻,那么這種系統(tǒng)就會玩命地推薦體育視頻宦棺,實(shí)際上這個(gè)人很有可能也喜歡藝術(shù)類的視頻瓣距,但是囿于冷啟動(dòng)問題,無法進(jìn)行推薦渺氧。

為了解決上面的問題旨涝,基于神經(jīng)網(wǎng)絡(luò)的協(xié)同過濾算法誕生了,神經(jīng)網(wǎng)絡(luò)的協(xié)同過濾算法可以通過將用戶和物品的特征向量作為輸入侣背,來預(yù)測用戶對新物品的評分白华,從而解決冷啟動(dòng)問題。

對數(shù)據(jù)稀疏性的魯棒性:神經(jīng)網(wǎng)絡(luò)的協(xié)同過濾算法可以自動(dòng)學(xué)習(xí)用戶和物品的特征向量贩耐,并能夠通過這些向量來預(yù)測評分弧腥,因此對于數(shù)據(jù)稀疏的情況也能進(jìn)行有效的預(yù)測。

更好的預(yù)測準(zhǔn)確率:神經(jīng)網(wǎng)絡(luò)的協(xié)同過濾算法可以通過多層非線性變換來學(xué)習(xí)用戶和物品之間的復(fù)雜關(guān)系潮太,從而能夠提高預(yù)測準(zhǔn)確率管搪。

可解釋性和靈活性:神經(jīng)網(wǎng)絡(luò)的協(xié)同過濾算法可以通過調(diào)整網(wǎng)絡(luò)結(jié)構(gòu)和參數(shù)來優(yōu)化預(yù)測準(zhǔn)確率虾攻,并且可以通過可視化方法來解釋預(yù)測結(jié)果。

所以基于神經(jīng)網(wǎng)絡(luò)協(xié)同過濾模型是目前推薦系統(tǒng)的主流形態(tài)更鲁。

基于稀疏矩陣的視頻完播數(shù)據(jù)

首先構(gòu)造我們的數(shù)據(jù)矩陣test.csv文件:

User,Video 1,Video 2,Video 3,Video 4,Video 5,Video 6  
User1,10,3,,,,  
User2,,10,,10,5,1  
User3,,,9,,,  
User4,6,1,,8,,9  
User5,1,,1,,10,4  
User6,1,4,1,,10,1  
User7,,2,1,2,,8  
User8,,,,1,,  
User9,1,,10,,3,1

這里橫軸是視頻數(shù)據(jù)霎箍,縱軸是用戶,對應(yīng)的數(shù)據(jù)是用戶對于視頻的完播程度澡为,10代表看完了漂坏,1則代表只看了百分之十,留空的代表沒有看媒至。

編寫ncf.py腳本顶别,將數(shù)據(jù)讀入內(nèi)存并輸出:

import pandas as pd  
# set pandas to show all columns without truncation and line breaks  
pd.set_option('display.max_columns', 1000)  
pd.set_option('display.width', 1000)  
  
# data = np.loadtxt('data/test-data.csv', delimiter=',', dtype=int, skiprows=1,)  
data = pd.read_csv('data/test-data.csv')  
print(data)

程序返回:

User  Video 1  Video 2  Video 3  Video 4  Video 5  Video 6  
0  User1     10.0      3.0      NaN      NaN      NaN      NaN  
1  User2      NaN     10.0      NaN     10.0      5.0      1.0  
2  User3      NaN      NaN      9.0      NaN      NaN      NaN  
3  User4      6.0      1.0      NaN      8.0      NaN      9.0  
4  User5      1.0      NaN      1.0      NaN     10.0      4.0  
5  User6      1.0      4.0      1.0      NaN     10.0      1.0  
6  User7      NaN      2.0      1.0      2.0      NaN      8.0  
7  User8      NaN      NaN      NaN      1.0      NaN      NaN  
8  User9      1.0      NaN     10.0      NaN      3.0      1.0

一目了然。

有數(shù)據(jù)的列代表用戶看過拒啰,1-10代表看了之后的完播程度驯绎,如果沒看過就是NAN,現(xiàn)在我們的目的就是“猜”出來這些沒看過的視頻的完播數(shù)據(jù)是多少谋旦?從而根據(jù)完播數(shù)據(jù)完成視頻推薦系統(tǒng)剩失。

矩陣拆解算法

有一種推薦算法是基于矩陣拆解,通過假設(shè)的因素去“猜”稀疏矩陣的空缺數(shù)據(jù)蛤织,猜出來之后赴叹,再通過反向傳播的逆運(yùn)算來反推稀疏矩陣已存在的數(shù)據(jù)是否正確鸿染,從而判斷“猜”出來的數(shù)據(jù)是否正確:

[圖片上傳失敗...(image-9a88e8-1680135441449)]

通俗地講指蚜,跟算命差不多,但是基于數(shù)學(xué)原理涨椒,如果通過反推證明針對一個(gè)人的算命策略都是對的摊鸡,那么就把這套流程應(yīng)用到其他人身上。

但是這套邏輯過于線性蚕冬,也就是因素過于單一免猾,比如我喜歡黑色的汽車,那么就會給我推所有黑色的東西囤热,其實(shí)可能黑色的因素僅局限于汽車猎提,是多重因素疊加導(dǎo)致的,所以矩陣拆解并不是一個(gè)非常好的解決方案旁蔼。

基于神經(jīng)網(wǎng)絡(luò)

使用神經(jīng)網(wǎng)絡(luò)計(jì)算锨苏,必須將數(shù)據(jù)進(jìn)行向量化操作:

# reset the column.index to be numeric  
user_index = data[data.columns[0]]  
book_index = data.columns  
data = data.reset_index(drop=True)  
data[data.columns[0]] = data.index.astype('int')  
# print(data)  
# print(data)  
scaler = 10  
  
# data = pd.DataFrame(data.to_numpy(), index=range(0,len(user_index)), columns=range(0,len(book_index)))  
df_long = pd.melt(data, id_vars=[data.columns[0]],   
                  ignore_index=True,   
                  var_name='video_id',   
                  value_name='rate').dropna()  
df_long.columns = ['user_id', 'video_id', 'rating']  
df_long['rating'] = df_long['rating'] / scaler  
# replace the user_id to user by match user_index  
df_long['user_id'] = df_long['user_id'].apply(lambda x: user_index[x])  
# data = df_long.to_numpy()  
  
print(df_long)

程序返回:

user_id video_id  rating  
0    User1  Video 1     1.0  
3    User4  Video 1     0.6  
4    User5  Video 1     0.1  
5    User6  Video 1     0.1  
8    User9  Video 1     0.1  
9    User1  Video 2     0.3  
10   User2  Video 2     1.0  
12   User4  Video 2     0.1  
14   User6  Video 2     0.4  
15   User7  Video 2     0.2  
20   User3  Video 3     0.9  
22   User5  Video 3     0.1  
23   User6  Video 3     0.1  
24   User7  Video 3     0.1  
26   User9  Video 3     1.0  
28   User2  Video 4     1.0  
30   User4  Video 4     0.8  
33   User7  Video 4     0.2  
34   User8  Video 4     0.1  
37   User2  Video 5     0.5  
40   User5  Video 5     1.0  
41   User6  Video 5     1.0  
44   User9  Video 5     0.3  
46   User2  Video 6     0.1  
48   User4  Video 6     0.9  
49   User5  Video 6     0.4  
50   User6  Video 6     0.1  
51   User7  Video 6     0.8  
53   User9  Video 6     0.1

這里scaler=10作為數(shù)據(jù)范圍的閾值,讓計(jì)算機(jī)將完播數(shù)據(jù)散列成0-1之間的浮點(diǎn)數(shù)棺聊,便于神經(jīng)網(wǎng)絡(luò)進(jìn)行計(jì)算伞租。

隨后安裝Tensorflow框架:

pip3 install tensorflow

如果是Mac用戶,請安裝mac版本:

pip3 install tensorflow-macos

接著針對數(shù)據(jù)進(jìn)行打標(biāo)簽操作:

import numpy as np  
import pandas as pd  
import tensorflow as tf  
from sklearn.model_selection import train_test_split  
from sklearn.preprocessing import LabelEncoder  
  
# dataset = pd.read_csv(url, compression='zip', usecols=['userId', 'movieId', 'rating'])  
dataset = df_long  
# Encode the user and video IDs  
user_encoder = LabelEncoder()  
video_encoder = LabelEncoder()  
dataset['user_id'] = user_encoder.fit_transform(dataset['user_id'])  
dataset['video_id'] = video_encoder.fit_transform(dataset['video_id'])  
  
# Split the dataset into train and test sets  
# train, test = train_test_split(dataset, test_size=0.2, random_state=42)  
train = dataset  
  
# Model hyperparameters  
num_users = len(dataset['user_id'].unique())  
num_countries = len(dataset['video_id'].unique())

隨后定義64個(gè)維度針對向量進(jìn)行處理:



embedding_dim = 64  
  
# Create the NCF model  
inputs_user = tf.keras.layers.Input(shape=(1,))  
inputs_video = tf.keras.layers.Input(shape=(1,))  
embedding_user = tf.keras.layers.Embedding(num_users, embedding_dim)(inputs_user)  
embedding_video = tf.keras.layers.Embedding(num_countries, embedding_dim)(inputs_video)  
  
# Merge the embeddings using concatenation, you can also try other merging methods like dot product or multiplication  
merged = tf.keras.layers.Concatenate()([embedding_user, embedding_video])  
merged = tf.keras.layers.Flatten()(merged)  
  
# Add fully connected layers  
dense = tf.keras.layers.Dense(64, activation='relu')(merged)  
dense = tf.keras.layers.Dense(32, activation='relu')(dense)  
output = tf.keras.layers.Dense(1, activation='sigmoid')(dense)  
  
# Compile the model  
model = tf.keras.Model(inputs=[inputs_user, inputs_video], outputs=output)  
model.compile(optimizer='adam', loss='mse', metrics=['mae'])


這里定義了一個(gè)64維度的 embedding 類用來對向量進(jìn)行處理限佩。相當(dāng)于就是把屬于數(shù)據(jù)當(dāng)中的所有特征都設(shè)定成一個(gè)可以用一個(gè)64維向量標(biāo)識的東西葵诈,然后通過降維處理之后使得機(jī)器能以一個(gè)低維的數(shù)據(jù)流形來“理解”高維的原始數(shù)據(jù)的方式來“理解”數(shù)據(jù)的“含義”裸弦,

從而實(shí)現(xiàn)機(jī)器學(xué)習(xí)的目的。而為了檢驗(yàn)機(jī)器學(xué)習(xí)的成果(即機(jī)器是否有真正理解特征的含義)作喘,則使用mask(遮罩)的方式理疙,將原始數(shù)據(jù)當(dāng)中的一部分無關(guān)核心的內(nèi)容“遮掉”,然后再嘗試進(jìn)行輸入輸出操作泞坦,如果輸入輸出操作的結(jié)果與沒有遮罩的結(jié)果進(jìn)行比較后足夠相近沪斟,或者完全相同,則判定機(jī)器有成功學(xué)習(xí)理解到向量的含義暇矫。

這里需要注意的是主之,因?yàn)閑mbedding 這個(gè)詞其實(shí)是有一定程度的誤用的關(guān)系,所以不要嘗試用原來的語義去理解這個(gè)詞李根,通俗地講槽奕,可以把它理解為“特征(feature)”,即從原始數(shù)據(jù)中提取出來的一系列的特征屬性房轿,至于具體是什么特征粤攒,不重要。

這里有64個(gè)維度囱持,那就可以認(rèn)為是從輸入的原始數(shù)據(jù)當(dāng)中提取64個(gè)“特征”夯接,然后用這個(gè)特征模型去套用所有的輸入的原始數(shù)據(jù),然后再將這些數(shù)據(jù)通過降維轉(zhuǎn)換纷妆,最終把每一個(gè)輸入的向量轉(zhuǎn)換成一個(gè)1維的特殊字符串盔几,然后讓機(jī)器實(shí)現(xiàn)“理解復(fù)雜的輸入”的目的,而那個(gè)所謂的訓(xùn)練過程掩幢,其實(shí)也就是不斷地用遮罩mask去遮掉非核心的數(shù)據(jù)逊拍,然后對比輸出結(jié)果,來看機(jī)器是否成功實(shí)現(xiàn)了學(xué)習(xí)的目的际邻。

說白了芯丧,和矩陣拆解差不多,只不過矩陣拆解是線性單維度世曾,而神經(jīng)網(wǎng)絡(luò)是非線性多維度缨恒。

最后進(jìn)行訓(xùn)練和輸出:

model.fit(  
    [train['user_id'].values, train['video_id'].values],  
    train['rating'].values,  
    batch_size=64,  
    epochs=100,  
    verbose=0,  
    # validation_split=0.1,  
)  
  
result_df = {}  
for user_i in range(1, 10):  
  user = f'User{user_i}'  
  result_df[user] = {}  
  for video_i in range(1, 7):      
    video = f'Video {video_i}'  
    pred_user_id = user_encoder.transform([user])  
    pred_video_id = video_encoder.transform([video])  
    result = model.predict(x=[pred_user_id, pred_video_id], verbose=0)  
    result_df[user][video] = result[0][0]  
result_df = pd.DataFrame(result_df).T  
result_df *= scaler  
  
print(result_df)

程序返回:

Video 1   Video 2   Video 3   Video 4   Video 5   Video 6  
User1  9.143433  3.122697  5.831852  8.930688  9.223139  9.148163  
User2  2.379406  9.317654  9.280337  9.586231  5.115635  0.710877  
User3  6.046935  8.950342  9.335093  9.546472  8.487216  5.069511  
User4  6.202362  1.341177  2.609368  7.755390  9.160558  8.974072  
User5  1.134012  1.772043  0.634183  3.741076  9.297663  3.924277  
User6  0.488006  4.060344  1.116192  4.625140  9.264144  1.199519  
User7  2.820735  0.898690  0.560579  2.215827  8.604731  7.889819  
User8  0.244587  1.062029  0.360087  1.069786  7.698551  1.286932  
User9  1.337930  8.537857  9.329366  9.123328  3.074733  0.774436

我們可以看到,機(jī)器通過神經(jīng)網(wǎng)絡(luò)的“學(xué)習(xí)”轮听,直接“猜出來”所有用戶未播放視頻的完播程度骗露。那么,我們只需要給這些用戶推薦他未看的蕊程,但是機(jī)器“猜”他完播高的視頻即可椒袍。

總結(jié)

我們可以看到,整個(gè)流程簡單的令人發(fā)指藻茂,深度學(xué)習(xí)框架Tensorflow幫我們做了大部分的工作驹暑,我們其實(shí)只是簡單的提供了基礎(chǔ)數(shù)據(jù)而已玫恳。

首先定義一個(gè)embedding (多維空間) 用來理解需要學(xué)習(xí)的原始數(shù)據(jù) :

一個(gè)用戶對象(含一個(gè)屬性userId)

一個(gè)視頻對象(含三個(gè)屬性:videoId, userId, rating (完播向量))

這里需要進(jìn)行學(xué)習(xí)的具體就是讓機(jī)器理解那個(gè)“完播向量:rating”的含義)這里定義的embedding 維度為64, 本質(zhì)就是讓機(jī)器把完播向量rating 的值當(dāng)作成一個(gè)64維度的空間來進(jìn)行理解(其實(shí)就是從這個(gè)rating值當(dāng)中提取出64個(gè)特征來重新定義這個(gè)rating)

隨后對embedding 進(jìn)行降維處理:

具體的操作與使用的降維函數(shù)曲線有關(guān),這里采用的是先降為32維再降為1維的兩道操作方式优俘,原來的代表rating 的embedding 空間從64維降低到了1維京办。而此時(shí)的輸出output 對象就是機(jī)器對rating完播向量所做出來的“自己的理解”。

最后通過對學(xué)習(xí)完的輸出項(xiàng)output 進(jìn)行mask(遮罩)測試帆焕,通過變換不同的mask(遮罩)來測試結(jié)果是否與原始數(shù)據(jù)相近惭婿,或一致,從而來證實(shí)機(jī)器學(xué)習(xí)的效果叶雹,也就是上文提到的反向傳播方式的逆運(yùn)算财饥。

結(jié)語

可能依然有朋友對這套系統(tǒng)的底層不太了解,那么折晦,如果我們用“白話文”的形式進(jìn)行解釋:比如有一幅油畫钥星,油畫相比完播量,肯定是多維度的满着,因?yàn)楫嬂锩嬗蓄伾础L(fēng)格、解析度风喇、對比度宁改、飽和度等等特征參數(shù),此時(shí)我們讓機(jī)器先看完整的這幅畫魂莫,然后用機(jī)器學(xué)習(xí)的方式讓它學(xué)習(xí)(即embedding方式)还蹲,接著把這幅畫遮掉一部分與主題無關(guān)的部分,然后再測試機(jī)器讓它用學(xué)習(xí)到的數(shù)據(jù)(即embedding完成降維處理之后的數(shù)據(jù))去嘗試復(fù)原整幅畫豁鲤,隨后對比復(fù)原的整幅畫和原始油畫有多大差別秽誊,如果差別沒有或者很小鲸沮,則證明機(jī)器學(xué)習(xí)成功了琳骡,機(jī)器確實(shí)學(xué)會了這副畫,然后就讓機(jī)器按照這套邏輯去畫類似的畫讼溺,最后把這一“類”的畫推薦給沒有鑒賞過的用戶楣号,從而完成推薦系統(tǒng),就這么簡單怒坯。

最后炫狱,奉上視頻推薦系統(tǒng)項(xiàng)目代碼,與眾鄉(xiāng)親同饗:github.com/zcxey2911/NeuralCollaborativeFiltering_NCF_Tensorflow

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剔猿,一起剝皮案震驚了整個(gè)濱河市视译,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌归敬,老刑警劉巖酷含,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鄙早,死亡現(xiàn)場離奇詭異,居然都是意外死亡椅亚,警方通過查閱死者的電腦和手機(jī)限番,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呀舔,“玉大人弥虐,你說我怎么就攤上這事∶睦担” “怎么了霜瘪?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長惧磺。 經(jīng)常有香客問我粥庄,道長,這世上最難降的妖魔是什么豺妓? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任惜互,我火速辦了婚禮,結(jié)果婚禮上琳拭,老公的妹妹穿的比我還像新娘训堆。我一直安慰自己,他們只是感情好白嘁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布坑鱼。 她就那樣靜靜地躺著絮缅,像睡著了一般耕魄。 火紅的嫁衣襯著肌膚如雪允扇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機(jī)與錄音揖赴,去河邊找鬼燥滑。 笑死铭拧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了逊彭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤分尸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后圆到,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掷邦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年宣蔚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了笋额。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铜秆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤厌衙,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布喻杈,位于F島的核電站,受9級特大地震影響撤蟆,放射性物質(zhì)發(fā)生泄漏奕塑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一家肯、第九天 我趴在偏房一處隱蔽的房頂上張望龄砰。 院中可真熱鬧,春花似錦讨衣、人聲如沸换棚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽固蚤。三九已至,卻和暖如春歹茶,著一層夾襖步出監(jiān)牢的瞬間夕玩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工惊豺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留燎孟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓尸昧,卻偏偏與公主長得像揩页,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子烹俗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評論 2 353

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