Skip to content

Commit 41150bb

Browse files
committed
Adds support for spatial size 1 processing, new scattering networks,
kappa and average accuracy scores, makes sure SVM regularization parameter is always used. Adds more gridsearches. Adds HSI resolution details to hsi_data.py. Adds more DL networks to run.
1 parent e81c9ce commit 41150bb

6 files changed

+529
-105
lines changed

hsi_data.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,20 @@
4848
'KSC': ('KSC', 'KSC_gt'),
4949
'IP': ('indian_pines_corrected', 'indian_pines_gt')
5050
}
51-
51+
# in nm/pixel
52+
bandwidth_dict = {
53+
'PaviaU': 430 / 103.0,
54+
'Botswana': 2100 / 242.0,
55+
'KSC': 2100 / 224.0,
56+
'IP': 2100 / 224.0
57+
}
58+
# in meters/pix
59+
spatial_res_dict = {
60+
'PaviaU': 1.3,
61+
'IP': 3.7,
62+
'Botswana': 30.0,
63+
'KSC': 18.0
64+
}
5265

5366
def load_data(trainimgname, trainimgfield, trainlabelname, trainlabelfield, dataset_path=DATASET_PATH):
5467
mat_contents = sio.loadmat(os.path.join(dataset_path, trainimgname))

hyper_pixelNN.py

+96-35
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import time
1717

1818
import argparse
19+
from sklearn.metrics import confusion_matrix, cohen_kappa_score, accuracy_score
1920
import numpy as np
2021
from PIL import Image
2122
import scipy.io as sio
@@ -26,7 +27,6 @@
2627

2728

2829
import windows as win
29-
from rle import myrlestring
3030
# import salt_baseline as sb
3131
# import salt_data as sd
3232
import fst3d_feat as fst
@@ -95,11 +95,20 @@ def scat3d_to_3d_nxn_2layer(x, reuse=tf.AUTO_REUSE, psis=None, phi=None, layer_p
9595
9: 7,
9696
7: 5,
9797
5: 3,
98-
3: 1
98+
3: 1,
99+
1: 1
99100
}
100-
lambda1_d = ds_amounts[psis[0].kernel_size[1]]; band1_d = 3
101-
lambda2_d = ds_amounts[psis[1].kernel_size[1]]; band2_d = 3
102-
lambdax_d = ds_amounts[phi.kernel_size[1]];
101+
def avg_cube_side(kernel_size):
102+
# started doing this for cubes with spatial size 1
103+
avg_cube_side_ = int(round(np.prod(kernel_size[:2])**(1/2.0)))
104+
if avg_cube_side_ % 2 == 0:
105+
avg_cube_side_ += 1
106+
return avg_cube_side_
107+
lambda1_d = ds_amounts[ avg_cube_side(psis[0].kernel_size) ];
108+
lambda2_d = ds_amounts[ avg_cube_side(psis[1].kernel_size) ];
109+
lambdax_d = ds_amounts[ avg_cube_side(phi.kernel_size) ];
110+
band1_d = 3
111+
band2_d = 3
103112

104113
U1 = tf.layers.max_pooling3d(U1, (lambda1_d,band1_d,1), (lambda1_d,band1_d,1), padding='same')
105114

