活动介绍

parser = argparse.ArgumentParser('DeiT training and evaluation script', add_help=False) parser.add_argument('--output_dir', default='../deit-main/checkpoint/', help='path where to save, empty for no saving')

时间: 2024-01-16 11:04:44 浏览: 172
这段代码是使用Python中的argparse库来解析命令行参数的。在这段代码中,我们首先创建了一个ArgumentParser对象,用于解析命令行参数。'DeiT training and evaluation script'是ArgumentParser的一个可选参数,用于设置程序的描述信息,add_help=False用于关闭默认的--help选项。 接下来,我们使用add_argument方法向ArgumentParser对象中添加一个参数。'--output_dir'表示参数名称,default='../deit-main/checkpoint/'表示默认值为'../deit-main/checkpoint/',help='path where to save, empty for no saving'表示该参数的描述信息,即该参数表示保存模型文件的路径,如果不设置该参数则不会保存模型文件。 通过这种方式,我们可以在命令行中传递参数,控制程序的行为。例如,我们可以在命令行中输入--output_dir=/path/to/save 来指定保存模型文件的路径。在程序中,我们可以通过args.output_dir来获取这个参数的值。
相关问题

def get_args_parser(): parser = argparse.ArgumentParser('DeiT training and evaluation script', add_help=False) parser.add_argument('--output_dir', default='../deit-main/checkpoint/', help='path where to save, empty for no saving')解释这段代码

