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

How to apply mask_rcnn segmentation on a balloon video ? #101

Closed
gireeshkbogu opened this issue Oct 17, 2019 · 28 comments
Closed

How to apply mask_rcnn segmentation on a balloon video ? #101

gireeshkbogu opened this issue Oct 17, 2019 · 28 comments

Comments

@gireeshkbogu
Copy link

gireeshkbogu commented Oct 17, 2019

Hi, I am going through the google colab example tutorial.

I am trying to apply mask_rcnn segmentation on a random youtube balloon-video instead of an balloon-image to detect balloon only (one class).

How can I assign .yaml and .pkl files that were generated using images earlier in the tutorial to a random video? thanks

I tried the foolowing but it didn't work. I think I am having trouble assign the trained config and model files.

!cd detectron2_repo && python demo/demo.py --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml --video-input ../video-clip_b.mp4 --confidence-threshold 0.6 --output ../video-clip_b_testing1.mkv \
  --opts MODEL.WEIGHTS detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl
@ppwwyyxx
Copy link
Contributor

You can find the following config in the tutorial, which is used to train the balloon model:

cfg.DATASETS.TRAIN = ("balloon/train",)
cfg.DATASETS.TEST = ()   # no metrics implemented for this dataset
cfg.DATALOADER.NUM_WORKERS = 2
cfg.MODEL.WEIGHTS = "detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl"  # initialize from model zoo
cfg.SOLVER.IMS_PER_BATCH = 2
cfg.SOLVER.BASE_LR = 0.00025
cfg.SOLVER.MAX_ITER = 300    # 300 iterations seems good enough, but you can certainly train longer
cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128   # faster, and good enough for this toy dataset
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 1  # only has one class (ballon)

the config file you're running demo.py with does not have these changes, so it won't work.

The model you trained will be in os.path.join(cfg.OUTPUT_DIR, "model_final.pth"), as you can find in the tutorial as well. You need to set MODEL.WEIGHTS to it for inference.

@ppwwyyxx ppwwyyxx added the usage label Oct 17, 2019
@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 17, 2019

I tried to do this but didn't work. Is this because ballon_dataset was directed to /dev/null in the tutorial and somehow this is messing with the paths?

cfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, "model_final.pth")

!cd detectron2_repo && python demo/demo.py --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml --video-input ../video-clip_b.mp4 --confidence-threshold 0.6 --output ../video-clip_b_testing1.mkv \
  --opts MODEL.WEIGHTS cfg.MODEL.WEIGHTS

Error

[10/17 04:02:19 detectron2]: Arguments: Namespace(confidence_threshold=0.6, config_file='configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml', input=None, opts=['MODEL.WEIGHTS', 'cfg.MODEL.WEIGHTS'], output='../video-clip_b_testing1.mkv', video_input='../video-clip_b.mp4', webcam=False)
WARNING [10/17 04:02:19 d2.config.compat]: Config 'configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml' has no VERSION. Assuming it to be compatible with latest v2.
Traceback (most recent call last):
  File "demo/demo.py", line 73, in <module>
    demo = VisualizationDemo(cfg)
  File "/content/detectron2_repo/demo/predictor.py", line 33, in __init__
    self.predictor = DefaultPredictor(cfg)
  File "/content/detectron2_repo/detectron2/engine/defaults.py", line 149, in __init__
    checkpointer.load(cfg.MODEL.WEIGHTS)
  File "/usr/local/lib/python3.6/dist-packages/fvcore/common/checkpoint.py", line 99, in load
    assert os.path.isfile(path), "Checkpoint {} not found!".format(path)
AssertionError: Checkpoint cfg.MODEL.WEIGHTS not found!

@ppwwyyxx
Copy link
Contributor

cfg.MODEL.WEIGHTS is a python statement. The second line is a shell command. No python variables will be available in the shell command.

@ppwwyyxx
Copy link
Contributor

Similarly, all the changes you made to cfg affect the python variable. It does not affect the shell command you run, which reads config from the given config file.

@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 17, 2019

Ok now it is running but the output is the same as input with no segmentation at all.

!cd detectron2_repo && python demo/demo.py --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml --video-input ../video-clip_b.mp4 --confidence-threshold 0.6 --output ../video-clip_b_testing2.mkv \
  --opts MODEL.WEIGHTS ../output/model_final.pth
