3
3
"""
4
4
5
5
import tensorflow as tf
6
+ import keras
6
7
import numpy as np
8
+ from typing import Any , Optional , Sequence , Tuple , List
9
+
10
+ NDArray = Any
11
+ kwargus = Any
7
12
8
13
9
14
class bagging : # A.K.A. voting
10
- def __init__ (self ):
11
- self .models = []
12
- self .is_trained = []
15
+ def __init__ (self ) -> None :
16
+ self .models : List [ keras . engine . functional . Functional ] = []
17
+ self .model_trained : List [ bool ] = []
13
18
self .count = 0
14
19
self .need_confidence = True # Help in reducing numbers of get_confidence runs
15
20
self .permit_train = False
16
21
17
- def append (self , model , is_trained ) :
22
+ def append (self , model : keras . engine . functional . Functional , model_trained : bool ) -> None :
18
23
"""
19
24
Add model to the voting method
20
25
"""
21
26
self .models .append (model )
22
- self .is_trained .append (is_trained )
27
+ self .model_trained .append (model_trained )
23
28
self .count += 1
24
29
25
- def __train_model (self , i , ** kwargs ) :
30
+ def __train_model (self , i : int , ** kwargs : kwargus ) -> None :
26
31
"""
27
32
Train a model if it isn't trained already
28
33
"""
29
- if not self .is_trained [i ]:
34
+ if not self .model_trained [i ]:
30
35
self .need_confidence = True
31
- self .is_trained [i ] = True
32
- self .models [i ]
36
+ self .model_trained [i ] = True
33
37
self .models [i ].trainable
34
38
self .models [i ].fit (** kwargs )
35
39
36
- def train (self , ** kwargs ) :
40
+ def train (self , ** kwargs : kwargus ) -> None :
37
41
"""
38
42
Train all models in the class, **kwargs expect to receive the argus that can be directly sent to tf.fit
39
43
Expected to be run after finishing compile
40
44
"""
41
45
if not self .permit_train :
42
- raise Exception ("Needed to be compiled before training" )
46
+ #raise Exception("Needed to be compiled before training")
47
+ raise ValueError ()
43
48
for i in range (self .count ):
44
49
if "verbose" in kwargs :
45
50
if kwargs ["verbose" ] == 1 :
@@ -48,15 +53,15 @@ def train(self, **kwargs):
48
53
print ("Model " , i + 1 , "/" , self .count , " is training..." )
49
54
self .__train_model (i , ** kwargs )
50
55
51
- def compile (self , ** kwargs ) :
56
+ def compile (self , ** kwargs : kwargus ) -> None :
52
57
"""
53
58
Compile code
54
59
"""
55
60
self .permit_train = True
56
61
for i in range (self .count ):
57
62
self .models [i ].compile (** kwargs )
58
63
59
- def __get_confidence (self , model_index , input ) :
64
+ def __get_confidence (self , model_index : int , input : NDArray ) -> NDArray :
60
65
"""
61
66
Get the confidence value that is needed by voting.
62
67
Number of calling this function is reduced by self.need_confidence
@@ -73,65 +78,45 @@ def __get_confidence(self, model_index, input):
73
78
More voting strategies can be added beneath, a single function, and a if function in self.predict
74
79
"""
75
80
76
- def __voting_weight (self , array ) :
81
+ def __voting_weight (self , array : NDArray ) -> NDArray :
77
82
result = []
78
83
for i in array :
79
84
result .append (self .__voting_weight_single (i ))
80
- return result
85
+ return np . array ( result )
81
86
82
- def __voting_most (self , array ):
83
- result = []
84
- for i in array :
85
- result .append (self .__voting_most_single (i ))
87
+ def __voting_average (self , array : NDArray ) -> NDArray :
88
+ result = np .mean (array , axis = 1 )
86
89
return result
87
90
88
- def __voting_average (self , array ):
89
- result = []
90
- for i in array :
91
- result .append (self .__voting_average_single (i ))
92
- return result
93
-
94
- def __voting_weight_single (self , array ):
91
+ def __voting_weight_single (self , array : NDArray ) -> float :
95
92
opp_array = np .ones (len (array )) - array
96
93
weight = np .absolute (opp_array - array )
97
94
weight_sum = np .sum (weight )
98
95
weight = weight / weight_sum
99
96
result = array * weight
100
- return np .sum (result )
101
-
102
- def __voting_most_single (self , array ):
103
- weight = array .size
104
- result = 0
105
- for i in array :
106
- result += i / weight
107
- return result
108
-
109
- def __voting_average_single (self , array ):
110
- result = array / array .size
111
- return np .sum (result )
97
+ return float (np .sum (result ))
112
98
113
- def predict (self , input_data , voting_policy : str = "none" ) :
99
+ def predict (self , input_data : NDArray , voting_policy : str = "None" ) -> NDArray :
114
100
"""
115
101
Input data is expected to be a 2D array that the first layer is different input data (into the trained models)
116
102
"""
117
103
if self .need_confidence :
118
104
predictions = []
119
105
for i in range (self .count ):
120
106
predictions .append (np .array (self .__get_confidence (i , input_data )))
121
- predictions = np .array (predictions )
122
- self .predictions = np .transpose (predictions )
107
+ self .predictions = np .transpose (np .array (predictions ))
123
108
if voting_policy == "weight" :
124
109
return self .__voting_weight (self .predictions )
125
110
elif voting_policy == "most" :
126
- return self .__voting_most (self .predictions )
111
+ return self .__voting_average (self .predictions )
127
112
elif voting_policy == "average" :
128
113
return self .__voting_average (self .predictions )
129
- elif voting_policy == "none" :
114
+ elif voting_policy == "None" or voting_policy == " none" :
130
115
return self .predictions
131
116
else :
132
- raise Exception ( "voting_policy must be none, weight, most, or average" )
117
+ raise ValueError ( )
133
118
134
- def __acc_binarify (self , array ) :
119
+ def __acc_binarify (self , array : NDArray ) -> NDArray :
135
120
"""
136
121
Needed for ACC test
137
122
"""
@@ -140,20 +125,20 @@ def __acc_binarify(self, array):
140
125
result .append (1 if (i > 0.5 ) else 0 )
141
126
return result
142
127
143
- def __eval_accuracy (self , input_data ) :
128
+ def __eval_accuracy (self , input_data : NDArray ) -> float :
144
129
input_data [1 ] = self .__acc_binarify (input_data [1 ])
145
130
algo = tf .keras .metrics .Accuracy ()
146
131
algo .reset_state ()
147
132
algo .update_state (input_data [0 ], input_data [1 ])
148
- return algo .result ().numpy ()
133
+ return float ( algo .result ().numpy () )
149
134
150
- def __eval_auc (self , input_data ) :
135
+ def __eval_auc (self , input_data : NDArray ) -> float :
151
136
algo = tf .keras .metrics .AUC ()
152
137
algo .reset_state ()
153
138
algo .update_state (input_data [0 ], input_data [1 ])
154
- return algo .result ().numpy ()
139
+ return float ( algo .result ().numpy () )
155
140
156
- def eval (self , input_data , evaluation_method : str = "acc" ):
141
+ def eval (self , input_data : List [ NDArray ] , evaluation_method : str = "acc" ) -> float :
157
142
"""
158
143
Expect input data to be a 2D array, which a 1D array of yTrue followed by a 1D array of yPred is expected to be the components of the 2D array
159
144
"""
@@ -162,4 +147,4 @@ def eval(self, input_data, evaluation_method: str = "acc"):
162
147
elif evaluation_method == "auc" :
163
148
return self .__eval_auc (input_data )
164
149
else :
165
- raise Exception ( "evaluation_method must be acc or auc" )
150
+ raise ValueError ( )
0 commit comments