您當前的位置:首頁 > 攝影

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

作者:由 sergio 發表于 攝影時間:2021-02-03

在上一篇文章中,我們介紹瞭如何去實現孿生網路,本篇文章將介紹,如何實現多輸入多輸出,並且自定義不同的loss以及不同的權重,實現多工訓練。具體將以 wide and deep 模型作文例子講解。

Wide & Deep 是推薦系統CTR領域一大神器,曾應用在 google play 的應用推薦之中。其主要將模型分為兩個部分,一邊是wide層,一邊是deep層,其中:

wide 層用於記憶特徵組合,提高模型的記憶性

deep 層用於泛化高階特徵組合,提高模型的泛化性

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

資料集構建

我們將使用load_breast_cancer,這是是一個二分類資料集(良性和惡性),具有30個數值型特徵。

from

sklearn。datasets

import

load_breast_cancer

demo_data

=

load_breast_cancer

()

print

demo_data

DESCR

print

demo_data

data

shape

print

demo_data

target

shape

具體介紹:[描述]

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

接著切分訓練集和測試集:

from

sklearn。model_selection

import

train_test_split

x_train_all

x_test

y_train_all

y_test

=

train_test_split

demo_data

data

demo_data

target

random_state

=

7

x_train

x_valid

y_train

y_valid

=

train_test_split

x_train_all

y_train_all

random_state

=

11

print

x_train

shape

y_train

shape

print

x_valid

shape

y_valid

shape

print

x_test

shape

y_test

shape

進行資料處理,對數值型的資料進行標準化:

from

sklearn。model_selection

import

train_test_split

x_train_all

x_test

y_train_all

y_test

=

train_test_split

demo_data

data

demo_data

target

random_state

=

7

x_train

x_valid

y_train

y_valid

=

train_test_split

x_train_all

y_train_all

random_state

=

11

print

x_train

shape

y_train

shape

print

x_valid

shape

y_valid

shape

print

x_test

shape

y_test

shape

模型構建

對於wide and deep 模型,我們將採用兩種方式進行實現,分別是 - Functional API - Model Subclassing 首先我們將實現多輸入單輸出的模型,除此之外,我們還將實現多輸出的模型,模擬進行模型的多工訓練。

多輸入單輸出

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

模型主要由兩個輸入層,兩個 dense 層, 一個 concate 層 以及一個 dense output層組成

Functional API

多輸入

input_wide

=

tf

keras

layers

Input

shape

=

15

],

name

=

‘input_wide’

input_deep

=

tf

keras

layers

Input

shape

=

15

],

name

=

‘input_deep’

hidden1

=

tf

keras

layers

Dense

30

activation

=

‘relu’

)(

input_deep

hidden2

=

tf

keras

layers

Dense

30

activation

=

‘relu’

)(

hidden1

concat

=

tf

keras

layers

concatenate

([

input_wide

hidden2

])

output

=

tf

keras

layers

Dense

1

activation

=

‘sigmoid’

)(

concat

model

=

tf

keras

models

Model

inputs

=

input_wide

input_deep

],

outputs

=

output

])

我們測試模型的結果,採用demo的資料:

# test

tf

random

set_seed

2

inputs

=

np

array

([

list

range

15

))]),

np

array

([

list

range

15

))])]

model

inputs

>>><

tf

Tensor

shape

=

1

1

),

dtype

=

float32

numpy

=

array

([[

2。8273863e-07

]],

dtype

=

float32

>

plot 模型結構:

# plot model

tf

keras

utils

plot_model

model

to_file

=

“model。png”

show_shapes

=

False

show_dtype

=

False

show_layer_names

=

True

rankdir

=

“TB”

expand_nested

=

False

dpi

=

96

Model Subclassing

對於上面的模型,我們採用 model subclassing 的方式重新實現一遍。

class

WideDeepModel

tf

keras

models

Model

):

def

__init__

self

**

kwargs

):

super

()

__init__

**

kwargs

self

hidden1

=

tf

keras

layers

Dense

30

activation

=

‘relu’

self

hidden2

=

tf

keras

layers

Dense

30

activation

=

‘relu’

self

concat

=

tf

keras

layers

concatenate

self

dense

=

tf

keras

layers

Dense

1

activation

=

‘sigmoid’

def

call

self