这段代码的作用是定义一个命令行参数解析器。 首先,创建一个`ArgumentParser`对象`parser`,其参数`'DeiT training and evaluation script'`为该脚本的描述信息,`add_help=False`表示不添加默认的`-h/--help`选项。 然后,使用`add_argument()`方法添加一个命令行参数`--output_dir`,其默认值为`'../deit-main/checkpoint/'`,表示保存模型参数的路径。`help`参数为该命令行参数的描述信息,使用者可以通过`-h/--help`选项来查看该信息。 最后,返回该解析器对象`parser`。

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license """ Train a YOLOv5 model on a custom dataset. Models and datasets download automatically from the latest YOLOv5 release. Usage - Single-GPU training: $ python train.py --data coco128.yaml --weights yolov5s.pt --img 640 # from pretrained (recommended) $ python train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640 # from scratch Usage - Multi-GPU DDP training: $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml --weights yolov5s.pt --img 640 --device 0,1,2,3 Models: https://github.com/ultralytics/yolov5/tree/master/models Datasets: https://github.com/ultralytics/yolov5/tree/master/data Tutorial: https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data """ import argparse import math import os os.environ["GIT_PYTHON_REFRESH"] = "quiet" # add there import random import sys import time from copy import deepcopy from datetime import datetime from pathlib import Path import numpy as np import torch import torch.distributed as dist import torch.nn as nn import yaml from torch.optim import lr_scheduler from tqdm import tqdm # import numpy # import torch.serialization # torch.serialization.add_safe_globals([numpy._core.multiarray._reconstruct]) FILE = Path(__file__).resolve() ROOT = FILE.parents[0] # YOLOv5 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative import val as validate # for end-of-epoch mAP from models.experimental import attempt_load from models.yolo import Model from utils.autoanchor import check_anchors from utils.autobatch import check_train_batch_size from utils.callbacks import Callbacks from utils.dataloaders import create_dataloader from utils.downloads import attempt_download, is_url from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, labels_to_image_weights, methods, one_cycle, print_args, print_mutation, strip_optimizer, yaml_save) from utils.loggers import Loggers from utils.loggers.comet.comet_utils import check_comet_resume from utils.loss import ComputeLoss from utils.metrics import fitness from utils.plots import plot_evolve from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, smart_resume, torch_distributed_zero_first) LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html RANK = int(os.getenv('RANK', -1)) WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) GIT_INFO = check_git_info() def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze callbacks.run('on_pretrain_routine_start') # Directories w = save_dir / 'weights' # weights dir (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir last, best = w / 'last.pt', w / 'best.pt' # Hyperparameters if isinstance(hyp, str): with open(hyp, errors='ignore') as f: hyp = yaml.safe_load(f) # load hyps dict LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) opt.hyp = hyp.copy() # for saving hyps to checkpoints # Save run settings if not evolve: yaml_save(save_dir / 'hyp.yaml', hyp) yaml_save(save_dir / 'opt.yaml', vars(opt)) # Loggers data_dict = None if RANK in {-1, 0}: loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance # Register actions for k in methods(loggers): callbacks.register_action(k, callback=getattr(loggers, k)) # Process custom dataset artifact link data_dict = loggers.remote_dataset if resume: # If resuming runs from remote artifact weights, epochs, hyp, batch_size = opt.weights, opt.epochs, opt.hyp, opt.batch_size # Config plots = not evolve and not opt.noplots # create plots cuda = device.type != 'cpu' init_seeds(opt.seed + 1 + RANK, deterministic=True) with torch_distributed_zero_first(LOCAL_RANK): data_dict = data_dict or check_dataset(data) # check if None train_path, val_path = data_dict['train'], data_dict['val'] nc = 1 if single_cls else int(data_dict['nc']) # number of classes names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset # Model check_suffix(weights, '.pt') # check weights pretrained = weights.endswith('.pt') if pretrained: with torch_distributed_zero_first(LOCAL_RANK): weights = attempt_download(weights) # download if not found locally ckpt = torch.load(weights, map_location='cpu', weights_only=False) # load checkpoint to CPU to avoid CUDA memory leak model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect model.load_state_dict(csd, strict=False) # load LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report else: model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create amp = check_amp(model) # check AMP # Freeze freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze for k, v in model.named_parameters(): v.requires_grad = True # train all layers # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) if any(x in k for x in freeze): LOGGER.info(f'freezing {k}') v.requires_grad = False # Image size gs = max(int(model.stride.max()), 32) # grid size (max stride) imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple # Batch size if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size batch_size = check_train_batch_size(model, imgsz, amp) loggers.on_params_update({"batch_size": batch_size}) # Optimizer nbs = 64 # nominal batch size accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) # Scheduler if opt.cos_lr: lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] else: lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA ema = ModelEMA(model) if RANK in {-1, 0} else None # Resume best_fitness, start_epoch = 0.0, 0 if pretrained: if resume: best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) del ckpt, csd # DP mode if cuda and RANK == -1 and torch.cuda.device_count() > 1: LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' 'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.') model = torch.nn.DataParallel(model) # SyncBatchNorm if opt.sync_bn and cuda and RANK != -1: model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) LOGGER.info('Using SyncBatchNorm()') # Trainloader train_loader, dataset = create_dataloader(train_path, imgsz, batch_size // WORLD_SIZE, gs, single_cls, hyp=hyp, augment=True, cache=None if opt.cache == 'val' else opt.cache, rect=opt.rect, rank=LOCAL_RANK, workers=workers, image_weights=opt.image_weights, quad=opt.quad, prefix=colorstr('train: '), shuffle=True) labels = np.concatenate(dataset.labels, 0) mlc = int(labels[:, 0].max()) # max label class assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' # Process 0 if RANK in {-1, 0}: val_loader = create_dataloader(val_path, imgsz, batch_size // WORLD_SIZE * 2, gs, single_cls, hyp=hyp, cache=None if noval else opt.cache, rect=True, rank=-1, workers=workers * 2, pad=0.5, prefix=colorstr('val: '))[0] if not resume: if not opt.noautoanchor: check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor model.half().float() # pre-reduce anchor precision callbacks.run('on_pretrain_routine_end', labels, names) # DDP mode if cuda and RANK != -1: model = smart_DDP(model) # Model attributes nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) hyp['box'] *= 3 / nl # scale to layers hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers hyp['label_smoothing'] = opt.label_smoothing model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights model.names = names # Start training t0 = time.time() nb = len(train_loader) # number of batches nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training last_opt_step = -1 maps = np.zeros(nc) # mAP per class results = (0, 0, 0, 0, 0, 0, 0) # P, R, [email protected], [email protected], val_loss(box, obj, cls) scheduler.last_epoch = start_epoch - 1 # do not move scaler = torch.cuda.amp.GradScaler(enabled=amp) stopper, stop = EarlyStopping(patience=opt.patience), False compute_loss = ComputeLoss(model) # init loss class callbacks.run('on_train_start') LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' f"Logging results to {colorstr('bold', save_dir)}\n" f'Starting training for {epochs} epochs...') for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ callbacks.run('on_train_epoch_start') model.train() # Update image weights (optional, single-GPU only) if opt.image_weights: cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx # Update mosaic border (optional) # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) # dataset.mosaic_border = [b - imgsz, -b] # height, width borders mloss = torch.zeros(3, device=device) # mean losses if RANK != -1: train_loader.sampler.set_epoch(epoch) pbar = enumerate(train_loader) LOGGER.info(('\n' + '%11s' * 7) % ('Epoch', 'GPU_mem', 'box_loss', 'obj_loss', 'cls_loss', 'Instances', 'Size')) if RANK in {-1, 0}: pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar optimizer.zero_grad() for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- callbacks.run('on_train_batch_start') ni = i + nb * epoch # number integrated batches (since train start) imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 # Warmup if ni <= nw: xi = [0, nw] # x interp # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) for j, x in enumerate(optimizer.param_groups): # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) if 'momentum' in x: x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) # Multi-scale if opt.multi_scale: sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size sf = sz / max(imgs.shape[2:]) # scale factor if sf != 1: ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) # Forward # with torch.cuda.amp.autocast(amp): with torch.amp.autocast(device_type='cuda'): pred = model(imgs) # forward loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size if RANK != -1: loss *= WORLD_SIZE # gradient averaged between devices in DDP mode if opt.quad: loss *= 4. # Backward scaler.scale(loss).backward() # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html if ni - last_opt_step >= accumulate: scaler.unscale_(optimizer) # unscale gradients torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients scaler.step(optimizer) # optimizer.step scaler.update() optimizer.zero_grad() if ema: ema.update(model) last_opt_step = ni # Log if RANK in {-1, 0}: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) pbar.set_description(('%11s' * 2 + '%11.4g' * 5) % (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths, list(mloss)) if callbacks.stop_training: return # end batch ------------------------------------------------------------------------------------------------ # Scheduler lr = [x['lr'] for x in optimizer.param_groups] # for loggers scheduler.step() if RANK in {-1, 0}: # mAP callbacks.run('on_train_epoch_end', epoch=epoch) ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) final_epoch = (epoch + 1 == epochs) or stopper.possible_stop if not noval or final_epoch: # Calculate mAP results, maps, _ = validate.run(data_dict, batch_size=batch_size // WORLD_SIZE * 2, imgsz=imgsz, half=amp, model=ema.ema, single_cls=single_cls, dataloader=val_loader, save_dir=save_dir, plots=False, callbacks=callbacks, compute_loss=compute_loss) # Update best mAP fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, [email protected], [email protected]] stop = stopper(epoch=epoch, fitness=fi) # early stop check if fi > best_fitness: best_fitness = fi log_vals = list(mloss) + list(results) + lr callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) # Save model if (not nosave) or (final_epoch and not evolve): # if save ckpt = { 'epoch': epoch, 'best_fitness': best_fitness, 'model': deepcopy(de_parallel(model)).half(), 'ema': deepcopy(ema.ema).half(), 'updates': ema.updates, 'optimizer': optimizer.state_dict(), 'opt': vars(opt), 'git': GIT_INFO, # {remote, branch, commit} if a git repo 'date': datetime.now().isoformat()} # Save last, best and delete torch.save(ckpt, last) if best_fitness == fi: torch.save(ckpt, best) if opt.save_period > 0 and epoch % opt.save_period == 0: torch.save(ckpt, w / f'epoch{epoch}.pt') del ckpt callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) # EarlyStopping if RANK != -1: # if DDP training broadcast_list = [stop if RANK == 0 else None] dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks if RANK != 0: stop = broadcast_list[0] if stop: break # must break all DDP ranks # end epoch ---------------------------------------------------------------------------------------------------- # end training ----------------------------------------------------------------------------------------------------- if RANK in {-1, 0}: LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') for f in last, best: if f.exists(): strip_optimizer(f) # strip optimizers if f is best: LOGGER.info(f'\nValidating {f}...') results, _, _ = validate.run( data_dict, batch_size=batch_size // WORLD_SIZE * 2, imgsz=imgsz, model=attempt_load(f, device).half(), iou_thres=0.65 if is_coco else 0.60, # best pycocotools at iou 0.65 single_cls=single_cls, dataloader=val_loader, save_dir=save_dir, save_json=is_coco, verbose=True, plots=plots, callbacks=callbacks, compute_loss=compute_loss) # val best model with plots if is_coco: callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) callbacks.run('on_train_end', last, best, epoch, results) torch.cuda.empty_cache() return results def parse_opt(known=False): parser = argparse.ArgumentParser() parser.add_argument('--weights', type=str, default='./weights/yolov5s.pt', help='initial weights path') parser.add_argument('--cfg', type=str, default='./models/yolov5s.yaml', help='model.yaml path') parser.add_argument('--data', type=str, default=r'C:data/AAAA.yaml', help='data.yaml path') parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') parser.add_argument('--epochs', type=int, default=100, help='total training epochs') parser.add_argument('--batch-size', type=int, default=1, help='total batch size for all GPUs, -1 for autobatch') parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') parser.add_argument('--noval', action='store_true', help='only validate final epoch') parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') parser.add_argument('--noplots', action='store_true', help='save no plot files') parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') parser.add_argument('--name', default='welding_defect_yolov5s_20241101_300', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--quad', action='store_true', help='quad dataloader') parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') parser.add_argument('--save-period', type=int, default=5, help='Save checkpoint every x epochs (disabled if < 1)') parser.add_argument('--seed', type=int, default=0, help='Global training seed') parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') # Logger arguments parser.add_argument('--entity', default=None, help='Entity') parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='Upload data, "val" option') parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval') parser.add_argument('--artifact_alias', type=str, default='latest', help='Version of dataset artifact to use') return parser.parse_known_args()[0] if known else parser.parse_args() def main(opt, callbacks=Callbacks()): # Checks if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() check_requirements() # Resume (from specified or most recent last.pt) if opt.resume and not check_comet_resume(opt) and not opt.evolve: last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml opt_data = opt.data # original dataset if opt_yaml.is_file(): with open(opt_yaml, errors='ignore') as f: d = yaml.safe_load(f) else: d = torch.load(last, map_location='cpu')['opt'] opt = argparse.Namespace(**d) # replace opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate if is_url(opt_data): opt.data = check_file(opt_data) # avoid HUB resume auth timeout else: opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' if opt.evolve: if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve opt.project = str(ROOT / 'runs/evolve') opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume if opt.name == 'cfg': opt.name = Path(opt.cfg).stem # use model.yaml as name opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # DDP mode device = select_device(opt.device, batch_size=opt.batch_size) if LOCAL_RANK != -1: msg = 'is not compatible with YOLOv5 Multi-GPU DDP training' assert not opt.image_weights, f'--image-weights {msg}' assert not opt.evolve, f'--evolve {msg}' assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") # Train if not opt.evolve: train(opt.hyp, opt, device, callbacks) # Evolve hyperparameters (optional) else: # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) meta = { 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr 'box': (1, 0.02, 0.2), # box loss gain 'cls': (1, 0.2, 4.0), # cls loss gain 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight 'iou_t': (0, 0.1, 0.7), # IoU training threshold 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) 'scale': (1, 0.0, 0.9), # image scale (+/- gain) 'shear': (1, 0.0, 10.0), # image shear (+/- deg) 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) 'mosaic': (1, 0.0, 1.0), # image mixup (probability) 'mixup': (1, 0.0, 1.0), # image mixup (probability) 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) with open(opt.hyp, errors='ignore') as f: hyp = yaml.safe_load(f) # load hyps dict if 'anchors' not in hyp: # anchors commented in hyp.yaml hyp['anchors'] = 3 if opt.noautoanchor: del hyp['anchors'], meta['anchors'] opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' if opt.bucket: os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}') # download evolve.csv if exists for _ in range(opt.evolve): # generations to evolve if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate # Select parent(s) parent = 'single' # parent selection method: 'single' or 'weighted' x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) n = min(5, len(x)) # number of previous results to consider x = x[np.argsort(-fitness(x))][:n] # top n mutations w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) if parent == 'single' or len(x) == 1: # x = x[random.randint(0, n - 1)] # random selection x = x[random.choices(range(n), weights=w)[0]] # weighted selection elif parent == 'weighted': x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination # Mutate mp, s = 0.8, 0.2 # mutation probability, sigma npr = np.random npr.seed(int(time.time())) g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 ng = len(meta) v = np.ones(ng) while all(v == 1): # mutate until a change occurs (prevent duplicates) v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) hyp[k] = float(x[i + 7] * v[i]) # mutate # Constrain to limits for k, v in meta.items(): hyp[k] = max(hyp[k], v[1]) # lower limit hyp[k] = min(hyp[k], v[2]) # upper limit hyp[k] = round(hyp[k], 5) # significant digits # Train mutation results = train(hyp.copy(), opt, device, callbacks) callbacks = Callbacks() # Write mutation results keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', 'val/box_loss', 'val/obj_loss', 'val/cls_loss') print_mutation(keys, results, hyp.copy(), save_dir, opt.bucket) # Plot results plot_evolve(evolve_csv) LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' f"Results saved to {colorstr('bold', save_dir)}\n" f'Usage example: $ python train.py --hyp {evolve_yaml}') def run(**kwargs): # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') opt = parse_opt(True) for k, v in kwargs.items(): setattr(opt, k, v) main(opt) return opt if __name__ == "__main__": opt = parse_opt() main(opt) 为什么训练之后,他的runs里面并没有显示best.pt跟last.pt 请查找原因