[10/17 04:49:22 detectron2]: Arguments: Namespace(confidence_threshold=0.7, config_file='configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml', input=None, opts=['MODEL.WEIGHTS', '../output/model_final.pth'], output='../video-clip_b_testing4.mkv', video_input='../video-clip_b.mp4', webcam=False)
WARNING [10/17 04:49:22 d2.config.compat]: Config 'configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml' has no VERSION. Assuming it to be compatible with latest v2.
'roi_heads.box_predictor.cls_score.weight' has shape (2, 1024) in the checkpoint but (81, 1024) in the model! Skipped.
'roi_heads.box_predictor.cls_score.bias' has shape (2,) in the checkpoint but (81,) in the model! Skipped.
'roi_heads.box_predictor.bbox_pred.weight' has shape (4, 1024) in the checkpoint but (320, 1024) in the model! Skipped.
'roi_heads.box_predictor.bbox_pred.bias' has shape (4,) in the checkpoint but (320,) in the model! Skipped.
'roi_heads.mask_head.predictor.weight' has shape (1, 256, 1, 1) in the checkpoint but (80, 256, 1, 1) in the model! Skipped.
'roi_heads.mask_head.predictor.bias' has shape (1,) in the checkpoint but (80,) in the model! Skipped.
100% 181/181 [01:28<00:00,  2.04it/s]

@ppwwyyxx
Copy link
Contributor

all the changes you made to cfg affect the python variable. It does not affect the shell command you run, which reads config from the given config file.

Which means you need to change the config file given to demo.py.

@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 18, 2019

to something like this? I ended up with the following error.
Do I need to for the detectron2 rep and change the yaml file instead?

_BASE_: "../Base-RCNN-FPN.yaml"
MODEL:
  WEIGHTS: "../output/model_final.pth"
  MASK_ON: True
  RESNETS:
    DEPTH: 50
SOLVER:
  STEPS: (210000, 250000)
  MAX_ITER: 270000

Error

Failed to load OpenCL runtime
[10/18 17:12:25 detectron2]: Arguments: Namespace(confidence_threshold=0.7, config_file='/content/gdrive/My Drive/fastai_files/datasets/test_samples/balloon.yaml', input=None, opts=['MODEL.WEIGHTS', '../output/model_final.pth'], output='../video-clip_bb_testing4.mkv', video_input='../video-clip_bb.mp4', webcam=False)
Traceback (most recent call last):
  File "demo/demo.py", line 71, in <module>
    cfg = setup_cfg(args)
  File "demo/demo.py", line 23, in setup_cfg
    cfg.merge_from_file(args.config_file)
  File "/content/detectron2_repo/detectron2/config/config.py", line 23, in merge_from_file
    loaded_cfg = _CfgNode.load_yaml_with_base(cfg_filename, allow_unsafe=allow_unsafe)
  File "/usr/local/lib/python3.6/dist-packages/fvcore/common/config.py", line 75, in load_yaml_with_base
    if BASE_KEY in cfg:
TypeError: argument of type 'NoneType' is not iterable

@ppwwyyxx
Copy link
Contributor

You need to create a yaml file which has the same content as configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml, except for the extra changes mentioned above in #101 (comment).

@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 18, 2019

I think that is what I did. I am writing all the steps just to be clear.

  1. First I ran this to create config on balloon train samples
from detectron2.engine import DefaultTrainer
from detectron2.config import get_cfg

cfg = get_cfg()
cfg.merge_from_file("./detectron2_repo/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml")
cfg.DATASETS.TRAIN = ("balloon/train",)
cfg.DATASETS.TEST = ()   # no metrics implemented for this dataset
cfg.DATALOADER.NUM_WORKERS = 2
cfg.MODEL.WEIGHTS = "detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl"  # initialize from model zoo
cfg.SOLVER.IMS_PER_BATCH = 2
cfg.SOLVER.BASE_LR = 0.00025
cfg.SOLVER.MAX_ITER = 300    # 300 iterations seems good enough, but you can certainly train longer
cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128   # faster, and good enough for this toy dataset
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 1  # only has one class (ballon)

os.makedirs(cfg.OUTPUT_DIR, exist_ok=True)
trainer = DefaultTrainer(cfg) 
trainer.resume_or_load(resume=False)
trainer.train()

configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml looks like the following ..

_BASE_: "../Base-RCNN-FPN.yaml"
MODEL:
  WEIGHTS: "detectron2://ImageNetPretrained/MSRA/R-50.pkl"
  MASK_ON: True
  RESNETS:
    DEPTH: 50
SOLVER:
  STEPS: (210000, 250000)
  MAX_ITER: 270000

  1. So I manually created a yaml file like this in a different folder (/content/gdrive/My Drive/fastai_files/datasets/test_samples/balloon.yaml).
_BASE_: "../Base-RCNN-FPN.yaml"
MODEL:
  WEIGHTS: "../output/model_final.pth"
  MASK_ON: True
  RESNETS:
    DEPTH: 50
SOLVER:
  STEPS: (210000, 250000)
  MAX_ITER: 270000
  1. and then finally ran like the command using my own yaml file and model weights
!cd detectron2_repo && python demo/demo.py --config-file '/content/gdrive/My Drive/fastai_files/datasets/test_samples/balloon.yaml' --video-input ../video-clip_bb.mp4 --confidence-threshold 0.7 --output ../video-clip_bb_testing_1.mkv \
  --opts MODEL.WEIGHTS ../output/model_final.pth

@ppwwyyxx
Copy link
Contributor

all the changes you made to cfg affect the python variable. It does not affect the shell command you run, which reads config from the given config file.

What the command run is demo.py. Running demo.py has nothing to with the changes

cfg = get_cfg()
cfg.merge_from_file("./detectron2_repo/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml")
cfg.DATASETS.TRAIN = ("balloon/train",)
cfg.DATASETS.TEST = ()   # no metrics implemented for this dataset
cfg.DATALOADER.NUM_WORKERS = 2
cfg.MODEL.WEIGHTS = "detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl"  # initialize from model zoo
cfg.SOLVER.IMS_PER_BATCH = 2
cfg.SOLVER.BASE_LR = 0.00025
cfg.SOLVER.MAX_ITER = 300    # 300 iterations seems good enough, but you can certainly train longer
cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128   # faster, and good enough for this toy dataset
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 1  # only has one class (ballon)

that you made during training, because these changes are not in demo.py, and not in the config file you gave to demo.py either.

You need to add these changes either to demo.py, or to the config file you provided to demo.py.

@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 18, 2019

This time I forked Detectron2 repo and re-ran all the code by adding config changes to the but still have issues.

!cd detectron2_repo && python demo/demo_balloon.py --config-file 'configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml' --video-input ../video-clip_bb.mp4 --confidence-threshold 0.7 --output ../video-clip_bb_testing_1.mkv \
  --opts MODEL.WEIGHTS ../output/model_final.pth
Failed to load OpenCL runtime
[10/18 22:35:43 detectron2]: Arguments: Namespace(confidence_threshold=0.7, config_file='configs/quick_schedules/e2e_mask_rcnn_R_50_FPN_inference_acc_test.yaml', input=None, opts=['MODEL.WEIGHTS', '../output/model_final.pth'], output='../video-clip_bb_testing_1.mkv', video_input='../video-clip_bb.mp4', webcam=False)
Traceback (most recent call last):
  File "demo/demo_balloon.py", line 79, in <module>
    cfg = setup_cfg(args)
  File "demo/demo_balloon.py", line 23, in setup_cfg
    cfg.merge_from_file("./detectron2_repo/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml")
  File "/content/detectron2_repo/detectron2/config/config.py", line 23, in merge_from_file
    loaded_cfg = _CfgNode.load_yaml_with_base(cfg_filename, allow_unsafe=allow_unsafe)
  File "/usr/local/lib/python3.6/dist-packages/fvcore/common/config.py", line 47, in load_yaml_with_base
    with open(filename, "r") as f:
FileNotFoundError: [Errno 2] No such file or directory: './detectron2_repo/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml'

@ppwwyyxx
Copy link
Contributor

FileNotFoundError: [Errno 2] No such file or directory: './detectron2_repo/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml'

As the error says, your code is trying to read a file that does not exist. Since your command has "cd detectron2_repo", you should remove "detectron2_repo" from the path.

@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 18, 2019

Thank you now having the following issue

!cd detectron2_repo && python demo/demo_balloon.py --video-input ../video-clip_bb.mp4 --confidence-threshold 0.7 --output ../video-clip_bb_testing_1.mkv \
  --opts MODEL.WEIGHTS ../output/model_final.pth
