PaddlePaddle 行人重识别(ReID)模型训练

前言:

 该项目已在AI Studio开源,建议上AI Studio哦!AI Studio项目地址
 该项目是在准备今年软件杯百度行人跟踪赛题的其中一个项目:行人重识别模型的训练。总共就只有三个步骤:数据集的准备模型的搭建、最后是***模型训练***。

下面是最终的跟踪效果图

最后跟踪的效果图

一、数据集的准备:

1、下载Market_net数据集或者MARS数据集

 我已经下载,并在AI Studio上开源了,有需要的小伙伴可以去我的个人中心查找。

#解压Market_net数据集以及MARS数据集
#!unzip -oq /home/aistudio/data/data9240/Market-1501-v15.09.15.zip
!unzip -oq /home/aistudio/data/data76843/archive.zip

2、处理数据,获得训练所需要的数据“形式”。

  下面这个脚本是用来process_data Market1501 数据集的,把它处理成我们训练需要的形式,进行数据集处理之前,首先必须要了解数据集的结构,只有在准确了解数据集结构的前提下,才能够有效的处理数据。整个数据集处理的逻辑是将相同的人放到同一个同一个文件夹下。所以,从这个角度理解ReID的训练,会发现,训练ReID模型,本质上是在做图像分类任务。
Market-1501数据集:
  bounding_box_test
  bounding_box_train
  gt_bbox
  gt_query
  readme.txt
图片的命名规则:
以 0001_C1S1_00151_01.jpg为例
1)0001表示每个人的编号,从0001 -> 1501;
2)C1表示第一个摄像头(Camera1),共6个;
3)S1表示第一个录像片段(Sequence1);
4)000151表示C1S1的第000151帧的图片。(视频帧率为25fps);
5)01表示C1S1_000151这一帧上的第一个检测框;
以上内容仅作为一个了解即可。
import os
from shutil import copyfile

download_path = 'Market-1501-v15.09.15' #解压数据集之后,数据集的根目录。

if not os.path.isdir(download_path):
    print('path wrong, please change the download_path')

save_path_root = 'data'
save_path = save_path_root + '/paddle'

if not os.path.isdir(save_path):
    os.mkdir(save_path)
#-----------------------------------------
#query
query_path = download_path + '/query'
query_save_path = save_path + '/query'
if not os.path.isdir(query_save_path):
    os.mkdir(query_save_path)

for root, dirs, files in os.walk(query_path, topdown=True):
    for name in files:
        if not name[-3:]=='jpg':
            continue
        ID  = name.split('_')
        src_path = query_path + '/' + name
        dst_path = query_save_path + '/' + ID[0]
        if not os.path.isdir(dst_path):
            os.mkdir(dst_path)
        copyfile(src_path, dst_path + '/' + name)

#-----------------------------------------
#multi-query
query_path = download_path + '/gt_bbox'
# for dukemtmc-reid, we do not need multi-query
if os.path.isdir(query_path):
    query_save_path = save_path + '/multi-query'
    if not os.path.isdir(query_save_path):
        os.mkdir(query_save_path)

    for root, dirs, files in os.walk(query_path, topdown=True):
        for name in files:
            if not name[-3:]=='jpg':
                continue
            ID  = name.split('_')
            src_path = query_path + '/' + name
            dst_path = query_save_path + '/' + ID[0]
            if not os.path.isdir(dst_path):
                os.mkdir(dst_path)
            copyfile(src_path, dst_path + '/' + name)

#-----------------------------------------
#gallery
gallery_path = download_path + '/bounding_box_test'
gallery_save_path = save_path + '/gallery'
if not os.path.isdir(gallery_save_path):
    os.mkdir(gallery_save_path)

for root, dirs, files in os.walk(gallery_path, topdown=True):
    for name in files:
        if not name[-3:]=='jpg':
            continue
        ID  = name.split('_')
        src_path = gallery_path + '/' + name
        dst_path = gallery_save_path + '/' + ID[0]
        if not os.path.isdir(dst_path):
            os.mkdir(dst_path)
        copyfile(src_path, dst_path + '/' + name)

#---------------------------------------
#train_all
train_path = download_path + '/bounding_box_train'
train_save_path = save_path + '/train_all'
if not os.path.isdir(train_save_path):
    os.mkdir(train_save_path)

for root, dirs, files in os.walk(train_path, topdown=True):
    for name in files:
        if not name[-3:]=='jpg':
            continue
        ID  = name.split('_')
        src_path = train_path + '/' + name
        dst_path = train_save_path + '/' + ID[0]
        if not os.path.isdir(dst_path):
            os.mkdir(dst_path)
        copyfile(src_path, dst_path + '/' + name)


#---------------------------------------
#train_val
train_path = download_path + '/bounding_box_train'
train_save_path = save_path + '/train'
val_save_path = save_path + '/val'
if not os.path.isdir(train_save_path):
    os.mkdir(train_save_path)
    os.mkdir(val_save_path)

for root, dirs, files in os.walk(train_path, topdown=True):
    for name in files:
        if not name[-3:]=='jpg':
            continue
        ID  = name.split('_')
        src_path = train_path + '/' + name
        dst_path = train_save_path + '/' + ID[0]
        if not os.path.isdir(dst_path):
            os.mkdir(dst_path)
            dst_path = val_save_path + '/' + ID[0]  #first image is used as val image
            os.mkdir(dst_path)
        copyfile(src_path, dst_path + '/' + name)
"""
用来获得类别数目。
"""
root_dir = 'bbox_train/bbox_train'

print(len(os.listdir(root_dir))) #所以说有751类,加上背景图片,有752类。

3、加载训练所需的数据集:

小细节的阐释:
 在class Market_dataset类,init 方法中有两种transforms:分别是transforms_train和transforms_test,会发现两种transforms有所不同。在train中我们多实用了RandomCrop、RandomHorizon和ColorJitter,而在测试中没有。因为我们想在训练集中通过这几种数据增广的方法来“模拟”行人跟踪中的遮挡的情况或者在晚上灯光较暗的时候。而在测试的时候或者说在使用模型进行正向推理的时候则不需要进行这种方式的数据增广。

import paddle
import os
from PIL import Image

class Market_dataset(paddle.io.Dataset):
    def __init__(self, path, train=False):
        self.img_list = []
        self.label_data = []
        self.train = train
        self.transforms_train = paddle.vision.transforms.Compose([
            paddle.vision.transforms.Resize((128, 64)),
            paddle.vision.transforms.RandomCrop((128,64)),
            paddle.vision.transforms.RandomHorizontalFlip(),
            paddle.vision.transforms.ColorJitter(0.4, 0.4, 0.4, 0.4),
            paddle.vision.transforms.ToTensor(),
            paddle.vision.transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ])
        self.transforms_test = paddle.vision.transforms.Compose([
            paddle.vision.transforms.Resize((128,64)),
            paddle.vision.transforms.ToTensor(),
            paddle.vision.transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ])
        count = 0
        for dir_ in os.listdir(path):
            for img_path in os.listdir(os.path.join(path, dir_)):
                self.img_list.append(os.path.join(path, dir_, img_path))
                self.label_data.append(count)
            count +=1
        
    def __len__(self):
        return len(self.img_list)

    def __getitem__(self, index):
        img_path = self.img_list[index]
        img_data = Image.open(img_path)
        if img_data.mode != 'RGB':
            img_data = img_data.convert('RGB')
        label = self.label_data[index]
        if self.train:
            img_data = self.transforms_train(img_data)
        else:
            img_data = self.transforms_test(img_data)

        return img_data, label
#Maket1501
"""train_data_path = 'data/paddle/train_all'
val_data_path = 'data/paddle/val'

train_data = Market_dataset(train_data_path, train=True)
val_data = Market_dataset(val_data_path, train=False)"""
#print(train_data[123][1]) #[1]打印数据的标签,[0]打印数据。

train_data_path = 'bbox_train/bbox_train'
val_data_path = 'bbox_test/bbox_test'

train_data = Market_dataset(train_data_path, train=True)
val_data = Market_dataset(val_data_path, train=False)

print(train_data[123][1])
0


/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/tensor/creation.py:143: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any behavior and is safe. 
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  if data.dtype == np.object:

二、特征提取(ShuffleNet、GhostNet、ResNet网络)的搭建:

1、ShuffleNet网络的搭建

"""
ShuffleNet网络模型的搭建
"""
import paddle
import paddle.nn as nn


def channel_shuffle(x, groups):

    g = groups

    x = paddle.reshape(x, (x.shape[0], g, x.shape[1] // g, x.shape[2], x.shape[3]))
    x = paddle.transpose(x, (0, 2, 1, 3, 4))
    x = paddle.reshape(x, (x.shape[0], -1, x.shape[3], x.shape[4]))
    
    return  x

class InvertedResidual(nn.Layer):
    def __init__(self, inp, oup, stride):
        super(InvertedResidual, self).__init__()

        if not (1 <= stride <= 3):
            raise ValueError('illegal stride value')
        self.stride = stride

        branch_features = oup // 2
        assert (self.stride != 1) or (inp == branch_features << 1)

        if self.stride > 1:
            self.branch1 = nn.Sequential(
                self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1),
                nn.BatchNorm2D(inp),
                nn.Conv2D(inp, branch_features, kernel_size=1, stride=1, padding=0, bias_attr=False),
                nn.BatchNorm2D(branch_features),
                nn.ReLU(),
            )

        self.branch2 = nn.Sequential(
            nn.Conv2D(inp if (self.stride > 1) else branch_features,
                      branch_features, kernel_size=1, stride=1, padding=0, bias_attr=False),
            nn.BatchNorm2D(branch_features),
            nn.ReLU(),
            self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1),
            nn.BatchNorm2D(branch_features),
            nn.Conv2D(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias_attr=False),
            nn.BatchNorm2D(branch_features),
            nn.ReLU(),
        )

    @staticmethod
    def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias_attr=False):
        return nn.Conv2D(i, o, kernel_size, stride, padding, groups=i, bias_attr=False)

    def forward(self, x):
        if self.stride == 1:
            x1, x2 = paddle.chunk(x, 2, axis=1)
            out = paddle.concat((x1, self.branch2(x2)), axis=1)
        else:
            out = paddle.concat((self.branch1(x), self.branch2(x)), axis=1)

        out = channel_shuffle(out, 2)

        return out


class ShuffleNetV2(nn.Layer):
    def __init__(self, stages_repeats, stages_out_channels, num_classes=1000, reid = False):
        super(ShuffleNetV2, self).__init__()

        if len(stages_repeats) != 3:
            raise ValueError('expected stages_repeats as list of 3 positive ints')
        if len(stages_out_channels) != 5:
            raise ValueError('expected stages_out_channels as list of 5 positive ints')
        self._stage_out_channels = stages_out_channels
        self.reid = reid

        input_channels = 3
        output_channels = self._stage_out_channels[0]
        self.conv1 = nn.Sequential(
            nn.Conv2D(input_channels, output_channels, 3, 2, 1, bias_attr=False),
            nn.BatchNorm2D(output_channels),
            nn.ReLU(),
        )
        input_channels = output_channels

        self.maxpool = nn.MaxPool2D(kernel_size=3, stride=(1,2), padding=1)

        stage_names = ['stage{}'.format(i) for i in [2, 3, 4]]
        for name, repeats, output_channels in zip(
                stage_names, stages_repeats, self._stage_out_channels[1:]):
            seq = [InvertedResidual(input_channels, output_channels, 2)]
            for i in range(repeats - 1):
                seq.append(InvertedResidual(output_channels, output_channels, 1))
            setattr(self, name, nn.Sequential(*seq))
            input_channels = output_channels

        output_channels = self._stage_out_channels[-1]
        self.conv5 = nn.Sequential(
            nn.Conv2D(input_channels, output_channels, 1, 1, 0, bias_attr=False),
            nn.BatchNorm2D(output_channels),
            nn.ReLU(),
        )

        self.class_out = nn.Linear(output_channels, num_classes)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool(x)
        x = self.stage2(x)
        x = self.stage3(x)
        x = self.stage4(x)
        x = self.conv5(x)
        x = x.mean([2, 3])  # globalpool
        if self.reid:
            x = paddle.divide(x, paddle.norm(x, p=2,dim=1,keepdim=True))
            return x
        x = self.class_out(x)

        return x

2、GhostNet网络搭建

"""
GhostNet网络模型的搭建
"""
import paddle
import paddle.nn as nn
import math

def _make_divisible(v, divisor, min_value=None):
   
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    # Make sure that round down does not go down by more than 10%.
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v


class SELayer(nn.Layer):
    def __init__(self, channel, reduction=4):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2D(1)
        self.fc = nn.Sequential(
                nn.Linear(channel, channel // reduction),
                nn.ReLU(),
                nn.Linear(channel // reduction, channel),        
            )

    def forward(self, x):
        b, c, _, _ = x.shape
        y = self.avg_pool(x)
        y = paddle.reshape(y, [b, c])
        y = self.fc(y)
        y = paddle.reshape(y, [b, c, 1, 1])
        y = paddle.clip(y, 0, 1) #maybe problem
        return x * y


def depthwise_conv(inp, oup, kernel_size=3, stride=1, relu=False):
    return nn.Sequential(
        nn.Conv2D(inp, oup, kernel_size, stride, kernel_size//2, groups=inp, bias_attr=False),
        nn.BatchNorm2D(oup),
        nn.ReLU() if relu else nn.Sequential(),
    )

class GhostModule(nn.Layer):
    def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):
        super(GhostModule, self).__init__()
        self.oup = oup
        init_channels = math.ceil(oup / ratio)
        new_channels = init_channels*(ratio-1)

        self.primary_conv = nn.Sequential(
            nn.Conv2D(inp, init_channels, kernel_size, stride, kernel_size//2, bias_attr=False),
            nn.BatchNorm2D(init_channels),
            nn.ReLU() if relu else nn.Sequential(),
        )

        self.cheap_operation = nn.Sequential(
            nn.Conv2D(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias_attr=False),
            nn.BatchNorm2D(new_channels),
            nn.ReLU() if relu else nn.Sequential(),
        )

    def forward(self, x):
        x1 = self.primary_conv(x)
        x2 = self.cheap_operation(x1)
        out = paddle.concat([x1,x2], axis=1)
        return out[:,:self.oup,:,:]


class GhostBottleneck(nn.Layer):
    def __init__(self, inp, hidden_dim, oup, kernel_size, stride, use_se):
        super(GhostBottleneck, self).__init__()
        assert stride in [1, 2]

        self.conv = nn.Sequential(
            # pw
            GhostModule(inp, hidden_dim, kernel_size=1, relu=True),
            # dw
            depthwise_conv(hidden_dim, hidden_dim, kernel_size, stride, relu=False) if stride==2 else nn.Sequential(),
            # Squeeze-and-Excite
            SELayer(hidden_dim) if use_se else nn.Sequential(),
            # pw-linear
            GhostModule(hidden_dim, oup, kernel_size=1, relu=False),
        )

        if stride == 1 and inp == oup:
            self.shortcut = nn.Sequential()
        else:
            self.shortcut = nn.Sequential(
                depthwise_conv(inp, inp, kernel_size, stride, relu=False),
                nn.Conv2D(inp, oup, 1, 1, 0, bias_attr=False),
                nn.BatchNorm2D(oup),
            )

    def forward(self, x):
        return self.conv(x) + self.shortcut(x)


class GhostNet(nn.Layer):
    def __init__(self, cfgs, num_classes=1000, width_mult=1.,reid=False):
        super(GhostNet, self).__init__()
        # setting of inverted residual blocks
        self.cfgs = cfgs
        self.reid = reid

        # building first layer
        output_channel = _make_divisible(16 * width_mult, 4)
        layers = [nn.Sequential(
            nn.Conv2D(3, output_channel, 3, 2, 1, bias_attr=False),
            nn.BatchNorm2D(output_channel),
            nn.ReLU()
        )]
        input_channel = output_channel

        # building inverted residual blocks
        block = GhostBottleneck
        for k, exp_size, c, use_se, s in self.cfgs:
            output_channel = _make_divisible(c * width_mult, 4)
            hidden_channel = _make_divisible(exp_size * width_mult, 4)
            layers.append(block(input_channel, hidden_channel, output_channel, k, s, use_se))
            input_channel = output_channel
        self.features = nn.Sequential(*layers)

        # building last several layers
        output_channel = _make_divisible(exp_size * width_mult, 4)
        self.squeeze = nn.Sequential(
            nn.Conv2D(input_channel, output_channel, 1, 1, 0, bias_attr=False),
            nn.BatchNorm2D(output_channel),
            nn.ReLU(),
            nn.AdaptiveAvgPool2D((1, 1)),
        )
        input_channel = output_channel

        output_channel = 1280
        self.classifier = nn.Sequential(
            nn.Linear(input_channel, output_channel, bias_attr=False),
            nn.BatchNorm1D(output_channel),
            nn.ReLU(),
            nn.Dropout(0.2),
            nn.Linear(output_channel, num_classes),
        )

        """self._initialize_weights()"""

    def forward(self, x):
        x = self.features(x)
        x = self.squeeze(x)
        x = paddle.reshape(x, [x.shape[0], -1])
        if self.reid:
            x = paddle.divide(x, paddle.norm(x, p=2,axis=1,keepdim=True))
            return x
        x = self.classifier(x)
        return x

3、ResNet50网络搭建

"""
ResNet网络模型的搭建
"""
import paddle
import paddle.nn as nn
import paddle.nn.functional as F

class BasicBlock(nn.Layer):
    def __init__(self, c_in, c_out,is_downsample=False):
        super(BasicBlock,self).__init__()
        self.is_downsample = is_downsample
        if is_downsample:
            self.conv1 = nn.Conv2D(c_in, c_out, 3, stride=2, padding=1, bias_attr=False)
        else:
            self.conv1 = nn.Conv2D(c_in, c_out, 3, stride=1, padding=1, bias_attr=False)
        self.bn1 = nn.BatchNorm2D(c_out)
        self.relu = nn.ReLU()
        self.conv2 = nn.Conv2D(c_out,c_out,3,stride=1,padding=1, bias_attr=False)
        self.bn2 = nn.BatchNorm2D(c_out)
        if is_downsample:
            self.downsample = nn.Sequential(
                nn.Conv2D(c_in, c_out, 1, stride=2, bias_attr=False),
                nn.BatchNorm2D(c_out)
            )
        elif c_in != c_out:
            self.downsample = nn.Sequential(
                nn.Conv2D(c_in, c_out, 1, stride=1, bias_attr=False),
                nn.BatchNorm2D(c_out)
            )
            self.is_downsample = True

    def forward(self,x):
        y = self.conv1(x)
        y = self.bn1(y)
        y = self.relu(y)
        y = self.conv2(y)
        y = self.bn2(y)
        if self.is_downsample:
            x = self.downsample(x)
        return F.relu(x.add(y))

def make_layers(c_in,c_out,repeat_times, is_downsample=False):
    blocks = []
    for i in range(repeat_times):
        if i ==0:
            blocks += [BasicBlock(c_in,c_out, is_downsample=is_downsample),]
        else:
            blocks += [BasicBlock(c_out,c_out),]
    return nn.Sequential(*blocks)

class Net(nn.Layer):
    def __init__(self, num_classes=625 ,reid=False):
        super(Net,self).__init__()
        # 3 128 64
        self.conv = nn.Sequential(
            nn.Conv2D(3,32,3,stride=1,padding=1),
            nn.BatchNorm2D(32),
            nn.ELU(),
            nn.Conv2D(32,32,3,stride=1,padding=1),
            nn.BatchNorm2D(32),
            nn.ELU(),
            nn.MaxPool2D(3,2,padding=1),
        )
        # 32 64 32
        self.layer1 = make_layers(32,32,2,False)
        # 32 64 32
        self.layer2 = make_layers(32,64,2,True)
        # 64 32 16
        self.layer3 = make_layers(64,128,2,True)
        # 128 16 8
        self.dense = nn.Sequential(
            nn.Dropout(p=0.6),
            nn.Linear(128*16*8, 128),
            nn.BatchNorm1D(128),
            nn.ELU()
        )
        # 256 1 1 
        self.reid = reid
        self.batch_norm = nn.BatchNorm1D(128)
        self.classifier = nn.Sequential(
            nn.Linear(128, num_classes),
        )
    
    def forward(self, x):
        x = self.conv(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)

        x = paddle.reshape(x, [x.shape[0],-1])
        if self.reid:
            x = self.dense[0](x)
            x = self.dense[1](x)
            x = paddle.divide(x, paddle.norm(x, p=2, axis=1,keepdim=True))
            return x
        x = self.dense(x)
        # B x 128
        # classifier
        x = self.classifier(x)
        return x

三、模型的训练:

input_define = paddle.static.InputSpec(shape=[-1,3,128,64], dtype="float32", name="img")
label_define = paddle.static.InputSpec(shape=[-1,1], dtype="int64", name="label")

1、ShuffleNetV2模型的训练:

"""
1、先对模型进行实例化,然后封装。
2、optimizerd的学习率(learning_rate)参数的设置。
tricks:稍微将以下关于learning_rate的一些小知识:如果learning_rate过大,会导致loss震荡无法收敛,这个时候可以适当调小一点学习率;
而如果learning_rate过小会使整个学习过程很长,收敛速度变慢;最后还有一点值得一提,“warm_up”,它的意思是在训练刚开始的时候学习率逐渐
一点一点的增加,最后到达设置的学习率,这个是适用于迁移学习的。
"""

model = ShuffleNetV2([4, 8, 4], [24, 48, 96, 192, 512], num_classes=625, reid=False)
model = paddle.Model(model,inputs=input_define,labels=label_define) #用Paddle.Model()对模型进行封装
optimizer = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())

model.prepare(optimizer=optimizer, #指定优化器
              loss=paddle.nn.CrossEntropyLoss(), #指定损失函数
              metrics=paddle.metric.Accuracy()) #指定评估方法

model.fit(train_data=train_data,     #训练数据集
          eval_data=val_data,         #测试数据集
          batch_size=64,                  #一个批次的样本数量
          epochs=80,                      #迭代轮次
          save_dir="ShuffleNet_ReID", #把模型参数、优化器参数保存至自定义的文件夹
          save_freq=20,                    #设定每隔多少个epoch保存模型参数及优化器参数
          shuffle=True,            
)

2、GhostNet模型的训练:

cfgs = [
        # k, t, c, SE, s 
        [3,  16,  16, 0, 1],
        [3,  48,  24, 0, 2],
        [3,  72,  24, 0, 1],
        [5,  72,  40, 1, 2],
        [5, 120,  40, 1, 1],
        [3, 240,  80, 0, 2],
        [3, 200,  80, 0, 1],
        [3, 184,  80, 0, 1],
        [3, 184,  80, 0, 1],
        [3, 480, 112, 1, 1],
        [3, 672, 112, 1, 1],
        [5, 672, 160, 1, 2],
        [5, 960, 160, 0, 1],
        [5, 960, 160, 1, 1],
        [5, 960, 160, 0, 1],
        [5, 960, 160, 1, 1]
    ]

model = GhostNet(cfgs=cfgs, num_classes=625, width_mult=1., reid=False)
model = paddle.Model(model,inputs=input_define,labels=label_define) 
optimizer = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())


model.prepare(optimizer=optimizer,
              loss=paddle.nn.CrossEntropyLoss(), 
              metrics=paddle.metric.Accuracy()) 

model.fit(train_data=train_data,     
          eval_data=val_data,         
          batch_size=64,                  
          epochs=80,                      
          save_dir="GhostNet_ReID", 
          save_freq=20,                   
          shuffle=True,        
)
The loss value printed in the log is the current step, and the metric is the average value of previous step.
Epoch 1/80
step  10/203 - loss: 6.9693 - acc: 0.0000e+00 - 282ms/step
step  20/203 - loss: 7.4490 - acc: 0.0016 - 273ms/step
step  30/203 - loss: 6.8297 - acc: 0.0031 - 277ms/step
step  40/203 - loss: 7.4432 - acc: 0.0035 - 284ms/step

3、ResNet50模型的训练:

model = Net(num_classes=625, reid=False)
model = paddle.Model(model,inputs=input_define,labels=label_define) 
optimizer = paddle.optimizer.Adam(learning_rate=0.0005, parameters=model.parameters())

model.prepare(optimizer=optimizer, 
              loss=paddle.nn.CrossEntropyLoss(), 
              metrics=paddle.metric.Accuracy()) 

model.fit(train_data=train_data,     
          eval_data=val_data,        
          batch_size=128,                  
          epochs=80,                      
          save_dir="ResNet50_ReID_Mars", 
          save_freq=20,                    
          shuffle=True,             
timizer.Adam(learning_rate=0.0005, parameters=model.parameters())

model.prepare(optimizer=optimizer, 
              loss=paddle.nn.CrossEntropyLoss(), 
              metrics=paddle.metric.Accuracy()) 

model.fit(train_data=train_data,     
          eval_data=val_data,        
          batch_size=128,                  
          epochs=80,                      
          save_dir="ResNet50_ReID_Mars", 
          save_freq=20,                    
          shuffle=True,             
)
The loss value printed in the log is the current step, and the metric is the average value of previous step.
Epoch 1/80
step   10/3984 - loss: 6.5432 - acc: 0.0070 - 411ms/step
step   20/3984 - loss: 6.2993 - acc: 0.0215 - 403ms/step
step   30/3984 - loss: 6.0832 - acc: 0.0320 - 401ms/step
step   40/3984 - loss: 6.1084 - acc: 0.0398 - 400ms/step
step   50/3984 - loss: 5.6830 - acc: 0.0469 - 399ms/step
step   60/3984 - loss: 5.6382 - acc: 0.0568 - 399ms/step
step   70/3984 - loss: 5.8908 - acc: 0.0635 - 398ms/step


我是一名热爱计算机视觉的小白一枚,现就读于成都信息工程大学电子信息科学与技术专业20级。
希望和大佬们多多交流,欢迎关注、fork、star哦!!!
完整项目建议上AI Studio哦!

AI Studio项目地址

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值