-
Notifications
You must be signed in to change notification settings - Fork 0
/
base-line.py
208 lines (194 loc) · 6.31 KB
/
base-line.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import random
import os.path as osp
from glob import glob
import random
import os
import os.path as osp
from copy import deepcopy
from functools import partial
import sys
sys.path.append('PaddleRS')
import numpy as np
import paddle
import paddlers as pdrs
from paddlers import transforms as T
from PIL import Image
from skimage.io import imread, imsave
from tqdm import tqdm
from matplotlib import pyplot as plt
# 随机数生成器种子
RNG_SEED = 114514
# 调节此参数控制训练集数据的占比
TRAIN_RATIO = 0.95
# 数据集路径
DATA_DIR = '/home/aistudio/data/data134796/dataset/'
def write_rel_paths(phase, names, out_dir, prefix=''):
"""将文件相对路径存储在txt格式文件中"""
with open(osp.join(out_dir, phase+'.txt'), 'w') as f:
for name in names:
f.write(
' '.join([
osp.join(prefix, 'A', name),
osp.join(prefix, 'B', name),
osp.join(prefix, 'label', name)
])
)
f.write('\n')
random.seed(RNG_SEED)
# 随机划分训练集/验证集
names = list(map(osp.basename, glob(osp.join(DATA_DIR, 'train', 'label', '*.png'))))
# 对文件名进行排序,以确保多次运行结果一致
names.sort()
random.shuffle(names)
len_train = int(len(names)*TRAIN_RATIO) # 向下取整
write_rel_paths('train', names[:len_train], DATA_DIR, prefix='train')
write_rel_paths('val', names[len_train:], DATA_DIR, prefix='train')
write_rel_paths(
'test',
map(osp.basename, glob(osp.join(DATA_DIR, 'test', 'A', '*.png'))),
DATA_DIR,
prefix='test'
)
SEED = 1919810
# 数据集路径
DATA_DIR = '/home/aistudio/data/data134796/dataset/'
# 实验路径。实验目录下保存输出的模型权重和结果
EXP_DIR = '/home/aistudio/exp/'
# 保存最佳模型的路径
BEST_CKP_PATH = osp.join(EXP_DIR, 'best_model', 'model.pdparams')
# 训练的epoch数
NUM_EPOCHS = 100
# 每多少个epoch保存一次模型权重参数
SAVE_INTERVAL_EPOCHS = 10
# 初始学习率
LR = 0.001
# 学习率衰减步长(注意,单位为迭代次数而非epoch数),即每多少次迭代将学习率衰减一半
DECAY_STEP = 1000
# 训练阶段 batch size
TRAIN_BATCH_SIZE = 16
# 推理阶段 batch size
INFER_BATCH_SIZE = 16
# 加载数据所使用的进程数
NUM_WORKERS = 4
# 裁块大小
CROP_SIZE = 256
# 模型推理阶段使用的滑窗步长
STRIDE = 64
# 影像原始大小
ORIGINAL_SIZE = (1024, 1024)
random.seed(SEED)
np.random.seed(SEED)
paddle.seed(SEED)
def info(msg, **kwargs):
print(msg, **kwargs)
def warn(msg, **kwargs):
print('\033[0;31m'+msg, **kwargs)
def quantize(arr):
return (arr*255).astype('uint8')
model = pdrs.tasks.BIT(
# 模型输出类别数
num_classes=2,
# 是否使用混合损失函数,默认使用交叉熵损失函数训练
use_mixed_loss=False,
# 模型输入通道数
in_channels=3,
# 模型使用的骨干网络,支持'resnet18'或'resnet34'
backbone='resnet18',
# 骨干网络中的resnet stage数量
n_stages=4,
# 是否使用tokenizer获取语义token
use_tokenizer=True,
# token的长度
token_len=4,
# 若不使用tokenizer,则使用池化方式获取token。此参数设置池化模式,有'max'和'avg'两种选项,分别对应最大池化与平均池化
pool_mode='max',
# 池化操作输出特征图的宽和高(池化方式得到的token的长度为pool_size的平方)
pool_size=2,
# 是否在Transformer编码器中加入位置编码(positional embedding)
enc_with_pos=True,
# Transformer编码器使用的注意力模块(attention block)个数
enc_depth=1,
# Transformer编码器中每个注意力头的嵌入维度(embedding dimension)
enc_head_dim=64,
# Transformer解码器使用的注意力模块个数
dec_depth=8,
# Transformer解码器中每个注意力头的嵌入维度
dec_head_dim=8
)
train_transforms = T.Compose([
# 随机裁剪
T.RandomCrop(
# 裁剪区域将被缩放到此大小
crop_size=CROP_SIZE,
# 将裁剪区域的横纵比固定为1
aspect_ratio=[1.0, 1.0],
# 裁剪区域相对原始影像长宽比例在一定范围内变动,最小不低于原始长宽的1/5
scaling=[0.2, 1.0]
),
# 以50%的概率实施随机水平翻转
T.RandomHorizontalFlip(prob=0.5),
# 以50%的概率实施随机垂直翻转
T.RandomVerticalFlip(prob=0.5),
# 数据归一化到[-1,1]
T.Normalize(
mean=[0.5, 0.5, 0.5],
std=[0.5, 0.5, 0.5]
)
])
eval_transforms = T.Compose([
# 在验证阶段,输入原始尺寸影像,对输入影像仅进行归一化处理
# 验证阶段与训练阶段的数据归一化方式必须相同
T.Normalize(
mean=[0.5, 0.5, 0.5],
std=[0.5, 0.5, 0.5]
)
])
# 实例化数据集
train_dataset = pdrs.datasets.CDDataset(
data_dir=DATA_DIR,
file_list=osp.join(DATA_DIR, 'train.txt'),
label_list=None,
transforms=train_transforms,
num_workers=NUM_WORKERS,
shuffle=True,
binarize_labels=True
)
eval_dataset = pdrs.datasets.CDDataset(
data_dir=DATA_DIR,
file_list=osp.join(DATA_DIR, 'val.txt'),
label_list=None,
transforms=eval_transforms,
num_workers=0,
shuffle=False,
binarize_labels=True
)
if not osp.exists(EXP_DIR):
os.makedirs(EXP_DIR)
lr_scheduler = paddle.optimizer.lr.StepDecay(
LR,
step_size=DECAY_STEP,
# 学习率衰减系数,这里指定每次减半
gamma=0.5
)
# 构造Adam优化器
optimizer = paddle.optimizer.Adam(
learning_rate=lr_scheduler,
parameters=model.net.parameters()
)
model.train(
num_epochs=NUM_EPOCHS,
train_dataset=train_dataset,
train_batch_size=TRAIN_BATCH_SIZE,
eval_dataset=eval_dataset,
optimizer=optimizer,
save_interval_epochs=SAVE_INTERVAL_EPOCHS,
# 每多少次迭代记录一次日志
log_interval_steps=10,
save_dir=EXP_DIR,
# 是否使用early stopping策略,当精度不再改善时提前终止训练
early_stop=False,
# 是否启用VisualDL日志功能
use_vdl=True,
# 指定从某个检查点继续训练
resume_checkpoint=None
)