Repository: open-compass/VLMEvalKit
Issue: llavabench评估代码bug
Root cause: Validation Gap

我发现llavabench的评估代码中调用`track_progress_rich`函数是没有传入要保存的文件，导致评估完在保存时一直卡在`track_progress_rich`的while循环中，以下是llavabench的dataset类代码：
```python
class LLaVABench(ImageBaseDataset):
    TYPE = "VQA"
    DATASET_URL = {
        "LLaVABench": "https://opencompass.openxlab.space/utils/VLMEval/LLaVABench.tsv"
    }
    DATASET_MD5 = {"LLaVABench": "d382a093f749a697820d3dadd61c8428"}

    # It returns a DataFrame
    @classmethod
    def evaluate(self, eval_file, **judge_kwargs):
        from .utils.llavabench import (
            build_prompt,
            LLaVABench_atomeval,
            LLaVABench_score,
        )

        suffix = "." + eval_file.split(".")[-1]
        record_file = eval_file.replace(suffix, "_openai_result" + suffix)
        score_file = eval_file.replace(suffix, "_score.csv")
        nproc = judge_kwargs.pop("nproc", 4)
        system_prompt = "You are a helpful and precise assistant for checking the quality of the answer."

        if not osp.exists(record_file):
            data = load(eval_file)
            lines = [data.iloc[i] for i in range(len(data))]
            model = build_judge(
                temperature=0.2, system_prompt=system_prompt, **judge_kwargs
            )
            assert model.working(), (
                "LLaVABench evaluation requires a working OPENAI API\n" + DEBUG_MESSAGE
            )

            prompts = [build_prompt(line) for line in lines]
            tups = [(model, prompt) for prompt in prompts]
            scores = track_progress_rich(
                LLaVABench_atomeval, tups, nproc=nproc, chunksize=nproc
            )
            data["gpt4_score"] = [x[0] for x in scores]
            data["score"] = [x[1] for x in scores]
            dump(data, record_file)

        data = load(record_file)
        ret = LLaVABench_score(data).round(1)
        dump(ret, score_file)
        return ret
```


以下是`track_progress_rich`多线程函数：
```python
def track_progress_rich(
    func: Callable,
    tasks: Iterable = tuple(),
    nproc: int = 1,
    save=None,
    keys=None,
    **kwargs,
) -> list:

    from concurrent.futures import ThreadPoolExecutor
    from tqdm import tqdm

    if save is not None:
        assert osp.exists(osp.dirname(save)) or osp.dirname(save) == ""
        if not osp.exists(save):
            dump({}, save)
    if keys is not None:
        assert len(keys) == len(tasks)
    if not callable(func):
        raise TypeError("func must be a callable object")
    if not isinstance(tasks, Iterable):
        raise TypeError(f"tasks must be an iterable object, but got {type(tasks)}")
    assert nproc > 0, "nproc must be a positive number"
    res = load(save) if save is not None else {}
    results = [None for _ in range(len(tasks))]

    with ThreadPoolExecutor(max_workers=nproc) as executor:
        futures = []
        print("开始提交任务...")

        for idx, inputs in enumerate(tasks):
            if not isinstance(inputs, (tuple, list, dict)):
                inputs = (inputs,)
            if isinstance(inputs, dict):
                future = executor.submit(func, **inputs)
            else:
                future = executor.submit(func, *inputs)
            futures.append(future)
            if idx % 10 == 0:
                print(f"已提交 {idx} 个任务")

        # print("\n\n")
        # print("-" * 80)
        # print(f"Score: {futures}")
        # print("-" * 80)
        # print("\n\n")

        print("所有任务已提交，初始化进度条...")
        unfinished = set(range(len(tasks)))
        pbar = tqdm(total=len(unfinished))
        print(f"unfinished:{unfinished}")
        print("开始监控任务进度...")
        while len(unfinished):
            new_finished = set()
            for idx in unfinished:
                if futures[idx].done():
                    results[idx] = futures[idx].result()
                    new_finished.add(idx)
                    if keys is not None:
                        res[keys[idx]] = results[idx]
            print("\n\n")
            print("-" * 80)
            print(f"All finished:{results}")
            print(f"New finished:{new_finished}")
            print(f"unfinished:{unfinished}")
            print(f"save to {save}:{res}")
            print("-" * 80)
            print("\n\n")
            if len(new_finished) and save is not None:
                dump(res, save)
                pbar.update(len(new_finished))
                for k in new_finished:
                    unfinished.remove(k)
            time.sleep(0.1)
        pbar.close()
        print("所有任务完成，进度条已关闭")

    if save is not None:
        dump(res, save)
    return results
```

@zhangzef  The problem is fixed in #695