-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbeam_f.py
More file actions
198 lines (160 loc) · 7.09 KB
/
beam_f.py
File metadata and controls
198 lines (160 loc) · 7.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import numpy as np
from beam_f_utils import *
#----------------- concave optimization -------------------#
def beam_f(N, weights, y,
bi_concave_iters, conf_opt_iters,
prob_estimates,
eps, reg, thresh, last_k,
out_put=True, seed=0):
'''
Args
-----------------
N: number of classes
weights: weights for classes
y: class labels for data
bi_concave_iters, conf_opt_iters: inner, outter loop max iterations
prob_estimates: class probability model (previously trained)
eps, reg: perturbation constant, regularization
thresh: convergence threshhold
last_k: number of objective function values
out_put: display/suppress output of optimization process
seed: type of initial confusion matrix
Return
-----------------
classifiers: array of classifiers found
classifier_weights: weights for classifiers found
perf: macro f-score performance on data set
'''
# Get initial Gain Matrix
#-------------- weighted initialization
if seed == 0:
G_diag = [weights[n] for n in xrange(N)]
G_0 = np.diag(G_diag)
#-------------- balanced initialization
elif seed == 1:
G_0 = np.eye(N)
#-------------- random initialization
else:
G_0 = 20 * np.random.random((N, N))
# Get the initial confusion matrix corresponding to the classifer
# for the initial gain matrix
Conf_t = compute_conf(G_0, prob_estimates, y)
# Find performance of initial confusion matrix
perf = eval_conf(Conf_t)
if out_put == True:
print 'initial:', perf, '\n'
# Record all classifiers found across all iterations, along with their weights
classifiers = np.zeros((bi_concave_iters * conf_opt_iters + 1, N, N))
classifier_weights = np.zeros(bi_concave_iters * conf_opt_iters + 1)
classifiers[0, : , :] = G_0
classifier_weights[0] = 1
classifier_index = 1
# Last k objective from outer loop
outer_obj = []
# Out loop: optimize u for fixed conf mat
for s in xrange(bi_concave_iters):
u_s = compute_u(np.copy(Conf_t), eps)
# Last k objective from inner loop
inner_obj = []
# Inner loop: optimize conf mat for fixed u
for t in xrange(conf_opt_iters):
# Compute biconcave objective for the confusion matrix at inner step t
obj = compute_biconcave_obj(Conf_t, u_s, reg)
if out_put == True:
print s, ',', t, ':', perf, ', ', obj
# Update last k objectives and terminate inner loop
# if insufficient improvement in obj function is observed
if t == conf_opt_iters - 1:
if len(outer_obj) >= last_k:
outer_obj.pop(0)
outer_obj.append(obj)
else:
outer_obj.append(obj)
else:
if len(inner_obj) >= last_k:
inner_obj.pop(0)
inner_obj.append(obj)
diff = np.absolute(np.array(inner_obj) \
- np.array(inner_obj[1:] + [0]))
if (diff <= thresh).all():
if len(outer_obj) >= 3:
outer_obj.pop(0)
outer_obj.append(obj)
else:
outer_obj.append(obj)
break
else:
inner_obj.append(obj)
# Compute the gain matrix at inner step t
G_t = compute_conf_grad(Conf_t, u_s, eps, reg)
# Find new confusion matrix for gain matrix at inner step t
Conf_new = compute_conf(G_t, prob_estimates ,y)
# Update the confusion matrix using line search
max_perf = -1
step_size = 0
for i in xrange(100):
l = i * 0.01
Conf_line = l * Conf_new + (1 - l) * Conf_t
perf_line = compute_biconcave_obj(Conf_line, u_s, reg)
if perf_line > max_perf:
max_perf = perf_line
Conf_t[:, :] = Conf_line
step_size = l
# Record the gain matrix and the corresponding weight
classifiers[classifier_index, :, :] = G_t
classifier_weights[:classifier_index] = classifier_weights[:classifier_index] * (1 - step_size)
classifier_weights[classifier_index] = step_size
classifier_index = classifier_index + 1
# Find performance of confusion matrix accepted at inner step t
perf = eval_conf(Conf_t)
# Terminate inner loop if insufficient improvement in
# obj function is observed
diff = np.absolute(np.array(outer_obj) \
- np.array(outer_obj[1:] + [0]))
if (diff <= thresh).all():
break
# Truncate the classifer and classifier weights arrays
classifiers = classifiers[:classifier_index, :, :]
classifier_weights = classifier_weights[:classifier_index]
if out_put == True:
print 'final: ', str(perf), '\n'
return classifiers, classifier_weights, perf
def seed_beam_f(N, weights, y,
bi_concave_iters, conf_opt_iters,
prob_estimates,
eps, reg, thresh, last_k,
out_put=None, restarts=5):
'''
Args
-----------------
N: number of classes
weights: weights for classes
y: class labels for data
bi_concave_iters, conf_opt_iters: inner, outter loop max iterations
prob_estimates: class probability model (previously trained)
eps, reg: perturbation constant, regularization
thresh: convergence threshhold
last_k: number of objective function values
out_put: display/suppress output of optimization process
restarts: number of restarts to use for beam_f
Return
-----------------
best_classifiers: best classifiers found using restarts
best_weights: weights for best classifiers found using restarts
'''
best_classifiers = np.zeros((bi_concave_iters * conf_opt_iters + 1, N, N))
best_weights = np.zeros(bi_concave_iters * conf_opt_iters + 1)
best_perf = -1
# Call beam_f for multiple restarts with different types
# of initial gain matrices
for i in range(restarts):
classifiers, classifier_weights, perf = beam_f(N, weights, y,
bi_concave_iters, conf_opt_iters,
prob_estimates,
eps, reg, thresh, last_k,
out_put=out_put, seed=i)
if perf > best_perf:
best_classifiers[:, :, :] = classifiers
best_weights[:] = classifier_weights
best_perf = perf
return best_classifiers, best_weights