classification.py 7.0 KB
Newer Older
D
dongshuilong 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import time
import platform
import paddle

from ppcls.utils.misc import AverageMeter
from ppcls.utils import logger


W
weishengyu 已提交
25
def classification_eval(engine, epoch_id=0):
D
dongshuilong 已提交
26 27 28 29 30 31 32
    output_info = dict()
    time_info = {
        "batch_cost": AverageMeter(
            "batch_cost", '.5f', postfix=" s,"),
        "reader_cost": AverageMeter(
            "reader_cost", ".5f", postfix=" s,"),
    }
W
weishengyu 已提交
33
    print_batch_step = engine.config["Global"]["print_batch_step"]
D
dongshuilong 已提交
34 35 36

    metric_key = None
    tic = time.time()
D
dongshuilong 已提交
37 38 39 40
    accum_samples = 0
    total_samples = len(
        engine.eval_dataloader.
        dataset) if not engine.use_dali else engine.eval_dataloader.size
W
weishengyu 已提交
41 42 43
    max_iter = len(engine.eval_dataloader) - 1 if platform.system(
    ) == "Windows" else len(engine.eval_dataloader)
    for iter_id, batch in enumerate(engine.eval_dataloader):
D
dongshuilong 已提交
44 45 46 47 48
        if iter_id >= max_iter:
            break
        if iter_id == 5:
            for key in time_info:
                time_info[key].reset()
W
weishengyu 已提交
49
        if engine.use_dali:
D
dongshuilong 已提交
50 51 52 53 54 55
            batch = [
                paddle.to_tensor(batch[0]['data']),
                paddle.to_tensor(batch[0]['label'])
            ]
        time_info["reader_cost"].update(time.time() - tic)
        batch_size = batch[0].shape[0]
56
        batch[0] = paddle.to_tensor(batch[0])
C
cuicheng01 已提交
57
        if not engine.config["Global"].get("use_multilabel", False):
C
cuicheng01 已提交
58
            batch[1] = batch[1].reshape([-1, 1]).astype("int64")
59

D
dongshuilong 已提交
60
        # image input
61 62 63
        if engine.amp and (
                engine.config['AMP'].get("level", "O1").upper() == "O2" or
                engine.config["AMP"].get("use_fp16_test", False)):
64
            amp_level = engine.config['AMP'].get("level", "O1").upper()
65 66 67 68 69

            if amp_level == "O2":
                msg = "Only support FP16 evaluation when AMP O2 is enabled."
                logger.warning(msg)

70 71 72 73 74
            with paddle.amp.auto_cast(
                    custom_black_list={
                        "flatten_contiguous_range", "greater_than"
                    },
                    level=amp_level):
Z
zhangbo9674 已提交
75 76 77 78 79 80 81
                out = engine.model(batch[0])
                # calc loss
                if engine.eval_loss_func is not None:
                    loss_dict = engine.eval_loss_func(out, batch[1])
                    for key in loss_dict:
                        if key not in output_info:
                            output_info[key] = AverageMeter(key, '7.5f')
82 83
                        output_info[key].update(loss_dict[key].numpy()[0],
                                                batch_size)
Z
zhangbo9674 已提交
84 85 86 87 88 89 90 91
        else:
            out = engine.model(batch[0])
            # calc loss
            if engine.eval_loss_func is not None:
                loss_dict = engine.eval_loss_func(out, batch[1])
                for key in loss_dict:
                    if key not in output_info:
                        output_info[key] = AverageMeter(key, '7.5f')
92 93
                    output_info[key].update(loss_dict[key].numpy()[0],
                                            batch_size)
D
dongshuilong 已提交
94 95 96 97 98

        # just for DistributedBatchSampler issue: repeat sampling
        current_samples = batch_size * paddle.distributed.get_world_size()
        accum_samples += current_samples

D
dongshuilong 已提交
99
        # calc metric
W
weishengyu 已提交
100
        if engine.eval_metric_func is not None:
D
dongshuilong 已提交
101
            if paddle.distributed.get_world_size() > 1:
D
dongshuilong 已提交
102 103 104
                label_list = []
                paddle.distributed.all_gather(label_list, batch[1])
                labels = paddle.concat(label_list, 0)
D
dongshuilong 已提交
105 106

                if isinstance(out, dict):
107
                    if "Student" in out:
G
gaotingquan 已提交
108
                        out = out["Student"]
wc晨曦's avatar
wc晨曦 已提交
109 110
                        if isinstance(out, dict):
                            out = out["logits"]
111 112
                    elif "logits" in out:
                        out = out["logits"]
G
gaotingquan 已提交
113 114 115
                    else:
                        msg = "Error: Wrong key in out!"
                        raise Exception(msg)
D
dongshuilong 已提交
116 117 118 119 120 121 122 123 124 125 126 127
                if isinstance(out, list):
                    pred = []
                    for x in out:
                        pred_list = []
                        paddle.distributed.all_gather(pred_list, x)
                        pred_x = paddle.concat(pred_list, 0)
                        pred.append(pred_x)
                else:
                    pred_list = []
                    paddle.distributed.all_gather(pred_list, out)
                    pred = paddle.concat(pred_list, 0)

D
dongshuilong 已提交
128
                if accum_samples > total_samples and not engine.use_dali:
D
dongshuilong 已提交
129 130 131 132 133 134 135 136
                    pred = pred[:total_samples + current_samples -
                                accum_samples]
                    labels = labels[:total_samples + current_samples -
                                    accum_samples]
                    current_samples = total_samples + current_samples - accum_samples
                metric_dict = engine.eval_metric_func(pred, labels)
            else:
                metric_dict = engine.eval_metric_func(out, batch[1])
137

D
dongshuilong 已提交
138 139 140 141 142 143 144
            for key in metric_dict:
                if metric_key is None:
                    metric_key = key
                if key not in output_info:
                    output_info[key] = AverageMeter(key, '7.5f')

                output_info[key].update(metric_dict[key].numpy()[0],
D
dongshuilong 已提交
145
                                        current_samples)
D
dongshuilong 已提交
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

        time_info["batch_cost"].update(time.time() - tic)

        if iter_id % print_batch_step == 0:
            time_msg = "s, ".join([
                "{}: {:.5f}".format(key, time_info[key].avg)
                for key in time_info
            ])

            ips_msg = "ips: {:.5f} images/sec".format(
                batch_size / time_info["batch_cost"].avg)

            metric_msg = ", ".join([
                "{}: {:.5f}".format(key, output_info[key].val)
                for key in output_info
            ])
            logger.info("[Eval][Epoch {}][Iter: {}/{}]{}, {}, {}".format(
                epoch_id, iter_id,
W
weishengyu 已提交
164
                len(engine.eval_dataloader), metric_msg, time_msg, ips_msg))
D
dongshuilong 已提交
165 166

        tic = time.time()
W
weishengyu 已提交
167 168
    if engine.use_dali:
        engine.eval_dataloader.reset()
D
dongshuilong 已提交
169 170 171 172 173 174
    metric_msg = ", ".join([
        "{}: {:.5f}".format(key, output_info[key].avg) for key in output_info
    ])
    logger.info("[Eval][Epoch {}][Avg]{}".format(epoch_id, metric_msg))

    # do not try to save best eval.model
W
weishengyu 已提交
175
    if engine.eval_metric_func is None:
D
dongshuilong 已提交
176 177 178
        return -1
    # return 1st metric in the dict
    return output_info[metric_key].avg