inputs

):

input_wide

input_deep

=

inputs

output_deep

=

self

hidden1

input_deep

output_deep

=

self

hidden2

output_deep

concat_input

=

self

concat

([

input_wide

output_deep

])

output

=

self

dense

concat_input

return

output

接著我們測試兩種實現是否一致:

# test

# load model

model

=

WideDeepModel

()

# load model by Squential

# model = tf。keras。models。Sequential([WideDeepModel(), ])

# # input_shape = [(None, 15), (None, 15)]

# # model。build(input_shape=(None, 15))

# # model。summary()

inputs

=

np

array

([

list

range

15

))])

astype

‘float32’

),

np

array

([

list

range

15

))])

astype

‘float32’

)]

model

inputs

>>>

<

tf

Tensor

shape

=

1

1

),

dtype

=

float32

numpy

=

array

([[

2。8273863e-07

]],

dtype

=

float32

>

輸出模型結構:

model。summary()

Model: “wide_deep_model_5”

_________________________________________________________________

Layer (type) Output Shape Param #

=================================================================

dense_18 (Dense) multiple 480

_________________________________________________________________

dense_19 (Dense) multiple 930

_________________________________________________________________

dense_20 (Dense) multiple 46

=================================================================

Total params: 1,456

Trainable params: 1,456

Non-trainable params: 0

_________________________________________________________________

視覺化模型:

# plot model

tf

keras

utils

plot_model

model

to_file

=

“model。png”

show_shapes

=

False

show_dtype

=

False

show_layer_names

=

True

rankdir

=

“TB”

expand_nested

=

False

dpi

=

96

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

對於model subclassing 的模型實現,我們需要視覺化模型的話,需要在 class 中實現

build_graph(self, shapes)

的方法

class

WideDeepModel

tf

keras

models

Model

):

def

__init__

self

**

kwargs

):

super

()

__init__

**

kwargs

self

hidden1

=

tf

keras

layers

Dense

30

activation

=

‘relu’

self

hidden2

=

tf

keras

layers

Dense

30

activation

=

‘relu’

self

concat

=

tf

keras

layers

concatenate

self

dense

=

tf

keras

layers

Dense

1

activation

=

‘sigmoid’

def

call

self

inputs

):

input_wide

input_deep

=

inputs

output_deep

=

self

hidden1

input_deep

output_deep

=

self

hidden2

output_deep

concat_input

=

self

concat

([

input_wide

output_deep

])

output

=

self

dense

concat_input

return

output

def

build_graph

self

shapes

):

shape1

shape2

=

shapes

input_wide

=

tf

keras

layers

Input

shape

=

shape1

input_deep

=

tf

keras

layers

Input

shape

=

shape2

return

tf

keras

models

Model

inputs

=

input_wide

input_deep

],

outputs

=

self

call

([

input_wide

input_deep

])])

然後呼叫

plot_model

運用

model。build_graph

實現模型視覺化:

# plot model

tf

keras

utils

plot_model

model

build_graph

([(

15

),

15

)]),

to_file

=

“model。png”

show_shapes

=

False

show_dtype

=

False

show_layer_names

=

True

rankdir

=

“TB”

expand_nested

=

False

dpi

=

96

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

多輸入多輸出

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

對於模型,通常只有一個輸出,也只有一個訓練任務,但是現在的趨勢是,我們一般模型有多個任務同時訓練,有多個輸出,然後每個人物有自己的訓練目標,並且具有不同的任務權重,下面我們將利用上述的wide & deep 模型,實現兩個output,並且使用兩個訓練目標。

Functional API 實現

input_wide

=

tf

keras

layers

Input

shape

=

15

],

name

=

‘input_wide’

input_deep

=

tf

keras

layers

Input

shape

=

15

],

name

=

‘input_deep’

hidden1

=

tf

keras

layers

Dense

30

activation

=

‘relu’

)(

input_deep

hidden2

=

tf

keras

layers

Dense

30

activation

=

‘relu’

)(

hidden1

concat

=

tf

keras

layers

concatenate

([

input_wide

hidden2

])

output1

=

tf

keras

layers

Dense

1

activation

=

‘sigmoid’

name

=

‘output_1’

)(

concat

output2

=

tf

keras

layers

Dense

1

activation

=

‘sigmoid’

name

=

‘output_2’

)(

concat

model

=

tf

keras

models

Model

inputs

=

input_wide

input_deep

],

