New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature Request] Augementation config file #415
Comments
Yes, I intended to add that probably in the version after 0.3.0 (i.e. after the next release). |
@aleju I actually did pretty much like this with my text generator. Here is my code (which is definitely very messy :P), hope this could help def process_list_augment(input_list, cval, random_state, is_binary):
"""Convert dictionary augmentation configs into augmentation object"""
current_pipeline = []
for _, each in enumerate(input_list):
function_name = next(iter(each))
augment_param = each[function_name]
if isinstance(augment_param, list):
prob = 1
for each_element in augment_param:
if isinstance(each_element, dict) and 'prob' in each_element.keys():
prob = each_element['prob']
augment_param.remove(each_element)
break
big_object = None
if function_name == 'Sequential':
for each_element in augment_param:
if isinstance(each_element, dict) and 'random_order' in each_element.keys():
random_order = each_element['random_order']
augment_param.remove(each_element)
big_object = iaa.Sequential(process_list_augment(
input_list=augment_param, cval=cval,
random_state=random_state, is_binary=is_binary), random_order=random_order, random_state=random_state)
elif function_name == 'SomeOf':
for each_element in augment_param:
if isinstance(each_element, dict) and 'n' in each_element.keys():
n = each_element['n']
augment_param.remove(each_element)
big_object = iaa.SomeOf(literal_eval(n), process_list_augment(
input_list=augment_param, cval=cval, random_state=random_state, is_binary=is_binary), random_state=random_state)
elif function_name == 'OneOf':
big_object = iaa.OneOf(process_list_augment(
input_list=augment_param, cval=cval, random_state=random_state, is_binary=is_binary), random_state=random_state)
if prob:
big_object = iaa.Sometimes(
prob, big_object, random_state=random_state)
current_pipeline.append(big_object)
elif isinstance(augment_param, dict):
prob = augment_param.pop('prob', None)
for key, value in augment_param.items():
if isinstance(value, str) and value[0] == '(' and value[-1] == ')' and len(value) > 2:
augment_param[key] = literal_eval(value)
try:
augment_function = getattr(iaa, function_name)
except AttributeError:
print(function_name, 'not found in imgaug lib, using custom')
augment_function = globals()[function_name]
required_param = list(inspect.getargspec(augment_function))[0]
if 'cval' in required_param:
augment_param['cval'] = cval
if 'is_binary' in required_param:
augment_param['is_binary'] = is_binary
augment_param['random_state'] = random_state
augment_object = augment_function(**augment_param)
if prob is not None:
augment_object = iaa.Sometimes(
prob, augment_object, random_state=random_state)
current_pipeline.append(augment_object)
return current_pipeline |
Also, here is what my augmentation_pipeline:
- Sequential:
- random_order: False
- ItalicizeLine:
prob: 0.3
- RotateLine:
prob: 0.3
- OneOf:
- Pad:
percent: ((0.05, 0.2),(0.05, 0.2),(0.05, 0.2),(0.05, 0.2))
pad_mode: constant
pad_cval: 1
- Pad:
px: ((0, 50), (0, 300), (0, 50), (0, 300))
pad_mode: constant
pad_cval: 1
- TransformPerspective:
prob: 0.3
scale: (0.1, 0.25)
keep_size: False
- ElasticTransformation:
prob: 0.3
alpha: (0, 1.5)
sigma: (0.4, 0.6)
- Skeletonize:
prob: 0.02
- Invert:
p: 0.1
max_value: 1 I can submit a PR, but I don't know where to start injecting my function yet @aleju :P |
Writing a proper config parsing method (or a few of them, one per augmenter) is not that straight forward and has quite some requirements, mainly:
It's not that hard to quickly come up with a parsing method. But it is equally easy to violate one or more of the above points and then e.g. suddenly spend ages of time writing unittests for dozens of augmenters. |
Damn :P. Sound kind da overwhelming for me lul |
You could break your code down into 2 or more modules, one of them being your configuration data (ie, the constructed sequence), and then import it into your main script. |
I think I did something that fulfills the requirements (proof of concept, not PR right now) ... Right now it is able to generate the example labelled "Heavy Augmentations" in the documentation (https://imgaug.readthedocs.io/en/latest/source/examples_basics.html) by using an equivalent yaml file: https://gist.github.com/jspaezp/6152733a644b8f6fe9b985b58c856997#file-complex_yaml_001-yaml only requiring to define the It more accurately parses the yaml and given a series of locations (similar to a PATH on the system level), looks for the names that match callable elements and greedily does the call. https://gist.github.com/jspaezp/6152733a644b8f6fe9b985b58c856997#file-yaml_parser-py right now I'm testing it with pytest and works fine, there is definitely some more work to do regarding unit tests, since I don't really know how to test if two augmenters are equivalent let me know what you think. |
Any updates on this issue? |
It would be great to be able to define augmentation using some kind of config file. I imagine YAML would for well. For example a config file could look like:
The text was updated successfully, but these errors were encountered: