由于无法确定预测数据集的格式以及具体的预测目标,当前版本的PaddleViT分类模型只提供了训练和验证代码,对应数据集包含图像数据和标签,具体数据的存放形式可以参考 这里。 本教程提供简单的流程,帮助用户使用PaddleViT进行模型预测。
dataset.py
: 添加目标数据集的加载方式main_single_gpu.py
/main_multi_gpu.py
: 添加predict方法run_test.sh
: 新建shell脚本启动预测程序
PaddleViT分类模型采用统一的数据加载方式:
from datasets import get_dataset
your_dataset = get_dataset(config, mode='train')
your_dataloader = get_dataloader(config, dataset, mode='train', multi_process=False)
在得到your_dataloader
之后,可以使用常见的for循环方式加载数据开始训练或测试:
for batch_id, batch_data in enumerate(your_dataloder):
# start your training/validation
...
config的基本概念参考这里
当需要使用自定义数据集时。我们需要:
- 在
datasets.py
(或者新建python文件)中创建YOUR_DATASET
类,继承paddle.io.Dataset
父类,并且实现__len__
和__getitem__
方法:class YOUR_DATASET(paddle.io.dataset): def __init__(self, file_folder, mode, transform=None): super().__init__() # TODO: load image list (if train, load corresponding label info) ... def __len__(self): # TODO: return num of data def __getitem__(self, index): # TODO: return image data given index, if transform is not none, apply transform first.
注意: 在
__getitem__
方法返回前可能需要先对数据进行预处理。 - 在
datasets.py
中修改数据处理方法get_train_transforms
和get_val_transforms
,也可以新建自己的transforms,例如get_test_transforms
:def get_test_transform(config): scale_size = int(math.floor(config.DATA.IMAGE_SIZE / config.DATA.CROP_PCT)) transforms_test = transforms.Compose([ transforms.Resize(scale_size, 'bicubic'), # single int for resize shorter side of image transforms.CenterCrop((config.DATA.IMAGE_SIZE, config.DATA.IMAGE_SIZE)), transforms.ToTensor(), transforms.Normalize(mean=config.DATA.IMAGENET_MEAN, std=config.DATA.IMAGENET_STD), ]) return transforms_test
- 在
datasets.py
中的get_dataset
方法增加该数据集的调用方法:def get_dataset(config, mode='train'): assert mode in ['train', 'val', 'test'] ... # ADD your dataset for testing: elif config.DATA.DATASET == "your_dataset_name": dataset = YOUR_DATASET(config.DATA.DATA_PATH, mode='test', transform=get_test_transforms(config)) ... return dataset
我们可以在主程序中,增加预测方法(predict
),和validate
方法的区别是,predict
方法不会加载到标签信息,所以不会返回acc等指标,仅返回预测结果,以main_single_gpu.py
为例,我们可以增加以下方法:
def predict(dataloader, model, total_batch, debug_steps=100, logger=None):
"""Predict for whole dataset
Args:
dataloader: paddle.io.DataLoader, dataloader instance
model: nn.Layer, a ViT model
total_batch: int, total num of batches for one epoch
debug_steps: int, num of iters to log info, default: 100
logger: logger for logging, default: None
Returns:
preds: prediction results
pred_time: float, prediction time
"""
model.eval()
time_st = time.time()
preds = []
with paddle.no_grad():
for batch_id, data in enumerate(dataloader):
image = data[0]
#label = data[1] # no label info in prediction
output = model(image)
#loss = criterion(output, label) # no criterion in prediction
pred = F.softmax(output)
# no acc in prediction
#acc1 = paddle.metric.accuracy(pred, label.unsqueeze(1))
#acc5 = paddle.metric.accuracy(pred, label.unsqueeze(1), k=5)
preds.append(pred)
if logger and batch_id % debug_steps == 0:
logger.info(f"Pred Step[{batch_id:04d}/{total_batch:04d}], done")
pred_time = time.time() - time_st
return preds, pred_time
返回结果为list
, 包含每个batch的预测结果(tensor
)和预测时间
在main
方法中,我们可以修改eval
相关部分用以完成prediction:
def main():
...
# STEP 2: Create train and val dataloader
...
dataset_test = get_dataset(config, mode='test')
dataloader_test = get_dataloader(config, dataset_test, 'test', False)
...
# STEP 7: Prediction
if config.EVAL:
logger.info('----- Start Prediction')
preds, pred_time = predict(
dataloader=dataloader_val,
model=model,
total_batch=len(dataloader_val),
debug_steps=config.REPORT_FREQ,
logger=logger)
# TODO: do your processing on predictions
return
CUDA_VISIBLE_DEVICES=0 \
python main_single_gpu.py \
-cfg='./configs/vit_base_patch16_224.yaml' \
-dataset='your_dataset_name' \
-batch_size=128 \
-data_path='your_dataset_path' \
-eval \
-pretrained='./vit_base_patch16_224'