提交 ca7c0a9a 编写于 作者: D dengkaipeng

refine accuracy

上级 a65ad557
...@@ -17,6 +17,7 @@ from __future__ import absolute_import ...@@ -17,6 +17,7 @@ from __future__ import absolute_import
import six import six
import abc import abc
import numpy as np import numpy as np
import paddle.fluid as fluid
import logging import logging
FORMAT = '%(asctime)s-%(levelname)s: %(message)s' FORMAT = '%(asctime)s-%(levelname)s: %(message)s'
...@@ -59,6 +60,12 @@ class Metric(object): ...@@ -59,6 +60,12 @@ class Metric(object):
""" """
raise NotImplementedError("function 'accumulate' not implemented in {}.".format(self.__class__.__name__)) raise NotImplementedError("function 'accumulate' not implemented in {}.".format(self.__class__.__name__))
def add_metric_op(self, pred, label):
"""
Add process op for metric in program
"""
return pred, label
class Accuracy(Metric): class Accuracy(Metric):
""" """
...@@ -71,19 +78,28 @@ class Accuracy(Metric): ...@@ -71,19 +78,28 @@ class Accuracy(Metric):
self.maxk = max(topk) self.maxk = max(topk)
self.reset() self.reset()
def update(self, pred, label, *args, **kwargs): def add_metric_op(self, pred, label, *args, **kwargs):
pred = np.argsort(pred[0])[:, ::-1][:, :self.maxk] pred = fluid.layers.argsort(pred[0], descending=True)[1][:, :self.maxk]
corr = (pred == np.repeat(label[0], self.maxk, 1)) correct = pred == label[0]
self.correct = np.append(self.correct, corr, axis=0) return correct
def update(self, correct, *args, **kwargs):
accs = []
for i, k in enumerate(self.topk):
num_corrects = correct[:, :k].sum()
num_samples = len(correct)
accs.append(float(num_corrects) / num_samples)
self.total[i] += num_corrects
self.count[i] += num_samples
return accs
def reset(self): def reset(self):
self.correct = np.empty((0, self.maxk), dtype="int32") self.total = [0.] * len(self.topk)
self.count = [0] * len(self.topk)
def accumulate(self): def accumulate(self):
res = [] res = []
num_samples = self.correct.shape[0] for t, c in zip(self.total, self.count):
for k in self.topk: res.append(float(t) / c)
correct_k = self.correct[:, :k].sum()
res.append(round(100.0 * correct_k / num_samples, 2))
return res return res
...@@ -150,20 +150,16 @@ def main(): ...@@ -150,20 +150,16 @@ def main():
for e in range(FLAGS.epoch): for e in range(FLAGS.epoch):
train_loss = 0.0 train_loss = 0.0
train_acc = 0.0
val_loss = 0.0 val_loss = 0.0
val_acc = 0.0
print("======== train epoch {} ========".format(e)) print("======== train epoch {} ========".format(e))
for idx, batch in enumerate(train_loader()): for idx, batch in enumerate(train_loader()):
outputs, losses = model.train(batch[0], batch[1], device='gpu', losses, metrics = model.train(batch[0], batch[1], device='gpu',
device_ids=device_ids) device_ids=device_ids)
acc = accuracy(outputs[0], batch[1])[0]
train_loss += np.sum(losses) train_loss += np.sum(losses)
train_acc += acc
if idx % 10 == 0: if idx % 10 == 0:
print("{:04d}: loss {:0.3f} top1: {:0.3f}%".format( print("{:04d}: loss {:0.3f} top1: {:0.3f}% top2: {:0.3f}%".format(
idx, train_loss / (idx + 1), train_acc / (idx + 1))) idx, train_loss / (idx + 1), metrics[0][0], metrics[0][1]))
for metric in model._metrics: for metric in model._metrics:
res = metric.accumulate() res = metric.accumulate()
print("train epoch {:03d}: top1: {:0.3f}%, top2: {:0.3f}".format(e, res[0], res[1])) print("train epoch {:03d}: top1: {:0.3f}%, top2: {:0.3f}".format(e, res[0], res[1]))
...@@ -171,15 +167,13 @@ def main(): ...@@ -171,15 +167,13 @@ def main():
print("======== eval epoch {} ========".format(e)) print("======== eval epoch {} ========".format(e))
for idx, batch in enumerate(val_loader()): for idx, batch in enumerate(val_loader()):
outputs, losses = model.eval(batch[0], batch[1], device='gpu', losses, metrics = model.eval(batch[0], batch[1], device='gpu',
device_ids=device_ids) device_ids=device_ids)
acc = accuracy(outputs[0], batch[1])[0]
val_loss += np.sum(losses) val_loss += np.sum(losses)
val_acc += acc
if idx % 10 == 0: if idx % 10 == 0:
print("{:04d}: loss {:0.3f} top1: {:0.3f}%".format( print("{:04d}: loss {:0.3f} top1: {:0.3f}% top2: {:0.3f}%".format(
idx, val_loss / (idx + 1), val_acc / (idx + 1))) idx, val_loss / (idx + 1), metrics[0][0], metrics[0][1]))
for metric in model._metrics: for metric in model._metrics:
res = metric.accumulate() res = metric.accumulate()
print("eval epoch {:03d}: top1: {:0.3f}%, top2: {:0.3f}".format(e, res[0], res[1])) print("eval epoch {:03d}: top1: {:0.3f}%, top2: {:0.3f}".format(e, res[0], res[1]))
......
...@@ -45,6 +45,26 @@ def to_numpy(var): ...@@ -45,6 +45,26 @@ def to_numpy(var):
return np.array(t) return np.array(t)
def flatten_list(l):
assert isinstance(l, list), "not a list"
outl = []
splits = []
for sl in l:
assert isinstance(sl, list), "sub content not a list"
splits.append(len(sl))
outl += sl
return outl, splits
def restore_flatten_list(l, splits):
outl = []
for split in splits:
assert len(l) >= split, "list length invalid"
sl, l = l[:split], l[split:]
outl.append(sl)
return outl
def extract_args(func): def extract_args(func):
if hasattr(inspect, 'getfullargspec'): if hasattr(inspect, 'getfullargspec'):
return inspect.getfullargspec(func)[0] return inspect.getfullargspec(func)[0]
...@@ -278,28 +298,26 @@ class StaticGraphAdapter(object): ...@@ -278,28 +298,26 @@ class StaticGraphAdapter(object):
feed[v.name] = labels[idx] feed[v.name] = labels[idx]
endpoints = self._endpoints[self.mode] endpoints = self._endpoints[self.mode]
fetch_list = endpoints['output'] + endpoints['label'] + endpoints['loss'] if self.mode == 'test':
num_output = len(endpoints['output']) fetch_list = endpoints['output']
num_label = len(endpoints['label']) else:
metric_list, metric_splits = flatten_list(endpoints['metric'])
fetch_list = endpoints['loss'] + metric_list
num_loss = len(endpoints['loss'])
rets = self._executor.run( rets = self._executor.run(
compiled_prog, feed=feed, compiled_prog, feed=feed,
fetch_list=fetch_list, fetch_list=fetch_list,
return_numpy=False) return_numpy=False)
# LoDTensor cannot be fetch as numpy directly # LoDTensor cannot be fetch as numpy directly
rets = [np.array(v) for v in rets] rets = [np.array(v) for v in rets]
outputs = rets[:num_output]
labels = rets[num_output:num_output+num_label]
losses = rets[num_output+num_label:]
if self.mode == 'test': if self.mode == 'test':
return outputs return rets[:]
elif self.mode == 'eval': losses = rets[:num_loss]
for metric in self.model._metrics: metric_states = restore_flatten_list(rets[num_loss:], metric_splits)
metric.update(outputs, labels) metrics = []
return outputs, losses for metric, state in zip(self.model._metrics, metric_states):
else: # train metrics.append(metric.update(*state))
for metric in self.model._metrics: return losses, metrics
metric.update(outputs, labels)
return outputs, losses
def _make_program(self, inputs): def _make_program(self, inputs):
prog = self._orig_prog.clone() prog = self._orig_prog.clone()
...@@ -314,6 +332,9 @@ class StaticGraphAdapter(object): ...@@ -314,6 +332,9 @@ class StaticGraphAdapter(object):
label_vars = self._infer_label_vars(outputs) label_vars = self._infer_label_vars(outputs)
self._label_vars[self.mode] = label_vars self._label_vars[self.mode] = label_vars
losses = self.model._loss_function(outputs, label_vars) losses = self.model._loss_function(outputs, label_vars)
metrics = []
for metric in self.model._metrics:
metrics.append(to_list(metric.add_metric_op(outputs, label_vars)))
if self.mode == 'train': if self.mode == 'train':
self._loss_endpoint = fluid.layers.sum(losses) self._loss_endpoint = fluid.layers.sum(losses)
self.model._optimizer.minimize(self._loss_endpoint) self.model._optimizer.minimize(self._loss_endpoint)
...@@ -322,8 +343,8 @@ class StaticGraphAdapter(object): ...@@ -322,8 +343,8 @@ class StaticGraphAdapter(object):
self._progs[self.mode] = prog self._progs[self.mode] = prog
self._endpoints[self.mode] = { self._endpoints[self.mode] = {
"output": outputs, "output": outputs,
"label": label_vars,
"loss": losses, "loss": losses,
"metric": metrics,
} }
def _infer_input_vars(self, inputs): def _infer_input_vars(self, inputs):
...@@ -421,16 +442,18 @@ class DynamicGraphAdapter(object): ...@@ -421,16 +442,18 @@ class DynamicGraphAdapter(object):
self.mode = 'train' self.mode = 'train'
inputs = to_list(inputs) inputs = to_list(inputs)
labels = to_list(labels) labels = to_list(labels)
outputs = self.model.forward(*[to_variable(x) for x in inputs]) outputs = to_list(self.model.forward(*[to_variable(x) for x in inputs]))
losses = self.model._loss_function(outputs, labels) losses = self.model._loss_function(outputs, labels)
final_loss = fluid.layers.sum(losses) final_loss = fluid.layers.sum(losses)
final_loss.backward() final_loss.backward()
self.model._optimizer.minimize(final_loss) self.model._optimizer.minimize(final_loss)
self.model.clear_gradients() self.model.clear_gradients()
metrics = []
for metric in self.model._metrics: for metric in self.model._metrics:
metric.update([to_numpy(o) for o in to_list(outputs)], labels) metric_outs = metric.add_metric_op(outputs, [to_variable(l) for l in labels])
return [to_numpy(o) for o in to_list(outputs)], \ m = metric.update(*[to_numpy(m) for m in to_list(metric_outs)])
[to_numpy(l) for l in losses] metrics.append(m)
return [to_numpy(l) for l in losses], metrics
def eval(self, inputs, labels, device='CPU', device_ids=None): def eval(self, inputs, labels, device='CPU', device_ids=None):
assert self.model._loss_function, \ assert self.model._loss_function, \
...@@ -439,12 +462,14 @@ class DynamicGraphAdapter(object): ...@@ -439,12 +462,14 @@ class DynamicGraphAdapter(object):
self.mode = 'eval' self.mode = 'eval'
inputs = to_list(inputs) inputs = to_list(inputs)
labels = to_list(labels) labels = to_list(labels)
outputs = self.model.forward(*[to_variable(x) for x in inputs]) outputs = to_list(self.model.forward(*[to_variable(x) for x in inputs]))
losses = self.model._loss_function(outputs, labels) losses = self.model._loss_function(outputs, labels)
metrics = []
for metric in self.model._metrics: for metric in self.model._metrics:
metric.update([to_numpy(o) for o in to_list(outputs)], labels) metric_outs = metric.add_metric_op(outputs, [to_variable(l) for l in labels])
return [to_numpy(o) for o in to_list(outputs)], \ m = metric.update(*[to_numpy(m) for m in to_list(metric_outs)])
[to_numpy(l) for l in losses] metrics.append(m)
return [to_numpy(l) for l in losses], metrics
def test(self, inputs, device='CPU', device_ids=None): def test(self, inputs, device='CPU', device_ids=None):
super(Model, self.model).eval() super(Model, self.model).eval()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册