Код: Выделить всё
python3 train.py --width 128 --height 64 --length 4 --symbols symbols.txt --batch-size 32 --epochs 1 --output-model test --train-dataset training_data --validate-dataset validation_data
Length of captcha symbols 36
Metal device set to: Apple M3
systemMemory: 16.00 GB
maxCacheSize: 5.33 GB
2024-09-28 15:26:54.529594: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support.
2024-09-28 15:26:54.529683: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:271] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: )
input_shape: (64, 128, 3)
Model: "model"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_1 (InputLayer) [(None, 64, 128, 3) 0 []
]
conv2d (Conv2D) (None, 64, 128, 32) 896 ['input_1[0][0]']
batch_normalization (BatchNorm (None, 64, 128, 32) 128 ['conv2d[0][0]']
alization)
activation (Activation) (None, 64, 128, 32) 0 ['batch_normalization[0][0]']
conv2d_1 (Conv2D) (None, 64, 128, 32) 9248 ['activation[0][0]']
batch_normalization_1 (BatchNo (None, 64, 128, 32) 128 ['conv2d_1[0][0]']
rmalization)
activation_1 (Activation) (None, 64, 128, 32) 0 ['batch_normalization_1[0][0]']
max_pooling2d (MaxPooling2D) (None, 32, 64, 32) 0 ['activation_1[0][0]']
conv2d_2 (Conv2D) (None, 32, 64, 64) 18496 ['max_pooling2d[0][0]']
batch_normalization_2 (BatchNo (None, 32, 64, 64) 256 ['conv2d_2[0][0]']
rmalization)
activation_2 (Activation) (None, 32, 64, 64) 0 ['batch_normalization_2[0][0]']
conv2d_3 (Conv2D) (None, 32, 64, 64) 36928 ['activation_2[0][0]']
batch_normalization_3 (BatchNo (None, 32, 64, 64) 256 ['conv2d_3[0][0]']
rmalization)
activation_3 (Activation) (None, 32, 64, 64) 0 ['batch_normalization_3[0][0]']
max_pooling2d_1 (MaxPooling2D) (None, 16, 32, 64) 0 ['activation_3[0][0]']
conv2d_4 (Conv2D) (None, 16, 32, 128) 73856 ['max_pooling2d_1[0][0]']
batch_normalization_4 (BatchNo (None, 16, 32, 128) 512 ['conv2d_4[0][0]']
rmalization)
activation_4 (Activation) (None, 16, 32, 128) 0 ['batch_normalization_4[0][0]']
conv2d_5 (Conv2D) (None, 16, 32, 128) 147584 ['activation_4[0][0]']
batch_normalization_5 (BatchNo (None, 16, 32, 128) 512 ['conv2d_5[0][0]']
rmalization)
activation_5 (Activation) (None, 16, 32, 128) 0 ['batch_normalization_5[0][0]']
max_pooling2d_2 (MaxPooling2D) (None, 8, 16, 128) 0 ['activation_5[0][0]']
conv2d_6 (Conv2D) (None, 8, 16, 256) 295168 ['max_pooling2d_2[0][0]']
batch_normalization_6 (BatchNo (None, 8, 16, 256) 1024 ['conv2d_6[0][0]']
rmalization)
activation_6 (Activation) (None, 8, 16, 256) 0 ['batch_normalization_6[0][0]']
conv2d_7 (Conv2D) (None, 8, 16, 256) 590080 ['activation_6[0][0]']
batch_normalization_7 (BatchNo (None, 8, 16, 256) 1024 ['conv2d_7[0][0]']
rmalization)
activation_7 (Activation) (None, 8, 16, 256) 0 ['batch_normalization_7[0][0]']
max_pooling2d_3 (MaxPooling2D) (None, 4, 8, 256) 0 ['activation_7[0][0]']
conv2d_8 (Conv2D) (None, 4, 8, 256) 590080 ['max_pooling2d_3[0][0]']
batch_normalization_8 (BatchNo (None, 4, 8, 256) 1024 ['conv2d_8[0][0]']
rmalization)
activation_8 (Activation) (None, 4, 8, 256) 0 ['batch_normalization_8[0][0]']
conv2d_9 (Conv2D) (None, 4, 8, 256) 590080 ['activation_8[0][0]']
batch_normalization_9 (BatchNo (None, 4, 8, 256) 1024 ['conv2d_9[0][0]']
rmalization)
activation_9 (Activation) (None, 4, 8, 256) 0 ['batch_normalization_9[0][0]']
max_pooling2d_4 (MaxPooling2D) (None, 2, 4, 256) 0 ['activation_9[0][0]']
flatten (Flatten) (None, 2048) 0 ['max_pooling2d_4[0][0]']
char_1 (Dense) (None, 36) 73764 ['flatten[0][0]']
char_2 (Dense) (None, 36) 73764 ['flatten[0][0]']
char_3 (Dense) (None, 36) 73764 ['flatten[0][0]']
char_4 (Dense) (None, 36) 73764 ['flatten[0][0]']
==================================================================================================
Total params: 2,653,360
Trainable params: 2,650,416
Non-trainable params: 2,944
__________________________________________________________________________________________________
Batch X shape: (32, 64, 128, 3)
Batch y shape: [(32, 36), (32, 36), (32, 36), (32, 36)]
Count 0 list(self.files.keys()) value ['N5R5', 'IZJO', 'I8CB', 'NZ9O']
IZJO
Count 1 list(self.files.keys()) value ['N5R5', 'I8CB', 'NZ9O']
N5R5
Count 2 list(self.files.keys()) value ['I8CB', 'NZ9O']
I8CB
Count 3 list(self.files.keys()) value ['NZ9O']
NZ9O
Count 4 list(self.files.keys()) value []
2024-09-28 15:26:54.847798: W tensorflow/core/platform/profile_utils/cpu_utils.cc:128] Failed to get CPU frequency: 0 Hz
Traceback (most recent call last):
File "/train.py", line 194, in
main()
File "/train.py", line 185, in main
model.fit(training_data,
File "/opt/anaconda3/envs/tf/lib/python3.9/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler
raise e.with_traceback(filtered_tb) from None
File "/opt/anaconda3/envs/tf/lib/python3.9/site-packages/keras/engine/training.py", line 1420, in fit
raise ValueError('Unexpected result of `train_function` '
ValueError: Unexpected result of `train_function` (Empty logs). Please use `Model.compile(..., run_eagerly=True)`, or `tf.config.run_functions_eagerly(True)` for more information of where went wrong, or file a issue/bug to `tf.keras`.
Код: Выделить всё
import os
import cv2
import numpy
import random
import argparse
import tensorflow as tf
# Build a Keras model given some parameters
def create_model(captcha_length, captcha_num_symbols, input_shape, model_depth=5, module_size=2):
print(f"input_shape: {input_shape}") # After loading the batch
input_tensor = tf.keras.Input(input_shape)
x = input_tensor
for i, module_length in enumerate([module_size] * model_depth):
for j in range(module_length):
x = tf.keras.layers.Conv2D((32*2**min(i,3)), kernel_size=3, padding='same', kernel_initializer='he_uniform')(x)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.Activation('relu')(x)
x = tf.keras.layers.MaxPooling2D(2)(x)
x = tf.keras.layers.Flatten()(x)
x = [tf.keras.layers.Dense(captcha_num_symbols, activation='softmax', name='char_%d'%(i+1))(x) for i in range(captcha_length)]
model = tf.keras.Model(inputs=input_tensor, outputs=x)
return model
class ImageSequence(tf.keras.utils.Sequence):
def __init__(self, directory_name, batch_size, captcha_length, captcha_symbols, captcha_width, captcha_height):
self.directory_name = directory_name
self.batch_size = batch_size
self.captcha_length = captcha_length
self.captcha_symbols = captcha_symbols
self.captcha_width = captcha_width
self.captcha_height = captcha_height
file_list = os.listdir(self.directory_name)
self.files = dict(zip(map(lambda x: x.split('.')[0], file_list), file_list))
self.used_files = []
self.count = len(file_list)
def __len__(self):
return int(numpy.floor(self.count / self.batch_size))
def __getitem__(self, idx):
X = numpy.zeros((self.batch_size, self.captcha_height, self.captcha_width, 3), dtype=numpy.float32)
y = [numpy.zeros((self.batch_size, len(self.captcha_symbols)), dtype=numpy.uint8) for i in range(self.captcha_length)]
# Add print statements to verify the data
print(f"Batch X shape: {X.shape}")
print(f"Batch y shape: {[yi.shape for yi in y]}")
for i in range(self.batch_size):
print("Count", i, "list(self.files.keys()) value", list(self.files.keys()))
if i == self.count:
break
random_image_label = random.choice(list(self.files.keys()))
print(random_image_label)
random_image_file = self.files[random_image_label]
# We've used this image now, so we can't repeat it in this iteration
self.used_files.append(self.files.pop(random_image_label))
# We have to scale the input pixel values to the range [0, 1] for
# Keras so we divide by 255 since the image is 8-bit RGB
raw_data = cv2.imread(os.path.join(self.directory_name, random_image_file))
rgb_data = cv2.cvtColor(raw_data, cv2.COLOR_BGR2RGB)
processed_data = numpy.array(rgb_data) / 255.0
X[i] = processed_data
# We have a little hack here - we save captchas as TEXT_num.png if there is more than one captcha with the text "TEXT"
# So the real label should have the "_num" stripped out.
random_image_label = random_image_label.split('_')[0]
if len(random_image_label) != self.captcha_length:
raise ValueError(f"Expected CAPTCHA length {self.captcha_length}, but got {len(random_image_label)} for image: {random_image_file}")
for j, ch in enumerate(random_image_label):
symbol_index = self.captcha_symbols.find(ch)
if symbol_index == -1:
raise ValueError(f"Character '{ch}' in CAPTCHA not found in symbols: {self.captcha_symbols}")
y[j][i, :] = 0
y[j][i, self.captcha_symbols.find(ch)] = 1
return X, y
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--width', help='Width of captcha image', type=int)
parser.add_argument('--height', help='Height of captcha image', type=int)
parser.add_argument('--length', help='Length of captchas in characters', type=int)
parser.add_argument('--batch-size', help='How many images in training captcha batches', type=int)
parser.add_argument('--train-dataset', help='Where to look for the training image dataset', type=str)
parser.add_argument('--validate-dataset', help='Where to look for the validation image dataset', type=str)
parser.add_argument('--output-model-name', help='Where to save the trained model', type=str)
parser.add_argument('--input-model', help='Where to look for the input model to continue training', type=str)
parser.add_argument('--epochs', help='How many training epochs to run', type=int)
parser.add_argument('--symbols', help='File with the symbols to use in captchas', type=str)
args = parser.parse_args()
if args.width is None:
print("Please specify the captcha image width")
exit(1)
if args.height is None:
print("Please specify the captcha image height")
exit(1)
if args.length is None:
print("Please specify the captcha length")
exit(1)
if args.batch_size is None:
print("Please specify the training batch size")
exit(1)
if args.epochs is None:
print("Please specify the number of training epochs to run")
exit(1)
if args.train_dataset is None:
print("Please specify the path to the training data set")
exit(1)
if args.validate_dataset is None:
print("Please specify the path to the validation data set")
exit(1)
if args.output_model_name is None:
print("Please specify a name for the trained model")
exit(1)
if args.symbols is None:
print("Please specify the captcha symbols file")
exit(1)
captcha_symbols = None
with open(args.symbols) as symbols_file:
captcha_symbols = symbols_file.readline()
print("Length of captcha symbols", len(captcha_symbols))
physical_devices = tf.config.experimental.list_physical_devices('GPU')
assert len(physical_devices) > 0, "No GPU available!"
tf.config.experimental.set_memory_growth(physical_devices[0], True)
with tf.device('/device:GPU:0'):
# with tf.device('/device:CPU:0'):
# with tf.device('/device:XLA_CPU:0'):
model = create_model(args.length, len(captcha_symbols), (args.height, args.width, 3))
if args.input_model is not None:
model.load_weights(args.input_model)
model.compile(loss='sparse_categorical_crossentropy',
optimizer=tf.keras.optimizers.Adam(1e-3, amsgrad=True),
metrics=['accuracy'],
run_eagerly=True)
model.summary()
training_data = ImageSequence(args.train_dataset, args.batch_size, args.length, captcha_symbols, args.width, args.height)
validation_data = ImageSequence(args.validate_dataset, args.batch_size, args.length, captcha_symbols, args.width, args.height)
callbacks = [tf.keras.callbacks.EarlyStopping(patience=3),
tf.keras.callbacks.CSVLogger('log.csv'),
tf.keras.callbacks.ModelCheckpoint(args.output_model_name+'.keras', save_best_only=False)]
with open(args.output_model_name+".json", "w") as json_file:
json_file.write(model.to_json())
try:
model.fit(training_data,
validation_data=validation_data,
epochs=args.epochs,
verbose=1)
except KeyboardInterrupt:
print('KeyboardInterrupt caught, saving current weights as ' + args.output_model_name+'_resume.h5')
model.save_weights(args.output_model_name+'_resume.h5')
if __name__ == '__main__':
main()
Код: Выделить всё
ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
Подробнее здесь: https://stackoverflow.com/questions/790 ... n-function