def call_for_each_tower(
            towers, func, devices=None, use_vs=None):
        """
        Run `func` on all GPUs (towers) and return the results.

        Args:
            towers (list[int]): a list of GPU id.
            func: a lambda to be called inside each tower
            devices: a list of devices to be used. By default will use '/gpu:{tower}'
            use_vs (list[bool]): list of use_vs to passed to TowerContext

        Returns:
            List of outputs of ``func``, evaluated on each tower.
        """

        ret = []
        if devices is not None:
            assert len(devices) == len(towers)
        if use_vs is not None:
            assert len(use_vs) == len(towers)

        tower_names = ['tower{}'.format(idx) for idx in range(len(towers))]

        for idx, t in enumerate(towers):
            device = devices[idx] if devices is not None else '/gpu:{}'.format(t)
            usevs = use_vs[idx] if use_vs is not None else False
            reuse = not usevs and idx > 0
            with tfv1.device(device), _maybe_reuse_vs(reuse), TrainTowerContext(
                    tower_names[idx],
                    vs_name=tower_names[idx] if usevs else '',
                    index=idx, total=len(towers)):
                if len(str(device)) < 10:   # a device function doesn't have good string description
                    logger.info("Building graph for training tower {} on device {} ...".format(idx, device))
                else:
                    logger.info("Building graph for training tower {} ...".format(idx))

                # When use_vs is True, use LOCAL_VARIABLES,
                # so these duplicated variables won't be saved by default.
                with override_to_local_variable(enable=usevs):
                    ret.append(func())
        return ret