更多参见darknet学习笔记
相关文档:darknet框架基于resnet34模型训练OCT图片;pytorch框架基于resnet18训练OCT数据
darknet与pytorch框架训练resnet34模型分类对比
模型对比
darknet resnet34在ImageNet上预训练,top1:72.4,top5:91.1.
初始召回率:
pytorch:正常图片:0.0217;异常图片:1.0
darknet:正常图片:0.9811;异常图片:0.0846
pytorch与darknet召回率是相反的。
调整学习率策略:
pytorch
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
torch.optim.lr_scheduler:调整学习率
darknet:
调整策略为poly,
darknet源代码中的公式
int batch_num = (*net.seen)/(net.batch*net.subdivisions);
//每增加一个net.batch,batch_num加1.
float get_current_rate(network net)
{
return net.learning_rate * pow(1 - (float)batch_num / net.max_batches, net.power);
}
matlab实现函数并绘制曲线
maxbatches = 40000;
begin = 0
rate = 0.01;
x = begin:maxbatches;
tm = x-begin
y=1-(tm/maxbatches);
k=y.^4;
rate= rate*k;
plot(x,rate)
学习过程中,学习率出现先变大后变小,是因为resnet34.txt有一个参数burn_in=1000
如果有burn_in参数:
if (batch_num < net.burn_in) return net.learning_rate * pow((float)batch_num / net.burn_in, net.power);
优化器:
pytorch:
torch.optim优化算法理解之optim.Adam()
optimizer_ft = optim.Adam(model_ft.parameters(), lr=learning_rate, weight_decay=1e-5)
darknet:
网络结构:
激活函数:
损失函数:
图像预处理:
pytorch图像预处理:
pytorch处理,第一步resize()
class BagDataset(Dataset):
def __init__(self, data_file, transform=None):
self.transform = transform
self.img_list = data_file
def __len__(self):
return len(self.img_list)
def __getitem__(self, idx):
img_name = self.img_list[idx]
print("imgname is {}\n idx is{}".format(img_name, idx))
img = cv2.imread(img_name)
img = cv2.resize(img, (512, 512))
cls = img_name.split('/')[0][10:15]
#cls = img_name.split('/')[0][5:10]
print("cls is {}".format(cls))
#cls = img_name.split('/')[0][:5]
#print("cls is {}".format(cls))
label = cls_dict[cls]
if self.transform:
try:
img = self.transform(transforms.ToPILImage()(img))
except TypeError:
print(img_name)
# img = self.transform(img)
return img, label
pytorch的resize使用opencv的resize方法,根据opencv改变图像大小cvResize和resize,可以初步判定darknet的resize()与pytorch的resize()方法效果基本一致,假设darknet代码实现没有bug的前提下。如果想要心安,需要验证两个方法是否效果一致。
pytorch处理,第二步翻转:
data_transforms = {
'train': transforms.Compose([
# transforms.RandomResizedCrop(224),
# transforms.Resize(input_size),
transforms.RandomHorizontalFlip(),
transforms.RandomVerticalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
# transforms.Resize(input_size),
# transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
翻转的代码主要是:
transforms.RandomHorizontalFlip(),
transforms.RandomVerticalFlip(),
其中:
所以,pytorch对图像同时做了水平翻转和垂直翻转。
pytorch处理第三步:归一化和标准化
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
参考PyTorch学习笔记——图像处理(transforms.Normalize 归一化) ,理解归一化代码。
为什么要进行归一化标准化?
归一化/标准化的本质是线性变换,线性变换不会是改变后的数据失效,例如线性变换不会改变数值的排序。除此之外,线性变换还可以提高数据的表现。
(1)某些模型求解需要
a.在使用梯度下降算法求解最优值问题时,归一化/标准化可以提高梯度下降算法的求解速度,从而加快模型收敛速度。
如下左图所示,没有归一化和标准化的等高线呈椭圆形,迭代时很可能沿着长轴走“之”字形,从而导致迭代很多次才收敛。
如下右图所示,进行了归一化和标准化的等高线呈圆形,在梯度下降进行求解时能够加快收敛。