機器學習練手項目——Dota2vec

機器學習練手項目——Dota2vec

52 人贊了文章

前言:

  • 這次練手項目思路源自 @景略集智 的如何用機器學習預測《守望先鋒》里的贏家?
  • 之前的項目發出來後發現了效果不好是因為數據處理時一個bug導致,發現後在文章中的代碼已經修改,修改後使用邏輯回歸能在數據集上跑出大概59%的準確率。
  • 此文章若有錯漏之處,請指正,敬請諒解。

項目背景

在做dota2的勝率模型預測中,特徵的編碼方式很大的影響了模型的準確率。之前的文章使用了獨熱編碼來對特徵進行處理。但是獨熱編碼也有很多問題,最主要的問題就是特徵的稀疏,既採用獨熱編碼時,大部分特徵值都為0。

本文中項目採用類似與word2vec中的詞袋模型通過隊伍英雄的配置來訓練英雄的嵌入層,獲取英雄的嵌入層。

與word2vec的相似點與不同點

dota2中想要獲取遊戲的勝利隊伍的配置必須合理,5個大哥或者5個醬油都是很難獲得遊戲的勝利的,所以在一個五個英雄組成的「句子」中,和自然語言的句子有很大的相同點。

例如:「我們 LGD 是 不可戰勝的!」

「我們 Ti8冠軍 是 不可戰勝的!「

兩個句子中LGD和Ti8指定冠軍是相近詞,在語義上具有相似性。(呃,希望不是毒奶。)

而對於英雄陣容來說,以下兩個陣容:

【幻影刺客 風暴之靈 馬格納斯 上古巨神 術士】

【敵法師 風暴之靈 馬格納斯 上古巨神 術士】

這兩個陣容也是相似的,因為敵法師和幻影刺客是具有相似性的。

但是對於英雄來說,上下文關係並是沒有語義的,這點和word2vec里Skip-gram有很大的不同,所以我們選用CBOW 來訓練模型。

相比與word2vec中大規模的詞向量,英雄的維度只有120+,所以原word2vec中hierarchical softmax和負採樣技巧在本模型中沒有使用。

數據處理

數據來源依舊是FunData-VARENA,這次我提取了大約百萬場的比賽數據,這次訓練選擇了其中6w+場的vh局天梯比賽數據。

dota2vec模型需要的是一個隊伍里出現的4個英雄來預測另外一個英雄,所以我們需要將每場比賽的數據處理成10條輸入為4個英雄編號,輸出為1個英雄。

代碼如下:

def dataset_to_features(dataset_df): # 構造一個空的x目標矩陣,列數為4,行數為樣本數量*10 x_matrix = np.zeros((dataset_df.shape[0] * 5 * 2, 4)) # 構造一個空的y目標矩陣,行數為樣本數量*10 y_matrix = np.zeros(dataset_df.shape[0] * 5 * 2) # 將原樣本中的數據,用pandas的values函數導出為一個numpy的矩陣類型 dataset_np = dataset_df.values # 對矩陣的每行每個英雄,分別映射到目標矩陣中 for i, row in enumerate(dataset_np): radiant_heroes = row[1:6] dire_heroes = row[6:11] for j in range(5): y_matrix[i * 10 + j] = radiant_heroes[j] y_matrix[i * 10 + j + 5] = dire_heroes[j] x_matrix[i * 10 + j] = np.delete(radiant_heroes, j, axis=0) x_matrix[i * 10 + j + 5] = np.delete(dire_heroes, j, axis=0) return [x_matrix, y_matrix]

模型結構

這裡引用原文中的模型結構圖

模型由一個嵌入層,一個全連接層已經一個softmax層組成,通過訓練我們最終需要提取嵌入層的參數作為我們要的結果。具體訓練過程我這裡就不貼出來了,有興趣的同學可以去看下文章末尾的源碼。

英雄的可視化表示

將訓練結果降維後進行可視化表示,結果如下圖:

英雄信息的二維表示

可以看出同類型的英雄降維後會更相近,也都符合英雄原本的定位。

英雄相似度

寫了個函數來計算與給定英雄最相似的10個英雄及其相似度。

def most_similar(hero_name,embeddings,hero_dict): 用於英雄相似度計算,對給定英雄,計算出與其最相近10個英雄並給出相似度 :param hero_name: 英雄名字 :param embeddings: 訓練好的模型參數 :param hero_dict: 英雄字典 :return: 最相近的英雄及其相似度 #正則化參數 normalized_embeddings = embeddings / (embeddings ** 2).sum(axis=1).reshape((-1, 1)) ** 0.5 #將英雄字典的key和value互換,新字典可以通過英雄名來訪問英雄id new_dict = {v:k for k,v in hero_dict.items()} #allname列表用於判斷輸入的英雄是否在字典內 allname = [] for id,name in hero_dict.items(): allname.append(name) if hero_name in allname: w = new_dict[hero_name] v = normalized_embeddings[w] sims = np.dot(normalized_embeddings, v) sort = sims.argsort()[::-1] sort = sort[sort > 0] return pd.Series([(hero_dict[i],sims[i]) for i in sort[:10]]) else: return 請輸入正確的英雄名稱

部分測試結果如下:

冰女的相似度

敵法的相似度

發條的相似度

藍貓的相似度

猛獁的相似度

基本是符合人們對於英雄定位的認知。

總結

將dota2vec的參數用於遊戲預測,我嘗試了幾個模型之後發現與獨熱編碼和普通的嵌入層也沒有太大的準確率差別。我的理解是當數據量充足的情況下,預訓練的嵌入層對於預測並沒有太大的幫助,如果有海量數據可能還會影響模型的結果。

但是如果實在一個小的數據集下,原本的數據量不足以支撐複雜模型,預訓練的嵌入層就可以取得更好的效果。比如在職業比賽中,一個版本的比賽數據可能不到1000場,如果有正常的模型很難去擬合,但是用預訓練的嵌入層可以取得還不錯的效果。

最後該文章的源碼:

wansunwu/dota2vec?

github.com圖標

感興趣的同學可以去跑一下,裡面也有一個6w+場的vh比賽數據集,可以用於跑一些自己的預測模型。


推薦閱讀:

TAG:機器學習 | 電子競技 |