123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- #-------------------------------------#
- # 对数据集进行训练
- #-------------------------------------#
- import os
- import datetime
- import numpy as np
- import torch
- import torch.backends.cudnn as cudnn
- import torch.optim as optim
- from torch.utils.data import DataLoader
- from nets.frcnn import FasterRCNN
- from nets.frcnn_training import (FasterRCNNTrainer, get_lr_scheduler,
- set_optimizer_lr, weights_init)
- from utils.callbacks import EvalCallback, LossHistory
- from utils.dataloader import FRCNNDataset, frcnn_dataset_collate
- from utils.utils import get_classes, show_config
- from utils.utils_fit import fit_one_epoch
- '''
- 训练自己的目标检测模型一定需要注意以下几点:
- 1、训练前仔细检查自己的格式是否满足要求,该库要求数据集格式为VOC格式,需要准备好的内容有输入图片和标签
- 输入图片为.jpg图片,无需固定大小,传入训练前会自动进行resize。
- 灰度图会自动转成RGB图片进行训练,无需自己修改。
- 输入图片如果后缀非jpg,需要自己批量转成jpg后再开始训练。
- 标签为.xml格式,文件中会有需要检测的目标信息,标签文件和输入图片文件相对应。
- 2、损失值的大小用于判断是否收敛,比较重要的是有收敛的趋势,即验证集损失不断下降,如果验证集损失基本上不改变的话,模型基本上就收敛了。
- 损失值的具体大小并没有什么意义,大和小只在于损失的计算方式,并不是接近于0才好。如果想要让损失好看点,可以直接到对应的损失函数里面除上10000。
- 训练过程中的损失值会保存在logs文件夹下的loss_%Y_%m_%d_%H_%M_%S文件夹中
-
- 3、训练好的权值文件保存在logs文件夹中,每个训练世代(Epoch)包含若干训练步长(Step),每个训练步长(Step)进行一次梯度下降。
- 如果只是训练了几个Step是不会保存的,Epoch和Step的概念要捋清楚一下。
- '''
- if __name__ == "__main__":
- #-------------------------------#
- # 是否使用Cuda
- # 没有GPU可以设置成False
- #-------------------------------#
- Cuda = True
- #---------------------------------------------------------------------#
- # train_gpu 训练用到的GPU
- # 默认为第一张卡、双卡为[0, 1]、三卡为[0, 1, 2]
- # 在使用多GPU时,每个卡上的batch为总batch除以卡的数量。
- #---------------------------------------------------------------------#
- train_gpu = [0]
- #---------------------------------------------------------------------#
- # fp16 是否使用混合精度训练
- # 可减少约一半的显存、需要pytorch1.7.1以上
- #---------------------------------------------------------------------#
- fp16 = False
- #---------------------------------------------------------------------#
- # classes_path 指向model_data下的txt,与自己训练的数据集相关
- # 训练前一定要修改classes_path,使其对应自己的数据集
- #---------------------------------------------------------------------#
- classes_path = './/model_data/voc_classes.txt'
- #----------------------------------------------------------------------------------------------------------------------------#
- # 权值文件的下载请看README,可以通过网盘下载。模型的 预训练权重 对不同数据集是通用的,因为特征是通用的。
- # 模型的 预训练权重 比较重要的部分是 主干特征提取网络的权值部分,用于进行特征提取。
- # 预训练权重对于99%的情况都必须要用,不用的话主干部分的权值太过随机,特征提取效果不明显,网络训练的结果也不会好
- #
- # 如果训练过程中存在中断训练的操作,可以将model_path设置成logs文件夹下的权值文件,将已经训练了一部分的权值再次载入。
- # 同时修改下方的 冻结阶段 或者 解冻阶段 的参数,来保证模型epoch的连续性。
- #
- # 当model_path = ''的时候不加载整个模型的权值。
- #
- # 此处使用的是整个模型的权重,因此是在train.py进行加载的,下面的pretrain不影响此处的权值加载。
- # 如果想要让模型从主干的预训练权值开始训练,则设置model_path = '',下面的pretrain = True,此时仅加载主干。
- # 如果想要让模型从0开始训练,则设置model_path = '',下面的pretrain = Fasle,Freeze_Train = Fasle,此时从0开始训练,且没有冻结主干的过程。
- #
- # 一般来讲,网络从0开始的训练效果会很差,因为权值太过随机,特征提取效果不明显,因此非常、非常、非常不建议大家从0开始训练!
- # 如果一定要从0开始,可以了解imagenet数据集,首先训练分类模型,获得网络的主干部分权值,分类模型的 主干部分 和该模型通用,基于此进行训练。
- #----------------------------------------------------------------------------------------------------------------------------#
- model_path = './/model_data/voc_weights_resnet.pth'
- #------------------------------------------------------#
- # input_shape 输入的shape大小
- #------------------------------------------------------#
- input_shape = [600, 600]
- #---------------------------------------------#
- # vgg
- # resnet50
- #---------------------------------------------#
- backbone = "resnet50"
- #----------------------------------------------------------------------------------------------------------------------------#
- # pretrained 是否使用主干网络的预训练权重,此处使用的是主干的权重,因此是在模型构建的时候进行加载的。
- # 如果设置了model_path,则主干的权值无需加载,pretrained的值无意义。
- # 如果不设置model_path,pretrained = True,此时仅加载主干开始训练。
- # 如果不设置model_path,pretrained = False,Freeze_Train = Fasle,此时从0开始训练,且没有冻结主干的过程。
- #----------------------------------------------------------------------------------------------------------------------------#
- pretrained = False
- #------------------------------------------------------------------------#
- # anchors_size用于设定先验框的大小,每个特征点均存在9个先验框。
- # anchors_size每个数对应3个先验框。
- # 当anchors_size = [8, 16, 32]的时候,生成的先验框宽高约为:
- # [90, 180] ; [180, 360]; [360, 720]; [128, 128];
- # [256, 256]; [512, 512]; [180, 90] ; [360, 180];
- # [720, 360]; 详情查看anchors.py
- # 如果想要检测小物体,可以减小anchors_size靠前的数。
- # 比如设置anchors_size = [4, 16, 32]
- #------------------------------------------------------------------------#
- anchors_size = [8, 16, 32]
- #----------------------------------------------------------------------------------------------------------------------------#
- # 训练分为两个阶段,分别是冻结阶段和解冻阶段。设置冻结阶段是为了满足机器性能不足的同学的训练需求。
- # 冻结训练需要的显存较小,显卡非常差的情况下,可设置Freeze_Epoch等于UnFreeze_Epoch,此时仅仅进行冻结训练。
- #
- # 在此提供若干参数设置建议,各位训练者根据自己的需求进行灵活调整:
- # (一)从整个模型的预训练权重开始训练:
- # Adam:
- # Init_Epoch = 0,Freeze_Epoch = 50,UnFreeze_Epoch = 100,Freeze_Train = True,optimizer_type = 'adam',Init_lr = 1e-4。(冻结)
- # Init_Epoch = 0,UnFreeze_Epoch = 100,Freeze_Train = False,optimizer_type = 'adam',Init_lr = 1e-4。(不冻结)
- # SGD:
- # Init_Epoch = 0,Freeze_Epoch = 50,UnFreeze_Epoch = 150,Freeze_Train = True,optimizer_type = 'sgd',Init_lr = 1e-2。(冻结)
- # Init_Epoch = 0,UnFreeze_Epoch = 150,Freeze_Train = False,optimizer_type = 'sgd',Init_lr = 1e-2。(不冻结)
- # 其中:UnFreeze_Epoch可以在100-300之间调整。
- # (二)从主干网络的预训练权重开始训练:
- # Adam:
- # Init_Epoch = 0,Freeze_Epoch = 50,UnFreeze_Epoch = 100,Freeze_Train = True,optimizer_type = 'adam',Init_lr = 1e-4。(冻结)
- # Init_Epoch = 0,UnFreeze_Epoch = 100,Freeze_Train = False,optimizer_type = 'adam',Init_lr = 1e-4。(不冻结)
- # SGD:
- # Init_Epoch = 0,Freeze_Epoch = 50,UnFreeze_Epoch = 150,Freeze_Train = True,optimizer_type = 'sgd',Init_lr = 1e-2。(冻结)
- # Init_Epoch = 0,UnFreeze_Epoch = 150,Freeze_Train = False,optimizer_type = 'sgd',Init_lr = 1e-2。(不冻结)
- # 其中:由于从主干网络的预训练权重开始训练,主干的权值不一定适合目标检测,需要更多的训练跳出局部最优解。
- # UnFreeze_Epoch可以在150-300之间调整,YOLOV5和YOLOX均推荐使用300。
- # Adam相较于SGD收敛的快一些。因此UnFreeze_Epoch理论上可以小一点,但依然推荐更多的Epoch。
- # (三)batch_size的设置:
- # 在显卡能够接受的范围内,以大为好。显存不足与数据集大小无关,提示显存不足(OOM或者CUDA out of memory)请调小batch_size。
- # faster rcnn的Batch BatchNormalization层已经冻结,batch_size可以为1
- #----------------------------------------------------------------------------------------------------------------------------#
- #------------------------------------------------------------------#
- # 冻结阶段训练参数
- # 此时模型的主干被冻结了,特征提取网络不发生改变
- # 占用的显存较小,仅对网络进行微调
- # Init_Epoch 模型当前开始的训练世代,其值可以大于Freeze_Epoch,如设置:
- # Init_Epoch = 60、Freeze_Epoch = 50、UnFreeze_Epoch = 100
- # 会跳过冻结阶段,直接从60代开始,并调整对应的学习率。
- # (断点续练时使用)
- # Freeze_Epoch 模型冻结训练的Freeze_Epoch
- # (当Freeze_Train=False时失效)
- # Freeze_batch_size 模型冻结训练的batch_size
- # (当Freeze_Train=False时失效)
- #------------------------------------------------------------------#
- Init_Epoch = 0
- Freeze_Epoch = 50
- Freeze_batch_size = 4
- #------------------------------------------------------------------#
- # 解冻阶段训练参数
- # 此时模型的主干不被冻结了,特征提取网络会发生改变
- # 占用的显存较大,网络所有的参数都会发生改变
- # UnFreeze_Epoch 模型总共训练的epoch
- # SGD需要更长的时间收敛,因此设置较大的UnFreeze_Epoch
- # Adam可以使用相对较小的UnFreeze_Epoch
- # Unfreeze_batch_size 模型在解冻后的batch_size
- #------------------------------------------------------------------#
- UnFreeze_Epoch = 100
- Unfreeze_batch_size = 2
- #------------------------------------------------------------------#
- # Freeze_Train 是否进行冻结训练
- # 默认先冻结主干训练后解冻训练。
- # 如果设置Freeze_Train=False,建议使用优化器为sgd
- #------------------------------------------------------------------#
- Freeze_Train = True
-
- #------------------------------------------------------------------#
- # 其它训练参数:学习率、优化器、学习率下降有关
- #------------------------------------------------------------------#
- #------------------------------------------------------------------#
- # Init_lr 模型的最大学习率
- # 当使用Adam优化器时建议设置 Init_lr=1e-4
- # 当使用SGD优化器时建议设置 Init_lr=1e-2
- # Min_lr 模型的最小学习率,默认为最大学习率的0.01
- #------------------------------------------------------------------#
- Init_lr = 1e-4
- Min_lr = Init_lr * 0.01
- #------------------------------------------------------------------#
- # optimizer_type 使用到的优化器种类,可选的有adam、sgd
- # 当使用Adam优化器时建议设置 Init_lr=1e-4
- # 当使用SGD优化器时建议设置 Init_lr=1e-2
- # momentum 优化器内部使用到的momentum参数
- # weight_decay 权值衰减,可防止过拟合
- # adam会导致weight_decay错误,使用adam时建议设置为0。
- #------------------------------------------------------------------#
- optimizer_type = "adam"
- momentum = 0.9
- weight_decay = 0
- #------------------------------------------------------------------#
- # lr_decay_type 使用到的学习率下降方式,可选的有'step'、'cos'
- #------------------------------------------------------------------#
- lr_decay_type = 'cos'
- #------------------------------------------------------------------#
- # save_period 多少个epoch保存一次权值
- #------------------------------------------------------------------#
- save_period = 5
- #------------------------------------------------------------------#
- # save_dir 权值与日志文件保存的文件夹
- #------------------------------------------------------------------#
- save_dir = 'logs_wm'
- #------------------------------------------------------------------#
- # eval_flag 是否在训练时进行评估,评估对象为验证集
- # 安装pycocotools库后,评估体验更佳。
- # eval_period 代表多少个epoch评估一次,不建议频繁的评估
- # 评估需要消耗较多的时间,频繁评估会导致训练非常慢
- # 此处获得的mAP会与get_map.py获得的会有所不同,原因有二:
- # (一)此处获得的mAP为验证集的mAP。
- # (二)此处设置评估参数较为保守,目的是加快评估速度。
- #------------------------------------------------------------------#
- eval_flag = True
- eval_period = 5
- #------------------------------------------------------------------#
- # num_workers 用于设置是否使用多线程读取数据,1代表关闭多线程
- # 开启后会加快数据读取速度,但是会占用更多内存
- # 在IO为瓶颈的时候再开启多线程,即GPU运算速度远大于读取图片的速度。
- #------------------------------------------------------------------#
- num_workers = 4
- #----------------------------------------------------#
- # 获得图片路径和标签
- #----------------------------------------------------#
- train_annotation_path = '2007_train_wm.txt'
- val_annotation_path = '2007_val_wm.txt'
-
- #----------------------------------------------------#
- # 获取classes和anchor
- #----------------------------------------------------#
- class_names, num_classes = get_classes(classes_path)
- #------------------------------------------------------#
- # 设置用到的显卡
- #------------------------------------------------------#
- os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(str(x) for x in train_gpu)
- ngpus_per_node = len(train_gpu)
- print('Number of devices: {}'.format(ngpus_per_node))
-
- model = FasterRCNN(num_classes, anchor_scales = anchors_size, backbone = backbone, pretrained = pretrained)
- if not pretrained:
- weights_init(model)
- if model_path != '':
- #------------------------------------------------------#
- # 权值文件请看README,百度网盘下载
- #------------------------------------------------------#
- print('Load weights {}.'.format(model_path))
-
- #------------------------------------------------------#
- # 根据预训练权重的Key和模型的Key进行加载
- #------------------------------------------------------#
- device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- model_dict = model.state_dict()
- pretrained_dict = torch.load(model_path, map_location = device)
- load_key, no_load_key, temp_dict = [], [], {}
- for k, v in pretrained_dict.items():
- if k in model_dict.keys() and np.shape(model_dict[k]) == np.shape(v):
- temp_dict[k] = v
- load_key.append(k)
- else:
- no_load_key.append(k)
- model_dict.update(temp_dict)
- model.load_state_dict(model_dict)
- #------------------------------------------------------#
- # 显示没有匹配上的Key
- #------------------------------------------------------#
- print("\nSuccessful Load Key:", str(load_key)[:500], "……\nSuccessful Load Key Num:", len(load_key))
- print("\nFail To Load Key:", str(no_load_key)[:500], "……\nFail To Load Key num:", len(no_load_key))
- print("\n\033[1;33;44m温馨提示,head部分没有载入是正常现象,Backbone部分没有载入是错误的。\033[0m")
- #----------------------#
- # 记录Loss
- #----------------------#
- time_str = datetime.datetime.strftime(datetime.datetime.now(),'%Y_%m_%d_%H_%M_%S')
- log_dir = os.path.join(save_dir, "loss_" + str(time_str))
- loss_history = LossHistory(log_dir, model, input_shape = input_shape)
- #------------------------------------------------------------------#
- # torch 1.2不支持amp,建议使用torch 1.7.1及以上正确使用fp16
- # 因此torch1.2这里显示"could not be resolve"
- #------------------------------------------------------------------#
- if fp16:
- from torch.cuda.amp import GradScaler as GradScaler
- scaler = GradScaler()
- else:
- scaler = None
- model_train = model.train()
- if Cuda:
- model_train = torch.nn.DataParallel(model_train)
- cudnn.benchmark = True
- model_train = model_train.cuda()
- #---------------------------#
- # 读取数据集对应的txt
- #---------------------------#
- with open(train_annotation_path, encoding='utf-8') as f:
- train_lines = f.readlines()
- with open(val_annotation_path, encoding='utf-8') as f:
- val_lines = f.readlines()
- num_train = len(train_lines)
- num_val = len(val_lines)
-
- show_config(
- classes_path = classes_path, model_path = model_path, input_shape = input_shape, \
- Init_Epoch = Init_Epoch, Freeze_Epoch = Freeze_Epoch, UnFreeze_Epoch = UnFreeze_Epoch, Freeze_batch_size = Freeze_batch_size, Unfreeze_batch_size = Unfreeze_batch_size, Freeze_Train = Freeze_Train, \
- Init_lr = Init_lr, Min_lr = Min_lr, optimizer_type = optimizer_type, momentum = momentum, lr_decay_type = lr_decay_type, \
- save_period = save_period, save_dir = save_dir, num_workers = num_workers, num_train = num_train, num_val = num_val
- )
- #---------------------------------------------------------#
- # 总训练世代指的是遍历全部数据的总次数
- # 总训练步长指的是梯度下降的总次数
- # 每个训练世代包含若干训练步长,每个训练步长进行一次梯度下降。
- # 此处仅建议最低训练世代,上不封顶,计算时只考虑了解冻部分
- #----------------------------------------------------------#
- wanted_step = 5e4 if optimizer_type == "sgd" else 1.5e4
- total_step = num_train // Unfreeze_batch_size * UnFreeze_Epoch
- if total_step <= wanted_step:
- if num_train // Unfreeze_batch_size == 0:
- raise ValueError('数据集过小,无法进行训练,请扩充数据集。')
- wanted_epoch = wanted_step // (num_train // Unfreeze_batch_size) + 1
- print("\n\033[1;33;44m[Warning] 使用%s优化器时,建议将训练总步长设置到%d以上。\033[0m"%(optimizer_type, wanted_step))
- print("\033[1;33;44m[Warning] 本次运行的总训练数据量为%d,Unfreeze_batch_size为%d,共训练%d个Epoch,计算出总训练步长为%d。\033[0m"%(num_train, Unfreeze_batch_size, UnFreeze_Epoch, total_step))
- print("\033[1;33;44m[Warning] 由于总训练步长为%d,小于建议总步长%d,建议设置总世代为%d。\033[0m"%(total_step, wanted_step, wanted_epoch))
- #------------------------------------------------------#
- # 主干特征提取网络特征通用,冻结训练可以加快训练速度
- # 也可以在训练初期防止权值被破坏。
- # Init_Epoch为起始世代
- # Freeze_Epoch为冻结训练的世代
- # UnFreeze_Epoch总训练世代
- # 提示OOM或者显存不足请调小Batch_size
- #------------------------------------------------------#
- if True:
- UnFreeze_flag = False
- #------------------------------------#
- # 冻结一定部分训练
- #------------------------------------#
- if Freeze_Train:
- for param in model.extractor.parameters():
- param.requires_grad = False
- # ------------------------------------#
- # 冻结bn层
- # ------------------------------------#
- model.freeze_bn()
- #-------------------------------------------------------------------#
- # 如果不冻结训练的话,直接设置batch_size为Unfreeze_batch_size
- #-------------------------------------------------------------------#
- batch_size = Freeze_batch_size if Freeze_Train else Unfreeze_batch_size
- #-------------------------------------------------------------------#
- # 判断当前batch_size,自适应调整学习率
- #-------------------------------------------------------------------#
- nbs = 16
- lr_limit_max = 1e-4 if optimizer_type == 'adam' else 5e-2
- lr_limit_min = 1e-4 if optimizer_type == 'adam' else 5e-4
- Init_lr_fit = min(max(batch_size / nbs * Init_lr, lr_limit_min), lr_limit_max)
- Min_lr_fit = min(max(batch_size / nbs * Min_lr, lr_limit_min * 1e-2), lr_limit_max * 1e-2)
-
- #---------------------------------------#
- # 根据optimizer_type选择优化器
- #---------------------------------------#
- optimizer = {
- 'adam' : optim.Adam(model.parameters(), Init_lr_fit, betas = (momentum, 0.999), weight_decay = weight_decay),
- 'sgd' : optim.SGD(model.parameters(), Init_lr_fit, momentum = momentum, nesterov=True, weight_decay = weight_decay)
- }[optimizer_type]
- #---------------------------------------#
- # 获得学习率下降的公式
- #---------------------------------------#
- lr_scheduler_func = get_lr_scheduler(lr_decay_type, Init_lr_fit, Min_lr_fit, UnFreeze_Epoch)
-
- #---------------------------------------#
- # 判断每一个世代的长度
- #---------------------------------------#
- epoch_step = num_train // batch_size
- epoch_step_val = num_val // batch_size
- if epoch_step == 0 or epoch_step_val == 0:
- raise ValueError("数据集过小,无法继续进行训练,请扩充数据集。")
- train_dataset = FRCNNDataset(train_lines, input_shape, train = True)
- val_dataset = FRCNNDataset(val_lines, input_shape, train = False)
- gen = DataLoader(train_dataset, shuffle = True, batch_size = batch_size, num_workers = num_workers, pin_memory = True,
- drop_last = True, collate_fn = frcnn_dataset_collate)
- gen_val = DataLoader(val_dataset , shuffle = True, batch_size = batch_size, num_workers = num_workers, pin_memory = True,
- drop_last = True, collate_fn = frcnn_dataset_collate)
- train_util = FasterRCNNTrainer(model_train, optimizer)
- #----------------------#
- # 记录eval的map曲线
- #----------------------#
- eval_callback = EvalCallback(model_train, input_shape, class_names, num_classes, val_lines, log_dir, Cuda, \
- eval_flag=eval_flag, period=eval_period)
- #---------------------------------------#
- # 开始模型训练
- #---------------------------------------#
- for epoch in range(Init_Epoch, UnFreeze_Epoch):
- #---------------------------------------#
- # 如果模型有冻结学习部分
- # 则解冻,并设置参数
- #---------------------------------------#
- if epoch >= Freeze_Epoch and not UnFreeze_flag and Freeze_Train:
- batch_size = Unfreeze_batch_size
- #-------------------------------------------------------------------#
- # 判断当前batch_size,自适应调整学习率
- #-------------------------------------------------------------------#
- nbs = 16
- lr_limit_max = 1e-4 if optimizer_type == 'adam' else 5e-2
- lr_limit_min = 1e-4 if optimizer_type == 'adam' else 5e-4
- Init_lr_fit = min(max(batch_size / nbs * Init_lr, lr_limit_min), lr_limit_max)
- Min_lr_fit = min(max(batch_size / nbs * Min_lr, lr_limit_min * 1e-2), lr_limit_max * 1e-2)
- #---------------------------------------#
- # 获得学习率下降的公式
- #---------------------------------------#
- lr_scheduler_func = get_lr_scheduler(lr_decay_type, Init_lr_fit, Min_lr_fit, UnFreeze_Epoch)
-
- for param in model.extractor.parameters():
- param.requires_grad = True
- # ------------------------------------#
- # 冻结bn层
- # ------------------------------------#
- model.freeze_bn()
- epoch_step = num_train // batch_size
- epoch_step_val = num_val // batch_size
- if epoch_step == 0 or epoch_step_val == 0:
- raise ValueError("数据集过小,无法继续进行训练,请扩充数据集。")
- gen = DataLoader(train_dataset, shuffle = True, batch_size = batch_size, num_workers = num_workers, pin_memory=True,
- drop_last=True, collate_fn=frcnn_dataset_collate)
- gen_val = DataLoader(val_dataset , shuffle = True, batch_size = batch_size, num_workers = num_workers, pin_memory=True,
- drop_last=True, collate_fn=frcnn_dataset_collate)
- UnFreeze_flag = True
-
- set_optimizer_lr(optimizer, lr_scheduler_func, epoch)
-
- fit_one_epoch(model, train_util, loss_history, eval_callback, optimizer, epoch, epoch_step, epoch_step_val, gen, gen_val, UnFreeze_Epoch, Cuda, fp16, scaler, save_period, save_dir)
-
- loss_history.writer.close()
|