提交 70cb5650 authored 作者: 1051780106@qq.com's avatar 1051780106@qq.com

create: 注释

上级 4751345d
......@@ -8,8 +8,11 @@
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
#数据集存放目录
path: ../datasets/coco128 # dataset root dir
#训练集存放目录
train: images/train2017 # train images (relative to 'path') 128 images
#验证集存放目录
val: images/train2017 # val images (relative to 'path') 128 images
test: # test images (optional)
......
差异被折叠。
......@@ -163,7 +163,7 @@ class BaseModel(nn.Module):
class DetectionModel(BaseModel):
# YOLOv5 detection model
# YOLOv5 detection model 模型初始化
def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes
super().__init__()
if isinstance(cfg, dict):
......@@ -357,6 +357,7 @@ def parse_model(d, ch): # model_dict, input_channels(3)
if __name__ == '__main__':
# 定义参数信息
parser = argparse.ArgumentParser()
parser.add_argument('--cfg', type=str, default='yolov5s.yaml', help='model.yaml')
parser.add_argument('--batch-size', type=int, default=1, help='total batch size for all GPUs')
......
差异被折叠。
......@@ -110,21 +110,22 @@ def replicate(im, labels):
def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
# Resize and pad image while meeting stride-multiple constraints
shape = im.shape[:2] # current shape [height, width]
if isinstance(new_shape, int):
shape = im.shape[:2] # current shape [height, width] 原图的高和宽[h,w] (1080,810)
if isinstance(new_shape, int): # 判断是不是int型的
new_shape = (new_shape, new_shape)
# Scale ratio (new / old)
# 按照新宽高/旧宽高 小的那一个,进行缩放
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
if not scaleup: # only scale down, do not scale up (for better val mAP)
r = min(r, 1.0)
# Compute padding
ratio = r, r # width, height ratios
new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding
if auto: # minimum rectangle
dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding
new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) # 求出缩放后的宽高 [width,height] 新图的尺寸 (480,640)
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding 160,0
if auto: # minimum rectangle 最小矩形
dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding 如果满足32的倍数,自动填充,例如480为32倍数,所以padding就为0,dw=0,dh=0
elif scaleFill: # stretch
dw, dh = 0.0, 0.0
new_unpad = (new_shape[1], new_shape[0])
......
......@@ -238,18 +238,18 @@ class LoadScreenshots:
class LoadImages:
# YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4`
def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1):
def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): # path:“data\\images\\bus.jpg”,img_size:[640,640]
if isinstance(path, str) and Path(path).suffix == '.txt': # *.txt file with img/vid/dir on each line
path = Path(path).read_text().rsplit()
files = []
for p in sorted(path) if isinstance(path, (list, tuple)) else [path]:
p = str(Path(p).resolve())
if '*' in p:
p = str(Path(p).resolve()) # 由相对路径得到绝对路径
if '*' in p: # 判断路径是否带"*"号
files.extend(sorted(glob.glob(p, recursive=True))) # glob
elif os.path.isdir(p):
elif os.path.isdir(p): # 判断路径是否是文件夹
files.extend(sorted(glob.glob(os.path.join(p, '*.*')))) # dir
elif os.path.isfile(p):
files.append(p) # files
elif os.path.isfile(p): # 判断是不是文件
files.append(p) # files, 变成列表形式
else:
raise FileNotFoundError(f'{p} does not exist')
......@@ -306,12 +306,13 @@ class LoadImages:
self.count += 1
im0 = cv2.imread(path) # BGR
assert im0 is not None, f'Image Not Found {path}'
s = f'image {self.count}/{self.nf} {path}: '
s = f'image {self.count}/{self.nf} {path}: ' # 打印图片输出到第几张了
if self.transforms:
im = self.transforms(im0) # transforms
else:
im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize
# 将原图变成特定大小的图片,resize
im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize (640,480,3)
im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB
im = np.ascontiguousarray(im) # contiguous
......
......@@ -130,12 +130,12 @@ def set_logging(name=LOGGING_NAME, verbose=True):
name: {
'class': 'logging.StreamHandler',
'formatter': name,
'level': level,}},
'level': level, }},
'loggers': {
name: {
'level': level,
'handlers': [name],
'propagate': False,}}})
'propagate': False, }}})
set_logging(LOGGING_NAME) # run before defining LOGGER
......
......@@ -317,7 +317,9 @@ def copy_attr(a, b, include=(), exclude=()):
def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5):
# YOLOv5 3-param group optimizer: 0) weights with decay, 1) weights no decay, 2) biases no decay
# 把模型每一层的参数,划分到三个组中
g = [], [], [] # optimizer parameter groups
# g[0]存所有卷积层的w参数,g[1] bn层的w,g[2]所有层的偏置项b
bn = tuple(v for k, v in nn.__dict__.items() if 'Norm' in k) # normalization layers, i.e. BatchNorm2d()
for v in model.modules():
for p_name, p in v.named_parameters(recurse=0):
......@@ -327,7 +329,7 @@ def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5):
g[1].append(p)
else:
g[0].append(p) # weight (with decay)
# 判断训练过程中所使用的优化器的类型
if name == 'Adam':
optimizer = torch.optim.Adam(g[2], lr=lr, betas=(momentum, 0.999)) # adjust beta1 to momentum
elif name == 'AdamW':
......@@ -335,11 +337,12 @@ def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5):
elif name == 'RMSProp':
optimizer = torch.optim.RMSprop(g[2], lr=lr, momentum=momentum)
elif name == 'SGD':
optimizer = torch.optim.SGD(g[2], lr=lr, momentum=momentum, nesterov=True)
# 默认随机梯度下降法
optimizer = torch.optim.SGD(g[2], lr=lr, momentum=momentum, nesterov=True) # lr 学习率, momentum 动量值
else:
raise NotImplementedError(f'Optimizer {name} not implemented.')
optimizer.add_param_group({'params': g[0], 'weight_decay': decay}) # add g0 with weight_decay
optimizer.add_param_group({'params': g[0], 'weight_decay': decay}) # add g0 with weight_decay weight_decay标明要对卷积层的w进行权重衰减
optimizer.add_param_group({'params': g[1], 'weight_decay': 0.0}) # add g1 (BatchNorm2d weights)
LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups "
f'{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias')
......@@ -369,10 +372,12 @@ def smart_resume(ckpt, optimizer, ema=None, weights='yolov5s.pt', epochs=300, re
ema.ema.load_state_dict(ckpt['ema'].float().state_dict()) # EMA
ema.updates = ckpt['updates']
if resume:
# 如果resume有值,且开始轮数大于0则接着训练,否则,抛出异常
assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.\n' \
f"Start a new training without --resume, i.e. 'python train.py --weights {weights}'"
LOGGER.info(f'Resuming training from {weights} from epoch {start_epoch} to {epochs} total epochs')
if epochs < start_epoch:
# 如果开始轮数大于epochs,会提示已训练了多少轮,接下来会用使用的轮数进行微调
LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.")
epochs += ckpt['epoch'] # finetune additional epochs
return best_fitness, start_epoch, epochs
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论