outputs

=

output1

output2

])

model

summary

()

“”“

Model: ”model_1“

__________________________________________________________________________________________________

Layer (type) Output Shape Param # Connected to

==================================================================================================

input_deep (InputLayer) [(None, 15)] 0

__________________________________________________________________________________________________

dense_12 (Dense) (None, 30) 480 input_deep[0][0]

__________________________________________________________________________________________________

input_wide (InputLayer) [(None, 15)] 0

__________________________________________________________________________________________________

dense_13 (Dense) (None, 30) 930 dense_12[0][0]

__________________________________________________________________________________________________

concatenate_4 (Concatenate) (None, 45) 0 input_wide[0][0]

dense_13[0][0]

__________________________________________________________________________________________________

output_1 (Dense) (None, 1) 46 concatenate_4[0][0]

__________________________________________________________________________________________________

output_2 (Dense) (None, 1) 46 concatenate_4[0][0]

==================================================================================================

Total params: 1,502

Trainable params: 1,502

Non-trainable params: 0

”“”

tf

keras

utils

plot_model

model

show_layer_names

=

True

我們可以測試,看模型的輸出是什麼樣子:

tf

random

set_seed

2

# test

inputs

=

np

array

([

list

range

15

))]),

np

array

([

list

range

15

))])]

model

inputs

>>>

<

tf

Tensor

shape

=

1

1

),

dtype

=

float32

numpy

=

array

([[

2。8273863e-07

]],

dtype

=

float32

>

<

tf

Tensor

shape

=

1

1

),

dtype

=

float32

numpy

=

array

([[

0。01569781

]],

dtype

=

float32

>

可以看到,得到兩個輸出

Model Subclassing 實現

class

WideDeepModel

tf

keras

models

Model

):

def

__init__

self

**

kwargs

):

super

()

__init__

**

kwargs

self

hidden1

=

tf

keras

layers

Dense

30

activation

=

‘relu’

self

hidden2

=

tf

keras

layers

Dense

30

activation

=

‘relu’

self

concat

=

tf

keras

layers

concatenate

self

dense1

=

tf

keras

layers

Dense

1

activation

=

‘sigmoid’

name

=

‘output_1’

self

dense2

=

tf

keras

layers

Dense

1

activation

=

‘sigmoid’

name

=

‘output_2’

def

call

self

inputs

):

input_wide

input_deep

=

inputs

output_deep

=

self

hidden1

input_deep

output_deep

=

self

hidden2

output_deep

concat_input

=

self

concat

([

input_wide

output_deep

])

output1

=

self

dense1

concat_input

output2

=

self

dense2

concat_input

return

output1

output2

def

build_graph

self

shapes

):

x_wide_shape

x_deep_shape

=

shapes

input_wide

=

tf

keras

layers

Input

shape

=

15

],

name

=

‘input_wide’

input_deep

=

tf

keras

layers

Input

shape

=

15

],

name

=

‘input_deep’

inputs

=

input_wide

input_deep

return

tf

keras

models

Model

inputs

=

inputs

outputs

=

self

call

inputs

))

視覺化模型結構:

model

build_graph

([(

15

,),

15

,)])

summary

()

“”“

Model: ”model_4“

__________________________________________________________________________________________________

Layer (type) Output Shape Param # Connected to

==================================================================================================

input_5 (InputLayer) [(None, 15)] 0

__________________________________________________________________________________________________

dense_24 (Dense) (None, 30) 480 input_5[0][0]

__________________________________________________________________________________________________

input_4 (InputLayer) [(None, 15)] 0

__________________________________________________________________________________________________

dense_25 (Dense) (None, 30) 930 dense_24[1][0]

__________________________________________________________________________________________________

concatenate_12 (Concatenate) (None, 45) 0 input_4[0][0]

dense_25[1][0]

__________________________________________________________________________________________________

dense_26 (Dense) (None, 1) 46 concatenate_12[0][0]

==================================================================================================

Total params: 1,456

Trainable params: 1,456

Non-trainable params: 0

”“”

tf

keras

utils

plot_model

model

build_graph

([(

15

,),

15

,)]))

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

測試模型結果:

# test

inputs

=

np

array

([

list

range

15

))])

astype

‘float32’

),

np

array

([

list

range

15

))])

astype

‘float32’

)]

model

inputs

>>>

<

tf

Tensor

shape

=

1

1

),

dtype

=

float32

numpy

=

array

([[

2。8273863e-07

]],

dtype

=

float32

>

<

tf

Tensor

shape

=

1

1

),

dtype

=

float32

numpy

=

array

([[

0。01569781

]],

dtype

=

float32

>

我們可以看到兩種不同的實現,模型的輸出是一樣的。

訓練和測試

模型訓練完畢之後,我們需要配合 loss function 以及 optimizer進行模型compile。

compile

如果我們的模型兩個輸出設定一個loss的話,我們的compile 步驟和單輸出模型一樣:

# 單個loss

model

compile

loss

=

‘binary_crossentropy’

optimizer

=

‘adam’

metrics

=

‘accuracy’

])

callbacks

=

tf

keras

callbacks

EarlyStopping

patience

=

5

min_delta

=

1e-2

如果我們模型的輸出具有不同的loss,例如一個輸出是分類的loss,一個輸出是迴歸的loss。我們需要設定一個losses字典,對不同的輸出指定不同的loss function,其中key是輸出的output name,value是對應的loss funtion 名稱。同時我們可以設定loss的權重,具體的引數是

loss_wights

,它同樣是一個字典,key是輸出的output name,value是對應的權重。

例如下面我們模擬兩個輸出,都是二分類,目前採用的loss function 先初定一樣都是

binary_crossentropy

, 實際中大家可以根據需要選擇,loss weights 權重採用第一個loss 佔1,第二個loss權重為2。

## specific loss and loss weights

losses

=

{

“output_1”

“binary_crossentropy”

“output_2”

“binary_crossentropy”

}

loss_weights

=

{

“output_1”

1。0

“output_2”

2

}

model

compile

loss

=

losses

loss_weights

=

loss_weights

metrics

=

‘accuracy’

])

train

我麼將訓練集的前15列作為 wide 部分的輸入,後15列作為 deep 部分的輸入, 訓練100輪,設定early stopping。

x_train_scaled_wide

=

x_train_scaled

[:,

15

x_train_scaled_deep

=

x_train_scaled

[:,

15

:]

x_valid_scaled_wide

=

x_valid_scaled

[:,

15

x_valid_scaled_deep

=

x_valid_scaled

[:,

15

:]

x_test_scaled_wide

=

x_test_scaled

[:,

15

x_test_scaled_deep

=

x_test_scaled

[:,

15

:]

history

=

model

fit

([

x_train_scaled_wide

x_train_scaled_deep

],

y_train

validation_data

=

([

x_valid_scaled_wide

x_valid_scaled_deep

],

y_valid

),

epochs

=

100

callbacks

=

callbacks

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

evaluation

我們可以畫出我們的學習曲線:

def

plot_learning_curves

history

):

pd

DataFrame

history

history

plot

figsize

=

8

5

))

plt

grid

True

plt

gca

()

set_ylim

0

1

plt

show

()

plot_learning_curves

history

可以看出,我們這邊展示了兩個輸出的loss, 並且可以看到 output_2_loss 更低,因為我們令它的權重更大,所以optimizer 會讓它更低從何使得最終的loss降低更多。

Tensorflow2.0 models 三種實現入門3(wide and deep 實現)

我們接著進行model 的evaluation。可以得到如下結果

model

evaluate

([

x_test_scaled_wide

x_test_scaled_deep

],

y_test

“”“

5/5 [==============================] - 0s 2ms/step - loss: 0。2223 - output_1_loss: 0。0675 - output_2_loss: 0。0774 - output_1_accuracy: 0。9790 - output_2_accuracy: 0。9720

[0。22231410443782806,

0。06749054789543152,

0。07741177827119827,

0。9790209531784058,

0。9720279574394226]

”“”

我們得到了一個數組,陣列中的值分別代表了[總的loss,output1的loss,output2的loss,output1的accuracy,output2的accuracy] 我們從這個值也能看到 總的

loss = output1的loss + 2* output2的loss。

和我們定義的 loss weights 一致。

Reference

tf2-study-notebook

標簽: input  Deep  tf  keras  Model