python-ldl 0.0.1__py3-none-any.whl → 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyldl/algorithms/__init__.py +26 -0
- pyldl/algorithms/_algorithm_adaptation.py +257 -0
- pyldl/algorithms/_classifier.py +133 -0
- pyldl/algorithms/_ensemble.py +99 -0
- pyldl/algorithms/_incomplete.py +45 -0
- pyldl/algorithms/_label_enhancement.py +328 -0
- pyldl/algorithms/_ldl_lrr.py +49 -0
- pyldl/algorithms/_ldl_scl.py +67 -0
- pyldl/algorithms/_ldlf.py +89 -0
- pyldl/algorithms/_problem_transformation.py +70 -0
- pyldl/algorithms/_specialized_algorithms.py +87 -0
- pyldl/algorithms/_ssg_ldl.py +58 -0
- pyldl/algorithms/base.py +226 -0
- pyldl/applications/__init__.py +0 -0
- pyldl/applications/emphasis_selection.py +145 -0
- pyldl/applications/facial_emotion_recognition.py +60 -0
- pyldl/applications/lesion_counting.py +137 -0
- pyldl/matlab_algorithms/AA_BP_fit.m +1 -1
- pyldl/matlab_algorithms/AA_BP_predict.m +7 -7
- pyldl/matlab_algorithms/AA_KNN.m +3 -3
- pyldl/matlab_algorithms/BFGS_Process.m +13 -13
- pyldl/matlab_algorithms/PT_Bayes_fit.m +1 -1
- pyldl/matlab_algorithms/PT_Bayes_predict.m +2 -2
- pyldl/matlab_algorithms/PT_SVM_fit.m +2 -2
- pyldl/matlab_algorithms/PT_SVM_predict.m +2 -2
- pyldl/matlab_algorithms/SA_BFGS_fit.m +2 -2
- pyldl/matlab_algorithms/SA_BFGS_predict.m +1 -1
- pyldl/matlab_algorithms/SA_IIS_fit.m +6 -6
- pyldl/matlab_algorithms/SA_IIS_predict.m +1 -1
- pyldl/matlab_algorithms/__init__.py +158 -158
- pyldl/metrics.py +98 -98
- pyldl/utils.py +135 -91
- {python_ldl-0.0.1.dist-info → python_ldl-0.0.2.dist-info}/METADATA +187 -170
- python_ldl-0.0.2.dist-info/RECORD +38 -0
- {python_ldl-0.0.1.dist-info → python_ldl-0.0.2.dist-info}/WHEEL +1 -1
- pyldl/algorithms.py +0 -1373
- pyldl/rprop.py +0 -75
- python_ldl-0.0.1.dist-info/RECORD +0 -23
- {python_ldl-0.0.1.dist-info → python_ldl-0.0.2.dist-info}/LICENSE +0 -0
- {python_ldl-0.0.1.dist-info → python_ldl-0.0.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from ._problem_transformation import PT_Bayes, PT_SVM, LDSVR
|
|
2
|
+
from ._algorithm_adaptation import AA_BP, AA_KNN, CAD, QFD2, CJS, CPNN, BCPNN, ACPNN
|
|
3
|
+
from ._specialized_algorithms import SA_BFGS, SA_IIS
|
|
4
|
+
|
|
5
|
+
from ._incomplete import IncomLDL
|
|
6
|
+
from ._classifier import LDL4C, LDL_HR, LDLM
|
|
7
|
+
from ._ensemble import DF_LDL, AdaBoostLDL
|
|
8
|
+
|
|
9
|
+
from ._ldlf import LDLF
|
|
10
|
+
from ._ldl_scl import LDL_SCL
|
|
11
|
+
from ._ldl_lrr import LDL_LRR
|
|
12
|
+
|
|
13
|
+
from ._ssg_ldl import SSG_LDL
|
|
14
|
+
|
|
15
|
+
from ._label_enhancement import FCM, KM, LP, ML, GLLE, LEVI, LIBLE
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["SA_BFGS", "SA_IIS", "AA_KNN", "AA_BP", "PT_Bayes", "PT_SVM",
|
|
19
|
+
"CPNN", "BCPNN", "ACPNN", "LDSVR",
|
|
20
|
+
"LDLF", "LDL_SCL", "LDL_LRR", "CAD", "QFD2", "CJS",
|
|
21
|
+
"DF_LDL", "AdaBoostLDL",
|
|
22
|
+
"LDL4C", "LDL_HR", "LDLM",
|
|
23
|
+
"IncomLDL",
|
|
24
|
+
"SSG_LDL",
|
|
25
|
+
"FCM", "KM", "LP", "ML", "GLLE",
|
|
26
|
+
"LEVI", 'LIBLE']
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from sklearn.neighbors import NearestNeighbors
|
|
3
|
+
from sklearn.preprocessing import OneHotEncoder
|
|
4
|
+
|
|
5
|
+
import keras
|
|
6
|
+
import tensorflow as tf
|
|
7
|
+
from keras import backend as K
|
|
8
|
+
|
|
9
|
+
from pyldl.algorithms.base import BaseLDL, BaseDeepLDL
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AA_KNN(BaseLDL):
|
|
13
|
+
|
|
14
|
+
def __init__(self,
|
|
15
|
+
k=5,
|
|
16
|
+
random_state=None):
|
|
17
|
+
|
|
18
|
+
super().__init__(random_state)
|
|
19
|
+
|
|
20
|
+
self.k = k
|
|
21
|
+
self._model = NearestNeighbors(n_neighbors=self.k)
|
|
22
|
+
|
|
23
|
+
def fit(self, X, y):
|
|
24
|
+
super().fit(X, y)
|
|
25
|
+
self._model.fit(self._X)
|
|
26
|
+
|
|
27
|
+
def predict(self, X):
|
|
28
|
+
_, inds = self._model.kneighbors(X)
|
|
29
|
+
return np.average(self._y[inds], axis=1)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AA_BP(BaseDeepLDL):
|
|
33
|
+
|
|
34
|
+
def __init__(self, n_hidden=None, n_latent=None, random_state=None):
|
|
35
|
+
super().__init__(n_hidden, n_latent, random_state)
|
|
36
|
+
|
|
37
|
+
@tf.function
|
|
38
|
+
def _loss_function(self, y, y_pred):
|
|
39
|
+
return tf.math.reduce_mean(keras.losses.mean_squared_error(y, y_pred))
|
|
40
|
+
|
|
41
|
+
def fit(self, X, y, learning_rate=5e-3, epochs=3000, batch_size=32,
|
|
42
|
+
model=None, activation='sigmoid', optimizer='SGD', X_test=None, y_test=None):
|
|
43
|
+
super().fit(X, y)
|
|
44
|
+
|
|
45
|
+
self._batch_size = batch_size
|
|
46
|
+
|
|
47
|
+
if self._n_hidden is None:
|
|
48
|
+
self._n_hidden = self._n_features * 3 // 2
|
|
49
|
+
|
|
50
|
+
self._model = model
|
|
51
|
+
if self._model is None:
|
|
52
|
+
self._model = keras.Sequential([keras.layers.InputLayer(input_shape=(self._n_features,)),
|
|
53
|
+
keras.layers.Dense(self._n_hidden, activation=activation),
|
|
54
|
+
keras.layers.Dense(self._n_outputs, activation='softmax')])
|
|
55
|
+
self._optimizer = eval(f'keras.optimizers.{optimizer}({learning_rate})')
|
|
56
|
+
data = tf.data.Dataset.from_tensor_slices((self._X, self._y)).batch(self._batch_size)
|
|
57
|
+
|
|
58
|
+
for _ in range(epochs):
|
|
59
|
+
total_loss = 0.
|
|
60
|
+
for batch in data:
|
|
61
|
+
with tf.GradientTape() as tape:
|
|
62
|
+
y_pred = self._model(batch[0])
|
|
63
|
+
loss = self._loss_function(batch[1], y_pred)
|
|
64
|
+
gradients = tape.gradient(loss, self.trainable_variables)
|
|
65
|
+
self._optimizer.apply_gradients(zip(gradients, self.trainable_variables))
|
|
66
|
+
total_loss += loss
|
|
67
|
+
|
|
68
|
+
def predict(self, X):
|
|
69
|
+
return self._model(X)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class CAD(AA_BP):
|
|
73
|
+
|
|
74
|
+
@tf.function
|
|
75
|
+
def _loss_function(self, y, y_pred):
|
|
76
|
+
def _CAD(y, y_pred):
|
|
77
|
+
return tf.reduce_mean(tf.abs(
|
|
78
|
+
tf.cumsum(y, axis=1) - tf.cumsum(y_pred, axis=1)
|
|
79
|
+
), axis=1)
|
|
80
|
+
return tf.math.reduce_sum(
|
|
81
|
+
tf.map_fn(lambda i: _CAD(y[:, :i], y_pred[:, :i]),
|
|
82
|
+
tf.range(1, self._n_outputs + 1),
|
|
83
|
+
fn_output_signature=tf.float32)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def fit(self, X, y, learning_rate=1e-4, epochs=500,
|
|
87
|
+
activation='relu', optimizer='Adam'):
|
|
88
|
+
return super().fit(X, y, learning_rate, epochs, activation, optimizer)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class QFD2(AA_BP):
|
|
92
|
+
|
|
93
|
+
@tf.function
|
|
94
|
+
def _loss_function(self, y, y_pred):
|
|
95
|
+
Q = y - y_pred
|
|
96
|
+
j = tf.reshape(tf.range(self._n_outputs), [self._n_outputs, 1])
|
|
97
|
+
k = tf.reshape(tf.range(self._n_outputs), [1, self._n_outputs])
|
|
98
|
+
A = tf.cast(1 - tf.abs(j - k) / (self._n_outputs - 1), dtype=tf.float32)
|
|
99
|
+
return tf.math.reduce_mean(
|
|
100
|
+
tf.linalg.diag_part(tf.matmul(tf.matmul(Q, A), tf.transpose(Q)))
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def fit(self, X, y, learning_rate=1e-4, epochs=500,
|
|
104
|
+
activation='relu', optimizer='Adam'):
|
|
105
|
+
return super().fit(X, y, learning_rate, epochs, activation, optimizer)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class CJS(AA_BP):
|
|
109
|
+
|
|
110
|
+
@tf.function
|
|
111
|
+
def _loss_function(self, y, y_pred):
|
|
112
|
+
def _CJS(y, y_pred):
|
|
113
|
+
m = 0.5 * (y + y_pred)
|
|
114
|
+
js = 0.5 * (keras.losses.kl_divergence(y, m) + keras.losses.kl_divergence(y_pred, m))
|
|
115
|
+
return tf.reduce_mean(js)
|
|
116
|
+
return tf.math.reduce_sum(
|
|
117
|
+
tf.map_fn(lambda i: _CJS(y[:, :i], y_pred[:, :i]),
|
|
118
|
+
tf.range(1, self._n_outputs + 1),
|
|
119
|
+
fn_output_signature=tf.float32)
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def fit(self, X, y, learning_rate=1e-4, epochs=500,
|
|
123
|
+
activation='relu', optimizer='Adam'):
|
|
124
|
+
return super().fit(X, y, learning_rate, epochs, activation, optimizer)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class RProp(keras.optimizers.Optimizer):
|
|
128
|
+
|
|
129
|
+
def __init__(self, init_alpha=1e-3, scale_up=1.2, scale_down=0.5, min_alpha=1e-6, max_alpha=50., **kwargs):
|
|
130
|
+
super(RProp, self).__init__(name='rprop', **kwargs)
|
|
131
|
+
self.init_alpha = K.variable(init_alpha, name='init_alpha')
|
|
132
|
+
self.scale_up = K.variable(scale_up, name='scale_up')
|
|
133
|
+
self.scale_down = K.variable(scale_down, name='scale_down')
|
|
134
|
+
self.min_alpha = K.variable(min_alpha, name='min_alpha')
|
|
135
|
+
self.max_alpha = K.variable(max_alpha, name='max_alpha')
|
|
136
|
+
|
|
137
|
+
def get_updates(self, params, gradients):
|
|
138
|
+
grads = gradients
|
|
139
|
+
shapes = [K.int_shape(p) for p in params]
|
|
140
|
+
alphas = [K.variable(np.ones(shape) * self.init_alpha) for shape in shapes]
|
|
141
|
+
old_grads = [K.zeros(shape) for shape in shapes]
|
|
142
|
+
prev_weight_deltas = [K.zeros(shape) for shape in shapes]
|
|
143
|
+
self.updates = []
|
|
144
|
+
|
|
145
|
+
for param, grad, old_grad, prev_weight_delta, alpha in zip(params, grads,
|
|
146
|
+
old_grads, prev_weight_deltas,
|
|
147
|
+
alphas):
|
|
148
|
+
|
|
149
|
+
new_alpha = K.switch(
|
|
150
|
+
K.greater(grad * old_grad, 0),
|
|
151
|
+
K.minimum(alpha * self.scale_up, self.max_alpha),
|
|
152
|
+
K.switch(K.less(grad * old_grad, 0), K.maximum(alpha * self.scale_down, self.min_alpha), alpha)
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
new_delta = K.switch(K.greater(grad, 0),
|
|
156
|
+
-new_alpha,
|
|
157
|
+
K.switch(K.less(grad, 0),
|
|
158
|
+
new_alpha,
|
|
159
|
+
K.zeros_like(new_alpha)))
|
|
160
|
+
|
|
161
|
+
weight_delta = K.switch(K.less(grad*old_grad, 0), -prev_weight_delta, new_delta)
|
|
162
|
+
|
|
163
|
+
new_param = param + weight_delta
|
|
164
|
+
|
|
165
|
+
grad = K.switch(K.less(grad*old_grad, 0), K.zeros_like(grad), grad)
|
|
166
|
+
|
|
167
|
+
self.updates.append(K.update(param, new_param))
|
|
168
|
+
self.updates.append(K.update(alpha, new_alpha))
|
|
169
|
+
self.updates.append(K.update(old_grad, grad))
|
|
170
|
+
self.updates.append(K.update(prev_weight_delta, weight_delta))
|
|
171
|
+
|
|
172
|
+
return self.updates
|
|
173
|
+
|
|
174
|
+
def get_config(self):
|
|
175
|
+
config = {
|
|
176
|
+
'init_alpha': float(K.get_value(self.init_alpha)),
|
|
177
|
+
'scale_up': float(K.get_value(self.scale_up)),
|
|
178
|
+
'scale_down': float(K.get_value(self.scale_down)),
|
|
179
|
+
'min_alpha': float(K.get_value(self.min_alpha)),
|
|
180
|
+
'max_alpha': float(K.get_value(self.max_alpha)),
|
|
181
|
+
}
|
|
182
|
+
base_config = super(RProp, self).get_config()
|
|
183
|
+
return dict(list(base_config.items()) + list(config.items()))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class CPNN(BaseDeepLDL):
|
|
187
|
+
|
|
188
|
+
def _not_proper_mode(self):
|
|
189
|
+
raise ValueError("The argument 'mode' can only be 'none', 'binary' or 'augment'.")
|
|
190
|
+
|
|
191
|
+
def __init__(self, mode='none', v=5, n_hidden=None, n_latent=None, random_state=None):
|
|
192
|
+
super().__init__(n_hidden, n_latent, random_state)
|
|
193
|
+
if mode == 'none' or mode == 'binary' or mode == 'augment':
|
|
194
|
+
self._mode = mode
|
|
195
|
+
else:
|
|
196
|
+
self._not_proper_mode()
|
|
197
|
+
self._v = v
|
|
198
|
+
|
|
199
|
+
def fit(self, X, y, learning_rate=5e-3, epochs=3000):
|
|
200
|
+
super().fit(X, y)
|
|
201
|
+
|
|
202
|
+
self._optimizer = RProp(init_alpha=learning_rate)
|
|
203
|
+
|
|
204
|
+
if self._n_hidden is None:
|
|
205
|
+
self._n_hidden = self._n_features * 3 // 2
|
|
206
|
+
|
|
207
|
+
if self._mode == 'augment':
|
|
208
|
+
one_hot = tf.one_hot(tf.math.argmax(self._y, axis=1), self.n_outputs)
|
|
209
|
+
self._X = tf.repeat(self._X, self._v, axis=0)
|
|
210
|
+
self._y = tf.repeat(self._y, self._v, axis=0)
|
|
211
|
+
one_hot = tf.repeat(one_hot, self._v, axis=0)
|
|
212
|
+
v = tf.reshape(tf.tile([1 / (i + 1) for i in range(self._v)], [X.shape[0]]), (-1, 1))
|
|
213
|
+
self._y += self._y * one_hot * v
|
|
214
|
+
|
|
215
|
+
input_shape = (self._n_features + (1 if self._mode == 'none' else self._n_outputs),)
|
|
216
|
+
self._model = keras.Sequential([keras.layers.InputLayer(input_shape=input_shape),
|
|
217
|
+
keras.layers.Dense(self._n_hidden, activation='sigmoid'),
|
|
218
|
+
keras.layers.Dense(1, activation=None)])
|
|
219
|
+
|
|
220
|
+
for _ in range(epochs):
|
|
221
|
+
with tf.GradientTape() as tape:
|
|
222
|
+
loss = self._loss(self._X, self._y)
|
|
223
|
+
gradients = tape.gradient(loss, self.trainable_variables)
|
|
224
|
+
self._optimizer.get_updates(self.trainable_variables, gradients)
|
|
225
|
+
|
|
226
|
+
def _make_inputs(self, X):
|
|
227
|
+
temp = tf.reshape(tf.tile([i + 1 for i in range(self._n_outputs)], [X.shape[0]]), (-1, 1))
|
|
228
|
+
if self._mode != 'none':
|
|
229
|
+
temp = OneHotEncoder(sparse=False).fit_transform(temp)
|
|
230
|
+
return tf.concat([tf.cast(tf.repeat(X, self._n_outputs, axis=0), dtype=tf.float32),
|
|
231
|
+
tf.cast(temp, dtype=tf.float32)],
|
|
232
|
+
axis=1)
|
|
233
|
+
|
|
234
|
+
def _call(self, X):
|
|
235
|
+
inputs = self._make_inputs(X)
|
|
236
|
+
outputs = self._model(inputs)
|
|
237
|
+
results = tf.reshape(outputs, (X.shape[0], self._n_outputs))
|
|
238
|
+
b = tf.reshape(-tf.math.log(tf.math.reduce_sum(tf.math.exp(results), axis=1)), (-1, 1))
|
|
239
|
+
return tf.math.exp(b + results)
|
|
240
|
+
|
|
241
|
+
def _loss(self, X, y):
|
|
242
|
+
return tf.math.reduce_mean(keras.losses.kl_divergence(y, self._call(X)))
|
|
243
|
+
|
|
244
|
+
def predict(self, X):
|
|
245
|
+
return self._call(X)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class BCPNN(CPNN):
|
|
249
|
+
|
|
250
|
+
def __init__(self, **params):
|
|
251
|
+
super().__init__(mode='binary', **params)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class ACPNN(CPNN):
|
|
255
|
+
|
|
256
|
+
def __init__(self, **params):
|
|
257
|
+
super().__init__(mode='augment', **params)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import keras
|
|
2
|
+
import tensorflow as tf
|
|
3
|
+
|
|
4
|
+
from pyldl.metrics import score
|
|
5
|
+
from pyldl.algorithms.base import BaseDeepLDL, BaseDeepLDLClassifier, DeepBFGS
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LDL4C(BaseDeepLDLClassifier, DeepBFGS):
|
|
9
|
+
|
|
10
|
+
def __init__(self, n_hidden=None, n_latent=None, random_state=None):
|
|
11
|
+
super().__init__(n_hidden, n_latent, random_state)
|
|
12
|
+
|
|
13
|
+
@tf.function
|
|
14
|
+
def _loss(self, X, y):
|
|
15
|
+
y_pred = self._model(X)
|
|
16
|
+
top2 = tf.gather(y_pred, self._top2, axis=1, batch_dims=1)
|
|
17
|
+
margin = tf.reduce_sum(tf.maximum(0., 1. - (top2[:, 0] - top2[:, 1]) / self._rho))
|
|
18
|
+
mae = keras.losses.mean_absolute_error(y, y_pred)
|
|
19
|
+
return tf.reduce_sum(self._entropy * mae) + self._alpha * margin + self._beta * BaseDeepLDL._l2_reg(self._model)
|
|
20
|
+
|
|
21
|
+
def fit(self, X, y, max_iterations=50, alpha=1e-2, beta=1e-6, rho=1e-2):
|
|
22
|
+
super().fit(X, y)
|
|
23
|
+
|
|
24
|
+
self._alpha = alpha
|
|
25
|
+
self._beta = beta
|
|
26
|
+
self._rho = rho
|
|
27
|
+
|
|
28
|
+
self._top2 = tf.math.top_k(self._y, k=2)[1]
|
|
29
|
+
self._entropy = tf.cast(-tf.reduce_sum(self._y * tf.math.log(self._y) + 1e-7, axis=1), dtype=tf.float32)
|
|
30
|
+
|
|
31
|
+
self._model = keras.Sequential(
|
|
32
|
+
[keras.layers.InputLayer(input_shape=self._n_features),
|
|
33
|
+
keras.layers.Dense(self._n_outputs, activation="softmax")])
|
|
34
|
+
|
|
35
|
+
self._optimize_bfgs(self._model, self._loss, self._X, self._y, max_iterations=max_iterations)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class LDL_HR(BaseDeepLDLClassifier, DeepBFGS):
|
|
39
|
+
|
|
40
|
+
def __init__(self, n_hidden=None, n_latent=None, random_state=None):
|
|
41
|
+
super().__init__(n_hidden, n_latent, random_state)
|
|
42
|
+
|
|
43
|
+
@tf.function
|
|
44
|
+
def _loss(self, X, y):
|
|
45
|
+
y_pred = self._model(X)
|
|
46
|
+
|
|
47
|
+
highest = tf.gather(y_pred, self._highest, axis=1, batch_dims=1)
|
|
48
|
+
rest = tf.gather(y_pred, self._rest, axis=1, batch_dims=1)
|
|
49
|
+
margin = tf.reduce_sum(tf.maximum(0., 1. - (highest - rest) / self._rho))
|
|
50
|
+
|
|
51
|
+
real_rest = tf.gather(y, self._rest, axis=1, batch_dims=1)
|
|
52
|
+
rest_mae = tf.reduce_sum(keras.losses.mean_absolute_error(real_rest, rest))
|
|
53
|
+
|
|
54
|
+
mae = tf.reduce_sum(keras.losses.mean_absolute_error(self._l, y_pred))
|
|
55
|
+
|
|
56
|
+
return mae + self._alpha * margin + self._beta * rest_mae + self._gamma * BaseDeepLDL._l2_reg(self._model)
|
|
57
|
+
|
|
58
|
+
def fit(self, X, y, max_iterations=50, alpha=1e-2, beta=1e-2, gamma=1e-6, rho=1e-2):
|
|
59
|
+
super().fit(X, y)
|
|
60
|
+
|
|
61
|
+
self._alpha = alpha
|
|
62
|
+
self._beta = beta
|
|
63
|
+
self._gamma = gamma
|
|
64
|
+
self._rho = rho
|
|
65
|
+
|
|
66
|
+
temp = tf.math.top_k(self._y, k=self._n_outputs)[1]
|
|
67
|
+
self._highest = temp[:, 0:1]
|
|
68
|
+
self._rest = temp[:, 1:]
|
|
69
|
+
|
|
70
|
+
self._l = tf.one_hot(tf.reshape(self._highest, -1), self._n_outputs)
|
|
71
|
+
|
|
72
|
+
self._model = keras.Sequential(
|
|
73
|
+
[keras.layers.InputLayer(input_shape=self._n_features),
|
|
74
|
+
keras.layers.Dense(self._n_outputs, activation="softmax")])
|
|
75
|
+
|
|
76
|
+
self._optimize_bfgs(self._model, self._loss, self._X, self._y, max_iterations=max_iterations)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class LDLM(BaseDeepLDLClassifier):
|
|
80
|
+
|
|
81
|
+
def __init__(self, n_hidden=None, n_latent=None, random_state=None):
|
|
82
|
+
super().__init__(n_hidden, n_latent, random_state)
|
|
83
|
+
|
|
84
|
+
@tf.function
|
|
85
|
+
def _loss(self, X, y):
|
|
86
|
+
y_pred = self._model(X)
|
|
87
|
+
|
|
88
|
+
pred_margin = tf.reduce_sum(tf.clip_by_value(
|
|
89
|
+
tf.reduce_sum(tf.abs(self._l - y_pred), axis=1) - self._rho,
|
|
90
|
+
0., float('inf')))
|
|
91
|
+
|
|
92
|
+
highest = tf.gather(y_pred, self._highest, axis=1, batch_dims=1)
|
|
93
|
+
rest = tf.gather(y_pred, self._rest, axis=1, batch_dims=1)
|
|
94
|
+
label_margin = tf.reduce_sum(tf.maximum(0., 1. - (highest - rest) / self._rho))
|
|
95
|
+
|
|
96
|
+
second_margin = tf.reduce_sum(tf.clip_by_value(
|
|
97
|
+
tf.reduce_sum(tf.abs((y - y_pred) * self._neg_l), axis=1) - self._second_margin,
|
|
98
|
+
0., float('inf')))
|
|
99
|
+
|
|
100
|
+
return pred_margin + self._alpha * label_margin + \
|
|
101
|
+
self._beta * second_margin + self._gamma * BaseDeepLDL._l2_reg(self._model)
|
|
102
|
+
|
|
103
|
+
def fit(self, X, y, learning_rate=5e-4, epochs=1000,
|
|
104
|
+
alpha=1e-2, beta=1e-2, gamma=1e-6, rho=1e-2):
|
|
105
|
+
super().fit(X, y)
|
|
106
|
+
|
|
107
|
+
self._alpha = alpha
|
|
108
|
+
self._beta = beta
|
|
109
|
+
self._gamma = gamma
|
|
110
|
+
self._rho = rho
|
|
111
|
+
|
|
112
|
+
temp = tf.math.top_k(self._y, k=self._n_outputs)[1]
|
|
113
|
+
self._highest = temp[:, 0:1]
|
|
114
|
+
self._rest = temp[:, 1:]
|
|
115
|
+
|
|
116
|
+
temp = tf.math.top_k(tf.gather(self._y, self._rest, axis=1, batch_dims=1), k=2)[0]
|
|
117
|
+
self._second_margin = temp[:, 0] - temp[:, 1]
|
|
118
|
+
|
|
119
|
+
self._l = tf.one_hot(tf.reshape(self._highest, -1), self._n_outputs)
|
|
120
|
+
self._neg_l = tf.where(tf.equal(self._l, 0.), 1., 0.)
|
|
121
|
+
|
|
122
|
+
self._model = keras.Sequential(
|
|
123
|
+
[keras.layers.InputLayer(input_shape=self._n_features),
|
|
124
|
+
keras.layers.Dense(self._n_outputs, activation="softmax")])
|
|
125
|
+
|
|
126
|
+
self._optimizer = keras.optimizers.SGD(learning_rate)
|
|
127
|
+
|
|
128
|
+
for _ in range(epochs):
|
|
129
|
+
with tf.GradientTape() as tape:
|
|
130
|
+
loss = self._loss(self._X, self._y)
|
|
131
|
+
|
|
132
|
+
gradients = tape.gradient(loss, self.trainable_variables)
|
|
133
|
+
self._optimizer.apply_gradients(zip(gradients, self.trainable_variables))
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from pyldl.algorithms.base import BaseEnsemble
|
|
6
|
+
from pyldl.metrics import sort_loss
|
|
7
|
+
from ._algorithm_adaptation import AA_KNN
|
|
8
|
+
from ._specialized_algorithms import SA_BFGS
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DF_LDL(BaseEnsemble):
|
|
12
|
+
|
|
13
|
+
def __init__(self, estimator=SA_BFGS(), random_state=None):
|
|
14
|
+
super().__init__(estimator, None, random_state)
|
|
15
|
+
|
|
16
|
+
def fit(self, X, y):
|
|
17
|
+
super().fit(X, y)
|
|
18
|
+
|
|
19
|
+
m, c = self._y.shape[0], self._y.shape[1]
|
|
20
|
+
L = {}
|
|
21
|
+
|
|
22
|
+
for i in range(c):
|
|
23
|
+
for j in range(i + 1, c):
|
|
24
|
+
|
|
25
|
+
ss1 = []
|
|
26
|
+
ss2 = []
|
|
27
|
+
|
|
28
|
+
for k in range(m):
|
|
29
|
+
if self._y[k, i] >= self._y[k, j]:
|
|
30
|
+
ss1.append(k)
|
|
31
|
+
else:
|
|
32
|
+
ss2.append(k)
|
|
33
|
+
|
|
34
|
+
l1 = copy.deepcopy(self._estimator)
|
|
35
|
+
l1.fit(self._X[ss1], self._y[ss1])
|
|
36
|
+
L[str(i)+","+str(j)] = copy.deepcopy(l1)
|
|
37
|
+
|
|
38
|
+
l2 = copy.deepcopy(self._estimator)
|
|
39
|
+
l2.fit(self._X[ss2], self._y[ss2])
|
|
40
|
+
L[str(j)+","+str(i)] = copy.deepcopy(l2)
|
|
41
|
+
|
|
42
|
+
self._estimators = L
|
|
43
|
+
|
|
44
|
+
self._knn = AA_KNN()
|
|
45
|
+
self._knn.fit(self._X, self._y)
|
|
46
|
+
|
|
47
|
+
def predict(self, X):
|
|
48
|
+
|
|
49
|
+
m, c = X.shape[0], self._y.shape[1]
|
|
50
|
+
p_knn = self._knn.predict(X)
|
|
51
|
+
p = np.zeros((m, c), dtype=np.float32)
|
|
52
|
+
|
|
53
|
+
for k in range(m):
|
|
54
|
+
for i in range(c):
|
|
55
|
+
for j in range(i + 1, c):
|
|
56
|
+
|
|
57
|
+
if p_knn[k, i] >= p_knn[k, j]:
|
|
58
|
+
l = self._estimators[str(i)+","+str(j)]
|
|
59
|
+
else:
|
|
60
|
+
l = self._estimators[str(j)+","+str(i)]
|
|
61
|
+
|
|
62
|
+
p[k] += l.predict(X[k].reshape(1, -1)).reshape(-1)
|
|
63
|
+
|
|
64
|
+
return p / (c * (c - 1) / 2)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AdaBoostLDL(BaseEnsemble):
|
|
68
|
+
|
|
69
|
+
def __init__(self, estimator=SA_BFGS(), n_estimators=10, random_state=None):
|
|
70
|
+
super().__init__(estimator, n_estimators, random_state)
|
|
71
|
+
|
|
72
|
+
def fit(self, X, y, loss=sort_loss, alpha=1.):
|
|
73
|
+
super().fit(X, y)
|
|
74
|
+
|
|
75
|
+
m = self._X.shape[0]
|
|
76
|
+
p = np.ones((m,)) / m
|
|
77
|
+
|
|
78
|
+
self._loss = np.zeros((self._n_estimators, m))
|
|
79
|
+
self._estimators = []
|
|
80
|
+
for i in range(self._n_estimators):
|
|
81
|
+
select = np.random.choice(m, size=m, p=p)
|
|
82
|
+
X_train, y_train = self._X[select], self._y[select]
|
|
83
|
+
|
|
84
|
+
model = copy.deepcopy(self._estimator)
|
|
85
|
+
model.fit(X_train, y_train)
|
|
86
|
+
self._estimators.append(copy.deepcopy(model))
|
|
87
|
+
|
|
88
|
+
y_pred = model.predict(self._X)
|
|
89
|
+
self._loss[i] = loss(y, y_pred, reduction=None)
|
|
90
|
+
p += alpha * (self._loss[i] / np.sum(self._loss))
|
|
91
|
+
p /= np.sum(p)
|
|
92
|
+
|
|
93
|
+
def predict(self, X):
|
|
94
|
+
w = np.sum(self._loss, axis=1)
|
|
95
|
+
w /= np.sum(w)
|
|
96
|
+
y = np.zeros((X.shape[0], self._n_outputs))
|
|
97
|
+
for i in range(self._n_estimators):
|
|
98
|
+
y += w[i] * self._estimators[i].predict(X)
|
|
99
|
+
return y
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import keras
|
|
2
|
+
import tensorflow as tf
|
|
3
|
+
import tensorflow_addons as tfa
|
|
4
|
+
|
|
5
|
+
from pyldl.metrics import score
|
|
6
|
+
from pyldl.algorithms.base import BaseDeepLDL
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class IncomLDL(BaseDeepLDL):
|
|
10
|
+
|
|
11
|
+
def __init__(self, n_hidden=None, n_latent=None, random_state=None):
|
|
12
|
+
super().__init__(n_hidden, n_latent, random_state)
|
|
13
|
+
|
|
14
|
+
def _loss(self, X, y):
|
|
15
|
+
y_pred = self._model(X)
|
|
16
|
+
trace_norm = 0.
|
|
17
|
+
for i in self._model.trainable_variables:
|
|
18
|
+
trace_norm += tf.linalg.trace(tf.sqrt(tf.matmul(tf.transpose(i), i)))
|
|
19
|
+
fro_norm = tf.reduce_sum(tf.square(self._mask * (y_pred - y)))
|
|
20
|
+
return fro_norm / 2. + self._alpha * trace_norm
|
|
21
|
+
|
|
22
|
+
def fit(self, X, y, mask, alpha=2., learning_rate=5e-2, epochs=5000):
|
|
23
|
+
super().fit(X, y)
|
|
24
|
+
|
|
25
|
+
self._alpha = alpha
|
|
26
|
+
self._mask = tf.where(mask, 0., 1.)
|
|
27
|
+
|
|
28
|
+
self._model = keras.Sequential([keras.layers.InputLayer(input_shape=self._n_features),
|
|
29
|
+
keras.layers.Dense(self._n_outputs, activation='softmax', use_bias=False)])
|
|
30
|
+
self._optimizer = tfa.optimizers.ProximalAdagrad(learning_rate)
|
|
31
|
+
|
|
32
|
+
for _ in range(epochs):
|
|
33
|
+
with tf.GradientTape() as tape:
|
|
34
|
+
loss = self._loss(self._X, self._y)
|
|
35
|
+
|
|
36
|
+
gradients = tape.gradient(loss, self.trainable_variables)
|
|
37
|
+
self._optimizer.apply_gradients(zip(gradients, self.trainable_variables))
|
|
38
|
+
|
|
39
|
+
def predict(self, X):
|
|
40
|
+
return self._model(X).numpy()
|
|
41
|
+
|
|
42
|
+
def score(self, X, y, metrics=None):
|
|
43
|
+
if metrics is None:
|
|
44
|
+
metrics = ["chebyshev", "clark", "canberra", "cosine", "intersection"]
|
|
45
|
+
return score(y, self.predict(X), metrics=metrics)
|