<think>我们正在分析用户的问题:YOLOv5训练完成后未生成best.pt和last.pt文件的原因。根据用户提供的错误信息,训练在100个epoch完成后,在保存模型时出现了`_pickle.UnpicklingError`错误,导致进程退出代码为1(非正常退出)。因此,训练过程在保存权重文件之前就失败了,所以不会生成best.pt和last.pt。错误的关键信息:```Traceback(mostrecent calllast):File"C:\Users\Administrator\Desktop\yolov5-7.0\train.py",line640,in <module>main(opt)File "C:\Users\Administrator\Desktop\yolov5-7.0\train.py", line534, inmaintrain(opt.hyp, opt, device, callbacks)File"C:\Users\Administrator\Desktop\yolov5-7.0\train.py",line414,in trainstrip_optimizer(f)#strip optimizersFile"C:\Users\Administrator\Desktop\yolov5-7.0\utils\general.py",line1004, instrip_optimizerx =torch.load(f,map_location=torch.device('cpu'))File"C:\ProgramData\anaconda3\envs\yolov5-7.0\lib\site-packages\torch\serialization.py", line1524,in loadraise pickle.UnpicklingError(_get_wo_message(str(e)))from None_pickle.UnpicklingError: Weights onlyload failed. Thisfile canstill beloaded,to doso youhave twooptions,do thosesteps onlyif youtrust thesource ofthe checkpoint.(1)In PyTorch2.6, wechanged thedefault valueof the`weights_only`argument in`torch.load` from`False` to`True`. Re-running `torch.load`with `weights_only` setto `False`will likelysucceed,but itcan resultin arbitrarycode execution. Doit onlyif yougot thefile froma trustedsource.(2) Alternatively, toload with`weights_only=True` pleasecheck therecommended stepsin thefollowing errormessage.WeightsUnpickler error: Unsupported global: GLOBAL numpy._core.multiarray._reconstructwas notan allowedglobal bydefault.Please use`torch.serialization.add_safe_globals([numpy._core.multiarray._reconstruct])` orthe `torch.serialization.safe_globals([numpy._core.multiarray._reconstruct])` contextmanager toallowlistthis globalif youtrust thisclass/function.```错误发生在`strip_optimizer`函数中,该函数在训练结束后被调用,用于去除优化器状态以减小文件大小。在加载一个中间文件(很可能是训练过程中保存的某个检查点)时,由于PyTorch2.6的`weights_only`安全机制,加载失败。原因分析:1.使用的PyTorch版本可能是2.6或更高,而训练过程中保存的检查点(可能是某个epoch的权重)包含了不被`weights_only=True`允许的全局对象(numpy._core.multiarray._reconstruct)。2.在训练结束阶段,YOLOv5会尝试加载最后一次保存的权重文件(可能是last.pt或best.pt)以去除优化器状态,然后重新保存。但在这个加载步骤中失败了。因此,训练过程在最后一步(保存精简权重)失败,导致最终没有生成best.pt和last.pt(或者生成了但随后被删除?实际上,在strip_optimizer步骤之前,训练过程中应该已经保存了best.pt和last.pt,但错误发生在训练结束后的清理步骤)。然而,我们注意到训练过程中每个epoch都会保存一次权重(包括last.pt和best.pt)。所以,在训练过程中,这些文件应该已经被保存了。但是错误发生在训练结束后(100个epoch完成)的strip_optimizer步骤,这个步骤会尝试加载一个.pt文件(可能是last.pt)并重新保存(去除优化器状态)。所以,在训练过程中保存的last.pt和best.pt应该是存在的,但可能在strip_optimizer步骤中被删除或覆盖?实际上,错误发生在加载时,所以文件可能没有被覆盖,但训练脚本在出错后可能删除了临时文件?或者,由于错误,脚本没有完成最后的保存步骤,但之前的保存步骤已经完成。但是用户的问题是没有生成best.pt和last.pt,所以我们需要考虑:1.训练过程中是否保存了这些文件?如果保存了,那么即使最后一步出错,这些文件应该还在。所以用户可能发现输出目录中只有一些中间检查点(比如epoch50.pt等),而没有最终保存的best.pt和last.pt?或者,训练脚本在最后一步删除或覆盖了这些文件?2.另一种可能是,由于错误发生在训练结束后的步骤,训练脚本可能在退出前删除了不完整的文件?但YOLOv5的代码中并没有这样的逻辑。实际上,在训练过程中,每个epoch结束后都会保存一次last.pt,并且在验证集上表现更好时会保存best.pt。所以,在训练过程中,这些文件应该已经被保存了。但是,在训练结束后的strip_optimizer步骤中,脚本会重新加载last.pt(也可能是best.pt)并去除优化器状态,然后覆盖保存。这个步骤失败了,所以可能覆盖操作没有完成,但原始的last.pt和best.pt应该还在。因此,用户可能发现输出目录中确实有best.pt和last.pt,但是它们的大小可能是0(因为覆盖时出错导致文件被截断)?或者,因为加载失败,脚本删除了这些文件?我们查看YOLOv5的代码(train.py):```python#Stripoptimizersforf inlast,best:iff.exists():strip_optimizer(f)#strip optimizers```所以,它会尝试对last和best两个文件都执行strip_optimizer。如果其中一个文件存在,就会尝试加载并去除优化器状态,然后覆盖保存。错误发生在加载其中一个文件(很可能是last.pt)时。因此,在strip_optimizer函数中,加载失败导致异常,脚本退出。所以,strip_optimizer操作没有完成,但原始文件(last.pt和best.pt)应该还在(因为是在覆盖之前加载的,加载失败就不会进行后续的覆盖保存)。那么,为什么用户说没有生成呢?可能是用户只检查了训练结束后的输出目录,而训练过程中保存的best.pt和last.pt在训练结束后被删除了?实际上,在YOLOv5的代码中,并没有删除这些文件的逻辑。所以,它们应该还在。但是,由于错误发生在训练结束后,用户可能看到错误信息后认为训练失败,然后去检查,发现没有生成,可能是因为训练过程中也没有保存?这不太可能,因为每个epoch都会保存。因此,我们需要考虑另一种情况:训练过程中保存的best.pt和last.pt在训练结束后被覆盖的操作中断,导致文件被破坏(比如写入过程中出错,文件不完整)。但是,根据错误信息,是在加载时出错,所以写入过程可能并没有发生。所以,最可能的原因是:训练过程中保存的best.pt和last.pt是存在的,但是它们本身在保存时就包含了不被允许的全局对象(因为保存时使用了可能包含numpy数组的结构?),所以在最后一步加载时出错。但是,为什么训练过程中保存的权重文件会包含numpy数组?通常,模型权重都是张量,优化器状态也是张量。所以,这可能是YOLOv5在保存检查点时保存了其他包含numpy数组的对象?比如,训练过程中保存的检查点包含了优化器状态,而优化器状态中可能包含了一些numpy数组?或者,在保存检查点时,一些数据被转换成了numpy数组?实际上,PyTorch的`torch.save`默认会使用pickle,如果保存的对象中包含numpy数组,那么就会使用numpy的_reconstruct函数。在PyTorch2.6之前,加载时不会检查,而现在默认`weights_only=True`会检查,所以不允许。因此,问题在于训练过程中保存的检查点(last.pt)包含了需要numpy._core.multiarray._reconstruct的对象,导致在训练结束后加载时失败。解决方案:根据错误提示,有两种方法:1.修改`torch.load`调用,设置`weights_only=False`。但要注意安全风险(仅当信任源时使用)。2.使用`torch.serialization.add_safe_globals`将`numpy._core.multiarray._reconstruct`添加到安全名单。但是,我们需要修改YOLOv5的代码。具体来说,是修改`utils/general.py`中的`strip_optimizer`函数。在`strip_optimizer`函数中,有一行:```pythonx =torch.load(f,map_location=torch.device('cpu'))```我们可以将其修改为:```pythontry:x= torch.load(f, map_location=torch.device('cpu'),weights_only=True)exceptpickle.UnpicklingError:#如果失败,尝试使用weights_only=False,但要注意安全x= torch.load(f, map_location=torch.device('cpu'), weights_only=False) ```或者,更安全的方式是允许这个特定的全局对象(需要PyTorch1.13+):```pythonimport torch.serializationtorch.serialization.add_safe_globals([numpy._core.multiarray._reconstruct])x =torch.load(f,map_location=torch.device('cpu'),weights_only=True)```但是,由于错误信息中已经给出了解决方案,我们可以采用第二种方法(允许特定的全局对象)来保证安全。具体修改步骤:1.打开`utils/general.py`文件,找到`strip_optimizer`函数(大约在1004行)。2.修改加载的代码,添加安全全局对象。但是,注意:我们需要先导入numpy,并且获取`numpy._core.multiarray._reconstruct`。但是,numpy可能没有安装?所以,需要先确保numpy已安装,然后修改代码:修改后的代码可能如下:```pythonimport numpyfrom torch.serialization importadd_safe_globalsadd_safe_globals([numpy._core.multiarray._reconstruct])x= torch.load(f, map_location=torch.device('cpu'), weights_only=True) ```但是,这样修改可能会遇到问题:因为numpy的模块路径可能不同?错误信息中是`numpy._core.multiarray._reconstruct`,所以我们使用这个。但是,如果用户没有安装numpy,那么需要先安装。不过,YOLOv5通常需要numpy。另一种方法是使用上下文管理器(如果PyTorch版本支持): ```pythonimportnumpyfrom torch.serialization importsafe_globalswithsafe_globals()as _:#在上下文中添加允许的全局对象safe_globals().add('numpy._core.multiarray._reconstruct', numpy._core.multiarray._reconstruct)x =torch.load(f,map_location=torch.device('cpu'),weights_only=True)```但是,根据PyTorch文档,更简单的方法是使用`add_safe_globals`函数(在PyTorch2.1+中引入)。然而,考虑到兼容性,最简单的临时解决方案是使用`weights_only=False`。因为用户是在训练自己的模型,所以可以信任。因此,我们可以将加载的那一行改为: ```pythonx= torch.load(f, map_location=torch.device('cpu'), weights_only=False) ```这样修改后,训练结束时的strip_optimizer步骤就不会出错了。修改步骤:1.打开文件:`utils/general.py`2.找到函数`strip_optimizer`3.找到代码行:`x= torch.load(f, map_location=torch.device('cpu'))`4.修改为:`x =torch.load(f,map_location=torch.device('cpu'),weights_only=False)`然后重新运行训练。另外,我们也可以考虑升级PyTorch到最新版本,并确保numpy也是最新版,看是否已经修复了这个问题。但根据错误信息,这是PyTorch2.6引入的安全特性,所以需要显式处理。总结:训练完成后未生成best.pt和last.pt文件的原因是在训练结束后的strip_optimizer步骤中加载权重文件失败(由于PyTorch2.6的安全机制),导致脚本异常退出。但训练过程中保存的best.pt和last.pt应该已经存在(除非训练过程中也没有保存,但这种情况不太可能)。因此,用户可能在输出目录中能够找到这些文件,但是训练脚本在最后一步报错退出。建议用户:1.检查输出目录(`runs/train/exp*/weights/`)中是否已经存在best.pt和last.pt(可能在训练过程中已经保存)。2.如果存在,那么可以直接使用,不需要重新训练。但是,这些文件包含优化器状态,文件较大。如果想去掉优化器状态,可以手动调用strip_optimizer(但同样会遇到上述错误)。3.如果不存在,那么可能是整个训练过程中都没有保存(比如训练一开始就出错了,但用户说100个epoch完成了,所以应该保存了)。因此,主要问题在于最后一步出错,但训练过程中保存的权重文件应该可用。不过,为了能够正常完成训练脚本(包括去除优化器状态),建议修改`utils/general.py`中的`strip_optimizer`函数,设置`weights_only=False`。另外,用户也可以尝试更新PyTorch和numpy到最新版本,看是否已经解决了兼容性问题。如果用户不想修改代码,也可以使用以下方法跳过最后一步:在train.py中找到调用`strip_optimizer`的地方(在train函数的最后),将其注释掉。这样训练结束后就不会尝试去除优化器状态,也就不会出错。但这样保存的last.pt和best.pt会包含优化器状态,文件较大。用户可以在之后手动去除优化器状态(但同样会遇到加载错误,所以还是需要修改strip_optimizer函数)。因此,推荐修改`utils/general.py`中的`strip_optimizer`函数。最后,注意:这个错误只发生在加载包含优化器状态的检查点时。训练结束后保存的最终权重文件(去除优化器状态后)不会包含优化器状态,所以不会触发这个问题。但是,在去除优化器状态的过程中,需要先加载包含优化器状态的文件,所以才会出错。所以,修改`strip_optimizer`函数是必要的。步骤总结:1.打开`yolov5/utils/general.py`2.搜索`def strip_optimizer(`,找到函数定义3.在函数内部找到`x= torch.load(f, map_location=torch.device('cpu'))`这一行(可能在1004行左右)4.将其修改为`x= torch.load(f, map_location=torch.device('cpu'), weights_only=False)`5.保存文件,重新运行训练这样,训练结束后就能正常生成去除优化器状态的best.pt和last.pt了。注意:如果用户使用的是PyTorch2.6之前的版本,`weights_only`参数可能不存在,但我们可以忽略,因为旧版本默认行为就是`weights_only=False`。所以,为了兼容旧版本,我们可以这样写:```pythontry:#尝试使用weights_only=False(对于旧版本,没有这个参数,所以用try)x= torch.load(f, map_location=torch.device('cpu'), weights_only=False)except TypeError:#如果出现TypeError(因为旧版本的torch.load没有weights_only参数),则不加这个参数x= torch.load(f, map_location=torch.device('cpu')) ```这样修改可以同时兼容新旧版本。因此,最终修改为: ```pythontry:x =torch.load(f,map_location=torch.device('cpu'),weights_only=False)exceptTypeError:x= torch.load(f, map_location=torch.device('cpu')) ```这样更安全。重新训练后,问题应该解决。另外,用户也可以尝试更新YOLOv5到最新版本(如果官方已经修复了这个问题)。相关问题:1.如何修改YOLOv5的代码以兼容PyTorch2.6的安全加载机制?2.为什么PyTorch2.6默认使用`weights_only=True`?3.训练过程中保存的权重文件包含哪些内容?4.如何手动去除YOLOv5权重文件中的优化器状态?</think>### YOLOv5训练后未生成best.pt和last.pt的原因分析 根据您的错误日志,训练过程在100个epoch完成后,在模型保存阶段失败(退出代码1),导致未生成最终的权重文件。根本原因是PyTorch 2.6的安全机制与权重文件兼容性问题。以下是具体原因和解决方案: #### 核心问题:PyTorch 2.6的安全限制 错误发生在`strip_optimizer()`函数中(`utils/general.py`第1004行): ```python x = torch.load(f, map_location=torch.device('cpu')) # 触发错误的代码行 ``` PyTorch 2.6默认启用`weights_only=True`安全模式,但您的权重文件包含`numpy._core.multiarray._reconstruct`对象,被判定为不安全元素[^1]。 #### 根本原因分析 1. **安全机制冲突** PyTorch 2.6+ 的`weights_only=True`会阻止包含NumPy对象的权重加载 $$\text{torch.load()} \xrightarrow{\text{安全检查}} \text{拒绝 numpy._core.multiarray._reconstruct}$$ 2. **训练过程中断** 错误发生在训练结束后的优化器剥离阶段: ```mermaid graph LR A[训练完成] --> B[加载last.pt] B --> C[剥离优化器] C --> D[保存精简权重] // 此处失败 ``` 导致最终权重文件未生成 3. **文件状态异常** 训练过程中生成的临时权重文件可能: - 被部分覆盖但未完整保存 - 保留优化器状态导致加载失败 - 文件大小异常(通常best.pt应≈last.pt) #### 解决方案 ##### 方法1:修改权重加载方式(推荐) 在`utils/general.py`中修改`strip_optimizer()`函数: ```python # 原始问题代码(约第1004行): # x = torch.load(f, map_location=torch.device('cpu')) # 修改为: x = torch.load(f, map_location=torch.device('cpu'), weights_only=False) ``` **注意**:仅当您信任训练数据来源时使用此方法[^1] ##### 方法2:使用安全上下文管理器 在`strip_optimizer()`中添加安全例外: ```python import numpy from torch.serialization import safe_globals with safe_globals(): safe_globals().add('numpy._core.multiarray._reconstruct', numpy._core.multiarray._reconstruct) x = torch.load(f, map_location=torch.device('cpu')) ``` ##### 方法3:手动恢复权重 如果训练已完成但文件未生成: 1. 检查`runs/train/exp/weights/`目录 2. 查找最近生成的`.pt`文件(如`epoch99.pt`) 3. 重命名为`last.pt`并手动剥离优化器: ```python from models.yolo import Model model = Model('yolov5s.yaml') # 使用对应配置文件 ckpt = torch.load('epoch99.pt', map_location='cpu') model.load_state_dict(ckpt['model'].state_dict()) torch.save(model.state_dict(), 'last.pt') # 保存纯权重 ``` #### 预防措施 1. **版本兼容** ```bash pip install torch==2.0.1 numpy==1.23.5 # 使用兼容版本 ``` 2. **安全保存模式** ```python # 训练中保存纯权重(不含优化器) torch.save(model.state_dict(), 'last.pt') ``` 3. **验证文件完整性** ```python # 训练结束后检查 assert os.path.exists('last.pt'), "权重文件未生成" assert os.path.getsize('last.pt') > 50e6, "文件大小异常" # 典型大小>50MB ``` ### 关键结论 训练未生成权重文件是由于PyTorch 2.6的安全机制中断了保存流程。通过修改`utils/general.py`中的权重加载代码或使用兼容的库版本可解决此问题[^1]。训练过程中生成的中间权重文件(如`epoch99.pt`)仍可使用,只需手动重命名和处理优化器状态。
阅读全文

相关推荐

大家在看

recommend-type

蒙特卡罗剂量模拟和可视化工具包:一组旨在帮助临床医生和研究人员使用 GEANT4 或 TOPAS 的 Matlab 函数-matlab开发

这里有 3 组代码,旨在帮助临床医生和研究人员将 GEANT4 或 TOPAS (MC) 与 3D Slicer 结合使用进行剂量可视化和比较 第一段代码“STLfromDicomRN.m”采用 Varian Eclipse 生成的双散射质子计划的 Dicom 计划文件,并以“.STL”格式生成计划中的Kong径和补偿器模型。 此文件使用 zip 文件中包含的“stlwrite”和“surf2solid”函数。 这些文件可以导入到 MC 模拟几何中。 第二个是一组用于处理Dicom剂量文件和分析剂量的代码。 “NormalizeDicomDose.m”代码将 MC 剂量标准化为 Eclipse 剂量等中心处的剂量,并包含有关如何标准化为其他点或体积的说明。 “ProfilePlot.m”代码只是生成比较两点之间两个剂量文件的剂量的剂量曲线。 包含的是一个 matlab gui,它在您
recommend-type

中科大版苏淳概率论答案

本资料是中科大版本 苏淳编著的概率论答案,此为本书前半部分答案,其中包含书中部分习题,系老师所布置的重点习题答案。包含初等概率论,随机变量,随机向量,数字特征与特征函数极限定理几章的内容
recommend-type

公开公开公开公开-openprotocol_specification 2.7

LY-WCS-2012-01-06-01 V 1.0 公开公开公开公开 产品名称:产品名称:产品名称:产品名称: WCS 系统简介系统简介系统简介系统简介-公开版公开版公开版公开版 共共共共 13 页页页页 WCSWCSWCSWCS 系统简介系统简介系统简介系统简介 ((((客户交流用客户交流用客户交流用客户交流用)))) 文文文文 档档档档 作作作作 者:者:者:者: 王 超 日期:日期:日期:日期:2012/01/06 开发开发开发开发/测试经理:测试经理:测试经理:测试经理: 程 达 日期:日期:日期:日期:2012/01/06 项项项项 目目目目 经经经经 理:理:理:理: 程 达 日期:日期:日期:日期:2012/01/06 文文文文 档档档档 编编编编 号:号:号:号: ___________ ___ LY-WCS-2012-01-06-01______________ 上海朗因智能科技有限公司上海朗因智能科技有限公司上海朗因智能科技有限公司上海朗因智能科技有限公司 版权所有版权所有版权所有版权所有 不得复制不得复制不得复制不得复制
recommend-type

xilinx.com_user_IIC_AXI_1.0.zip

可以直接用在vivado 2017.4版本里。查看各个寄存器就知道用来干什么了,一号寄存器分频系数,二号的start、stop信号,三号寄存器8bit数据,四号寄存器只读,返回IIC状态和ACK信号,其中二号的一个bit可以用来不等待从机ACK,方便使用。
recommend-type

extjs6.2加SenchaCmd-6.5.3.6-windows-64bit

SenchaCmd-6.5.3.6-windows-64bit ext6.2.0gpl SenchaCmd-6.5.3.6-windows-64bit ext6.2.0gpl

最新推荐

recommend-type

精选Java案例开发技巧集锦

从提供的文件信息中,我们可以看出,这是一份关于Java案例开发的集合。虽然没有具体的文件名称列表内容,但根据标题和描述,我们可以推断出这是一份包含了多个Java编程案例的开发集锦。下面我将详细说明与Java案例开发相关的一些知识点。 首先,Java案例开发涉及的知识点相当广泛,它不仅包括了Java语言的基础知识,还包括了面向对象编程思想、数据结构、算法、软件工程原理、设计模式以及特定的开发工具和环境等。 ### Java基础知识 - **Java语言特性**:Java是一种面向对象、解释执行、健壮性、安全性、平台无关性的高级编程语言。 - **数据类型**:Java中的数据类型包括基本数据类型(int、short、long、byte、float、double、boolean、char)和引用数据类型(类、接口、数组)。 - **控制结构**:包括if、else、switch、for、while、do-while等条件和循环控制结构。 - **数组和字符串**:Java数组的定义、初始化和多维数组的使用;字符串的创建、处理和String类的常用方法。 - **异常处理**:try、catch、finally以及throw和throws的使用,用以处理程序中的异常情况。 - **类和对象**:类的定义、对象的创建和使用,以及对象之间的交互。 - **继承和多态**:通过extends关键字实现类的继承,以及通过抽象类和接口实现多态。 ### 面向对象编程 - **封装、继承、多态**:是面向对象编程(OOP)的三大特征,也是Java编程中实现代码复用和模块化的主要手段。 - **抽象类和接口**:抽象类和接口的定义和使用,以及它们在实现多态中的不同应用场景。 ### Java高级特性 - **集合框架**:List、Set、Map等集合类的使用,以及迭代器和比较器的使用。 - **泛型编程**:泛型类、接口和方法的定义和使用,以及类型擦除和通配符的应用。 - **多线程和并发**:创建和管理线程的方法,synchronized和volatile关键字的使用,以及并发包中的类如Executor和ConcurrentMap的应用。 - **I/O流**:文件I/O、字节流、字符流、缓冲流、对象序列化的使用和原理。 - **网络编程**:基于Socket编程,使用java.net包下的类进行网络通信。 - **Java内存模型**:理解堆、栈、方法区等内存区域的作用以及垃圾回收机制。 ### Java开发工具和环境 - **集成开发环境(IDE)**:如Eclipse、IntelliJ IDEA等,它们提供了代码编辑、编译、调试等功能。 - **构建工具**:如Maven和Gradle,它们用于项目构建、依赖管理以及自动化构建过程。 - **版本控制工具**:如Git和SVN,用于代码的版本控制和团队协作。 ### 设计模式和软件工程原理 - **设计模式**:如单例、工厂、策略、观察者、装饰者等设计模式,在Java开发中如何应用这些模式来提高代码的可维护性和可扩展性。 - **软件工程原理**:包括软件开发流程、项目管理、代码审查、单元测试等。 ### 实际案例开发 - **项目结构和构建**:了解如何组织Java项目文件,合理使用包和模块化结构。 - **需求分析和设计**:明确项目需求,进行系统设计,如数据库设计、系统架构设计等。 - **代码编写和实现**:根据设计编写符合要求的代码,实现系统的各个模块功能。 - **测试和维护**:进行单元测试、集成测试,确保代码质量,对项目进行维护和升级。 ### 其他相关知识点 - **Java虚拟机(JVM)**:了解JVM的基本工作原理,包括类加载机制、内存管理、垃圾回收算法等。 - **常用Java框架**:比如Spring、Hibernate、MyBatis等,在实际开发中常常与Java基础结合使用,提高开发效率。 以上知识点可以作为学习Java案例开发的基础框架。在实际的开发实践中,开发者需要结合具体的项目需求,对这些知识点进行灵活运用。通过反复的案例实践,可以加深对Java编程的理解,并逐步提升开发技能。这份集锦可能包含的案例可能涉及上述知识点的具体应用,能够帮助学习者更好地理解理论与实践的结合,从而快速提升个人的Java开发能力。
recommend-type

【VASP报错深度解析】:5大技巧识别并永久解决离子距离太近警告

# 1. VASP软件简介及离子距离太近问题概述 ## 1.1 VASP软件简介 **VASP(Vienna Ab initio Simulation Package)** 是一款广泛应用于计算材料科学的软件,它基于密度泛函理论(DFT)计算固体、表面和分子的电子结构和性质。
recommend-type

npm error A complete log of this run can be found in: D:\Program Files\nodejs\node_cache\_logs\2025-04-20T15_11_51_454Z-debug-0.log

<think>好的,我需要帮助用户找到npm的错误调试日志位置,并解决他们遇到的npm错误。首先,用户已经提供了一个具体的日志路径:'D:\Program Files\nodejs\node_cache\_logs\2025-04-20T15_11_51_454Z-debug-0.log',但看起来这个路径可能有问题,因为日期是2025年,这可能是一个示例或输入错误。我需要确认正确的日志路径生成方式。 根据npm的默认配置,日志文件通常位于npm的缓存目录下的_logs文件夹中。默认情况下,Windows系统中npm的缓存路径是%AppData%\npm-cache,而日志文件会以当前日期和
recommend-type

深入理解内存技术文档详解

由于文件内容无法查看,仅能根据文件的标题、描述、标签以及文件名称列表来构建相关知识点。以下是对“内存详解”这一主题的详细知识点梳理。 内存,作为计算机硬件的重要组成部分,负责临时存放CPU处理的数据和指令。理解内存的工作原理、类型、性能参数等对优化计算机系统性能至关重要。本知识点将从以下几个方面来详细介绍内存: 1. 内存基础概念 内存(Random Access Memory,RAM)是易失性存储器,这意味着一旦断电,存储在其中的数据将会丢失。内存允许计算机临时存储正在执行的程序和数据,以便CPU可以快速访问这些信息。 2. 内存类型 - 动态随机存取存储器(DRAM):目前最常见的RAM类型,用于大多数个人电脑和服务器。 - 静态随机存取存储器(SRAM):速度较快,通常用作CPU缓存。 - 同步动态随机存取存储器(SDRAM):在时钟信号的同步下工作的DRAM。 - 双倍数据速率同步动态随机存取存储器(DDR SDRAM):在时钟周期的上升沿和下降沿传输数据,大幅提升了内存的传输速率。 3. 内存组成结构 - 存储单元:由存储位构成的最小数据存储单位。 - 地址总线:用于选择内存中的存储单元。 - 数据总线:用于传输数据。 - 控制总线:用于传输控制信号。 4. 内存性能参数 - 存储容量:通常用MB(兆字节)或GB(吉字节)表示,指的是内存能够存储多少数据。 - 内存时序:指的是内存从接受到请求到开始读取数据之间的时间间隔。 - 内存频率:通常以MHz或GHz为单位,是内存传输数据的速度。 - 内存带宽:数据传输速率,通常以字节/秒为单位,直接关联到内存频率和数据位宽。 5. 内存工作原理 内存基于电容器和晶体管的工作原理,电容器存储电荷来表示1或0的状态,晶体管则用于读取或写入数据。为了保持数据不丢失,动态内存需要定期刷新。 6. 内存插槽与安装 - 计算机主板上有专用的内存插槽,常见的有DDR2、DDR3、DDR4和DDR5等不同类型。 - 安装内存时需确保兼容性,并按照正确的方向插入内存条,避免物理损坏。 7. 内存测试与优化 - 测试:可以使用如MemTest86等工具测试内存的稳定性和故障。 - 优化:通过超频来提高内存频率,但必须确保稳定性,否则会导致数据损坏或系统崩溃。 8. 内存兼容性问题 不同内存条可能由于制造商、工作频率、时序、电压等参数的不匹配而产生兼容性问题。在升级或更换内存时,必须检查其与主板和现有系统的兼容性。 9. 内存条的常见品牌与型号 诸如金士顿(Kingston)、海盗船(Corsair)、三星(Samsung)和芝奇(G.Skill)等知名品牌提供多种型号的内存条,针对不同需求的用户。 由于“内存详解.doc”是文件标题指定的文件内容,我们可以预期在该文档中将详细涵盖以上知识点,并有可能包含更多的实践案例、故障排查方法以及内存技术的最新发展等高级内容。在实际工作中,理解并应用这些内存相关的知识点对于提高计算机性能、解决计算机故障有着不可估量的价值。
recommend-type

【机械特性分析进阶秘籍】:频域与时域对比的全面研究

# 1. 机械特性分析的频域与时域概述 ## 1.1 频域与时域分析的基本概念 机械特性分析是通
recommend-type

dslicsrv安装报错Too many errors

<think>好的,用户遇到了安装dslicsrv时出现“Too many errors”的问题,需要帮助解决。首先,我需要明确dslicsrv是什么。可能是指某个特定的软件服务,但根据常见软件库和搜索引擎的信息,没有直接对应的结果。可能是拼写错误,或者是某个特定领域的专有软件?比如,可能与Dell的某个服务有关?例如,Dell System License Manager Service(dsLicSvc)可能更接近。假设用户可能拼写错误,将dslicsrv理解为dsLicSvc,即Dell的系统许可证管理服务。 接下来,用户遇到的错误是安装时出现“Too many errors”,这通常
recommend-type

深入解析Pro Ajax与Java技术的综合应用框架

根据提供的文件信息,我们可以推断出一系列与标题《Pro Ajax and Java》相关的IT知识点。这本书是由Apress出版,关注的是Ajax和Java技术。下面我将详细介绍这些知识点。 ### Ajax技术 Ajax(Asynchronous JavaScript and XML)是一种无需重新加载整个页面即可更新网页的技术。它通过在后台与服务器进行少量数据交换,实现了异步更新网页内容的目的。 1. **异步通信**:Ajax的核心是通过XMLHttpRequest对象或者现代的Fetch API等技术实现浏览器与服务器的异步通信。 2. **DOM操作**:利用JavaScript操作文档对象模型(DOM),能够实现页面内容的动态更新,而无需重新加载整个页面。 3. **数据交换格式**:Ajax通信中常使用的数据格式包括XML和JSON,但近年来JSON因其轻量级和易用性更受青睐。 4. **跨浏览器兼容性**:由于历史原因,实现Ajax的JavaScript代码需要考虑不同浏览器的兼容性问题。 5. **框架和库**:有许多流行的JavaScript库和框架支持Ajax开发,如jQuery、Dojo、ExtJS等,这些工具简化了Ajax的实现和数据操作。 ### Java技术 Java是一种广泛使用的面向对象编程语言,其在企业级应用、移动应用开发(Android)、Web应用开发等方面有着广泛应用。 1. **Java虚拟机(JVM)**:Java程序运行在Java虚拟机上,这使得Java具有良好的跨平台性。 2. **Java标准版(Java SE)**:包含了Java的核心类库和API,是Java应用开发的基础。 3. **Java企业版(Java EE)**:为企业级应用提供了额外的API和服务,如Java Servlet、JavaServer Pages(JSP)、Enterprise JavaBeans(EJB)等。 4. **面向对象编程(OOP)**:Java是一种纯粹的面向对象语言,它的语法和机制支持封装、继承和多态性。 5. **社区和生态系统**:Java拥有庞大的开发者社区和丰富的第三方库和框架,如Spring、Hibernate等,这些资源极大丰富了Java的应用范围。 ### 结合Ajax和Java 在结合使用Ajax和Java进行开发时,我们通常会采用MVC(模型-视图-控制器)架构模式,来构建可维护和可扩展的应用程序。 1. **服务器端技术**:Java经常被用来构建服务器端应用逻辑。例如,使用Servlet来处理客户端的请求,再将数据以Ajax请求的响应形式返回给客户端。 2. **客户端技术**:客户端的JavaScript(或使用框架库如jQuery)用于发起Ajax请求,并更新页面内容。 3. **数据格式**:Java后端通常会使用JSON或XML格式与Ajax进行数据交换。 4. **安全性**:Ajax请求可能涉及敏感数据,因此需要考虑如跨站请求伪造(CSRF)等安全问题。 5. **性能优化**:合理使用Ajax可以提升用户体验,但同时也需要注意对服务器和网络的负载,以及客户端脚本的执行性能。 ### 出版信息及文件信息 《Pro Ajax and Java》由Apress出版社出版,通常这种出版物会包含丰富的实例代码、开发指导、最佳实践以及相关的技术讨论。它旨在帮助开发者深化对Ajax和Java技术的理解和应用能力。 文件名“Apress.Pro.Ajax.and.Java.Frameworks.Jul.2006.HAPPY.NEW.YEAR.pdf”暗示了这份文档可能是一本专业的技术书籍。从文件名可以看出,该书还可能包含了框架使用方面的内容,并且是2006年出版的。标题中的“HAPPY.NEW.YEAR”可能仅仅是为了庆祝新年而加入的非标准部分。 总结而言,了解Ajax和Java的结合使用,不仅需要掌握两种技术的基本原理和使用方法,还要熟悉如何将它们整合到实际项目中,解决可能出现的技术挑战,从而构建功能强大且用户友好的Web应用。
recommend-type

【频域分析深度解读】:揭秘机械系统分析中的实用应用

# 1. 频域分析基础理论 频域分析是信号处理领域的一个重要分支,其核心在于研究信号在频率维度上的特性。与时域分析不同,频域分析关注的是信号频率成分的组成,这允许我们以一种直观的方式识别和处理信号中的特定频率特征。通过对信号进行傅里叶变换,原始的时域信号可以被转换为频域信号,这样就可以清晰地显示出各频率成分的幅度和相位信息。这种分析手段对于信号去噪、特征提取、压缩编码等应用场景至关重
recommend-type

openmv与stm32通信的时候,openmv的vin接5v会出问题吗

<think>我们正在处理用户关于OpenMV与STM32通信时,将OpenMV的VIN引脚连接到5V是否会引发问题。 根据引用[3]中的信息,AMG8833传感器在STM32上使用时,由单片机的3.3V和GND引脚供电。同时,引用[3]提到OpenMV相机作为配套计算机的情况,但用户的问题具体是OpenMV的VIN引脚接5V的问题。 我们需要明确OpenMV的电源要求: - OpenMV Cam的VIN引脚是电源输入引脚,其可接受电压范围通常在3.6V至5V。因此,5V是在可接受范围内的。 但是,我们还需要注意: 1. OpenMV Cam内部有稳压电路,会将输入电压降到3.3V
recommend-type

电脑上的KTV体验:FreeKaraoke麦克风软件

标题中提到的“FreeKaraoke麦克风软件”,指的是这款软件允许用户在个人电脑上使用麦克风进行卡拉OK演唱。安装此软件后,用户无需前往KTV实体店,在家中或任何有电脑的环境下,即可以享受到卡拉OK的乐趣。这可以理解为是一种数字娱乐软件,它将传统KTV的唱歌体验转移到了个人电脑上。 描述部分简单介绍了该软件的功能,即通过安装它,用户能够获得在个人电脑上进行卡拉OK演唱的能力。这说明了FreeKaraoke软件的使用场景和主要用途,同时也向潜在用户传达了其便利性和易用性。对于喜欢唱歌或想要随时随地享受K歌体验的用户来说,这款软件提供了一个成本相对较低且方便快捷的解决方案。 虽然标题和描述没有直接提到技术细节,但我们可以推断,该软件可能包括以下技术特点和功能: 1. 音频处理能力,用于对麦克风输入的声音进行实时处理,并与背景音乐进行混合。 2. 用户界面设计,让用户能够选择歌曲、调整音量、切换音轨等操作。 3. 兼容性,软件应该兼容主流的操作系统和音频输入设备。 4. 歌曲库,软件可能内置或可以联网下载各种卡拉OK曲目。 标签“J2EE”指的是Java 2 Enterprise Edition,这是用于开发企业级应用程序的一个Java平台。它提供了完整的中间件服务、组件模型、以及用于开发和运行大型、多层、分布式网络应用的安全性规范。J2EE是为大型企业级应用而设计,它支持多种服务,包括但不限于事务管理、安全性、web服务和消息服务等。尽管标题和描述与J2EE没有直接关联,但这可能表明FreeKaraoke麦克风软件在开发过程中使用了J2EE相关技术,尤其是如果软件提供了在线分享、社群互动等企业级功能时。然而,仅凭标题与描述中的信息,我们无法确切了解J2EE技术在该软件中的具体应用。 文件名称“FreeKaraoke_0906_5.5.0301_minor0.exe”为软件的安装包。从文件名可以得知,该安装包可能属于FreeKaraoke软件的5.5.0301版本。版本号中的“minor0”通常表示这是一个小版本更新,可能包含了bug修复或性能优化等改进,而没有引入新的重大功能。文件名中的日期“0906”可能代表了该版本发布的时间,即9月6日,但具体年份未在文件名中给出。 从文件名称列表中,我们无法得知更多关于软件的具体技术细节,但可以推测该软件可能通过定期更新来改进性能并修复可能出现的问题。此外,文件名的格式暗示该软件可能有持续的维护和版本迭代,这对于用户来说是一个积极信号,表明软件将持续获得更新和优化。