<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Keras構(gòu)建多輸入和多輸出模型

          共 7552字,需瀏覽 16分鐘

           ·

          2021-01-22 22:58




          本文含?7496?37?圖表截屏
          建議閱讀?38?分鐘



          1
          數(shù)據(jù)分析


          在本貼中使用的是從 1985 年到?2018 年美國大學(xué)籃球比賽 (US College Basketball tournament games)數(shù)據(jù)。它屬于 NCAA 下面的籃球比賽,始于每年的十一月下旬,跨時四個月,約在三月初左右結(jié)束常規(guī)賽 (season)。在三月初常規(guī)賽季結(jié)束后,絕大多數(shù)聯(lián)盟都會取該聯(lián)盟的前八名球隊,交叉配對 (第一名對第八名,第二名對第七名,以此類推)進行新一輪一場定勝負的錦標賽 (tourament)

          ?

          讀取常規(guī)賽和錦標賽的數(shù)據(jù),發(fā)現(xiàn)前者比后者的數(shù)據(jù)量大很多,而本貼的目標就是用常規(guī)賽數(shù)據(jù)來訓(xùn)練神經(jīng)網(wǎng)絡(luò)再預(yù)測錦標賽結(jié)果。首先讀取數(shù)據(jù)并查看數(shù)據(jù)特征。

          season = pd.read_csv('season.csv')tourney?=?pd.read_csv('tourney.csv')
          season.info()
          <class?'pandas.core.frame.DataFrame'>
          RangeIndex: 312178?entries, 0?to 312177
          Data columns (total 8?columns):
          ?# Column Non-Null Count Dtype
          --- ------ -------------- -----
          ?0???season 312178?non-null??int64
          ?1???team_1 312178?non-null??int64
          ?2???team_2 312178?non-null??int64
          ?3???home 312178?non-null??int64
          ?4???score_diff 312178?non-null??int64
          ?5???score_1 312178?non-null??int64
          ?6???score_2 312178?non-null??int64
          ?7???won 312178?non-null??int64
          dtypes: int64(8)
          memory usage: 19.1?MB


          tourney.info()
          <class?'pandas.core.frame.DataFrame'>
          RangeIndex: 4234?entries, 0?to 4233
          Data columns (total 9?columns):
          ?# Column Non-Null Count Dtype
          --- ------ -------------- -----
          ?0???season 4234?non-null???int64
          ?1???team_1 4234?non-null???int64
          ?2???team_2 4234?non-null???int64
          ?3???home 4234?non-null???int64
          ?4???seed_diff 4234?non-null???int64
          ?5???score_diff 4234?non-null???int64
          ?6???score_1 4234?non-null???int64
          ?7???score_2 4234?non-null???int64
          ?8???won 4234?non-null???int64
          dtypes: int64(9)
          memory usage: 297.8?KB


          前者有 8 個特征,而后者有 9 個特征,多了一個 seed_diff。球隊打完常規(guī)賽后會排名,按照名次來打錦標賽,這個 seed_diff?就是兩隊的排名差。訓(xùn)練一個模型,輸入是排名差,輸出是比分差 (score_diff)。


          • 所有排名以 1 到 16 來表示,那么排名差的范圍從 -15 到 15

          • 比分差大概范圍從 -50 到 50


          打印出錦標賽數(shù)據(jù)的前五行,發(fā)現(xiàn)隊伍的字符串都由整數(shù)來編碼了。再者該數(shù)據(jù)是對稱的,比如行?0 4,是隊伍 288 和?73 的一場比賽結(jié)果,但分別把 288 當作 team_1 team_2,因此兩行中的 seed_diff score_diff 都互為相反數(shù)。


          tourney.head()


          有了 NCAA 數(shù)據(jù),在接下三節(jié)里構(gòu)建簡單模型、多輸入模型 (multi-input model) 和多輸出模型 (multi-output model)



          2
          簡單模型


          2.1

          知識回顧



          雖然 Keras 構(gòu)建的都是神經(jīng)網(wǎng)絡(luò),但也能構(gòu)建線性回歸和對率回歸模型,因為兩種模型都是神經(jīng)網(wǎng)絡(luò)的特殊形式,即不帶隱含層。再精簡一步,對于單變量線性回歸和對率回歸模型,那么該神經(jīng)網(wǎng)絡(luò)就只有一個輸入和一個輸出,示意圖如下:



          上圖中 ?是輸入,?是激活函數(shù),對于線性回歸 ;對于對率回歸 ,因此 ?將輸入轉(zhuǎn)換成輸出。從功能上講,Keras 將輸入和輸出類比成張量 (tensor),將函數(shù)類比成層 (layer),將輸入經(jīng)過若干層得到輸出的流程類比成模型 (model)。結(jié)合 Keras 中定義的示意圖如下:



          根據(jù)上圖在牢記以下四點便可以輕松在 Keras 中構(gòu)建模型了:


          1. Input()中形狀參數(shù)代表輸入維度,Input((1,))指輸入張量是一維標量

          2. Dense()中參數(shù)代表輸出維數(shù),Dense(1)指輸出一個標量

          3. 層函數(shù)作用在張量上并返回另一個張量,這兩個張量分別稱為該層的輸入張量和輸出張量

          4. 構(gòu)建模型只需將最初的輸入張量和最終的輸出張量“捆綁”在一起即可

          ?

          趁熱打鐵用代碼鞏固以上知識,首先引入需要的模塊,Input 創(chuàng)建輸入張量,Dense 創(chuàng)建層,Model 構(gòu)建模型,plot_model 可視模型。


          from keras.layers import Input, Densefrom keras.models import Modelfrom?keras.utils?import?plot_model


          Input()創(chuàng)建輸入張量,檢查其類型是 Tensor,形狀是 (None, 1)None 指的是每批訓(xùn)練的數(shù)據(jù)個數(shù),通常在訓(xùn)練時?fit() 函數(shù)中?batch_size 參數(shù)決定。

          input_tensor = Input(shape=(1,))print(type(input_tensor),?'\n',?input_tensor)
          'tensorflow.python.framework.ops.Tensor'> 
          ?Tensor("input_1:0", shape=(None, 1), dtype=float32)



          Dense()創(chuàng)建輸出層,檢查其類型是 layers,是層對象。

          output_layer = Dense(1)print(type(output_layer),?'\n',?output_layer)
          'tensorflow.python.keras.layers.core.Dense'> 
          ?python.keras.layers.core.Dense object at 0x7fb1df536e80>



          將輸出張量傳入層得到輸出張量,檢查其類型是 Tensor,形狀是 (None, 1)

          output_tensor = output_layer(input_tensor)print(type(output_tensor),?'\n',?output_tensor)
          'tensorflow.python.framework.ops.Tensor'> 
          ?Tensor("dense/BiasAdd:0", shape=(None, 1), dtype=float32)



          Model()創(chuàng)建模型,將輸入和輸出張量“綁在”一起。檢查其類型是 Functional,是函數(shù)對象。

          model = Model(input_tensor, output_tensor)print(type(model),?'\n',?model)
          'tensorflow.python.keras.engine.functional.Functional'> 
          ?python.keras.engine.functional.Functional object at 0x7fb1df5591d0>



          模型創(chuàng)建完后,用 plot_model()函數(shù)可視化網(wǎng)絡(luò)結(jié)構(gòu)。

          plot_model(model, to_file='model.png')



          還可用 .summary()函數(shù)來打出網(wǎng)絡(luò)每層信息,以及參數(shù)總數(shù)。

          model.summary()


          根據(jù)上面信息發(fā)現(xiàn) Input 也當成一層了,之前提到過層其實類比函數(shù),但輸入只是一個張量,如真要當成函數(shù),那么對應(yīng)的就是個自身函數(shù) f(x) = x。在 Dense 層對應(yīng)的參數(shù)是 2,因為多了一個偏置項,但這些細節(jié)沒有在上面可視圖中體現(xiàn)。補充完細節(jié)的示意圖如下:


          最后用 .compile()函數(shù)來編譯模型,在函數(shù)中設(shè)定優(yōu)化器、損失函數(shù)和監(jiān)控指標等參數(shù)。

          model.compile(optimizer='adam', loss='mae', metrics=['accuracy'])



          2.2

          線性回歸模型



          2010 年之前的錦標賽當作訓(xùn)練集,2011年之后的錦標賽當作測試集。構(gòu)建-編譯-擬合-評估走一波。


          該模型是單變量線性回歸 y = wx + b,順著模型調(diào)出最后一層再使用 get_weights() 方法打印權(quán)重,并可視化擬合效果。

          w, b = model.layers[1].get_weights()print(w,?b)
          [[1.2168913]] [0.00527138]


          plt.scatter(test['seed_diff'], test['score_diff'])x = np.linspace(test['seed_diff'].min(),test['seed_diff'].max(), 200)plt.plot(?x,?w[0]*x+b,?color='red'?);



          2.3

          對率回歸模型




          該模型是單變量對率回歸?,調(diào)出最后一層再使用 get_weights() 方法打印權(quán)重,并可視化預(yù)測結(jié)果。標簽中的勝負各占一半,但該極簡模型預(yù)測出來的勝比負略多一些。

          w, b = model.layers[1].get_weights()print(w,?b)
          [[0.16914853]] [0.00290928]


          results = test[['seed_diff','won']]preds = model.predict(test['seed_diff'])a = np.zeros(preds.shape, dtype=int)a[preds>=0.5] = 1results['pred_won'] = aplt.figure( figsize=(8,4), dpi=100 )plt.subplot(1,2,1)sns.countplot(data=results, x='won')plt.subplot(1,2,2)sns.countplot(data=results,?x='pred_won')



          3
          多輸入模型


          上節(jié)只用了 seed_diff 一個特征來構(gòu)建模型,本節(jié)用隊伍?ID team_1 team_2 和主客場 home 來建模。首先引入必要的模塊。

          from keras.layers import Input, Dense, Embedding, Flatten, Substract, Concatenate


          嵌入層 (Embedding Layer)

          特征 team_1 和 team_2 的值類型雖然是整數(shù),但本質(zhì)上是個類別型標簽 (categorical label),強隊對應(yīng)的 team 值不見得大,弱隊對應(yīng)的 team 值也不見得小,因此不能將它們當整數(shù)用。通常使用獨熱編碼(one-hot encoding) 向量化,但有兩個缺點:一是向量之間缺乏有意義的關(guān)系,二是總共有10000 多支球隊而向量過于稀疏。解決這些問題的方法是使用嵌入層,將高維稀疏向量轉(zhuǎn)換為低維稠密向量。

          ?

          具體而言,構(gòu)建一個嵌入層代表團隊實力 (team strengh),輸入維度 input_dim 就是所有隊伍個數(shù),輸出維度 output_dim為 1,即用一個標量代表團隊實力值 (類比 word2vec 中用 300 維的向量代表一個詞)。每個輸入長度 input_length 為 1,因為 team_1 的值就是一個標量。



          嵌入層本質(zhì)就是查找表 (lookup table),將輸入team ID 和團隊實力一一對應(yīng),接著將所有球隊的實力值打平作為“團隊實力模型”的輸出。



          嵌入層首先用獨熱編碼將 Team ID 裝成向量,再通過查找表矩陣(元素是訓(xùn)練出來的) 獲取權(quán)重,最后打平拼接起來。整套流程的可視圖如下。



          球隊個數(shù)為 10,888,由于輸出維度是?1,那么對應(yīng)的參數(shù)也是 10,888


          team_strength_model.summary()

          plot_model(team_strength_model)


          共享層 (Shared Layer)

          數(shù)據(jù)中有 team_1 team_2,如果任何一對球隊互相比賽,模型就可以預(yù)測得分,即便這兩隊之前從未參加過比賽。此外無論是主隊還是客隊,它們強度等級相同。為此,可使用一個共享層,即重用上面模型team_strength_model()


          了解了每隊的實力后,有兩種處理方式:


          1. 相減層 (Substract Layer)

          2. 拼接層 (Concatenate Layer)

          ?

          先看相減層,對 team_1 和 team_2 實力相減來確定贏得比賽的隊。這有點像比賽委員會使用的種子,也是衡量團隊實力的標準。但是之后將不使用種子差異來預(yù)測得分差異,而是使用自己的團隊實力模型差異來預(yù)測得分差異。



          可視化該模型,發(fā)現(xiàn) Team-1-In Team-2-In 共享之前構(gòu)建好的“團隊實力”模型,得出的兩組實力值在“相減層”中做差值。


          plot_model(model)


          現(xiàn)在有兩個輸入,將它們傳入列表作為 model.fit() 的參數(shù)。



          眾所周知籃球中有一個有據(jù)可查的主隊優(yōu)勢,因此將向模型中添加新的輸入以捕獲這種效果。該模型將具有三個特征?team_1team_2?h ome,前兩個用嵌入層轉(zhuǎn)成“團隊實力”,而 home?是一個二進制變量,如果?team_1?作為主隊比賽為?1;否則為?0

          ?

          使用拼接層將兩隊的實力、主客場結(jié)合在一起,然后將結(jié)果傳遞給稠密層。



          可視化該模型,發(fā)現(xiàn) Team-1-In 和?Team-2-In 共享之前構(gòu)建好的“團隊實力”模型,得出的兩組實力值和額外的主客場在“拼接層”中做合并,最后連接一個稠密層。

          plot_model(model)


          現(xiàn)在有三個輸入,將它們傳入列表作為 model.fit() 的參數(shù),和上面兩個輸入的代碼比較,唯一的區(qū)別就是列表從包含兩個元素增加到三個元素。由此可見?Keras 寫起來真的非常靈活和優(yōu)雅。



          打印嵌入層 (layers[2]) 和稠密層 (layers[5])?的參數(shù),具體索引哪層可參考 model.summary()的信息。



          嵌入層中的參數(shù)有 10,888 個,而稠密層中的參數(shù)有 4 個,包括 3 個 w 和 1 個 b。


          堆積法 (Stacking)

          之前使用常規(guī)賽模型對錦標賽數(shù)據(jù)進行了預(yù)測,效果不錯,因此可將常規(guī)賽模型預(yù)測作為錦標賽模型的輸入,能進一步提高模型預(yù)測效果,這是“模型堆疊”的一種形式。首先用常規(guī)賽季模型為基礎(chǔ),并根據(jù)錦標賽數(shù)據(jù)進行預(yù)測,將此預(yù)測作為新列添加到錦標賽數(shù)據(jù)中。

          tourney['pred'] = model.predict([tourney['team_1'], ?????????????????????????????????tourney['team_2'],??????????????????????????????????tourney['home']])


          該模型的輸入是錦標賽數(shù)據(jù)中 'seed_diff' 'pred' 兩列,而輸出是得分差異。



          在測試集得到的結(jié)果 9.13 比之前的?10.09 更好一些。




          4
          多輸出模型


          本節(jié)將構(gòu)建具有多個輸出的神經(jīng)網(wǎng)絡(luò),這些神經(jīng)網(wǎng)絡(luò)可用于


          • 解決具有多個目標的回歸問題。

          • 同時解決回歸問題和分類問題。

          ?

          用錦標賽數(shù)據(jù)來建立一個做兩個預(yù)測的模型,輸入是兩隊的種子差異,輸出它們得分。注意代碼中褐色部分,為什么使用這樣的學(xué)習(xí)率 lr、期數(shù)epochs 和批大小 batch_size?通過調(diào)節(jié)超參數(shù),在 Keras 下篇后會細講。



          由于該模型是單輸入雙輸出,那么兩個回歸模型都有各自的 w 和 b,參數(shù)一共有 4 個。


          multi_reg_model.summary()


          打印參數(shù)發(fā)現(xiàn)兩隊得分的模型為



          由于 x 代表的是種子差,其均值為 0,那么兩隊得分的均值大概就是 70.9。對于一隊,排名差距增加一個單位,分數(shù)可增加 0.63?分,對于二隊,排名差距增加一個單位 (二隊增加相當于一隊減少),分數(shù)可增加 0.54?分。

          w, b = multi_reg_model.layers[-1].get_weights()print(w, w.shape)print(b,?b.shape)
          [[ 0.62823033 -0.54407144]] (1, 2)
          [70.91642 70.94076]?(2,)


          計算真實種子差的均值得到是 0,因為該數(shù)據(jù)是完全對稱的,兩隊一場比賽分為兩條數(shù)據(jù)記錄。兩隊得分的均值為 71.8,跟上面模型學(xué)到的 70.9 也很接近。

          train[['seed_diff','score_1','score_2']].mean()
          seed_diff?????0.000000
          score_1??????71.786711
          score_2??????71.786711
          dtype: float64



          接著將創(chuàng)建另一種類型的兩輸出模型。 它不僅能預(yù)測得分差異,還然后預(yù)測一隊贏得比賽的概率。該模型非常酷,它將同時進行分類和回歸。



          由于該模型是單輸入雙輸出,那么線性回歸和對率回歸模型都有各自的 w 和 b,參數(shù)一共有 4 個。


          multi_regcls_model.summary()

          plot_model(multi_regcls_model)


          由上圖可知用于對率回歸的層緊接著用于線性回歸的層,因此分別從 layers[1] layers[2] 獲取對應(yīng)的參數(shù)。



          用上面的結(jié)果可看出兩隊種子每相差一位,比分就相差 1.21 分。使用 tf.keras 中的 sigmoid() 函數(shù),將訓(xùn)練好的權(quán)重和偏置帶入,得到當一隊比二隊多 1?分的時候,一隊的勝率為 0.53;當一隊比二隊少 10 分的時候,一隊的勝率為 0.21







          總結(jié):在本貼中我們復(fù)習(xí)了 Keras 中構(gòu)建、編譯、擬合和評估模型的步驟,并從簡單模型開始講解,到多輸入模型 (介紹了嵌入層、共享層、合并層和堆積法等知識點),到多輸出模型 (同時做兩個回歸、同時做回歸和分類)。


          Stay Tuned!


          瀏覽 215
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产九九九九九九 | 一级黄色免费视屏 | 日本高潮视频在线观看 | 乱轮小说网站日韩 | 色老扳AV |