@@ -119,7 +128,6 @@ def scat3d_to_3d_nxn_2layer(x, reuse=tf.AUTO_REUSE, psis=None, phi=None, layer_p
119128
increasing_psi = win.fst3d_psi_factory(psis[1].kernel_size, used_params)
120129
if increasing_psi.nfilt > 0:
121130
U2s.append(fst.scat3d(U1[res_i:(res_i+1),:,:,:,:], increasing_psi, layer_params[1]))
122-
123131
U2 = tf.concat(U2s, 4)
124132
# U2 is (1,bands,h,w,lambda2)
125133

@@ -157,8 +165,17 @@ def slice_idx(s, k, f):
157165
[p1b, p1h, p1w] = slice_idxs(U1.shape[1:4], phi.kernel_size)
158166
[p2b, p2h, p2w] = slice_idxs(x.shape[1:4], phi.kernel_size)
159167

160-
S1 = fst.scat3d(U1[:, :,(p1h):-(p1h), (p1w):-(p1w), :], phi, layer_params[2])
161-
S0 = fst.scat3d(x[:, :,(p2h):-(p2h), (p2w):-(p2w), :], phi, layer_params[2])
168+
if not (p1h == 0 and p1w == 0):
169+
S1 = fst.scat3d(U1[:, :,(p1h):-(p1h), (p1w):-(p1w), :], phi, layer_params[2])
170+
else:
171+
# if the size of the spatial kernel is 1 in the spatial dimension we
172+
# don't need to do this.
173+
S1 = fst.scat3d(U1, phi, layer_params[2])
174+
175+
if not (p2h == 0 and p2w == 0):
176+
S0 = fst.scat3d(x[:, :,(p2h):-(p2h), (p2w):-(p2w), :], phi, layer_params[2])
177+
else:
178+
S0 = fst.scat3d(x, phi, layer_params[2])
162179

163180
# just to get the size down to 1 (flattening step)
164181
S0 = tf.reshape(S0, [-1, final_size, final_size, 1])
@@ -205,12 +222,17 @@ def gabor_mag_filter(x, reuse=tf.AUTO_REUSE, psis=None, layer_params=None, final
205222
9: 7,
206223
7: 5,
207224
5: 3,
208-
3: 1
225+
3: 1,
226+
1: 1
209227
}
210228
lambda1_d = ds_amounts[psis[0].kernel_size[1]]; band1_d = 3
211229

212230
U1 = tf.layers.max_pooling3d(U1, (lambda1_d,band1_d,1), (lambda1_d,band1_d,1), padding='same')
213-
U1 = tf.reshape(U1, [-1, final_size, final_size])
231+
U1 = tf.reshape(U1, [1, -1, final_size, final_size, 1])
232+
233+
# SX downsampling from ST for comparable feature size
234+
U1 = tf.layers.max_pooling3d(U1, (lambda1_d,1,1), (lambda1_d,1,1), padding='same')
235+
U1 = tf.squeeze(U1)
214236

215237
return tf.transpose(U1, [1, 2, 0])
216238

@@ -587,19 +609,30 @@ def load_or_preprocess_data(data, write_path, backup_write_root, st_net_spec=pav
587609
}
588610
sts_dict = {
589611
'paviaU': st_net_spec_struct([9,9,9],[9,9,9],[9,9,9]),
612+
'paviaU_dist': st_net_spec_struct([5,7,7],[5,7,7],[5,7,7]),
613+
'paviaU_SSS': st_net_spec_struct([7,3,3],[7,3,3],[7,3,3]),
590614
'7': st_net_spec_struct([7,7,7],[7,7,7],[7,7,7]),
591615
'9': st_net_spec_struct([9,9,9],[9,9,9],[9,9,9]),
592616
'5': st_net_spec_struct([5,5,5],[5,5,5],[5,5,5]),
593617
'3': st_net_spec_struct([3,3,3],[3,3,3],[3,3,3]),
594618
'Botswana': st_net_spec_struct([7,7,7],[7,5,5],[7,5,5]),
619+
'Botswana_dist': st_net_spec_struct([7,9,9],[7,5,5],[7,5,5]),
620+
'Botswana_SSS': st_net_spec_struct([3,5,5],[3,5,5],[3,5,5]),
595621
'KSC': st_net_spec_struct([5,9,9],[5,7,7],[5,7,7]),
596-
'PU_SSS': st_net_spec_struct([9,7,7],[9,3,3],[9,3,3]),
597-
'IP_SSS': st_net_spec_struct([5,9,9],[5,5,5],[5,5,5]),
598-
'IP_gabor': st_net_spec_struct([5,9,9],None,None),
599-
'PU_gabor': st_net_spec_struct([9,7,7],None,None),
600-
'KSC_gabor': st_net_spec_struct([5,9,9],None,None),
601-
'Botswana_gabor': st_net_spec_struct([7,7,7],None,None),
622+
'KSC_SSS': st_net_spec_struct([3,7,7],[3,1,1],[3,1,1]),
623+
'KSC_dist': st_net_spec_struct([3,7,7],[3,7,7],[3,7,7]),
624+
'IP': st_net_spec_struct([5,9,9],[5,5,5],[5,5,5]),
625+
'IP_dist': st_net_spec_struct([7,9,9],[7,9,9],[7,9,9]),
626+
'IP_SSS': st_net_spec_struct([5,1,1],[5,1,1],[5,1,1]),
602627
'tang': st_net_spec_struct(None,None,None),
628+
'IP_dist_gabor': st_net_spec_struct([7,9,9],None,None),
629+
'IP_SSS_gabor': st_net_spec_struct([5,1,1],None,None),
630+
'KSC_dist_gabor': st_net_spec_struct([3,7,7],None,None),
631+
'KSC_SSS_gabor': st_net_spec_struct([3,7,7],None,None),
632+
'Botswana_dist_gabor': st_net_spec_struct([7,9,9],None,None),
633+
'Botswana_SSS_gabor': st_net_spec_struct([3,5,5],None,None),
634+
'paviaU_dist_gabor': st_net_spec_struct([5,7,7],None,None),
635+
'paviaU_SSS_gabor': st_net_spec_struct([7,3,3],None,None),
603636
}
604637

605638
def many_svm_evals(args):
@@ -645,14 +678,17 @@ def many_svm_evals(args):
645678
end = time.time()
646679
print('Training done. Took %is' % int(end - start))
647680

648-
n_correct = 0
681+
predictions = np.zeros_like(valY)
649682
for i in tqdm(range(0,valY.shape[0],bs), desc='Getting Val Accuracy'):
650-
p_label = clf.predict(valX.squeeze()[i:i+bs]);
651-
n_correct += (p_label == valY[i:i+bs]).sum()
652-
acc = float(n_correct) / valY.shape[0]
683+
predictions[i:i+bs] = clf.predict(valX.squeeze()[i:i+bs])
684+
overall_acc = accuracy_score(valY, predictions)
685+
C = confusion_matrix(valY, predictions).astype(float)
686+
per_class = np.diag(C) / C.sum(axis=1)
687+
average_acc = np.mean(per_class)
688+
kappa = cohen_kappa_score(valY, predictions)
653689
print('Done with %s' % mask_path )
654-
print('SVM has validation accuracy %.2f' % (acc*100) )
655-
results[mask_path] = acc
690+
print('SVM has validation OA %.2f, AA %.2f, kappa %.4f' % (overall_acc*100, average_acc*100, kappa) )
691+
results[mask_path] = (overall_acc, average_acc, kappa)
656692

657693
npz_path = os.path.join(args.model_root, 'SVM_results_%i.npz' % (random.randint(0,1e10)))
658694
np.savez(npz_path, results=results)
@@ -683,19 +719,37 @@ def svm_predict(args):
683719
s = args.network_spatial_size - 1
684720
trainX, trainY, valX, valY = get_train_val_splits(data, labels, train_mask, val_mask, (s,s,0))
685721

722+
# Cs = 2.0**np.array(range(-20,21,2))
723+
# accs = np.zeros_like(Cs)
724+
# for j, C in enumerate(Cs):
725+
# print('starting training')
726+
# start = time.time()
727+
# clf = SVC(kernel='linear', C=C)
728+
# clf.fit(trainX.squeeze(), trainY)
729+
# overall_acc = clf.score(valX.squeeze(), valY)
730+
# accs[j] = overall_acc
731+
# end = time.time()
732+
# print('Training done. Took %is' % int(end - start))
733+
# print('C %f. Got %f' % (C, overall_acc))
734+
735+
686736
print('starting training')
687737
start = time.time()
688-
clf = SVC(kernel='linear')
738+
clf = SVC(kernel='linear', C=args.svm_regularization_param)
689739
clf.fit(trainX.squeeze(), trainY)
690740
end = time.time()
691741
print('Training done. Took %is' % int(end - start))
692742

693-
n_correct = 0
743+
744+
predictions = np.zeros_like(valY)
694745
for i in tqdm(range(0,valY.shape[0],bs), desc='Getting Val Accuracy'):
695-
p_label = clf.predict(valX.squeeze()[i:i+bs]);
696-
n_correct += (p_label == valY[i:i+bs]).sum()
697-
acc = float(n_correct) / valY.shape[0]
698-
print('SVM has validation accuracy %.2f' % (acc*100) )
746+
predictions[i:i+bs] = clf.predict(valX.squeeze()[i:i+bs])
747+
overall_acc = accuracy_score(valY, predictions)
748+
C = confusion_matrix(valY, predictions).astype(float)
749+
per_class = np.diag(C) / C.sum(axis=1)
750+
average_acc = np.mean(per_class)
751+
kappa = cohen_kappa_score(valY, predictions)
752+
print('SVM has validation OA %.2f, AA %.2f, kappa %.4f' % (overall_acc*100, average_acc*100, kappa) )
699753

700754
# test everything
701755
y_predicted = []
@@ -708,15 +762,17 @@ def svm_predict(args):
708762

709763
imgmatfiledata = {}
710764
imgmatfiledata[u'imgHat'] = pred_image
711-
groundtruthfilename = os.path.splitext(trainlabelname)[0]
712-
imgmatfiledata[u'groundtruthfilename'] = '%s_%s.mat' % (groundtruthfilename, args.network)
765+
# groundtruthfilename = os.path.splitext(trainlabelname)[0]
766+
npzfilename = '%s_pred.npz' % args.mask_root.split('/')[-1].split('.')[0]
767+
# imgmatfiledata[u'groundtruthfilename'] = '%s_%s.mat' % (groundtruthfilename, args.network)
768+
imgmatfiledata[u'groundtruthfilename'] = '%s_pred.mat' % args.mask_root.split('/')[-1].split('.')[0]
713769
hdf5storage.write(imgmatfiledata,
714770
filename=os.path.join(args.model_root, imgmatfiledata[u'groundtruthfilename']),
715771
matlab_compatible=True)
716772

717773
print('Saved %s' % os.path.join(args.model_root, imgmatfiledata[u'groundtruthfilename']))
718774

719-
npz_path = os.path.join(args.model_root, '%s_SVM.npz' % (groundtruthfilename))
775+
npz_path = os.path.join(args.model_root, npzfilename)
720776
np.savez(npz_path, pred_image=pred_image)
721777
print('Saved %s' % npz_path)
722778

@@ -846,7 +902,8 @@ def model_fn(features, labels, mode):
846902

847903
# Evaluate the accuracy of the model
848904
acc_op = tf.metrics.accuracy(labels=labels, predictions=pred_classes)
849-
905+
avg_acc_op = tf.metrics.mean_per_class_accuracy(labels=labels, predictions=pred_classes, num_classes=n_classes)
906+
kappa_op = tf.contrib.metrics.cohen_kappa(labels=labels, predictions_idx=pred_classes, num_classes=n_classes)
850907
# tf.summary.scalar('min', loss_op)
851908

852909
# TF Estimators requires to return a EstimatorSpec, that specify
@@ -856,7 +913,7 @@ def model_fn(features, labels, mode):
856913
predictions=pred_classes,
857914
loss=loss_op,
858915
train_op=train_op,
859-
eval_metric_ops={'accuracy': acc_op})
916+
eval_metric_ops={'accuracy': acc_op, 'avg_accuracy': avg_acc_op, 'kappa': kappa_op})
860917