Failed to load OpenCL runtime
[10/18 23:13:30 detectron2]: Arguments: Namespace(confidence_threshold=0.7, config_file='configs/quick_schedules/e2e_mask_rcnn_R_50_FPN_inference_acc_test.yaml', input=None, opts=['MODEL.WEIGHTS', '../output/model_final.pth'], output='../video-clip_bb_testing_1.mkv', video_input='../video-clip_bb.mp4', webcam=False)
WARNING [10/18 23:13:30 d2.config.compat]: Config 'configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml' has no VERSION. Assuming it to be compatible with latest v2.
Traceback (most recent call last):
  File "demo/demo_balloon.py", line 81, in <module>
    demo = VisualizationDemo(cfg)
  File "/content/detectron2_repo/demo/predictor.py", line 24, in __init__
    self.metadata = MetadataCatalog.get(cfg.DATASETS.TEST[0])
IndexError: tuple index out of range

@ppwwyyxx
Copy link
Contributor

ppwwyyxx commented Oct 18, 2019

Set cfg.DATASETS.TEST = ("balloon/val",)
// UPDATE: or balloon_val for latest tutorial

@gireeshkbogu
Copy link
Author

Thank you. Seems to be running but got stuck here

Failed to load OpenCL runtime
[10/18 23:37:22 detectron2]: Arguments: Namespace(confidence_threshold=0.7, config_file='configs/quick_schedules/e2e_mask_rcnn_R_50_FPN_inference_acc_test.yaml', input=None, opts=['MODEL.WEIGHTS', '../output/model_final.pth'], output='../video-clip_bb_testing_1.mkv', video_input='../video-clip_bb.mp4', webcam=False)
WARNING [10/18 23:37:22 d2.config.compat]: Config 'configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml' has no VERSION. Assuming it to be compatible with latest v2.
'roi_heads.box_predictor.cls_score.weight' has shape (81, 1024) in the checkpoint but (2, 1024) in the model! Skipped.
'roi_heads.box_predictor.cls_score.bias' has shape (81,) in the checkpoint but (2,) in the model! Skipped.
'roi_heads.box_predictor.bbox_pred.weight' has shape (320, 1024) in the checkpoint but (4, 1024) in the model! Skipped.
'roi_heads.box_predictor.bbox_pred.bias' has shape (320,) in the checkpoint but (4,) in the model! Skipped.
'roi_heads.mask_head.predictor.weight' has shape (80, 256, 1, 1) in the checkpoint but (1, 256, 1, 1) in the model! Skipped.
'roi_heads.mask_head.predictor.bias' has shape (80,) in the checkpoint but (1,) in the model! Skipped.
  5% 9/181 [00:04<01:26,  1.99it/s]Traceback (most recent call last):
  File "demo/demo_balloon.py", line 145, in <module>
    for vis_frame in tqdm.tqdm(demo.run_on_video(video), total=num_frames):
  File "/usr/local/lib/python3.6/dist-packages/tqdm/std.py", line 1081, in __iter__
    for obj in iterable:
  File "/content/detectron2_repo/demo/predictor.py", line 127, in run_on_video
    yield process_predictions(frame, self.predictor(frame))
  File "/content/detectron2_repo/demo/predictor.py", line 96, in process_predictions
    vis_frame = video_visualizer.draw_instance_predictions(frame, predictions)
  File "/content/detectron2_repo/detectron2/utils/video_visualizer.py", line 90, in draw_instance_predictions
    labels = _create_text_labels(classes, scores, self.metadata.thing_classes)
  File "/content/detectron2_repo/detectron2/data/catalog.py", line 116, in __getattr__
    key, self.name, str(self.__dict__.keys())
AttributeError: Attribute 'thing_classes' does not exist in the metadata of 'balloon/val'. Available keys are dict_keys(['name']).
  5% 9/181 [00:05<01:37,  1.77it/s]

@ppwwyyxx
Copy link
Contributor

This error is addressed by 22e04d1

@gireeshkbogu
Copy link
Author

If I have to add this new change do I need to repeat the forking/install and rerun things?

@ppwwyyxx
Copy link
Contributor

If you install detectron2 in the same way as the tutorial, then git pull in the repo is sufficient.

@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 19, 2019

All ran well but the output is the same as the input. There was no object detection in the video.

Do you think this could be a threshold score issue? When I change it from 0.7 to 0.6, there were boxes popping everywhere but not where the balloons are. This is strange.

