Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

env(zjow): add Huggingface model card support for ppof envs #737

Merged
merged 3 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ding/bonus/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,27 @@
from ding.policy import PPOFPolicy


def get_instance_config(env_id: str, algorithm: str) -> EasyDict:

Check warning on line 10 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L10

Added line #L10 was not covered by tests
if algorithm == 'PPOF':
cfg = PPOFPolicy.default_config()
if env_id == 'LunarLander-v2':

Check warning on line 13 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L13

Added line #L13 was not covered by tests
cfg.n_sample = 512
cfg.value_norm = 'popart'
cfg.entropy_weight = 1e-3
elif env_id == 'LunarLanderContinuous-v2':

Check warning on line 17 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L17

Added line #L17 was not covered by tests
cfg.action_space = 'continuous'
cfg.n_sample = 400
elif env_id == 'BipedalWalker-v3':

Check warning on line 20 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L20

Added line #L20 was not covered by tests
cfg.learning_rate = 1e-3
cfg.action_space = 'continuous'
cfg.n_sample = 1024
elif env_id == 'Pendulum-v1':
cfg.action_space = 'continuous'
cfg.n_sample = 400
elif env_id == 'acrobot':

Check warning on line 27 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L24-L27

Added lines #L24 - L27 were not covered by tests
cfg.learning_rate = 1e-4
cfg.n_sample = 400
elif env_id == 'rocket_landing':

Check warning on line 30 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L30

Added line #L30 was not covered by tests
cfg.n_sample = 2048
cfg.adv_norm = False
cfg.model = dict(
Expand All @@ -32,13 +35,13 @@
actor_head_hidden_size=128,
critic_head_hidden_size=128,
)
elif env_id == 'drone_fly':

Check warning on line 38 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L38

Added line #L38 was not covered by tests
cfg.action_space = 'continuous'
cfg.adv_norm = False
cfg.epoch_per_collect = 5
cfg.learning_rate = 5e-5
cfg.n_sample = 640
elif env_id == 'hybrid_moving':

Check warning on line 44 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L44

Added line #L44 was not covered by tests
cfg.action_space = 'hybrid'
cfg.n_sample = 3200
cfg.entropy_weight = 0.03
Expand All @@ -50,13 +53,13 @@
fixed_sigma_value=0.3,
bound_type='tanh',
)
elif env_id == 'evogym_carrier':

Check warning on line 56 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L56

Added line #L56 was not covered by tests
cfg.action_space = 'continuous'
cfg.n_sample = 2048
cfg.batch_size = 256
cfg.epoch_per_collect = 10
cfg.learning_rate = 3e-3
elif env_id == 'mario':

Check warning on line 62 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L62

Added line #L62 was not covered by tests
cfg.n_sample = 256
cfg.batch_size = 64
cfg.epoch_per_collect = 2
Expand All @@ -66,14 +69,14 @@
critic_head_hidden_size=128,
actor_head_hidden_size=128,
)
elif env_id == 'di_sheep':

Check warning on line 72 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L72

Added line #L72 was not covered by tests
cfg.n_sample = 3200
cfg.batch_size = 320
cfg.epoch_per_collect = 10
cfg.learning_rate = 3e-4
cfg.adv_norm = False
cfg.entropy_weight = 0.001
elif env_id == 'procgen_bigfish':

Check warning on line 79 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L79

Added line #L79 was not covered by tests
cfg.n_sample = 16384
cfg.batch_size = 16384
cfg.epoch_per_collect = 10
Expand All @@ -83,7 +86,7 @@
critic_head_hidden_size=256,
actor_head_hidden_size=256,
)
elif env_id in ['KangarooNoFrameskip-v4', 'BowlingNoFrameskip-v4']:

Check warning on line 89 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L89

Added line #L89 was not covered by tests
cfg.n_sample = 1024
cfg.batch_size = 128
cfg.epoch_per_collect = 10
Expand All @@ -94,7 +97,7 @@
critic_head_hidden_size=128,
critic_head_layer_num=2,
)
elif env_id == 'PongNoFrameskip-v4':

Check warning on line 100 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L100

Added line #L100 was not covered by tests
cfg.n_sample = 3200
cfg.batch_size = 320
cfg.epoch_per_collect = 10
Expand All @@ -104,7 +107,7 @@
actor_head_hidden_size=128,
critic_head_hidden_size=128,
)
elif env_id == 'SpaceInvadersNoFrameskip-v4':

Check warning on line 110 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L110

Added line #L110 was not covered by tests
cfg.n_sample = 320
cfg.batch_size = 320
cfg.epoch_per_collect = 1
Expand All @@ -116,7 +119,7 @@
actor_head_hidden_size=128,
critic_head_hidden_size=128,
)
elif env_id == 'QbertNoFrameskip-v4':

Check warning on line 122 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L122

Added line #L122 was not covered by tests
cfg.n_sample = 3200
cfg.batch_size = 320
cfg.epoch_per_collect = 10
Expand All @@ -127,13 +130,13 @@
actor_head_hidden_size=128,
critic_head_hidden_size=128,
)
elif env_id == 'minigrid_fourroom':

Check warning on line 133 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L133

Added line #L133 was not covered by tests
cfg.n_sample = 3200
cfg.batch_size = 320
cfg.learning_rate = 3e-4
cfg.epoch_per_collect = 10
cfg.entropy_weight = 0.001
elif env_id == 'metadrive':

Check warning on line 139 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L139

Added line #L139 was not covered by tests
cfg.learning_rate = 3e-4
cfg.action_space = 'continuous'
cfg.entropy_weight = 0.001
Expand All @@ -146,61 +149,61 @@
critic_head_hidden_size=128,
critic_head_layer_num=2,
)
elif env_id == 'Hopper-v3':
cfg.action_space = "continuous"
cfg.n_sample = 3200
cfg.batch_size = 320
cfg.epoch_per_collect = 10
cfg.learning_rate = 3e-4
elif env_id == 'HalfCheetah-v3':
cfg.action_space = "continuous"
cfg.n_sample = 3200
cfg.batch_size = 320
cfg.epoch_per_collect = 10
cfg.learning_rate = 3e-4
elif env_id == 'Walker2d-v3':

Check warning on line 164 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L152-L164

Added lines #L152 - L164 were not covered by tests
cfg.action_space = "continuous"
cfg.n_sample = 3200
cfg.batch_size = 320
cfg.epoch_per_collect = 10
cfg.learning_rate = 3e-4
else:
raise KeyError("not supported env type: {}".format(env_id))

Check warning on line 171 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L171

Added line #L171 was not covered by tests
else:
raise KeyError("not supported algorithm type: {}".format(algorithm))

return cfg


def get_instance_env(env_id: str) -> BaseEnv:
if env_id == 'LunarLander-v2':

Check warning on line 179 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L178-L179

Added lines #L178 - L179 were not covered by tests
return DingEnvWrapper(gym.make('LunarLander-v2'))
elif env_id == 'LunarLanderContinuous-v2':
return DingEnvWrapper(gym.make('LunarLanderContinuous-v2', continuous=True))
elif env_id == 'BipedalWalker-v3':

Check warning on line 183 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L181-L183

Added lines #L181 - L183 were not covered by tests
return DingEnvWrapper(gym.make('BipedalWalker-v3'), cfg={'act_scale': True, 'rew_clip': True})
elif env_id == 'Pendulum-v1':

Check warning on line 185 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L185

Added line #L185 was not covered by tests
return DingEnvWrapper(gym.make('Pendulum-v1'), cfg={'act_scale': True})
elif env_id == 'acrobot':

Check warning on line 187 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L187

Added line #L187 was not covered by tests
return DingEnvWrapper(gym.make('Acrobot-v1'))
elif env_id == 'rocket_landing':

Check warning on line 189 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L189

Added line #L189 was not covered by tests
from dizoo.rocket.envs import RocketEnv
cfg = EasyDict({
'task': 'landing',
'max_steps': 800,
})
return RocketEnv(cfg)
elif env_id == 'drone_fly':

Check warning on line 196 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L196

Added line #L196 was not covered by tests
from dizoo.gym_pybullet_drones.envs import GymPybulletDronesEnv
cfg = EasyDict({
'env_id': 'flythrugate-aviary-v0',
'action_type': 'VEL',
})
return GymPybulletDronesEnv(cfg)
elif env_id == 'hybrid_moving':

Check warning on line 203 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L203

Added line #L203 was not covered by tests
import gym_hybrid
return DingEnvWrapper(gym.make('Moving-v0'))
elif env_id == 'evogym_carrier':

Check warning on line 206 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L206

Added line #L206 was not covered by tests
import evogym.envs
from evogym import sample_robot, WorldObject
path = os.path.join(os.path.dirname(__file__), '../../dizoo/evogym/envs/world_data/carry_bot.json')
Expand All @@ -215,7 +218,7 @@
]
}
)
elif env_id == 'mario':

Check warning on line 221 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L221

Added line #L221 was not covered by tests
import gym_super_mario_bros
from nes_py.wrappers import JoypadSpace
return DingEnvWrapper(
Expand All @@ -231,10 +234,10 @@
]
}
)
elif env_id == 'di_sheep':

Check warning on line 237 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L237

Added line #L237 was not covered by tests
from sheep_env import SheepEnv
return DingEnvWrapper(SheepEnv(level=9))
elif env_id == 'procgen_bigfish':

Check warning on line 240 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L240

Added line #L240 was not covered by tests
return DingEnvWrapper(
gym.make('procgen:procgen-bigfish-v0', start_level=0, num_levels=1),
cfg={
Expand All @@ -246,7 +249,7 @@
},
seed_api=False,
)
elif env_id == 'Hopper-v3':

Check warning on line 252 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L252

Added line #L252 was not covered by tests
cfg = EasyDict(
env_id='Hopper-v3',
env_wrapper='mujoco_default',
Expand All @@ -254,7 +257,7 @@
rew_clip=True,
)
return DingEnvWrapper(gym.make('Hopper-v3'), cfg=cfg)
elif env_id == 'HalfCheetah-v3':

Check warning on line 260 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L260

Added line #L260 was not covered by tests
cfg = EasyDict(
env_id='HalfCheetah-v3',
env_wrapper='mujoco_default',
Expand All @@ -262,7 +265,7 @@
rew_clip=True,
)
return DingEnvWrapper(gym.make('HalfCheetah-v3'), cfg=cfg)
elif env_id == 'Walker2d-v3':

Check warning on line 268 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L268

Added line #L268 was not covered by tests
cfg = EasyDict(
env_id='Walker2d-v3',
env_wrapper='mujoco_default',
Expand All @@ -271,7 +274,7 @@
)
return DingEnvWrapper(gym.make('Walker2d-v3'), cfg=cfg)

elif env_id in [

Check warning on line 277 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L277

Added line #L277 was not covered by tests
'BowlingNoFrameskip-v4',
'BreakoutNoFrameskip-v4',
'GopherNoFrameskip-v4'
Expand All @@ -285,9 +288,9 @@
'env_id': env_id,
'env_wrapper': 'atari_default',
})
ding_env_atari = DingEnvWrapper(gym.make(env_id), cfg=cfg)

Check warning on line 291 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L291

Added line #L291 was not covered by tests
return ding_env_atari
elif env_id == 'minigrid_fourroom':

Check warning on line 293 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L293

Added line #L293 was not covered by tests
import gymnasium
return DingEnvWrapper(
gymnasium.make('MiniGrid-FourRooms-v0'),
Expand All @@ -300,7 +303,7 @@
]
}
)
elif env_id == 'metadrive':

Check warning on line 306 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L306

Added line #L306 was not covered by tests
from dizoo.metadrive.env.drive_env import MetaDrivePPOOriginEnv
from dizoo.metadrive.env.drive_wrapper import DriveEnvWrapper
cfg = dict(
Expand All @@ -313,7 +316,7 @@
cfg = EasyDict(cfg)
return DriveEnvWrapper(MetaDrivePPOOriginEnv(cfg))
else:
raise KeyError("not supported env type: {}".format(env_id))

Check warning on line 319 in ding/bonus/config.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/config.py#L319

Added line #L319 was not covered by tests


def get_hybrid_shape(action_space) -> EasyDict:
Expand Down
1 change: 1 addition & 0 deletions ding/bonus/ppof.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import os
import gym
import gymnasium
import numpy as np

Check warning on line 8 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L8

Added line #L8 was not covered by tests
import torch
from ding.framework import task, OnlineRLContext
from ding.framework.middleware import interaction_evaluator_ttorch, PPOFStepCollector, multistep_trainer, CkptSaver, \
Expand All @@ -13,7 +13,7 @@
from ding.envs import BaseEnv, BaseEnvManagerV2, SubprocessEnvManagerV2
from ding.policy import PPOFPolicy, single_env_forward_wrapper_ttorch
from ding.utils import set_pkg_seed
from ding.utils import get_env_fps, render

Check warning on line 16 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L16

Added line #L16 was not covered by tests
from ding.config import save_config_py
from .model import PPOFModel
from .config import get_instance_config, get_instance_env, get_hybrid_shape
Expand All @@ -26,6 +26,7 @@
'LunarLander-v2',
'LunarLanderContinuous-v2',
'BipedalWalker-v3',
'Pendulum-v1',
'acrobot',
# ch2: action
'rocket_landing',
Expand Down Expand Up @@ -63,40 +64,40 @@
cfg: Optional[Union[EasyDict, dict]] = None,
policy_state_dict: str = None
) -> None:
assert env_id is not None or cfg is not None, "Please specify env_id or cfg."

Check warning on line 67 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L67

Added line #L67 was not covered by tests

if cfg is not None and not isinstance(cfg, EasyDict):
cfg = EasyDict(cfg)

Check warning on line 70 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L69-L70

Added lines #L69 - L70 were not covered by tests

if env_id is not None:
assert env_id in PPOF.supported_env_list, "Please use supported envs: {}".format(PPOF.supported_env_list)

Check warning on line 73 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L72-L73

Added lines #L72 - L73 were not covered by tests
if cfg is None:
cfg = get_instance_config(env_id, algorithm="PPOF")

Check warning on line 75 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L75

Added line #L75 was not covered by tests

if not hasattr(cfg, "env_id"):
cfg.env_id = env_id
assert cfg.env_id == env_id, "env_id in cfg should be the same as env_id in args."

Check warning on line 79 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L77-L79

Added lines #L77 - L79 were not covered by tests
else:
assert hasattr(cfg, "env_id"), "Please specify env_id in cfg."
assert cfg.env_id in PPOF.supported_env_list, "Please use supported envs: {}".format(

Check warning on line 82 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L81-L82

Added lines #L81 - L82 were not covered by tests
PPOF.supported_env_list
)

if exp_name is not None:
cfg.exp_name = exp_name
elif not hasattr(cfg, "exp_name"):
cfg.exp_name = "{}-{}".format(cfg.env_id, "PPO")
self.cfg = cfg
self.exp_name = self.cfg.exp_name

Check warning on line 91 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L86-L91

Added lines #L86 - L91 were not covered by tests

if env is None:
self.env = get_instance_env(self.cfg.env_id)

Check warning on line 94 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L93-L94

Added lines #L93 - L94 were not covered by tests
else:
self.env = env

Check warning on line 96 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L96

Added line #L96 was not covered by tests

logging.getLogger().setLevel(logging.INFO)
self.seed = seed
set_pkg_seed(self.seed, use_cuda=self.cfg.cuda)

Check warning on line 100 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L100

Added line #L100 was not covered by tests

if not os.path.exists(self.exp_name):
os.makedirs(self.exp_name)
Expand Down Expand Up @@ -176,7 +177,7 @@

return TrainingReturn(wandb_url=task.ctx.wandb_url)

def deploy(

Check warning on line 180 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L180

Added line #L180 was not covered by tests
self,
enable_save_replay: bool = False,
concatenate_all_replay: bool = False,
Expand All @@ -189,23 +190,23 @@
# define env and policy
env = self.env.clone(caller='evaluator')

if seed is not None and isinstance(seed, int):
seeds = [seed]
elif seed is not None and isinstance(seed, list):
seeds = seed

Check warning on line 196 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L193-L196

Added lines #L193 - L196 were not covered by tests
else:
seeds = [self.seed]

Check warning on line 198 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L198

Added line #L198 was not covered by tests

returns = []
images = []
if enable_save_replay:
replay_save_path = os.path.join(self.exp_name, 'videos') if replay_save_path is None else replay_save_path

Check warning on line 203 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L200-L203

Added lines #L200 - L203 were not covered by tests
env.enable_save_replay(replay_path=replay_save_path)
else:
logging.warning('No video would be generated during the deploy.')
if concatenate_all_replay:
logging.warning('concatenate_all_replay is set to False because enable_save_replay is False.')
concatenate_all_replay = False

Check warning on line 209 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L207-L209

Added lines #L207 - L209 were not covered by tests

forward_fn = single_env_forward_wrapper_ttorch(self.policy.eval, self.cfg.cuda)

Expand All @@ -213,31 +214,31 @@
# env will be reset again in the main loop
env.reset()

for seed in seeds:
env.seed(seed, dynamic_seed=False)
return_ = 0.
step = 0
obs = env.reset()
images.append(render(env)[None]) if concatenate_all_replay else None
while True:
action = forward_fn(obs)
obs, rew, done, info = env.step(action)
images.append(render(env)[None]) if concatenate_all_replay else None
return_ += rew
step += 1
if done:
break
logging.info(f'DQN deploy is finished, final episode return with {step} steps is: {return_}')
returns.append(return_)

Check warning on line 232 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L217-L232

Added lines #L217 - L232 were not covered by tests

env.close()

if concatenate_all_replay:
images = np.concatenate(images, axis=0)
import imageio
imageio.mimwrite(os.path.join(replay_save_path, 'deploy.mp4'), images, fps=get_env_fps(env))

Check warning on line 239 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L236-L239

Added lines #L236 - L239 were not covered by tests

return EvalReturn(eval_value=np.mean(returns), eval_value_std=np.std(returns))

Check warning on line 241 in ding/bonus/ppof.py

View check run for this annotation

Codecov / codecov/patch

ding/bonus/ppof.py#L241

Added line #L241 was not covered by tests

def collect_data(
self,
Expand Down
Loading