longyi8013

0  前言

最近学习了李牧的动手学深度学习V2,他在kaggle平台上发起了一个目标检测的比赛,本着动手学习的态度,先使用他人的代码模型跑通试试看,一方面是熟悉学校服务器的一些配置,一方面是学习代码。

检测主要包括:牛仔夹克、墨镜、靴子、牛仔帽、腰带

使用的是yolov5l,参考别人的模型代码,代码获取:【windows下使用Yolov5l用于牛仔行头检测

他的一些代码配置有点小小的问题,在这里记录一下。

本次牛仔行头检测我使用的是ultralytics/yolov5 ,该仓库提供了s、m、l、x四个规模的预训练模型,我使用的预训练模型是Yolov5l,最后可以在公榜(也就是valid.csv)上达到60的MAP值。

本次是目标检测竞赛,一张图片上可能存在多个目标,每个目标可以用四个值来进行表示,即目标的种类和目标的位置,位置用四个值来进行表示,目标检测常用的格式可以为了3种:coco、voc和yolo。coco的坐标表示为[x, y, w, h],即bbox左上角的坐标和bbox的宽和高;voc的坐标表示为[x_min, y_min, x_max, y_max],即bbox左上角的坐标和右下角的坐标;yolo的坐标表示为[center_x, center_y, w, h],yolo这里表示的是bbox中心点的坐标和bbox的宽高,注意yolo这里是值是经过归一化处理的,都是介于0到1之前的浮点数。本次比赛我们使用的是coco格式,我使用yolo模型来进行训练的,所以在训练和提交结果之前要对格式进行转换,否则大家可能遇到训练的MAP和提交测试的MAP相差过多的情况出现。

1 环境配置