Failed to load OpenCL runtime
[10/19 00:15:48 detectron2]: Arguments: Namespace(confidence_threshold=0.7, config_file='configs/quick_schedules/e2e_mask_rcnn_R_50_FPN_inference_acc_test.yaml', input=None, opts=['MODEL.WEIGHTS', '../output/model_final.pth'], output='../video-clip_bb_testing_1.mkv', video_input='../video-clip_bb.mp4', webcam=False)
WARNING [10/19 00:15:48 d2.config.compat]: Config 'configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml' has no VERSION. Assuming it to be compatible with latest v2.
'roi_heads.box_predictor.cls_score.weight' has shape (81, 1024) in the checkpoint but (2, 1024) in the model! Skipped.
'roi_heads.box_predictor.cls_score.bias' has shape (81,) in the checkpoint but (2,) in the model! Skipped.
'roi_heads.box_predictor.bbox_pred.weight' has shape (320, 1024) in the checkpoint but (4, 1024) in the model! Skipped.
'roi_heads.box_predictor.bbox_pred.bias' has shape (320,) in the checkpoint but (4,) in the model! Skipped.
'roi_heads.mask_head.predictor.weight' has shape (80, 256, 1, 1) in the checkpoint but (1, 256, 1, 1) in the model! Skipped.
'roi_heads.mask_head.predictor.bias' has shape (80,) in the checkpoint but (1,) in the model! Skipped.
100% 181/181 [01:32<00:00,  1.97it/s]

@ppwwyyxx
Copy link
Contributor

As I said in #101 (comment)

The model you trained will be in os.path.join(cfg.OUTPUT_DIR, "model_final.pth"), as you can find in the tutorial as well. You need to set MODEL.WEIGHTS to it for inference.

You load a wrong model.

@gireeshkbogu
Copy link
Author

In the tutorial .pkl file was set to weights. Setting .pth is the same as .pkl?
Also when I build the model with balloon data, where does it save the .pkl file?

@ppwwyyxx
Copy link
Contributor

In the tutorial .pkl file was set to weights. Setting .pth is the same as .pkl?

Both file extensions are supported.

Also when I build the model with balloon data, where does it save the .pkl file?

I do not know what you mean by "when I build the model", and when saying "the .pkl file" it is unclear to me what pkl file you're referring to.

@gireeshkbogu
Copy link
Author

gireeshkbogu commented Oct 19, 2019

Here is the line from the tutorial where *.pkl file set to model weights in the demo.py

#cfg.MODEL.WEIGHTS = "detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl"

If I understand correctly, I just replace this .pkl with my own .pth file in demo.py?

@ppwwyyxx
Copy link
Contributor

Yes

@gireeshkbogu
Copy link
Author

Yey!!! it is working. Thank you for being so patient with me.
I really really appreciate your help even at this time. I hope you have a nice weekend :)

@Haow235
Copy link

Haow235 commented Jan 2, 2020

Set cfg.DATASETS.TEST = ("balloon/val",)

@ppwwyyxx

I trained just like the balloon tutorial, got the trained result, and I have the same error when predict in my own new dataset, which doesn't have label, only image, I think it's because I don't set the config correctly, would you please tell me how to set the cfg correctly when predict in new dataset.
The following is my code:
`from google.colab.patches import cv2_imshow

cfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, "model_final.pth")
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.7 # set the testing threshold for this model
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 6 # only has one class (ballon)
predictor = DefaultPredictor(cfg)
outputs = predictor(im) IndexError Traceback (most recent call last)

in ()
6 cfg.MODEL.ROI_HEADS.NUM_CLASSES = 6 # only has one class (ballon)
7 # cfg.DATASETS.TEST = ("balloon_val", )
----> 8 predictor = DefaultPredictor(cfg)
9 outputs = predictor(im)

/content/detectron2_repo/detectron2/engine/defaults.py in init(self, cfg)
157 self.model = build_model(self.cfg)
158 self.model.eval()
--> 159 self.metadata = MetadataCatalog.get(cfg.DATASETS.TEST[0])
160
161 checkpointer = DetectionCheckpointer(self.model)

IndexError: tuple index out of range`

anyhelp would be appreciate, thank you so much!

@ppwwyyxx
Copy link
Contributor

ppwwyyxx commented Jan 2, 2020

#101 (comment)

@Haow235
Copy link

Haow235 commented Jan 2, 2020

thank you, I figured it out. I need to register the test data before using it, and then do as you say. thanks a lot~

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants