I trained my model with maskrcnn and now I need to test it. How can I extract AP and AR and plot the graph, ok I know how to plot with matplotlib, but I need to plot Precision-recall curve but for that don't know how to access AP and AR values. Where are they saved?
I'm using this coco_eval script, and from here I see in function summarize there are print("IoU metric: {}".format(iou_type)) and this I got in output and under that AP and AR results, but I can't find it here in code. Where is this calculation?
coco_eval.py
import json
import tempfile
import numpy as np
import copy
import time
import torch
import torch._six
from pycocotools.cocoeval import COCOeval
from pycocotools.coco import COCO
import pycocotools.mask as mask_util
from collections import defaultdict
import utils
class CocoEvaluator(object):
def __init__(self, coco_gt, iou_types):
assert isinstance(iou_types, (list, tuple))
coco_gt = copy.deepcopy(coco_gt)
self.coco_gt = coco_gt
self.iou_types = iou_types
self.coco_eval = {}
for iou_type in iou_types:
self.coco_eval[iou_type] = COCOeval(coco_gt, iouType=iou_type)
self.img_ids = []
self.eval_imgs = {k: [] for k in iou_types}
def update(self, predictions):
img_ids = list(np.unique(list(predictions.keys())))
self.img_ids.extend(img_ids)
for iou_type in self.iou_types:
results = self.prepare(predictions, iou_type)
coco_dt = loadRes(self.coco_gt, results) if results else COCO()
coco_eval = self.coco_eval[iou_type]
coco_eval.cocoDt = coco_dt
coco_eval.params.imgIds = list(img_ids)
img_ids, eval_imgs = evaluate(coco_eval)
self.eval_imgs[iou_type].append(eval_imgs)
def synchronize_between_processes(self):
for iou_type in self.iou_types:
self.eval_imgs[iou_type] = np.concatenate(self.eval_imgs[iou_type], 2)
create_common_coco_eval(self.coco_eval[iou_type], self.img_ids, self.eval_imgs[iou_type])
def accumulate(self):
for coco_eval in self.coco_eval.values():
coco_eval.accumulate()
def summarize(self):
for iou_type, coco_eval in self.coco_eval.items():
print("IoU metric: {}".format(iou_type))
coco_eval.summarize()
def prepare(self, predictions, iou_type):
if iou_type == "bbox":
return self.prepare_for_coco_detection(predictions)
elif iou_type == "segm":
return self.prepare_for_coco_segmentation(predictions)
elif iou_type == "keypoints":
return self.prepare_for_coco_keypoint(predictions)
else:
raise ValueError("Unknown iou type {}".format(iou_type))
def prepare_for_coco_detection(self, predictions):
coco_results = []
for original_id, prediction in predictions.items():
if len(prediction) == 0:
continue
boxes = prediction["boxes"]
boxes = convert_to_xywh(boxes).tolist()
scores = prediction["scores"].tolist()
labels = prediction["labels"].tolist()
coco_results.extend(
[
{
"image_id": original_id,
"category_id": labels[k],
"bbox": box,
"score": scores[k],
}
for k, box in enumerate(boxes)
]
)
return coco_results
def prepare_for_coco_segmentation(self, predictions):
coco_results = []
for original_id, prediction in predictions.items():
if len(prediction) == 0:
continue
scores = prediction["scores"]
labels = prediction["labels"]
masks = prediction["masks"]
masks = masks > 0.5
scores = prediction["scores"].tolist()
labels = prediction["labels"].tolist()
rles = [
mask_util.encode(np.array(mask[0, :, :, np.newaxis], dtype=np.uint8, order="F"))[0]
for mask in masks
]
for rle in rles:
rle["counts"] = rle["counts"].decode("utf-8")
coco_results.extend(
[
{
"image_id": original_id,
"category_id": labels[k],
"segmentation": rle,
"score": scores[k],
}
for k, rle in enumerate(rles)
]
)
return coco_results
def prepare_for_coco_keypoint(self, predictions):
coco_results = []
for original_id, prediction in predictions.items():
if len(prediction) == 0:
continue
boxes = prediction["boxes"]
boxes = convert_to_xywh(boxes).tolist()
scores = prediction["scores"].tolist()
labels = prediction["labels"].tolist()
keypoints = prediction["keypoints"]
keypoints = keypoints.flatten(start_dim=1).tolist()
coco_results.extend(
[
{
"image_id": original_id,
"category_id": labels[k],
'keypoints': keypoint,
"score": scores[k],
}
for k, keypoint in enumerate(keypoints)
]
)
return coco_results
def convert_to_xywh(boxes):
xmin, ymin, xmax, ymax = boxes.unbind(1)
return torch.stack((xmin, ymin, xmax - xmin, ymax - ymin), dim=1)
def merge(img_ids, eval_imgs):
all_img_ids = utils.all_gather(img_ids)
all_eval_imgs = utils.all_gather(eval_imgs)
merged_img_ids = []
for p in all_img_ids:
merged_img_ids.extend(p)
merged_eval_imgs = []
for p in all_eval_imgs:
merged_eval_imgs.append(p)
merged_img_ids = np.array(merged_img_ids)
merged_eval_imgs = np.concatenate(merged_eval_imgs, 2)
# keep only unique (and in sorted order) images
merged_img_ids, idx = np.unique(merged_img_ids, return_index=True)
merged_eval_imgs = merged_eval_imgs[..., idx]
return merged_img_ids, merged_eval_imgs
def create_common_coco_eval(coco_eval, img_ids, eval_imgs):
img_ids, eval_imgs = merge(img_ids, eval_imgs)
img_ids = list(img_ids)
eval_imgs = list(eval_imgs.flatten())
coco_eval.evalImgs = eval_imgs
coco_eval.params.imgIds = img_ids
coco_eval._paramsEval = copy.deepcopy(coco_eval.params)
#################################################################
# From pycocotools, just removed the prints and fixed
# a Python3 bug about unicode not defined
#################################################################
# Ideally, pycocotools wouldn't have hard-coded prints
# so that we could avoid copy-pasting those two functions
def createIndex(self):
# create index
# print('creating index...')
anns, cats, imgs = {}, {}, {}
imgToAnns, catToImgs = defaultdict(list), defaultdict(list)
if 'annotations' in self.dataset:
for ann in self.dataset['annotations']:
imgToAnns[ann['image_id']].append(ann)
anns[ann['id']] = ann
if 'images' in self.dataset:
for img in self.dataset['images']:
imgs[img['id']] = img
if 'categories' in self.dataset:
for cat in self.dataset['categories']:
cats[cat['id']] = cat
if 'annotations' in self.dataset and 'categories' in self.dataset:
for ann in self.dataset['annotations']:
catToImgs[ann['category_id']].append(ann['image_id'])
# print('index created!')
# create class members
self.anns = anns
self.imgToAnns = imgToAnns
self.catToImgs = catToImgs
self.imgs = imgs
self.cats = cats
maskUtils = mask_util
def loadRes(self, resFile):
"""
Load result file and return a result api object.
Args:
self (obj): coco object with ground truth annotations
resFile (str): file name of result file
Returns:
res (obj): result api object
"""
res = COCO()
res.dataset['images'] = [img for img in self.dataset['images']]
# print('Loading and preparing results...')
# tic = time.time()
if isinstance(resFile, torch._six.string_classes):
anns = json.load(open(resFile))
elif type(resFile) == np.ndarray:
anns = self.loadNumpyAnnotations(resFile)
else:
anns = resFile
assert type(anns) == list, 'results in not an array of objects'
annsImgIds = [ann['image_id'] for ann in anns]
assert set(annsImgIds) == (set(annsImgIds) & set(self.getImgIds())), \
'Results do not correspond to current coco set'
if 'caption' in anns[0]:
imgIds = set([img['id'] for img in res.dataset['images']]) & set([ann['image_id'] for ann in anns])
res.dataset['images'] = [img for img in res.dataset['images'] if img['id'] in imgIds]
for id, ann in enumerate(anns):
ann['id'] = id + 1
elif 'bbox' in anns[0] and not anns[0]['bbox'] == []:
res.dataset['categories'] = copy.deepcopy(self.dataset['categories'])
for id, ann in enumerate(anns):
bb = ann['bbox']
x1, x2, y1, y2 = [bb[0], bb[0] + bb[2], bb[1], bb[1] + bb[3]]
if 'segmentation' not in ann:
ann['segmentation'] = [[x1, y1, x1, y2, x2, y2, x2, y1]]
ann['area'] = bb[2] * bb[3]
ann['id'] = id + 1
ann['iscrowd'] = 0
elif 'segmentation' in anns[0]:
res.dataset['categories'] = copy.deepcopy(self.dataset['categories'])
for id, ann in enumerate(anns):
# now only support compressed RLE format as segmentation results
ann['area'] = maskUtils.area(ann['segmentation'])
if 'bbox' not in ann:
ann['bbox'] = maskUtils.toBbox(ann['segmentation'])
ann['id'] = id + 1
ann['iscrowd'] = 0
elif 'keypoints' in anns[0]:
res.dataset['categories'] = copy.deepcopy(self.dataset['categories'])
for id, ann in enumerate(anns):
s = ann['keypoints']
x = s[0::3]
y = s[1::3]
x1, x2, y1, y2 = np.min(x), np.max(x), np.min(y), np.max(y)
ann['area'] = (x2 - x1) * (y2 - y1)
ann['id'] = id + 1
ann['bbox'] = [x1, y1, x2 - x1, y2 - y1]
# print('DONE (t={:0.2f}s)'.format(time.time()- tic))
res.dataset['annotations'] = anns
createIndex(res)
return res
def evaluate(self):
'''
Run per image evaluation on given images and store results (a list of dict) in self.evalImgs
:return: None
'''
# tic = time.time()
# print('Running per image evaluation...')
p = self.params
# add backward compatibility if useSegm is specified in params
if p.useSegm is not None:
p.iouType = 'segm' if p.useSegm == 1 else 'bbox'
print('useSegm (deprecated) is not None. Running {} evaluation'.format(p.iouType))
# print('Evaluate annotation type *{}*'.format(p.iouType))
p.imgIds = list(np.unique(p.imgIds))
if p.useCats:
p.catIds = list(np.unique(p.catIds))
p.maxDets = sorted(p.maxDets)
self.params = p
self._prepare()
# loop through images, area range, max detection number
catIds = p.catIds if p.useCats else [-1]
if p.iouType == 'segm' or p.iouType == 'bbox':
computeIoU = self.computeIoU
elif p.iouType == 'keypoints':
computeIoU = self.computeOks
self.ious = {
(imgId, catId): computeIoU(imgId, catId)
for imgId in p.imgIds
for catId in catIds}
evaluateImg = self.evaluateImg
maxDet = p.maxDets[-1]
evalImgs = [
evaluateImg(imgId, catId, areaRng, maxDet)
for catId in catIds
for areaRng in p.areaRng
for imgId in p.imgIds
]
# this is NOT in the pycocotools code, but could be done outside
evalImgs = np.asarray(evalImgs).reshape(len(catIds), len(p.areaRng), len(p.imgIds))
self._paramsEval = copy.deepcopy(self.params)
# toc = time.time()
# print('DONE (t={:0.2f}s).'.format(toc-tic))
return p.imgIds, evalImgs
#################################################################
# end of straight copy from pycocotools, just removing the prints
#################################################################
And this is my code for evaluation:
def evaluate(model, data_loader, device):
n_threads = torch.get_num_threads()
# FIXME remove this and make paste_masks_in_image run on the GPU
torch.set_num_threads(1)
cpu_device = torch.device("cpu")
model.eval()
metric_logger = utils.MetricLogger(delimiter=" ")
header = 'Test:'
coco = get_coco_api_from_dataset(data_loader.dataset)
iou_types = _get_iou_types(model)
coco_evaluator = CocoEvaluator(coco, iou_types)
for images, targets in metric_logger.log_every(data_loader, 100, header):
images = list(img.to(device) for img in images)
if torch.cuda.is_available():
torch.cuda.synchronize()
model_time = time.time()
outputs = model(images)
outputs = [{k: v.to(cpu_device) for k, v in t.items()} for t in outputs]
model_time = time.time() - model_time
res = {target["image_id"].item(): output for target, output in zip(targets, outputs)}
evaluator_time = time.time()
coco_evaluator.update(res)
evaluator_time = time.time() - evaluator_time
metric_logger.update(model_time=model_time, evaluator_time=evaluator_time)
# gather the stats from all processes
metric_logger.synchronize_between_processes()
print("Averaged stats:", metric_logger)
coco_evaluator.synchronize_between_processes()
# accumulate predictions from all images
coco_evaluator.accumulate()
coco_evaluator.summarize()
torch.set_num_threads(n_threads)
return coco_evaluator
This is my results what I got:
Related
The solution I have now works, but the downside is that takes over 1 hour to fit a simple model. Most of the training time is lost in the python generator, in the code called WindowGenerator.gen
If we postfix all the data, I would think it would affect the models performance since we will then have zeros for most of the data.
I have an eventlog with data on the format (approximates): (600 000, 500)
The first feature is the group/caseID and the three last are labels. Each case has on average 6 events, but it deviates from 4 all the way to 100. In tensorflow v1 there was a generator that seemed like what I wanted: tf.contrib.training.batch_sequences_with_states
I want to load in batches that get postfixed, my solution was to create an empty 3d array in the desired shape defined by (batchsize, the max length case, num_features)
The idea is to create a sliding window, where we are guessing the target columns by an offset/shift.
Example:
batch_1 = pd.DataFrame([[1,1,0.1,11],
[1,2,0.2,12],
[1,3,0.3,13],
[1,4,0.4,14],
[1,4,0.4,14],
[2,5,0.5,15],
[2,6,0.6,16],
[2,7,0.7,17],
[3,8,0.8,18],
[3,9,0.9,19],
[3,10,0.7,20]], columns=["id", "x1","x2", "target"])
# we want to be on the form before sliding:
[ [[1,1,0.1,11],
[1,2,0.2,12],
[1,3,0.3,13],
[1,4,0.4,14],
[1,4,0.4,14] ],
[[2,5,0.5,15],
[2,6,0.6,16],
[2,7,0.7,17],
[2,7,0.7,17],
[2,0,0,0],
[2,0,0,0] ],
[3,8,0.8,18],
[3,9,0.9,19],
[3,10,0.7,20]
[3,0,0,0],
[3,0,0,0], ]
]
The splitting of data:
unique_caseids = eventvise_training_data.caseid.unique()
np.random.shuffle(unique_caseids)
n = len(unique_caseids)
train_ids = unique_caseids[0:int(n*0.7)]
val_ids = unique_caseids[int(n*0.7):int(n*0.9)]
test_ids = unique_caseids[int(n*0.9):]
train_df = eventvise_training_data[eventvise_training_data.caseid.isin(train_ids)]
val_df = eventvise_training_data[eventvise_training_data.caseid.isin(val_ids)]
test_df = eventvise_training_data[eventvise_training_data.caseid.isin(test_ids)]
The WindowGenerator object
class WindowGenerator(object):
def __init__(self, input_width, label_width, shift,
train_df=train_df, val_df=val_df, test_df=test_df,id_column=0,
label_columns=None, batchsize=32, target_neg_ind=-3):
# Store the raw data.
self.train_df = train_df
self.val_df = val_df
self.test_df = test_df
self.batchsize = batchsize
self.id_column = id_column
self.id_name = id_column
self.unique_ids = unique_ids
self.target_neg_ind = target_neg_ind
self.generated_train_counter = 0
self.generated_val_counter = 0
self.generated_test_counter = 0
if self.unique_ids is None:
if type(id_column) == int:
self.unique_train_ids = train_df[train_df.columns[id_column]].unique()
self.unique_val_ids = val_df[val_df.columns[id_column]].unique()
self.unique_test_ids = test_df[test_df.columns[id_column]].unique()
self.id_name = train_df.columns[id_column]
elif type(id_column) == str:
self.unique_train_ids = train_df[id_column].unique()
self.unique_val_ids = val_df[id_column].unique()
self.unique_test_ids = test_df[id_column].unique()
# need the length of unique ids
self.num_unique_train = len(self.unique_train_ids)
self.num_unique_val = len(self.unique_val_ids)
self.num_unique_test = len(self.unique_test_ids)
# Work out the label column indices.
self.label_columns = label_columns
if label_columns is not None:
self.label_columns_indices = {name: i for i, name in
enumerate(label_columns)}
self.column_indices = {name: i for i, name in
enumerate(train_df.columns)}
# Work out the window parameters.
self.input_width = input_width
self.label_width = label_width
self.shift = shift
self.total_window_size = input_width + shift
self.input_slice = slice(0, input_width)
self.input_indices = np.arange(self.total_window_size)[self.input_slice]
self.label_start = self.total_window_size - self.label_width
self.labels_slice = slice(self.label_start, None)
self.label_indices = np.arange(self.total_window_size)[self.labels_slice]
self.label_name = list(self.label_columns_indices.keys())
def split_window(self, data, index_start_of_target=-3, type_of_data="train", seq_sliding=0, features=None):
seq_sliding = 0
if features is None:
features = self.generate_split_by_id(data, type_of_data=type_of_data)
if features is None:
return None, None, None, True
max_sliding = features.shape[1] - self.total_window_size
if seq_sliding > max_sliding:
return inputs, labels, features, False
if seq_sliding < 1:
input_slice = self.input_slice
output_slice = self.labels_slice
elif seq_sliding >= 1:
input_slice = slice(0+seq_sliding, self.input_width + seq_sliding)
output_slice = slice(0+seq_sliding, None)
inputs = features[:, input_slice, :index_start_of_target]
labels = features[:, output_slice, :]
if self.label_columns is not None:
labels = tf.stack( #-1 since we have removed the id columns
[labels[:, seq_sliding + self.label_start:seq_sliding+self.total_window_size, self.column_indices[name] - 1] for name in self.label_columns],
axis=-1)
# Slicing doesn't preserve static shape information, so set the shapes
# manually.
inputs.set_shape([None, self.input_width, None])
labels.set_shape([None, self.label_width, len(self.label_columns)])
return inputs, labels, features, False
def generate_split_by_id(self, data, type_of_data):
# to get the appropriate data for continuing on generating new batches
counter, num_unique, unique_ids = self.get_data_info(type_of_data=type_of_data)
start = counter
end = counter+self.batchsize
id_num = []
if end > num_unique: # to stop the batch collection before we run out caseIDs
end = num_unique
print("§§Finished training on all the data -- reseting counter§§")
flag = 1
counter = 0
self.set_data_info(type_of_data=type_of_data, counter=counter)
return
for num in range(start, end):
id_num.append(unique_ids[num])
counter += 1
self.set_data_info(type_of_data=type_of_data, counter=counter)
stacking_blocks = []
max_timesteps = 0
for ids in id_num[:]:
temp = data[data[self.id_name] == ids].drop(columns=[self.id_name]).to_numpy("float64")
if temp.shape[0] > max_timesteps:
max_timesteps = temp.shape[0]
stacking_blocks.append(temp)
# will create a postfix 3d-tensor
fill_array = np.zeros((len(id_num),max_timesteps,temp.shape[1]))
for sample_idx, sample in enumerate(stacking_blocks):
for time_step_idx, time_step in enumerate(sample):
fill_array[sample_idx, time_step_idx] = time_step
return tf.stack(fill_array)
def gen(self, data, type_of_data):
while 1:
# reset the sliding
sliding = 0
features = None
while 1:
input_data, output_data, features, stop_flag = self.split_window(data,
index_start_of_target=self.target_neg_ind,
type_of_data=type_of_data, seq_sliding=sliding)
sliding += 1
# break whens we run out of batches
if input_data is None:
break
yield input_data, output_data
if stop_flag:
break
def get_data_info(self, type_of_data=None):
if type_of_data == "train":
counter = self.generated_train_counter
num_unique = self.num_unique_train
unique_ids = self.unique_train_ids
elif type_of_data == "val":
counter = self.generated_val_counter
num_unique = self.num_unique_val
unique_ids = self.unique_val_ids
elif type_of_data == "test":
counter = self.generated_test_counter
num_unique = self.num_unique_test
unique_ids = self.unique_test_ids
return counter, num_unique, unique_ids
def set_data_info(self, type_of_data=None, counter=0):
if type_of_data == "train":
self.generated_train_counter = counter
elif type_of_data == "val":
self.generated_val_counter = counter
elif type_of_data == "test":
self.generated_test_counter = counter
I have extracted features from face and left and right iris using MobileNetV2 in keras tensorflow transfer learning. The features are then concatenated. I have tried to find the cosine similarity, euclidean distance and squared euclidean distance between the concatenated features. The distance scores I get for all the metrics do not show much difference between features belonging to the same sample pairs and feature belonging to different samples pairs. I will like have distances between sample features to have smaller distance than distances of different sample pairs. I think I am doing something fundamentally wrong somewhere. I want to be able to plot probability distribution from the scores I get in that the distributions from the different scores should not overlap.
Attached is my code. Any help would be much appreciated. Thank you
import pandas as pd
import datetime
from scipy.spatial import distance
from sklearn.preprocessing import LabelEncoder
from tensorflow.keras import backend as K
import h5py
import argparse
import random
import math
import tensorflow as tf
modelPath_face = 'HACK-FACE-SMALL-5-02.hdf5'
modelPath_liris = 'HACK-LIRIS-SMALL-5-02.hdf5'
modelPath_riris = 'HACK-RIRIS-SMALL-5-02.hdf5'
def cosine_distance(vests):
x, y = vests
x = K.l2_normalize(x, axis=-1)
y = K.l2_normalize(y, axis=-1)
return -K.mean(x * y, axis=-1, keepdims=True)
def compute_cosine_distances(a, b):
# x shape is n_a * dim
# y shape is n_b * dim
# results shape is n_a * n_b
normalize_a = tf.nn.l2_normalize(a, 1)
normalize_b = tf.nn.l2_normalize(b, 1)
distance = 1 - tf.matmul(normalize_a, normalize_b, transpose_b=True)
return distance
def cos_dist_output_shape(shapes):
shape1, shape2 = shapes
return (shape1[0], 1)
def eudis(v1, v2):
dist = [(a - b) ** 2 for a, b in zip(v1, v2)]
dist = math.sqrt(sum(dist))
return dist
def Extract(lst):
return [item[0] for item in lst]
if __name__ == '__main__':
import cv2
ap = argparse.ArgumentParser()
ap.add_argument("-df", "--db-face", default=modelPath_face, help="path to face HDF5 file")
ap.add_argument("-dli", "--db-liris", default=modelPath_liris, help="path to left iris HDF5 file")
ap.add_argument("-dri", "--db-riris", default=modelPath_riris, help="path to right iris HDF5 file")
ap.add_argument("-b", "--batch-size", type=int, default=8,
help="batch size of images to be passed through network")
ap.add_argument("-s", "--buffer-size", type=int, default=1000, help="size of feature extraction buffer")
ap.add_argument('--num-classes', default=53, type=int, metavar='NC',
help='number of classes (default: 10000)')
args = vars(ap.parse_args())
le = LabelEncoder()
db_face = h5py.File(args["db_face"], "r")
db_liris = h5py.File(args["db_liris"], "r")
db_riris = h5py.File(args["db_riris"], "r")
face_features = db_face["face_features"][:]
liris_features = db_liris["liris_features"][:]
riris_features = db_riris["riris_features"][:]
face_labels = db_face["labels"][:]
liris_labels = db_liris["labels"][:]
riris_labels = db_riris["labels"][:]
n_classes_to_find = le.fit_transform(face_labels)
n_classes = len(le.classes_)
args['num_classes'] = n_classes
face_labels = tf.keras.utils.to_categorical(face_labels, num_classes=args['num_classes'])
liris_labels = tf.keras.utils.to_categorical(liris_labels, num_classes=args['num_classes'])
riris_labels = tf.keras.utils.to_categorical(riris_labels, num_classes=args['num_classes'])
all_features = np.concatenate([face_features, liris_features, riris_features], axis=1)
all_labels = np.concatenate([face_labels, liris_labels, riris_labels], axis=1)
all_labels = np.argmax(all_labels, axis=-1)
stacked_all_ft = np.column_stack((all_features, all_labels))
columnIndex = stacked_all_ft.shape[1] - 1
sorted_stacked_all_ft = stacked_all_ft[stacked_all_ft[:, columnIndex].argsort()]
mylabels = sorted_stacked_all_ft[:, -1]
myfeatures = sorted_stacked_all_ft[:, :-1]
unique_labels = np.unique(mylabels)
myfeatures_shape = myfeatures.shape
# pca = PCA(0.9)
#
# pca.fit(myfeatures)
#
# PCA(copy=True, iterated_power='auto', n_components=0.9, random_state=None,
# svd_solver='auto', tol=0.0, whiten=False)
#
# print(pca.n_components_)
#
# myfeatures_pca = pca.transform(myfeatures)
df_pos_pair = pd.DataFrame()
df_neg_pair = pd.DataFrame()
positive_counter = 0
general_counter = 0
start_time = datetime.datetime.now().replace(microsecond=0)
print("COMPARISON OF ALL FILES: Started")
myfeatures_pca = myfeatures
for i in range(myfeatures_pca.shape[0]):
for j in range(myfeatures_pca.shape[0]):
if j > i:
general_counter += 1
pair_pos = mylabels[j] == mylabels[i]
if pair_pos:
positive_counter += 1
try:
f1 = myfeatures_pca[i]
f2 = myfeatures_pca[j]
# score = tf.keras.losses.cosine_similarity(f1, f2, axis=-1)
# score = score.numpy()
# aa = f1.reshape(1, -1)
# ba = f2.reshape(1, -1)
# score = cosine_similarity(aa, ba)
# score = score[0][0]
# score = eudis(f1, f2)
score = distance.sqeuclidean(f1, f2)
# if i in data1.index and j in data1.columns:
df_pos_pair = df_pos_pair.append({'score': score}, ignore_index=True)
general_counter += 1
if general_counter % 25 == 0:
end_time = datetime.datetime.now().replace(microsecond=0)
print("COMPLETED OF ALL FILES: {}, TOTAL TIME: {}".format(general_counter,
(end_time - start_time)))
except Exception as e:
print(e)
else:
for k2 in range(positive_counter):
r = random.randint(j + 1, myfeatures_pca.shape[0] - 2)
if mylabels[r] != mylabels[i]:
try:
f3 = myfeatures_pca[i]
f4 = myfeatures_pca[r]
# scoren = tf.keras.losses.cosine_similarity(f3, f4, axis=-1)
# scoren = score.numpy()
scoren = distance.sqeuclidean(f3, f4)
# aa2 = f3.reshape(1, -1)
# ba2 = f4.reshape(1, -1)
# scoren = cosine_similarity(aa2, ba2)
# scoren = scoren[0][0]
# scoren = eudis(f3, f4)
df_neg_pair = df_neg_pair.append({'score': scoren}, ignore_index=True)
general_counter += 1
end_time = datetime.datetime.now().replace(microsecond=0)
print("COMPLETED OF ALL FILES: {}, TOTAL TIME: {}".format(general_counter,
(end_time - start_time)))
except Exception as e:
print(e)
positive_counter = 0
break
end_time = datetime.datetime.now().replace(microsecond=0)
print("COMPARISON OF ALL FILES: Ended in {} ".format((end_time - start_time)))
df_neg_pair.to_csv("sqed_face_iris_neg_scores_pca_feb_01.csv", index=False)
df_pos_pair.to_csv("sqed_face_iris_pos_scores_pca_feb_01.csv", index=False)
I am trying to implement Keras triplet learning.
Here are two versions of get_triplet() I used:
"Trivial":
def get_triplet(nSplitIdx, bIsTrain):
positiveClass = np.random.choice(arrLabels)
# Depending train or validate, select range.
# say we have 10 images per class, and 70% does to train. Then 0-6 (train); 7-9 (valid, at least 3)
if(bIsTrain):
nMinIdx = 0
nMaxIdx = nSplitIdx - 1
else:
nMinIdx = nSplitIdx
nMaxIdx = NUM_OF_IMAGES_PER_CLASS - 1 - TESTING_IMAGES_PER_CLASS
# Get 3 indices: for base image and for positive example, from same class. And one more for negative example.
# TBD: figure (test) if SAME image should be used in a positive pair, like [img[1], img[1]]?
nImageIdx = np.random.choice(range(nMinIdx, nMaxIdx), 3)
while nImageIdx[0] == nImageIdx[1]:
nImageIdx[1] = np.random.choice(range(nMinIdx, nMaxIdx))
negativeClass = np.random.choice(arrLabels)
while negativeClass['Id'] == positiveClass['Id']:
negativeClass = np.random.choice(arrLabels)
negativeFileName = negativeClass['ImageNames'][nImageIdx[2]]
# nImageIdx is an array of 3 indexes: base and positive in positiveClass and negative in negativeClass.
# Ex: positiveClass[nImageIdx[0], positiveClass[nImageIdx[1]], negativeClass[nImageIdx[2]]
return nImageIdx, positiveClass, negativeClass
and "semi-hard" (though not so elegant):
# Used to mine ONLY
def getDistance(a, b):
distance = (a - b)**2
distance = sum(distance)
return distance
graph = tf.get_default_graph()
def getExampleIdx(positiveClass, negativeClass, bIsPositive, nAncorIdx):
global embedding_model
# tensorflow model is not loaded and used in the same thread. One workaround is to force tensorflow to use the gloabl default graph.
global graph
with graph.as_default():
imgAncor = positiveClass['Images'][nAncorIdx]
if(bIsPositive):
cClass = positiveClass
else:
cClass = negativeClass
arrExamples = []
arrExamples.append(np.array(imgAncor, dtype="float32") / 255.) # Add ancor image as 0th element
if(bIsPositive):
for i in range(TRAINING_IMAGES_PER_CLASS):
# img = loadImage(cClass, i, datagen)
# arrExamples.append(np.array(img, dtype="float32") / 255.)
# Note: no augmentation here
img = cClass['Images'][i]
arrExamples.append(np.array(img, dtype="float32") / 255.)
else:
# For a batch
if(BATCH_SIZE > len(arrLabels)):
nMinRange = len(arrLabels)
nStartClassIdx = 0
else:
nMinRange = BATCH_SIZE + 1
nStartClassIdx = np.random.choice(range(len(arrLabels) - nMinRange))
for nClassId in range(nStartClassIdx, nStartClassIdx + nMinRange):
cClass = arrLabels[nClassId]
if cClass['Id'] == positiveClass['Id']:
continue
# We do it to speed it up, but generally, it should be uncommented: for instead of rand
i = np.random.choice(range(TRAINING_IMAGES_PER_CLASS))
#for i in range(TRAINING_IMAGES_PER_CLASS):
# Note: no augmentation here
img = cClass['Images'][i]
arrExamples.append(np.array(img, dtype="float32") / 255.)
arrPredictionsPos = embedding_model.predict([arrExamples])
# Get distances between 0th predictions and other predictions
arrDistancesPos = []
for i in range(1, len(arrPredictionsPos)):
arrDistancesPos.append(getDistance(arrPredictionsPos[0], arrPredictionsPos[i]))
#print("{}, ".format(arrDistancesPos[i - 1]))
if(bIsPositive):
#print("Positive: {}, ".format(arrDistancesPos[np.array(arrDistancesPos).argmax()]))
return np.array(arrDistancesPos).argmax(), positiveClass
else:
#print("Negative: {}, ".format(arrDistancesPos[np.array(arrDistancesPos).argmin()]))
nNegativeIdx = np.array(arrDistancesPos).argmin() % TRAINING_IMAGES_PER_CLASS
return nNegativeIdx, arrLabels[nStartClassIdx + nNegativeIdx // TRAINING_IMAGES_PER_CLASS]
# ---
def get_triplet(nSplitIdx, bIsTrain):
# Select random class
positiveClass = np.random.choice(arrLabels)
negativeClass = np.random.choice(arrLabels)
while negativeClass['Id'] == positiveClass['Id']:
negativeClass = np.random.choice(arrLabels)
# Depending train or validate, select range.
# say we have 10 images per class, and 70% does to train. Then 0-6 (train); 7-9 (valid, at least 3)
if(bIsTrain):
nMinIdx = 0
nMaxIdx = nSplitIdx
else:
nMinIdx = nSplitIdx
nMaxIdx = NUM_OF_IMAGES_PER_CLASS - TESTING_IMAGES_PER_CLASS
arrImageIdx = np.random.choice(range(nMinIdx, nMaxIdx), 3)
if(bIsTrain):
arrImageIdx[1], positiveClass = getExampleIdx(positiveClass, positiveClass, True, arrImageIdx[0])
arrImageIdx[2], negativeClass = getExampleIdx(positiveClass, negativeClass, False, arrImageIdx[0])
else:
while arrImageIdx[0] == arrImageIdx[1]:
arrImageIdx[1] = np.random.choice(range(nMinIdx, nMaxIdx))
#negativeFileName = negativeClass['ImageNames'][arrImageIdx[2]]
# nImageIdx is an array of 3 indexes: base and positive in positiveClass and negative in negativeClass.
# Ex: positiveClass[nImageIdx[0], positiveClass[nImageIdx[1]], negativeClass[nImageIdx[2]]
return arrImageIdx, positiveClass, negativeClass
Now, the generator:
from time import time
#t0 = time()
#t1 = time()
#print('get_triplet takes %f' %(t1-t0))
def gen(bIsTrain):
#nSplitIdx = int(NUM_OF_IMAGES_PER_CLASS * TESTING_SPLIT)
while True:
arrBaseExamples = []
arrPositiveExamples = []
arrNegativeExamples = []
for i in range(BATCH_SIZE):
nImageIdx, positiveClass, negativeClass = get_triplet(TRAINING_IMAGES_PER_CLASS, bIsTrain)
#t0 = time()
baseExampleImg = loadImage(positiveClass, nImageIdx[0], datagen)
positiveExampleImg = loadImage(positiveClass, nImageIdx[1], datagen)
negativeExampleImg = loadImage(negativeClass, nImageIdx[2], datagen)
#t1 = time()
#print('loaded in %f' %(t1-t0))
arrBaseExamples.append(baseExampleImg)
arrPositiveExamples.append(positiveExampleImg)
arrNegativeExamples.append(negativeExampleImg)
#base = preprocess_input(np.array(arrBaseExamples)) / 255. #'a' #preprocess_input(np.array(arrBaseExamples))
base = np.array(arrBaseExamples) / 255.
#train_datagen.fit(base)
#positive = preprocess_input(np.array(arrPositiveExamples)) / 255.
positive = np.array(arrPositiveExamples) / 255.
#train_datagen.fit(positive)
#negative = preprocess_input(np.array(arrNegativeExamples)) / 255.
negative = np.array(arrNegativeExamples) / 255.
#train_datagen.fit(negative)
label = None
yield ({'anchor_input': base, 'positive_input': positive, 'negative_input': negative}, label)
and finally, triplet_loss function (stolen from Kaggle):
ALPHA = 0.2 # Triplet Loss Parameter
def triplet_loss(inputs, dist='sqeuclidean', margin='maxplus'):
anchor, positive, negative = inputs
positive_distance = K.square(anchor - positive)
negative_distance = K.square(anchor - negative)
if dist == 'euclidean':
positive_distance = K.sqrt(K.sum(positive_distance, axis=-1, keepdims=True))
negative_distance = K.sqrt(K.sum(negative_distance, axis=-1, keepdims=True))
elif dist == 'sqeuclidean':
positive_distance = K.sum(positive_distance, axis=-1, keepdims=True)
negative_distance = K.sum(negative_distance, axis=-1, keepdims=True)
loss = positive_distance - negative_distance + ALPHA
if margin == 'maxplus':
loss = K.maximum(0.0, 1 + loss)
elif margin == 'softplus':
loss = K.log(1 + K.exp(loss))
return K.mean(loss)
The model is "transfer learning":
def createModel(nL2):
base_model = ResNet50(weights='imagenet', include_top=False, pooling='max')
for layer in base_model.layers:
layer.trainable = False
x = base_model.output
x = Dropout(0.6, name="classifier_dropout")(x)
x = Dense(EMBEDDING_DIM, activation='relu', name="classifier_dense_0", kernel_regularizer=regularizers.l2(nL2))(x)
x = Dense(EMBEDDING_DIM, activation='relu', name="classifier_dense_1", kernel_regularizer=regularizers.l2(nL2))(x)
x = Dense(EMBEDDING_DIM, activation='softmax', name="classifier_dense", kernel_regularizer=regularizers.l2(nL2))(x)
x = Lambda(lambda x: K.l2_normalize(x,axis=1), name="lambda")(x)
embedding_model = Model(base_model.input, x, name="embedding")
input_shape = (IMAGE_SIZE, IMAGE_SIZE, 3)
anchor_input = Input(input_shape, name='anchor_input')
positive_input = Input(input_shape, name='positive_input')
negative_input = Input(input_shape, name='negative_input')
anchor_embedding = embedding_model(anchor_input)
positive_embedding = embedding_model(positive_input)
negative_embedding = embedding_model(negative_input)
inputs = [anchor_input, positive_input, negative_input]
outputs = [anchor_embedding, positive_embedding, negative_embedding]
triplet_model = Model(inputs, outputs)
triplet_model.add_loss(K.mean(triplet_loss(outputs)))
return embedding_model, triplet_model
I create and teach it on four Kaggle's dog species (the original dataset has 120, I only use four):
BATCH_SIZE = 16
EPOCHS = 200
arrParams = [[0.8, 3]]
checkpoint = ModelCheckpoint(best_weights_filepath, monitor="val_loss", save_best_only=True, save_weights_only=True, mode='auto')
callbacks_list = [checkpoint] # , early]
gen_train = gen(True)
gen_valid = gen(False)
for i in range(0, len(arrParams)):
nL2 = arrParams[i][0]
EMBEDDING_DIM = arrParams[i][1]
deleteSavedNet(best_weights_filepath)
embedding_model, triplet_model = createModel(nL2)
nNumOfClasses = len(arrLabels)
nNumOfTrainSamples = TRAINING_IMAGES_PER_CLASS * nNumOfClasses
nNumOfValidSamples = VALIDATION_IMAGES_PER_CLASS * nNumOfClasses
STEP_SIZE_TRAIN = nNumOfTrainSamples // BATCH_SIZE
if(STEP_SIZE_TRAIN == 0):
STEP_SIZE_TRAIN = 1
STEP_SIZE_VALID = nNumOfValidSamples // BATCH_SIZE
if(STEP_SIZE_VALID == 0):
STEP_SIZE_VALID = 1
triplet_model.compile(loss=None, optimizer="adam", metrics=['binary_accuracy']) #metrics=['accuracy'])
history = triplet_model.fit_generator(gen_train, validation_data=gen_valid,
epochs=EPOCHS, verbose=1, steps_per_epoch=STEP_SIZE_TRAIN, validation_steps=STEP_SIZE_VALID, callbacks=callbacks_list)
print(nL2, EMBEDDING_DIM)
plotHistoryLoss()
It learns:
deleteSavedNet():File removed
Initializing model
Finished initializing model
Epoch 1/200
6/6 [==============================] - 44s 7s/step - loss: 8.0306 - val_loss: 7.6388
Epoch 2/200
6/6 [==============================] - 15s 2s/step - loss: 7.0082 - val_loss: 6.7307
...
Epoch 200/200
6/6 [==============================] - 15s 3s/step - loss: 0.7046 - val_loss: 0.7043
But (notice I used 3 dim. embeding) when I plot results, I see line, not clasters :
nL2 = arrParams[0][0]
EMBEDDING_DIM = arrParams[0][1]
embedding_model, triplet_model = createModel(nL2)
loadBestModel()
def data_generator_simple(arrAllImages, arrAllImageLabels, arrAllImageClasses):
i = 0
arrImages = []
arrImageLabels = []
arrImageClasses = []
for nImageIdx in range(len(arrAllImages)):
if(i == 0):
arrImages = []
arrImageLabels = []
arrImageClasses = []
i += 1
arrImg = img_to_array(arrAllImages[nImageIdx])
arrImg = datagen.random_transform(arrImg) / 255.
arrImg = np.array(arrImg, dtype="float32")
arrImages.append(arrImg)
arrImageLabels.append(arrAllImageLabels[nImageIdx])
arrImageClasses.append(arrAllImageClasses[nImageIdx])
if i == BATCH_SIZE:
i = 0
arrImages = np.array(arrImages)
yield arrImages, arrImageLabels, arrImageClasses
if i != 0:
arrImages = np.array(arrImages)
yield arrImages, arrImageLabels, arrImageClasses
raise StopIteration()
arrAllImages = []
arrAllImageLabels = []
arrAllImageClasses = []
for cClass in arrLabels:
for nIdx in range(TRAINING_IMAGES_PER_CLASS):
arrAllImages.append(cClass['Images'][nIdx])
arrAllImageLabels.append(cClass['ImageNames'][nIdx])
arrAllImageClasses.append(cClass['Id'])
train_preds = []
train_file_names = []
train_class_names = []
np.random.seed(7)
for imgs, fnames, classes in data_generator_simple(arrAllImages, arrAllImageLabels, arrAllImageClasses):
predicts = embedding_model.predict(imgs)
predicts = predicts.tolist()
train_preds += predicts
train_file_names += fnames
train_class_names += classes
train_preds = np.array(train_preds)
arrAllImages = []
arrAllImageLabels = []
arrAllImageClasses = []
for cClass in arrLabels:
#for nIdx in range(TRAINING_IMAGES_PER_CLASS + VALIDATION_IMAGES_PER_CLASS, TRAINING_IMAGES_PER_CLASS + VALIDATION_IMAGES_PER_CLASS + TESTING_IMAGES_PER_CLASS):
#for nIdx in range(TRAINING_IMAGES_PER_CLASS):
for nIdx in range(TRAINING_IMAGES_PER_CLASS + VALIDATION_IMAGES_PER_CLASS, TRAINING_IMAGES_PER_CLASS + VALIDATION_IMAGES_PER_CLASS + TESTING_IMAGES_PER_CLASS):
arrAllImages.append(cClass['Images'][nIdx])
arrAllImageLabels.append(cClass['ImageNames'][nIdx])
arrAllImageClasses.append(cClass['Id'])
test_preds = []
test_file_names = []
test_class_names = []
np.random.seed(7)
for imgs, fnames, classes in data_generator_simple(arrAllImages, arrAllImageLabels, arrAllImageClasses):
predicts = embedding_model.predict(imgs)
predicts = predicts.tolist()
test_preds += predicts
test_file_names += fnames
test_class_names += classes
test_preds = np.array(test_preds)
neigh = NearestNeighbors(n_neighbors=6)
neigh.fit(train_preds)
#neigh.fit(arrTrainingClasterCenters)
distances_test, neighbors_test = neigh.kneighbors(test_preds)
distances_test, neighbors_test = distances_test.tolist(), neighbors_test.tolist()
data = pd.read_csv(working_path + "DogRecognizer/dogs/train_dogs.csv")
file_id_mapping = {k: v for k, v in zip(data.Image.values, data.Id.values)}
preds_str = []
arrSearchPositions = []
for filepath, distance, neighbour_ in zip(test_file_names, distances_test, neighbors_test):
sample_result = []
sample_classes = []
for d, n in zip(distance, neighbour_):
#class_train = arrLabels[n]['Id']
train_file = train_file_names[n].split(os.sep)[-1]
class_train = file_id_mapping[train_file]
sample_classes.append(class_train)
sample_result.append((class_train, d))
#if "new_whale" not in sample_classes:
# sample_result.append(("new_whale", 0.1))
sample_result.sort(key=lambda x: x[1], reverse=True)
sample_result = sample_result[:5]
preds_str.append(" ".join([x[0] for x in sample_result]))
nTotalSuccess = 0
for i, strClassNames in enumerate(preds_str):
if(test_class_names[i] in strClassNames):
strContains = ": Yes"
nTotalSuccess += 1
else:
strContains = ": No"
#print(test_class_names[i], ": ", strClassNames, " (", strContains, ")")
print ("Success rate: ", nTotalSuccess / (i+1) )
import pylab as pl
from sklearn import neighbors, datasets
import matplotlib.cm as cm
h = 0.02
knn=neighbors.KNeighborsClassifier(n_neighbors=6)
knn.fit(test_preds, test_class_names)
x_min, x_max = test_preds[:,0].min() - .01, test_preds[:,0].max() + .02
y_min, y_max = test_preds[:,1].min() - .01, test_preds[:,1].max() + .02
z_min, z_max = test_preds[:,2].min() - .01, test_preds[:,2].max() + .01
xx, yy, zz = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h), np.arange(z_min, z_max, h))
#Z = knn.predict(np.c_[xx.ravel(), yy.ravel(), zz.ravel()])
color_space = []
for i in range(len(test_class_names)):
if(test_class_names[i] == 'pembroke'):
color_space.append('red')
#test_preds[:,1][i] += 0.01
elif(test_class_names[i] == 'maltese_dog'):
color_space.append('green')
#test_preds[:,1][i] += 0.02
elif(test_class_names[i] == 'gordon_setter'):
color_space.append('orange')
#test_preds[:,1][i] += 0.03
else:
color_space.append('blue')
from matplotlib import pyplot
from mpl_toolkits.mplot3d import Axes3D
import random
fig = pyplot.figure(figsize=(16, 8))
ax = Axes3D(fig)
pl.set_cmap(pl.cm.Paired)
ax.scatter(test_preds[:,0], test_preds[:,1], test_preds[:,2], c= color_space)
pyplot.show()
Here is the plot:
Why is it line, not clasters?
I'm trying to modify the following code by training OpenCV's Fisher Face classifier for particular images of faces. And I don't know why the code below shows
Traceback (most recent call last):
File "create_model.py", line 109, in <module>
update(emotions)
File "create_model.py", line 104, in update
run_recognizer(emotions)
File "create_model.py", line 101, in run_recognizer
fishface.train(np.array(training_data), npar_trainlabs)
TypeError: src is not a numpy array, neither a scalar
training_data contains dlib's vectorized_landmarks and I'm converting them to numpy array, and training_labels is just either label 1 or 2.
Functions involved in Traceback are following ones:
fishface = cv2.face.createFisherFaceRecognizer()
emotions = ["True", "Glasses"]
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
def get_landmarks(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cimage = clahe.apply(gray)
detections = detector(cimage, 1)
landmarks_vectorised = []
for k, d in enumerate(detections): # For all detected face instances individually
shape = predictor(cimage, d) # Draw Facial Landmarks with the predictor class
xlist = []
ylist = []
for i in range(1, 68): # Store X and Y coordinates in two lists
xlist.append(float(shape.part(i).x))
ylist.append(float(shape.part(i).y))
xmean = np.mean(xlist) # Get the mean of both axes to determine centre of gravity
ymean = np.mean(ylist)
xcentral = [(x - xmean) for x in xlist] # get distance between each point and the central point in both axes
ycentral = [(y - ymean) for y in ylist]
if xlist[26] == xlist[
29]: # If x-coordinates of the set are the same, the angle is 0, catch to prevent 'divide by 0' error in function
anglenose = 0
else:
anglenose = int(math.atan((ylist[26] - ylist[29]) / (xlist[26] - xlist[29])) * 180 / math.pi)
if anglenose < 0:
anglenose += 90
else:
anglenose -= 90
landmarks_vectorised = []
if len(detections) < 1:
landmarks_vectorised = "error"
for x, y, w, z in zip(xcentral, ycentral, xlist, ylist):
landmarks_vectorised.append(x)
landmarks_vectorised.append(y)
meannp = np.asarray((ymean, xmean))
coornp = np.asarray((z, w))
dist = np.linalg.norm(coornp - meannp)
anglerelative = (math.atan((z - ymean) / (w - xmean)) * 180 / math.pi) - anglenose
landmarks_vectorised.append(dist)
landmarks_vectorised.append(anglerelative)
return landmarks_vectorised
def make_sets(labels):
training_data = []
training_labels = []
for label in labels:
training = glob.glob("data\\%s\\*" % label)
print(len(training))
for item in training:
try:
image = cv2.imread(item)
except:
continue
print(item)
landmarks_vectorised = get_landmarks(image)
if landmarks_vectorised == "error":
print("error with landmarks")
pass
else:
training_data.append(landmarks_vectorised)
if str(label) == "True":
training_labels.append(2)
elif str(label) == "Glasses":
training_labels.append(1)
print("sets created")
return training_data, training_labels
def make_sets(labels):
training_data = []
training_labels = []
for label in labels:
training = glob.glob("data\\%s\\*" % label)
print(len(training))
for item in training:
try:
image = cv2.imread(item)
except:
continue
print(item)
landmarks_vectorised = get_landmarks(image)
if landmarks_vectorised == "error":
print("error with landmarks")
pass
else:
training_data.append(landmarks_vectorised)
if str(label) == "True":
training_labels.append(2)
elif str(label) == "Glasses":
training_labels.append(1)
print("sets created")
return training_data, training_labels
def run_recognizer(emotions):
training_data, training_labels = make_sets(emotions)
print("training fisher face classifier")
print(type(training_data))
print(type(training_labels))
npar_train = np.array(training_data)
npar_trainlabs = np.array(training_labels)
fishface.train(np.array(training_data), npar_trainlabs)
def update(emotions):
run_recognizer(emotions)
fishface.save("glasses.xml")
update(emotions)
Please help me understand the meaning of such an error.
Try to print your training_data and its dtype, maybe you can put them in a list, then transform the list to np.array. Do the same operations to your labels.
Previously I created a lot of Python objects of class A, and I would like to add a new function plotting_in_PC_space_with_coloring_option() (the purpose of this function is to plot some data in this object) to class A and use those old objects to call plotting_in_PC_space_with_coloring_option().
An example is:
import copy
import numpy as np
from math import *
from pybrain.structure import *
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.datasets.supervised import SupervisedDataSet
import pickle
import neural_network_related
class A(object):
"""the neural network for simulation"""
'''
todo:
- find boundary
- get_angles_from_coefficients
'''
def __init__(self,
index, # the index of the current network
list_of_coor_data_files, # accept multiple files of training data
energy_expression_file, # input, output files
preprocessing_settings = None,
connection_between_layers = None, connection_with_bias_layers = None,
PCs = None, # principal components
):
self._index = index
self._list_of_coor_data_files = list_of_coor_data_files
self._energy_expression_file = energy_expression_file
self._data_set = []
for item in list_of_coor_data_files:
self._data_set += self.get_many_cossin_from_coordiantes_in_file(item)
self._preprocessing_settings = preprocessing_settings
self._connection_between_layers = connection_between_layers
self._connection_with_bias_layers = connection_with_bias_layers
self._node_num = [8, 15, 2, 15, 8]
self._PCs = PCs
def save_into_file(self, filename = None):
if filename is None:
filename = "network_%s.pkl" % str(self._index) # by default naming with its index
with open(filename, 'wb') as my_file:
pickle.dump(self, my_file, pickle.HIGHEST_PROTOCOL)
return
def get_cossin_from_a_coordinate(self, a_coordinate):
num_of_coordinates = len(a_coordinate) / 3
a_coordinate = np.array(a_coordinate).reshape(num_of_coordinates, 3)
diff_coordinates = a_coordinate[1:num_of_coordinates, :] - a_coordinate[0:num_of_coordinates - 1,:] # bond vectors
diff_coordinates_1=diff_coordinates[0:num_of_coordinates-2,:];diff_coordinates_2=diff_coordinates[1:num_of_coordinates-1,:]
normal_vectors = np.cross(diff_coordinates_1, diff_coordinates_2);
normal_vectors_normalized = np.array(map(lambda x: x / sqrt(np.dot(x,x)), normal_vectors))
normal_vectors_normalized_1 = normal_vectors_normalized[0:num_of_coordinates-3, :];normal_vectors_normalized_2 = normal_vectors_normalized[1:num_of_coordinates-2,:];
diff_coordinates_mid = diff_coordinates[1:num_of_coordinates-2]; # these are bond vectors in the middle (remove the first and last one), they should be perpendicular to adjacent normal vectors
cos_of_angles = range(len(normal_vectors_normalized_1))
sin_of_angles_vec = range(len(normal_vectors_normalized_1))
sin_of_angles = range(len(normal_vectors_normalized_1)) # initialization
for index in range(len(normal_vectors_normalized_1)):
cos_of_angles[index] = np.dot(normal_vectors_normalized_1[index], normal_vectors_normalized_2[index])
sin_of_angles_vec[index] = np.cross(normal_vectors_normalized_1[index], normal_vectors_normalized_2[index])
sin_of_angles[index] = sqrt(np.dot(sin_of_angles_vec[index], sin_of_angles_vec[index])) * np.sign(sum(sin_of_angles_vec[index]) * sum(diff_coordinates_mid[index]));
return cos_of_angles + sin_of_angles
def get_many_cossin_from_coordinates(self, coordinates):
return map(self.get_cossin_from_a_coordinate, coordinates)
def get_many_cossin_from_coordiantes_in_file (self, filename):
coordinates = np.loadtxt(filename)
return self.get_many_cossin_from_coordinates(coordinates)
def mapminmax(self, my_list): # for preprocessing in network
my_min = min(my_list)
my_max = max(my_list)
mul_factor = 2.0 / (my_max - my_min)
offset = (my_min + my_max) / 2.0
result_list = np.array(map(lambda x : (x - offset) * mul_factor, my_list))
return (result_list, (mul_factor, offset)) # also return the parameters for processing
def get_mapminmax_preprocess_result_and_coeff(self,data=None):
if data is None:
data = self._data_set
data = np.array(data)
data = np.transpose(data)
result = []; params = []
for item in data:
temp_result, preprocess_params = self.mapminmax(item)
result.append(temp_result)
params.append(preprocess_params)
return (np.transpose(np.array(result)), params)
def mapminmax_preprocess_using_coeff(self, input_data=None, preprocessing_settings=None):
# try begin
if preprocessing_settings is None:
preprocessing_settings = self._preprocessing_settings
temp_setttings = np.transpose(np.array(preprocessing_settings))
result = []
for item in input_data:
item = np.multiply(item - temp_setttings[1], temp_setttings[0])
result.append(item)
return result
# try end
def get_expression_of_network(self, connection_between_layers=None, connection_with_bias_layers=None):
if connection_between_layers is None:
connection_between_layers = self._connection_between_layers
if connection_with_bias_layers is None:
connection_with_bias_layers = self._connection_with_bias_layers
node_num = self._node_num
expression = ""
# first part: network
for i in range(2):
expression = '\n' + expression
mul_coef = connection_between_layers[i].params.reshape(node_num[i + 1], node_num[i])
bias_coef = connection_with_bias_layers[i].params
for j in range(np.size(mul_coef, 0)):
temp_expression = 'layer_%d_unit_%d = tanh( ' % (i + 1, j)
for k in range(np.size(mul_coef, 1)):
temp_expression += ' %f * layer_%d_unit_%d +' % (mul_coef[j, k], i, k)
temp_expression += ' %f);\n' % (bias_coef[j])
expression = temp_expression + expression # order of expressions matter in OpenMM
# second part: definition of inputs
index_of_backbone_atoms = [2, 5, 7, 9, 15, 17, 19];
for i in range(len(index_of_backbone_atoms) - 3):
index_of_coss = i
index_of_sins = i + 4
expression += 'layer_0_unit_%d = (raw_layer_0_unit_%d - %f) * %f;\n' % \
(index_of_coss, index_of_coss, self._preprocessing_settings[index_of_coss][1], self._preprocessing_settings[index_of_coss][0])
expression += 'layer_0_unit_%d = (raw_layer_0_unit_%d - %f) * %f;\n' % \
(index_of_sins, index_of_sins, self._preprocessing_settings[index_of_sins][1], self._preprocessing_settings[index_of_sins][0])
expression += 'raw_layer_0_unit_%d = cos(dihedral_angle_%d);\n' % (index_of_coss, i)
expression += 'raw_layer_0_unit_%d = sin(dihedral_angle_%d);\n' % (index_of_sins, i)
expression += 'dihedral_angle_%d = dihedral(p%d, p%d, p%d, p%d);\n' % \
(i, index_of_backbone_atoms[i], index_of_backbone_atoms[i+1],index_of_backbone_atoms[i+2],index_of_backbone_atoms[i+3])
return expression
def write_expression_into_file(self, out_file = None):
if out_file is None: out_file = self._energy_expression_file
expression = self.get_expression_of_network()
with open(out_file, 'w') as f_out:
f_out.write(expression)
return
def get_mid_result(self, input_data=None, connection_between_layers=None, connection_with_bias_layers=None):
if input_data is None: input_data = self._data_set
if connection_between_layers is None: connection_between_layers = self._connection_between_layers
if connection_with_bias_layers is None: connection_with_bias_layers = self._connection_with_bias_layers
node_num = self._node_num
temp_mid_result = range(4)
mid_result = []
# first need to do preprocessing
for item in self.mapminmax_preprocess_using_coeff(input_data, self._preprocessing_settings):
for i in range(4):
mul_coef = connection_between_layers[i].params.reshape(node_num[i + 1], node_num[i]) # fix node_num
bias_coef = connection_with_bias_layers[i].params
previous_result = item if i == 0 else temp_mid_result[i - 1]
temp_mid_result[i] = np.dot(mul_coef, previous_result) + bias_coef
if i != 3: # the last output layer is a linear layer, while others are tanh layers
temp_mid_result[i] = map(tanh, temp_mid_result[i])
mid_result.append(copy.deepcopy(temp_mid_result)) # note that should use deepcopy
return mid_result
def get_PC_and_save_it_to_network(self):
'''get PCs and save the result into _PCs
'''
mid_result = self.get_mid_result()
self._PCs = [item[1] for item in mid_result]
return
def train(self):
####################### set up autoencoder begin #######################
node_num = self._node_num
in_layer = LinearLayer(node_num[0], "IL")
hidden_layers = [TanhLayer(node_num[1], "HL1"), TanhLayer(node_num[2], "HL2"), TanhLayer(node_num[3], "HL3")]
bias_layers = [BiasUnit("B1"),BiasUnit("B2"),BiasUnit("B3"),BiasUnit("B4")]
out_layer = LinearLayer(node_num[4], "OL")
layer_list = [in_layer] + hidden_layers + [out_layer]
molecule_net = FeedForwardNetwork()
molecule_net.addInputModule(in_layer)
for item in (hidden_layers + bias_layers):
molecule_net.addModule(item)
molecule_net.addOutputModule(out_layer)
connection_between_layers = range(4); connection_with_bias_layers = range(4)
for i in range(4):
connection_between_layers[i] = FullConnection(layer_list[i], layer_list[i+1])
connection_with_bias_layers[i] = FullConnection(bias_layers[i], layer_list[i+1])
molecule_net.addConnection(connection_between_layers[i]) # connect two neighbor layers
molecule_net.addConnection(connection_with_bias_layers[i])
molecule_net.sortModules() # this is some internal initialization process to make this module usable
####################### set up autoencoder end #######################
trainer = BackpropTrainer(molecule_net, learningrate=0.002,momentum=0.4,verbose=False, weightdecay=0.1, lrdecay=1)
data_set = SupervisedDataSet(node_num[0], node_num[4])
sincos = self._data_set
(sincos_after_process, self._preprocessing_settings) = self.get_mapminmax_preprocess_result_and_coeff(data = sincos)
for item in sincos_after_process: # is it needed?
data_set.addSample(item, item)
trainer.trainUntilConvergence(data_set, maxEpochs=50)
self._connection_between_layers = connection_between_layers
self._connection_with_bias_layers = connection_with_bias_layers
print("Done!\n")
return
def create_sge_files_for_simulation(self,potential_centers = None):
if potential_centers is None:
potential_centers = self.get_boundary_points()
neural_network_related.create_sge_files(potential_centers)
return
def get_boundary_points(self, list_of_points = None, num_of_bins = 5):
if list_of_points is None: list_of_points = self._PCs
x = [item[0] for item in list_of_points]
y = [item[1] for item in list_of_points]
temp = np.histogram2d(x,y, bins=[num_of_bins, num_of_bins])
hist_matrix = temp[0]
# add a set of zeros around this region
hist_matrix = np.insert(hist_matrix, num_of_bins, np.zeros(num_of_bins), 0)
hist_matrix = np.insert(hist_matrix, 0, np.zeros(num_of_bins), 0)
hist_matrix = np.insert(hist_matrix, num_of_bins, np.zeros(num_of_bins + 2), 1)
hist_matrix = np.insert(hist_matrix, 0, np.zeros(num_of_bins +2), 1)
hist_matrix = (hist_matrix != 0).astype(int)
sum_of_neighbors = np.zeros(np.shape(hist_matrix)) # number of neighbors occupied with some points
for i in range(np.shape(hist_matrix)[0]):
for j in range(np.shape(hist_matrix)[1]):
if i != 0: sum_of_neighbors[i,j] += hist_matrix[i - 1][j]
if j != 0: sum_of_neighbors[i,j] += hist_matrix[i][j - 1]
if i != np.shape(hist_matrix)[0] - 1: sum_of_neighbors[i,j] += hist_matrix[i + 1][j]
if j != np.shape(hist_matrix)[1] - 1: sum_of_neighbors[i,j] += hist_matrix[i][j + 1]
bin_width_0 = temp[1][1]-temp[1][0]
bin_width_1 = temp[2][1]-temp[2][0]
min_coor_in_PC_space_0 = temp[1][0] - 0.5 * bin_width_0 # multiply by 0.5 since we want the center of the grid
min_coor_in_PC_space_1 = temp[2][0] - 0.5 * bin_width_1
potential_centers = []
for i in range(np.shape(hist_matrix)[0]):
for j in range(np.shape(hist_matrix)[1]):
if hist_matrix[i,j] == 0 and sum_of_neighbors[i,j] != 0: # no points in this block but there are points in neighboring blocks
temp_potential_center = [round(min_coor_in_PC_space_0 + i * bin_width_0, 2), round(min_coor_in_PC_space_1 + j * bin_width_1, 2)]
potential_centers.append(temp_potential_center)
return potential_centers
# this function is added after those old objects of A were created
def plotting_in_PC_space_with_coloring_option(self,
list_of_coordinate_files_for_plotting=None, # accept multiple files
color_option='pure'):
'''
by default, we are using training data, and we also allow external data input
'''
if list_of_coordinate_files_for_plotting is None:
PCs_to_plot = self._PCs
else:
temp_sincos = []
for item in list_of_coordinate_files_for_plotting:
temp_sincos += self.get_many_cossin_from_coordiantes_in_file(item)
temp_mid_result = self.get_mid_result(input_data = temp_sincos)
PCs_to_plot = [item[1] for item in temp_mid_result]
(x, y) = ([item[0] for item in PCs_to_plot], [item[1] for item in PCs_to_plot])
# coloring
if color_option == 'pure':
coloring = 'red'
elif color_option == 'step':
coloring = range(len(x))
fig, ax = plt.subplots()
ax.scatter(x,y, c=coloring)
ax.set_xlabel("PC1")
ax.set_ylabel("PC2")
plt.show()
return
But it seems that plotting_in_PC_space_with_coloring_option() was not binded to those old objects, is here any way to fix it (I do not want to recreate these objects since creation involves CPU-intensive calculation and would take very long time to do it)?
Thanks!
Something like this:
class A:
def q(self): print 1
a = A()
def f(self): print 2
setattr(A, 'f', f)
a.f()
This is called a monkey patch.