配置之前请确保已经安装好了英伟达显卡的驱动,在命令行中输入nvidia-smi会输出相应的显卡信息。由于我们使用的是anconda来控制虚拟环境,使用conda命令安装Pytorch的时候会自动检查依赖并进行安装,所以不需要额外在本地安装cuda。(这些我的没有问题,毕竟用的学校服务器,之前装好了anconda

1.1 把代码下载到本地

执行下列命令。(下载完后一般是在C盘的具体用户文件夹下会有一个yolov5的文件夹,这个需要上传到服务器,如果是自己电脑放工程文件夹下就行

cmd
git clone https://github.com/ultralytics/yolov5.git

1.2 创建并激活虚拟环境

在服务器上创建一个专门yolo使用的虚拟环境,然后激活转到yolo环境下操作;

conda create -n yolo python==3.8.5
conda activate yolo

1.3 安装相关模块包、库文件

1、安装GPU版本的Pytorch,注意30系列显卡是安培架构,只支持11版本的cuda。(我不知道学校的服务器什么情况,反正我装的10.2可以

conda install pytorch==1.7.0 torchvision torchaudio cudatoolkit=10.2

这个我的报错了,说找不到pytorch==1.7.0,所以我去网站https://pytorch.org/找下载命令,CUDA可以选10.2或者11.1,这里我和他一致选10.2。

conda install pytorch torchvision torchaudio cudatoolkit=10.2 -c pytorch

 

 2、安装程序所需的其他的第三方库

把下载的模型文件夹上传到服务器后,cd到文件目录下,然后进行相关环境依赖安装;安装要求都在requirements.txt文件中

它这里会把所有满足要求比如大于等于某个版本的全部安装,时间有点久。

cd yolov5
pip install -r requirements.txt

我的一开始没成功,因为这是个requirements.txt文件,他原本没有加后缀txt;

后面又报错scipy安装不上:

ERROR: Could not find a version that satisfies the requirement scipy>=1.4.1 (from versions: none)
ERROR: No matching distribution found for scipy>=1.4.1

如果遇到安装不上的,就单独使用pip install scipy这种命令安装,然后再用下面的命令安装即可。

pip install -r requirements.txt

2 数据预处理

数据部分需要处理成yolo的数据格式,如果觉得比较麻烦的小伙伴可以使用我处理好的,链接如下:

链接:https://pan.baidu.com/s/1SGdjCTAq6Sa4LLgAG9Xx5w 提取码:v9re

 为了方便,我直接使用的这个处理好的,想自己处理的,前言中给了链接,自行获取代码处理。

原始的数据包含四部分的内容:

images # 存放图片文件
test.csv # 私榜需要测试的图片 
train.json # 训练的数据以及标注
vaild.csv # 公榜需要测试的图片

下载他的文件夹包括:

cow_yolo_dataset:
  score: # 存放训练的图片文件
    images:
      test
      train # 后面配置用到
      val  # 后面配置用到
    lables:
      test
      train
      val
  test_val:# 测试的照片
    test
    val # 后面转换格式的时候用到

 

3 修改配置文件

所有的修改都是在yolov5之前下载的文件夹下进行操作。

3.1 在data目录下设置数据集的配置文件

我们在data目录下新建一个cow_data.yaml的文件,在文件中指定训练集和验证集的地址(需要更改为自己的存放路径)、数据集的目标数目和目标类名;(这个暂时还没找到在哪用,后续发现在运行的时候指定了这个文件

# Custom data for safety helmet

# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: /data1/scm/2021/com/cow/cow_yolo_dataset/score/images/train # 这个就是上面train的文件路径,改成自己的
val: /data1/scm/2021/com/cow/cow_yolo_dataset/score/images/val # 这个就是训练的val的文件路径,改成自己的

# number of classes
nc: 5

# class names
names: ["belt", "sunglasses", "boot", "cowboy_hat", "jacket"]

3.2 在models目录下设置模型的配置文件

在models目录下新建一个cow_yolov5l.yaml的模型配置文件,这个文件应该是模型读取那一块要用的,在yolo.py的79行(盲猜的)。(实际也是在运行的时候指定的,这里改不改应该没什么问题)

具体内容如下:(无更改,直接使用)

# parameters
nc: 5  # number of classes # 修改为我们模型的类别数目
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple

# anchors
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Focus, [64, 3]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 9, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 1, SPP, [1024, [5, 9, 13]]],
   [-1, 3, C3, [1024, False]],  # 9
  ]

# YOLOv5 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, \'nearest\']],
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 13

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, \'nearest\']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

4 训练模型

首先从点这里下载预训练的模型yolov5l(yolov5l.pt)到本地,存放在yolov5的weights目录下(没有就创建weights文件夹)。

上面的过程中我们已经设置好了数据集和模型的配置文件,我们只需要在项目的根目录下执行下列代码即可开始训练,由于我的显卡只有8G,所以这里的batchsize设置为4,训练的轮数设置为200;

(由于我用的服务器,我申请了两块CPU,所以batchsize我改大了也没什么问题,轮数200会有点久,差不多3小时吧,batchsize设置为4,轮数设置为50的时候是0.5小时,我的batch大,所以久点)

具体的命令如下:(记得cd到train.py的文件目录下,这个文件yolov5有,我是直接用的,没有复制他给出的代码)

python train.py --data data/cow_data.yaml --cfg models/cow_yolov5l.yaml --weights weights/yolov5l.pt --batch-size 8 --epochs 200

训练的结果会保存在runs/train/exp目录下,其中有各种可视化的过程图,weights目录下是训练好的权重文件,也就是我们最后需要的模型

!!!注意:在这里可以看到,上面的配置文件在这里运行的时候指定了,所以我们可以不要在源码中进行更改。

到目前没什么问题,正在跑模型中,跑的有点久。

4.1 训练运行结果

可视化结果

训练结果

 

 

训练锚框标记结果

 

验证标记结果

 

 验证预测结果

 

5 测试模型

Yolov5中自带的代码可以直接调用模型对结果进行推理,我对detect的代码进行了修改,直接运行cow_detect_kaggle.py就能将图片和文本文件的检测结果保存在runs/detect目录下,代码如下:

(这里的文件夹没有这个文件,我们新建一个python文件在train同一级目录下即可,这里要注意的是158行的目录要改成你自己的目录!!!改前面的就可以了)

  1 # 用于生成txt文件
  2 import argparse
  3 import time
  4 from pathlib import Path
  5 
  6 import cv2
  7 import torch
  8 import torch.backends.cudnn as cudnn
  9 
 10 from models.experimental import attempt_load
 11 from utils.datasets import LoadStreams, LoadImages
 12 from utils.general import check_img_size, check_requirements, check_imshow, non_max_suppression, apply_classifier, \
 13     scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path, save_one_box
 14 from utils.plots import colors, plot_one_box
 15 from utils.torch_utils import select_device, load_classifier, time_sync #  time_synchronized
 16 # import utils.torch_utils
 17 
 18 @torch.no_grad()
 19 def detect(opt):
 20     source, weights, view_img, save_txt, imgsz = opt.source, opt.weights, opt.view_img, opt.save_txt, opt.img_size
 21     save_img = not opt.nosave and not source.endswith(\'.txt\')  # save inference images
 22     webcam = source.isnumeric() or source.endswith(\'.txt\') or source.lower().startswith(
 23         (\'rtsp://\', \'rtmp://\', \'http://\', \'https://\'))
 24     save_txt = True
 25     print(save_txt)
 26 
 27     # Directories
 28     save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)  # increment run
 29     (save_dir / \'labels\' if save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir
 30 
 31     # Initialize
 32     set_logging()
 33     device = select_device(opt.device)
 34     half = opt.half and device.type != \'cpu\'  # half precision only supported on CUDA
 35 
 36     # Load model
 37     model = attempt_load(weights, map_location=device)  # load FP32 model
 38     stride = int(model.stride.max())  # model stride
 39     imgsz = check_img_size(imgsz, s=stride)  # check img_size
 40     names = model.module.names if hasattr(model, \'module\') else model.names  # get class names
 41     if half:
 42         model.half()  # to FP16
 43 
 44     # Second-stage classifier
 45     classify = False
 46     if classify:
 47         modelc = load_classifier(name=\'resnet101\', n=2)  # initialize
 48         modelc.load_state_dict(torch.load(\'weights/resnet101.pt\', map_location=device)[\'model\']).to(device).eval()
 49 
 50     # Set Dataloader
 51     vid_path, vid_writer = None, None
 52     if webcam:
 53         view_img = check_imshow()
 54         cudnn.benchmark = True  # set True to speed up constant image size inference
 55         dataset = LoadStreams(source, img_size=imgsz, stride=stride)
 56     else:
 57         dataset = LoadImages(source, img_size=imgsz, stride=stride)
 58 
 59     # Run inference
 60     if device.type != \'cpu\':
 61         model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters())))  # run once
 62     t0 = time.time()
 63     for path, img, im0s, vid_cap in dataset:
 64         img = torch.from_numpy(img).to(device)
 65         img = img.half() if half else img.float()  # uint8 to fp16/32
 66         img /= 255.0  # 0 - 255 to 0.0 - 1.0
 67         if img.ndimension() == 3:
 68             img = img.unsqueeze(0)
 69 
 70         # Inference
 71         t1 = time_sync() # time_synchronized()
 72         pred = model(img, augment=opt.augment)[0]
 73 
 74         # Apply NMS
 75         pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, opt.classes, opt.agnostic_nms,
 76                                    max_det=opt.max_det)
 77         t2 = time_sync() # time_synchronized()
 78 
 79         # Apply Classifier
 80         if classify:
 81             pred = apply_classifier(pred, modelc, img, im0s)
 82 
 83         # Process detections
 84         for i, det in enumerate(pred):  # detections per image
 85             if webcam:  # batch_size >= 1
 86                 p, s, im0, frame = path[i], f\'{i}: \', im0s[i].copy(), dataset.count
 87             else:
 88                 p, s, im0, frame = path, \'\', im0s.copy(), getattr(dataset, \'frame\', 0)
 89 
 90             p = Path(p)  # to Path
 91             save_path = str(save_dir / p.name)  # img.jpg
 92             txt_path = str(save_dir / \'labels\' / p.stem) + (\'\' if dataset.mode == \'image\' else f\'_{frame}\')  # img.txt
 93             s += \'%gx%g \' % img.shape[2:]  # print string
 94             gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh
 95             imc = im0.copy() if opt.save_crop else im0  # for opt.save_crop
 96             if len(det):
 97                 # Rescale boxes from img_size to im0 size
 98                 det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
 99 
100                 # Print results
101                 for c in det[:, -1].unique():
102                     n = (det[:, -1] == c).sum()  # detections per class
103                     s += f"{n} {names[int(c)]}{\'s\' * (n > 1)}, "  # add to string
104 
105                 # Write results
106                 for *xyxy, conf, cls in reversed(det):
107                     if save_txt:  # Write to file
108                         xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
109                         line = (cls, *xywh, conf) if opt.save_conf else (cls, *xywh)  # label format
110                         with open(txt_path + \'.txt\', \'a\') as f:
111                             f.write((\'%g \' * len(line)).rstrip() % line + \'\n\')
112 
113                     if save_img or opt.save_crop or view_img:  # Add bbox to image
114                         c = int(cls)  # integer class
115                         label = None if opt.hide_labels else (names[c] if opt.hide_conf else f\'{names[c]} {conf:.2f}\')
116                         plot_one_box(xyxy, im0, label=label, color=colors(c, True), line_thickness=opt.line_thickness)
117                         if opt.save_crop:
118                             save_one_box(xyxy, imc, file=save_dir / \'crops\' / names[c] / f\'{p.stem}.jpg\', BGR=True)
119 
120             # Print time (inference + NMS)
121             print(f\'{s}Done. ({t2 - t1:.3f}s)\')
122 
123             # Stream results
124             if view_img:
125                 cv2.imshow(str(p), im0)
126                 cv2.waitKey(1)  # 1 millisecond
127 
128             # Save results (image with detections)
129             if save_img:
130                 if dataset.mode == \'image\':
131                     cv2.imwrite(save_path, im0)
132                 else:  # \'video\' or \'stream\'
133                     if vid_path != save_path:  # new video
134                         vid_path = save_path
135                         if isinstance(vid_writer, cv2.VideoWriter):
136                             vid_writer.release()  # release previous video writer
137                         if vid_cap:  # video
138                             fps = vid_cap.get(cv2.CAP_PROP_FPS)
139                             w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
140                             h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
141                         else:  # stream
142                             fps, w, h = 30, im0.shape[1], im0.shape[0]
143                             save_path += \'.mp4\'
144                         vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*\'mp4v\'), fps, (w, h))
145                     vid_writer.write(im0)
146 
147     if save_txt or save_img:
148         s = f"\n{len(list(save_dir.glob(\'labels/*.txt\')))} labels saved to {save_dir / \'labels\'}" if save_txt else \'\'
149         print(f"Results saved to {save_dir}{s}")
150 
151     print(f\'Done. ({time.time() - t0:.3f}s)\')
152 
153 
154 if __name__ == \'__main__\':
155     parser = argparse.ArgumentParser()
156     parser.add_argument(\'--weights\', nargs=\'+\', type=str, default=\'runs/train/exp/weights/best.pt\',  # 设置模型位置
157                         help=\'model.pt path(s)\')
158     parser.add_argument(\'--source\', type=str, default=\'../kaggleCode/cowboyOutfits_object_detection/cow_yolo_dataset/cow_yolo_dataset/test_val/val\',  # todo 设置验证集图片位置
159                         help=\'source\')  # file/folder, 0 for webcam
160     parser.add_argument(\'--img-size\', type=int, default=640, help=\'inference size (pixels)\')
161     parser.add_argument(\'--conf-thres\', type=float, default=0.25, help=\'object confidence threshold\')
162     parser.add_argument(\'--iou-thres\', type=float, default=0.45, help=\'IOU threshold for NMS\')
163     parser.add_argument(\'--max-det\', type=int, default=1000, help=\'maximum number of detections per image\')
164     parser.add_argument(\'--device\', default=\'\', help=\'cuda device, i.e. 0 or 0,1,2,3 or cpu\')
165     parser.add_argument(\'--view-img\', action=\'store_true\', help=\'display results\')
166     parser.add_argument(\'--save-txt\', default="True", action=\'store_true\',
167                         help=\'save results to *.txt\')  # todo 设置是否保存txt检测结果
168     parser.add_argument(\'--save-conf\', default="True", action=\'store_true\',
169                         help=\'save confidences in --save-txt labels\')  # todo 设置是否保存置信度
170     parser.add_argument(\'--save-crop\', action=\'store_true\', help=\'save cropped prediction boxes\')
171     parser.add_argument(\'--nosave\', action=\'store_true\', help=\'do not save images/videos\')
172     parser.add_argument(\'--classes\', nargs=\'+\', type=int, help=\'filter by class: --class 0, or --class 0 2 3\')
173     parser.add_argument(\'--agnostic-nms\', action=\'store_true\', help=\'class-agnostic NMS\')
174     parser.add_argument(\'--augment\', action=\'store_true\', help=\'augmented inference\')
175     parser.add_argument(\'--update\', action=\'store_true\', help=\'update all models\')
176     parser.add_argument(\'--project\', default=\'runs/detect\', help=\'save results to project/name\')
177     parser.add_argument(\'--name\', default=\'exp\', help=\'save results to project/name\')
178     parser.add_argument(\'--exist-ok\', action=\'store_true\', help=\'existing project/name ok, do not increment\')
179     parser.add_argument(\'--line-thickness\', default=3, type=int, help=\'bounding box thickness (pixels)\')
180     parser.add_argument(\'--hide-labels\', default=False, action=\'store_true\', help=\'hide labels\')
181     parser.add_argument(\'--hide-conf\', default=False, action=\'store_true\', help=\'hide confidences\')
182     parser.add_argument(\'--half\', action=\'store_true\', help=\'use FP16 half-precision inference\')
183     opt = parser.parse_args()
184     print(opt)
185     check_requirements(exclude=(\'tensorboard\', \'pycocotools\', \'thop\'))
186 
187     if opt.update:  # update all models (to fix SourceChangeWarning)
188         for opt.weights in [\'yolov5s.pt\', \'yolov5m.pt\', \'yolov5l.pt\', \'yolov5x.pt\']:
189             detect(opt=opt)
190             strip_optimizer(opt.weights)
191     else:
192         detect(opt=opt)

5.1 测试结果

会输出一连串这样的数字,主要是你测试生成锚框的图片的数字

6 生成可提交的测试文件

为了能够在竞赛的网站上进行提交,我们还需要将得到的txt格式的yolo文件转化一下,转化为竞赛网站所需的json格式,转化的代码如下:

!!!注意:需要修改的地方已标记出来

 1 import os
 2 import pandas as pd
 3 # import tqdm
 4 from PIL import Image
 5 import zipfile
 6 
 7 
 8 
 9 
10 # convert yolo to coco annotation format
11 def yolo2cc_bbox(img_width, img_height, bbox):
12     x = (bbox[0] - bbox[2] * 0.5) * img_width
13     y = (bbox[1] - bbox[3] * 0.5) * img_height
14     w = bbox[2] * img_width
15     h = bbox[3] * img_height
16     return (x, y, w, h)
17 
18 
19 
20 
21 
22 def make_submission(df, PRED_PATH, IMAGE_PATH):
23     output = []
24     # for i in tqdm(range(len(df))):
25     for i in range(len(df)):
26         # print(i)
27         row = df.loc[i]
28         image_id = row[\'id\']
29         file_name = row[\'file_name\'].split(\'.\')[0]
30         if f\'{file_name}.txt\' in prediction_files:# 这里文件名不在里面,如果val的文件在预测的文件里,就打印;问题找到了,出在cow_detect_kaggle.py的val的图片路径搞错了
31             print(file_name)
32             img = Image.open(f\'{IMAGE_PATH}/{file_name}.jpg\')
33             width, height = img.size
34             with open(f\'{PRED_PATH}/{file_name}.txt\', \'r\') as file:
35                 for line in file:
36                     preds = line.strip(\'\n\').split(\' \')
37                     preds = list(map(float, preds))  # conver string to float
38                     print(preds)
39                     print(preds[1:-1])
40                     cc_bbox = yolo2cc_bbox(width, height, preds[1:-1])
41                     result = {
42                         \'image_id\': image_id,
43                         \'category_id\': re_cate_id_map[preds[0]],
44                         \'bbox\': cc_bbox,
45                         \'score\': preds[-1]
46                     }
47 
48                     output.append(result)
49         
50     return output
51 
52 
53 
54 
55 if __name__ == \'__main__\':
56 
57     valid_df = pd.read_csv(\'../kaggleCode/cowboyOutfits_object_detection/valid.csv\') # 这是你kaggle下载的原始的数据文件下的valid.csv
58 # test_df = pd.read_csv(\'../kaggleCode/cowboyOutfits_object_detection/test.csv\')
59 # valid_df.head() 60 61 cate_id_map = {87: 0, 1034: 1, 131: 2, 318: 3, 588: 4} 62 PRED_PATH = "../kaggleCode/cowboyOutfits_object_detection/yolov5/runs/detect/exp/labels/" # 这是你运行之后生成的文件目录
63 IMAGE_PATH = "../kaggleCode/cowboyOutfits_object_detection/images/" # 这是你kaggle下载的原始的数据文件下的图片目录
64 65 #with open(\'../kaggleCode/cowboyOutfits_object_detection/yolov5/runs/detect/exp/labels/0030eb25a4d98400.txt\', \'r\') as file:
66 # for line in file: 67 # print(line) 68 69 # Image.open(\'../kaggleCode/cowboyOutfits_object_detection/yolov5/runs/detect/exp/0030eb25a4d98400.jpg\')
70 71 # list our prediction files path 72 prediction_files = os.listdir(PRED_PATH) 73 print(\'Number of test images with detections: \n\', len(prediction_files)) 74 75 # reverse the categories numer to the origin id 76 re_cate_id_map = dict(zip(cate_id_map.values(), cate_id_map.keys())) 77 78 print(\'origin id: \n\', re_cate_id_map) 79 80 81 sub_data = make_submission(valid_df, PRED_PATH, IMAGE_PATH) 82 83 op_pd = pd.DataFrame(sub_data) 84 85 op_pd.sample(10) 86 87 # 这个文件夹的目录都没有,需要自己创建,创建在工程文件下就行,改成自己的,answer.json复制train.json改下名字 88 op_pd.to_json(\'../kaggleCode/cowboyOutfits_object_detection/cow_yolo_dataset/cow_answer/answer.json\', orient=\'records\') 89 zf = zipfile.ZipFile(\'../kaggleCode/cowboyOutfits_object_detection/cow_yolo_dataset/cow_answer/sample_answer.zip\', \'w\')
90 zf.write(\'../kaggleCode/cowboyOutfits_object_detection/cow_yolo_dataset/cow_answer/answer.json\', \'answer.json\')
91 zf.close()

6.1 提交结果

上面会生成answer.json和sample_answer.zip两个文件,我们在网站上提交sample_answer.zip即可。

 

 写在最后

最近teacher催其他事情催的紧,没有时间继续学习和优化,痛苦,今天都是忙里偷闲把这个再弄一下,后面再慢慢找时间学习优化以及学习使用其他的模型吧,毕竟今天就截止了。
 

分类:

技术点:

相关文章: