Skip to content

Commit 381b06f

Browse files
committed
training: Add Learning Rate Warmup
1 parent 05857b6 commit 381b06f

11 files changed

Lines changed: 226 additions & 75 deletions

File tree

lib/cli/args_train.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,17 @@ def get_argument_list() -> list[dict[str, T.Any]]:
164164
"stop training when you are happy with the previews. However, if you want the "
165165
"model to stop automatically at a set number of iterations, you can set that "
166166
"value here.")})
167+
argument_list.append({
168+
"opts": ("-a", "--warmup"),
169+
"action": Slider,
170+
"min_max": (0, 5000),
171+
"rounding": 100,
172+
"type": int,
173+
"default": 0,
174+
"group": _("training"),
175+
"help": _(
176+
"Learning rate warmup. Linearly increase the learning rate from 0 to the chosen "
177+
"target rate over the number of iterations given here. 0 to disable.")})
167178
argument_list.append({
168179
"opts": ("-D", "--distribution-strategy"),
169180
"dest": "distribution_strategy",

lib/gui/wrapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ def _read_stdout(self) -> None:
366366
if output and self._process_progress_stdout(output):
367367
continue
368368

369-
if output:
369+
if output.strip():
370370
self._process_training_stdout(output)
371371
print(output.rstrip())
372372

lib/training/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .augmentation import ImageAugmentation
88
from .generator import Feeder
99
from .lr_finder import LearningRateFinder
10+
from .lr_warmup import LearningRateWarmup
1011
from .preview_cv import PreviewBuffer, TriggerType
1112

1213
if T.TYPE_CHECKING:

lib/training/lr_warmup.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#! /usr/env/bin/python3
2+
""" Handles Learning Rate Warmup when training a model """
3+
from __future__ import annotations
4+
5+
import logging
6+
import typing as T
7+
8+
import keras.backend as K
9+
10+
logger = logging.getLogger(__name__)
11+
12+
if T.TYPE_CHECKING:
13+
from keras.models import Model
14+
15+
16+
class LearningRateWarmup():
17+
""" Handles the updating of the model's learning rate during Learning Rate Warmup
18+
19+
Parameters
20+
----------
21+
model : :class:`keras.models.Model`
22+
The keras model that is to be trained
23+
target_learning_rate : float
24+
The final learning rate at the end of warmup
25+
steps : int
26+
The number of iterations to warmup the learning rate for
27+
"""
28+
def __init__(self, model: Model, target_learning_rate: float, steps: int) -> None:
29+
self._model = model
30+
self._target_lr = target_learning_rate
31+
self._steps = steps
32+
self._current_lr = 0.0
33+
self._current_step = 0
34+
self._reporting_points = [int(self._steps * i / 10) for i in range(11)]
35+
logger.debug("Initialized %s", self)
36+
37+
def __repr__(self) -> str:
38+
""" Pretty string representation for logging """
39+
params = ", ".join(f"{k}={v}" for k, v in self.__dict__.items())
40+
return f"{self.__class__.__name__}({params})"
41+
42+
@classmethod
43+
def _format_notation(cls, value: float) -> str:
44+
""" Format a float to scientific notation at 1 decimal place
45+
46+
Parameters
47+
----------
48+
value : float
49+
The value to format
50+
51+
Returns
52+
-------
53+
str
54+
The formatted float in scientific notation at 1 decimal place
55+
"""
56+
return f"{value:.1e}"
57+
58+
def _set_learning_rate(self) -> None:
59+
""" Set the learning rate for the current step """
60+
self._current_lr = self._current_step / self._steps * self._target_lr
61+
K.set_value(self._model.optimizer.lr, self._current_lr)
62+
logger.debug("Learning rate set to %s for step %s/%s",
63+
self._current_lr, self._current_step, self._steps)
64+
65+
def _output_status(self) -> None:
66+
""" Output the progress of Learning Rate Warmup at set intervals """
67+
if self._current_step == 1:
68+
logger.info("[Learning Rate Warmup] Start: %s, Target: %s, Steps: %s",
69+
self._format_notation(self._current_lr),
70+
self._format_notation(self._target_lr), self._steps)
71+
return
72+
73+
if self._current_step == self._steps:
74+
print()
75+
logger.info("[Learning Rate Warmup] Final Learning Rate: %s",
76+
self._format_notation(self._target_lr))
77+
return
78+
79+
if self._current_step in self._reporting_points:
80+
print()
81+
progress = int(round(100 / (len(self._reporting_points) - 1) *
82+
self._reporting_points.index(self._current_step), 0))
83+
logger.info("[Learning Rate Warmup] Step: %s/%s (%s), Current: %s, Target: %s",
84+
self._current_step,
85+
self._steps,
86+
f"{progress}%",
87+
self._format_notation(self._current_lr),
88+
self._format_notation(self._target_lr))
89+
90+
def __call__(self) -> None:
91+
""" If a learning rate update is required, update the model's learning rate, otherwise
92+
do nothing """
93+
if self._steps == 0 or self._current_step >= self._steps:
94+
return
95+
96+
self._current_step += 1
97+
self._set_learning_rate()
98+
self._output_status()
373 Bytes
Binary file not shown.

locales/kr/LC_MESSAGES/lib.cli.args_train.po

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ msgid ""
77
msgstr ""
88
"Project-Id-Version: \n"
99
"Report-Msgid-Bugs-To: \n"
10-
"POT-Creation-Date: 2024-03-28 18:04+0000\n"
11-
"PO-Revision-Date: 2024-03-28 18:16+0000\n"
10+
"POT-Creation-Date: 2025-11-21 17:32+0000\n"
11+
"PO-Revision-Date: 2025-11-21 17:47+0000\n"
1212
"Last-Translator: \n"
1313
"Language-Team: \n"
1414
"Language: ko_KR\n"
1515
"MIME-Version: 1.0\n"
1616
"Content-Type: text/plain; charset=UTF-8\n"
1717
"Content-Transfer-Encoding: 8bit\n"
1818
"Plural-Forms: nplurals=1; plural=0;\n"
19-
"X-Generator: Poedit 3.4.2\n"
19+
"X-Generator: Poedit 3.6\n"
2020

2121
#: lib/cli/args_train.py:30
2222
msgid ""
@@ -157,8 +157,8 @@ msgstr ""
157157
"성 옵션이 있을 수 있습니다."
158158

159159
#: lib/cli/args_train.py:147 lib/cli/args_train.py:160
160-
#: lib/cli/args_train.py:175 lib/cli/args_train.py:191
161-
#: lib/cli/args_train.py:200
160+
#: lib/cli/args_train.py:174 lib/cli/args_train.py:186
161+
#: lib/cli/args_train.py:202 lib/cli/args_train.py:211
162162
msgid "training"
163163
msgstr "훈련"
164164

@@ -187,7 +187,15 @@ msgstr ""
187187
"다. 그러나 설정된 반복 횟수에서 모델이 자동으로 중지되도록 하려면 여기에서 해"
188188
"당 값을 설정할 수 있습니다."
189189

190-
#: lib/cli/args_train.py:177
190+
#: lib/cli/args_train.py:176
191+
msgid ""
192+
"Learning rate warmup. Linearly increase the learning rate from 0 to the "
193+
"chosen target rate over the number of iterations given here. 0 to disable."
194+
msgstr ""
195+
"학습률 워밍업. 여기에 주어진 반복 횟수에 따라 학습률을 0에서 선택한 목표 속도"
196+
"까지 선형적으로 증가시킵니다. 0으로 설정하면 비활성화됩니다."
197+
198+
#: lib/cli/args_train.py:188
191199
msgid ""
192200
"R|Select the distribution stategy to use.\n"
193201
"L|default: Use Tensorflow's default distribution strategy.\n"
@@ -208,15 +216,15 @@ msgstr ""
208216
"L|mirrored: 여러 로컬 GPU에서 동기화 분산 훈련을 지원합니다. 모델의 복사본과 "
209217
"모든 변수는 각 반복에서 각 GPU에 배포된 배치들와 함께 각 GPU에 로드됩니다."
210218

211-
#: lib/cli/args_train.py:193
219+
#: lib/cli/args_train.py:204
212220
msgid ""
213221
"Disables TensorBoard logging. NB: Disabling logs means that you will not be "
214222
"able to use the graph or analysis for this session in the GUI."
215223
msgstr ""
216224
"텐서보드 로깅을 비활성화합니다. 주의: 로그를 비활성화하면 GUI에서 이 세션에 "
217225
"대한 그래프 또는 분석을 사용할 수 없습니다."
218226

219-
#: lib/cli/args_train.py:202
227+
#: lib/cli/args_train.py:213
220228
msgid ""
221229
"Use the Learning Rate Finder to discover the optimal learning rate for "
222230
"training. For new models, this will calculate the optimal learning rate for "
@@ -229,28 +237,28 @@ msgstr ""
229237
"때 발견된 최적의 학습률을 사용합니다. 이 옵션을 설정하면 수동으로 구성된 학습"
230238
"률(기차 설정에서 구성 가능)이 무시됩니다."
231239

232-
#: lib/cli/args_train.py:215 lib/cli/args_train.py:225
240+
#: lib/cli/args_train.py:226 lib/cli/args_train.py:236
233241
msgid "Saving"
234242
msgstr "저장"
235243

236-
#: lib/cli/args_train.py:216
244+
#: lib/cli/args_train.py:227
237245
msgid "Sets the number of iterations between each model save."
238246
msgstr "각 모델 저장 사이의 반복 횟수를 설정합니다."
239247

240-
#: lib/cli/args_train.py:227
248+
#: lib/cli/args_train.py:238
241249
msgid ""
242250
"Sets the number of iterations before saving a backup snapshot of the model "
243251
"in it's current state. Set to 0 for off."
244252
msgstr ""
245253
"현재 상태에서 모델의 백업 스냅샷을 저장하기 전에 반복할 횟수를 설정합니다. 0"
246254
"으로 설정하면 꺼집니다."
247255

248-
#: lib/cli/args_train.py:234 lib/cli/args_train.py:246
249-
#: lib/cli/args_train.py:258
256+
#: lib/cli/args_train.py:245 lib/cli/args_train.py:257
257+
#: lib/cli/args_train.py:269
250258
msgid "timelapse"
251259
msgstr "타임랩스"
252260

253-
#: lib/cli/args_train.py:236
261+
#: lib/cli/args_train.py:247
254262
msgid ""
255263
"Optional for creating a timelapse. Timelapse will save an image of your "
256264
"selected faces into the timelapse-output folder at every save iteration. "
@@ -263,7 +271,7 @@ msgstr ""
263271
"랩스를 만드는 데 사용할 'A' 얼굴의 입력 폴더여야 합니다. 또한 사용자는 --"
264272
"timelapse-output 및 --timelapse-input-B 매개 변수를 제공해야 합니다."
265273

266-
#: lib/cli/args_train.py:248
274+
#: lib/cli/args_train.py:259
267275
msgid ""
268276
"Optional for creating a timelapse. Timelapse will save an image of your "
269277
"selected faces into the timelapse-output folder at every save iteration. "
@@ -276,7 +284,7 @@ msgstr ""
276284
"다. 타임 랩스를 만드는 데 사용할 'B' 얼굴의 입력 폴더여야 합니다. 또한 사용자"
277285
"는 --timelapse-output 및 --timelapse-input-A 매개 변수를 제공해야 합니다."
278286

279-
#: lib/cli/args_train.py:260
287+
#: lib/cli/args_train.py:271
280288
msgid ""
281289
"Optional for creating a timelapse. Timelapse will save an image of your "
282290
"selected faces into the timelapse-output folder at every save iteration. If "
@@ -288,27 +296,27 @@ msgstr ""
288296
"다. 입력 폴더가 제공되었지만 출력 폴더가 없는 경우 모델 폴더에/timelapse/로 "
289297
"기본 설정됩니다"
290298

291-
#: lib/cli/args_train.py:269 lib/cli/args_train.py:276
299+
#: lib/cli/args_train.py:280 lib/cli/args_train.py:287
292300
msgid "preview"
293301
msgstr "미리보기"
294302

295-
#: lib/cli/args_train.py:270
303+
#: lib/cli/args_train.py:281
296304
msgid "Show training preview output. in a separate window."
297305
msgstr "훈련 미리보기 결과를 각기 다른 창에서 보여줍니다."
298306

299-
#: lib/cli/args_train.py:278
307+
#: lib/cli/args_train.py:289
300308
msgid ""
301309
"Writes the training result to a file. The image will be stored in the root "
302310
"of your FaceSwap folder."
303311
msgstr ""
304312
"훈련 결과를 파일에 씁니다. 이미지는 Faceswap 폴더의 최상위 폴더에 저장됩니다."
305313

306-
#: lib/cli/args_train.py:285 lib/cli/args_train.py:295
307-
#: lib/cli/args_train.py:305 lib/cli/args_train.py:315
314+
#: lib/cli/args_train.py:296 lib/cli/args_train.py:306
315+
#: lib/cli/args_train.py:316 lib/cli/args_train.py:326
308316
msgid "augmentation"
309317
msgstr "보정"
310318

311-
#: lib/cli/args_train.py:287
319+
#: lib/cli/args_train.py:298
312320
msgid ""
313321
"Warps training faces to closely matched Landmarks from the opposite face-set "
314322
"rather than randomly warping the face. This is the 'dfaker' way of doing "
@@ -317,7 +325,7 @@ msgstr ""
317325
"무작위로 얼굴을 변환하지 않고 반대쪽 얼굴 세트에서 특징점과 밀접하게 일치하도"
318326
"록 훈련 얼굴을 변환해줍니다. 이것은 변환하는 'dfaker' 방식이다."
319327

320-
#: lib/cli/args_train.py:297
328+
#: lib/cli/args_train.py:308
321329
msgid ""
322330
"To effectively learn, a random set of images are flipped horizontally. "
323331
"Sometimes it is desirable for this not to occur. Generally this should be "
@@ -327,7 +335,7 @@ msgstr ""
327335
"런 일이 일어나지 않는 것이 바람직합니다. 일반적으로 'fit training' 중을 제외"
328336
"하고는 이 작업을 중단해야 합니다."
329337

330-
#: lib/cli/args_train.py:307
338+
#: lib/cli/args_train.py:318
331339
msgid ""
332340
"Color augmentation helps make the model less susceptible to color "
333341
"differences between the A and B sets, at an increased training time cost. "
@@ -337,7 +345,7 @@ msgstr ""
337345
"이 되며, 훈련 시간 비용이 증가합니다. 색상 보저를 사용하지 않으려면 이 옵션"
338346
"을 사용합니다."
339347

340-
#: lib/cli/args_train.py:317
348+
#: lib/cli/args_train.py:328
341349
msgid ""
342350
"Warping is integral to training the Neural Network. This option should only "
343351
"be enabled towards the very end of training to try to bring out more detail. "

0 commit comments

Comments
 (0)