861918
return estim_specs
862919

@@ -901,6 +958,9 @@ def identity_serving_input_receiver_fn():
901958
model.train(train_input_fn)
902959

903960
e = model.evaluate(eval_input_fn, name='eval')
961+
tp = float(n_eval) / nlabeled # test percentage
962+
avg_acc_at_best_eval_acc = 0
963+
kappa_at_best_eval_acc = 0
904964

905965
if e['accuracy'] > best_acc:
906966
tf.logging.info("{:06d}: High Accuracy. Saving model with Validation Accuracy: {:.4f}".format(i*args.eval_period, e['accuracy']))
@@ -924,6 +984,8 @@ def identity_serving_input_receiver_fn():
924984
test_e = model.evaluate(test_input_fn, name='test')
925985
if e['accuracy'] > best_acc:
926986
test_acc_at_best_eval_acc = test_e['accuracy']
987+
avg_acc_at_best_eval_acc = tp*test_e['avg_accuracy'] + (1-tp)*e['avg_accuracy']
988+
kappa_at_best_eval_acc = tp*test_e['kappa'] + (1-tp)*e['kappa']
927989
if e['loss'] < best_loss:
928990
test_acc_at_best_eval_loss = test_e['accuracy']
929991

@@ -932,13 +994,12 @@ def identity_serving_input_receiver_fn():
932994
tf.logging.info("{:06d}: Validation Accuracy: {:.4f} (At lowest loss: {:.4f}) (Best Ever: {:.4f})".format(i*args.eval_period, e['accuracy'], acc_at_best_loss, best_acc))
933995
tf.logging.info("{:06d}: Test Accuracy: Best by Eval Acc: {:.4f}. Best by Eval Loss: {:.4f}".format(i*args.eval_period, test_acc_at_best_eval_acc, test_acc_at_best_eval_loss))
934996

935-
tp = float(n_eval) / nlabeled # test percentage
936997
overall_acc_at_best_eval_acc = tp*test_acc_at_best_eval_acc + (1-tp)*best_acc
937998
overall_acc_at_best_eval_loss = tp*test_acc_at_best_eval_loss + (1-tp)*acc_at_best_loss
938999
tf.logging.info("{:06d}: Overall Accuracy: Best by Eval Acc: {:.4f}. Best by Eval Loss: {:.4f}".format(i*args.eval_period, overall_acc_at_best_eval_acc, overall_acc_at_best_eval_loss))
9391000

9401001
npz_path = os.path.join(args.model_root, 'results.npz')
941-
np.savez(npz_path, results={args.mask_root: overall_acc_at_best_eval_acc})
1002+
np.savez(npz_path, results={args.mask_root: (overall_acc_at_best_eval_acc, avg_acc_at_best_eval_acc, kappa_at_best_eval_acc)})
9421003
print('Saved %s' % npz_path)
9431004

9441005
if n_nondecreasing_evals >= args.terminate_if_n_nondecreasing_evals:

0 commit comments

Comments
 (0)