Skip to main content
Version: 10.3.2

Create AutoML SDK configuration

AutoML SDK configuration is a Java Spring-like set of definitions for AutoML SDK components: Annotators, Feature Extractors, Post-Processors, and so on. The configuration is created declaratively using Java annotations. There are two primary annotations (similar to Spring @Configuration and @Bean annotations accordingly):

  • @ModelConfiguration indicates that the annotated class is used as a source of component definitions.

  • @Named declares a component and tells that a method returns an actual component that should be registered in ComponentRegistry.

The @ModelConfiguration-annotated class can have a declaration for more than one @Named. Once your classes are defined, you can use the configuration for model training.

Basic configuration

The basic configuration involves the following:

  1. Use @ModelConfiguration to declare a class as a configuration instance.
  2. Add the @HypermodelConfiguration main configuration class to the hyper model declaration.
@ModelConfiguration
public class ExampleConfiguration {
}

@HypermodelConfiguration(ExampleConfiguration.class)
public class ExampleHypermodel extends GenericIeHypermodel {

public ExampleHypermodel() throws Exception {
super();
}

}

Note that the example above extends the default GenericIeHypermodel configuration. You can change this during the Archetype generation by specifying the importConfigurationFromGenericModel parameter.

Component configuration

To declare one or multiple AutoML SDK components, use @Named annotation with a string value to attach a name identifier to a component. Note that @Named can return a single component or a list of components. Components are recognized based on the response type.

The following example declares three named components: basePostProcessors, featureExtractors, and a list of annotators.

import java.util.ArrayList;
import java.util.List;

import com.workfusion.vds.sdk.api.hypermodel.annotation.ModelConfiguration;
import com.workfusion.vds.sdk.api.hypermodel.annotation.Named;
import com.workfusion.vds.sdk.api.nlp.annotator.Annotator;
import com.workfusion.vds.sdk.api.nlp.fe.FeatureExtractor;
import com.workfusion.vds.sdk.api.nlp.model.Cell;
import com.workfusion.vds.sdk.api.nlp.model.Element;
import com.workfusion.vds.sdk.api.nlp.model.IeDocument;
import com.workfusion.vds.sdk.api.nlp.processing.Processor;
import com.workfusion.vds.sdk.nlp.component.annotator.EntityBoundaryAnnotator;
import com.workfusion.vds.sdk.nlp.component.annotator.tokenizer.SplitterTokenAnnotator;
import com.workfusion.vds.sdk.nlp.component.fe.ner.IsFirstNerInFocusElementFE;
import com.workfusion.vds.sdk.nlp.component.processing.grouping.RowBasedGroupingProcessor;

@ModelConfiguration
public class ExampleConfiguration {

@Named("basePostProcessors")
public Processor<IeDocument> postProcessors() {
return new RowBasedGroupingProcessor();
}

@Named("featureExtractors")
public FeatureExtractor<Element> featureExtractors() {
return new IsFirstNerInFocusElementFE(Cell.class);
}

@Named("annotators")
public List<Annotator> annotators() {
List<Annotator> annotators = new ArrayList<>();
annotators.add(new SplitterTokenAnnotator("\\s+"));
annotators.add(new EntityBoundaryAnnotator());
return annotators;
}

}

The result of this configuration is as follows:

  • Post-Processor from basePostProcessors
  • Feature Extractor from featureExtractors
  • Two Annotators from annotators

For advanced configuration components, refer to the Advanced configuration components section.

ConfigurationContext

ConfigurationContext is an interface that provides a map of initial configuration parameters and a reference to a Field object. The Field value is used to specify the settings for a specific sub-model configuration, for example, to apply specific annotators only to the field of the ADDRESS type.

For information extraction models,@Named methods can accept a ConfigurationContext or IeConfigurationContext object.

ConfigurationContex and IeConfigurationContext contain methods to access different properties. The most common property is FieldInfo: a class for information extraction containing information about the current sub-modelconfiguration. With the property, one @Named method can produce different sets of AutoML SDK components for different sub-models using a switch case or an if-else statement.

The following ConfigurationContext methods are considered the most useful:

For a full list of methods, refer to the ConfigurationContext documentation.

getField

getField gets the FieldInfo associated with the current sub-model configuration. For the ConfigurationContext that isn't related to a particular field, getField returns empty FieldInfo with code by default.

FieldInfo getField()

The following example contains an IeConfigurationContext object. In this case, each AutoML SDK configuration produces a different set of Annotators, depending on the code type: invoice_number or address.

import java.util.ArrayList;
import java.util.List;

import com.workfusion.vds.sdk.api.hypermodel.annotation.ModelConfiguration;
import com.workfusion.vds.sdk.api.hypermodel.annotation.Named;
import com.workfusion.vds.sdk.api.nlp.annotator.Annotator;
import com.workfusion.vds.sdk.api.nlp.configuration.IeConfigurationContext;
import com.workfusion.vds.sdk.nlp.component.annotator.EntityBoundaryAnnotator;
import com.workfusion.vds.sdk.nlp.component.annotator.ner.BaseRegexNerAnnotator;
import com.workfusion.vds.sdk.nlp.component.annotator.tokenizer.SplitterTokenAnnotator;

@ModelConfiguration
public class TrainingIeModelConfiguration {

public static final String REGEX_SPLITTER_TOKEN = "\\s+";
public static final String REGEX_ZIP = "[0-9]{5}(-[0-9]{4,5})?";
public static final String REGEX_CITY = "[A-Z][a-z]{3,18}";
public static final String REGEX_INVOICE_NUMBER = "([\\d]{10,11})";

@Named("annotators")
public List<Annotator> annotators(IeConfigurationContext context) {
List<Annotator> annotators = new ArrayList<>();
annotators.add(new SplitterTokenAnnotator(REGEX_SPLITTER_TOKEN));
annotators.add(new EntityBoundaryAnnotator());

String codeType = context.getField().getCode();
switch (codeType) {
case "invoice_number": {
annotators.add(BaseRegexNerAnnotator.getJavaPatternRegexNerAnnotator("invoice_number", REGEX_INVOICE_NUMBER));
break;
}
case "address": {
annotators.add(BaseRegexNerAnnotator.getJavaPatternRegexNerAnnotator("city", REGEX_CITY));
annotators.add(BaseRegexNerAnnotator.getJavaPatternRegexNerAnnotator("zip", REGEX_ZIP));
break;
}
}
return annotators;
}

}

For more information, refer to the FieldInfo documentation.

getResource

getResource provides a Resource instance for a specified path:

  • Classpath resource, for example, classpath:test.csv
  • Model resource, for example, /ref-data/test.csv/dictionaries/test.csv, /corrections/test.csv
Resource getResource(String path)

Here's an example of getResource usage with a dictionary:

@Named("annotators")
public List<Annotator> annotators(IeConfigurationContext context) {
List<Annotator> annotators = new ArrayList<>();
annotators.add(new AhoCorasickDictionaryNerAnnotator("company_name",
new CsvDictionaryKeywordProvider(context.getResource("/dictionaries/CompanyNames.csv"))));
return annotators;
}

InputStream

In case a Resource instance is provided by an external WorkFusion source, for example, are attached to a Manual Task or use an input stream to read data, apply the try-with-resources construct to ensure that the opened stream is closed at the end of the statement.

InputStream openInputStream()

getParameter

getParameter gets a configuration parameter (for example, parameter name) acquired externally from a WorkFusion service. This parameter can be used for advanced model configuration.

Object getParameter(String name)

For more information, refer to the getParameter() documentation.

ComponentRegistry

ComponentRegistry is an interface to provide access to @Named components as Java Objects. You can get an instance of such an object in a @Named method. Using the interface, you can obtain a component instance by ID or internal return type (for example, FeatureExtactor.class ). In some cases, this can simplify the configuration code.

ComponentRegistry default implementation contains the following methods:

For usage information, refer to the ComponentRegistry documentation.

getComponent

getComponent gets a single component based on a unique component ID.

Component getComponent(String componentName)
ParameterDescription
@componentName@Named component annotation value
@returnSingle component

getComponents

getComponents gets a collection of @Named components based on the return type.

Collection<Component> getComponents(Class<?> type)
ParameterDescription
@typeComponent type
@returnCollection of components
import com.workfusion.vds.nlp.model.configuration.DefaultComponentRegistry;
import com.workfusion.vds.sdk.api.hypermodel.annotation.ModelConfiguration;
import com.workfusion.vds.sdk.api.hypermodel.annotation.Named;
import com.workfusion.vds.sdk.api.nlp.annotator.Annotator;
import com.workfusion.vds.sdk.api.nlp.configuration.IeConfigurationContext;
import com.workfusion.vds.sdk.nlp.component.annotator.ner.BaseRegexNerAnnotator;

@ModelConfiguration
public class Config {

public static final String REGEX_ZIP = "[0-9]{5}(-[0-9]{4,5})?";
public static final String REGEX_CITY = "[A-Z][a-z]{3,18}";
public static final String REGEX_INVOICE_NUMBER = "([\\d]{10,11})";

@Named("a1")
public Annotator a1() {
return BaseRegexNerAnnotator.getJavaPatternRegexNerAnnotator("invoice_number", REGEX_INVOICE_NUMBER);
}

@Named("a2")
public Annotator a2() {
return BaseRegexNerAnnotator.getJavaPatternRegexNerAnnotator("zip", REGEX_ZIP);
}

@Named("a3")
public Annotator a3() {
return BaseRegexNerAnnotator.getJavaPatternRegexNerAnnotator("city", REGEX_CITY);
}

}

Configuration import

To avoid coding a configuration from scratch, you can import one or multiple other configurations into it. In this case, the imported configuration is considered a child, and the target configuration is considered a parent. The resulting configuration contains all components from the child and parent configurations.

To import one or more configurations to another configuration, use the @Import class-level annotation together with @ModelConfiguration. The latter contains a reference to the child configuration class.

import com.workfusion.vds.sdk.api.hypermodel.annotation.Import;
import com.workfusion.vds.sdk.api.hypermodel.annotation.ModelConfiguration;
import com.workfusion.vds.sdk.api.hypermodel.annotation.Named;
import com.workfusion.vds.sdk.api.nlp.processing.Processor;

@ModelConfiguration
class PostProcessorConfig {

@Named("presentationPostProcessor")
public Processor getPostProcessors() {
return new ExamplePostProcessing1();
}

@Named("basePostProcessor")
public Processor postProcessors() {
return new ExamplePostProcessing2();
}

}

@ModelConfiguration
@Import(configurations = {
@Import.Configuration(PostProcessorConfig.class)
})
class GenericPostProcessorConfig {

@Named("basePostProcessor")
public Processor postProcessors() {
return new ExamplePostProcessing3();
}

}

The GenericPostProcessorConfig processing output comprises all named components from the child PostProcessorConfig configuration and all components from the parent GenericPostProcessorConfig one.

note

Both configurations contain a basePostProcessor post-processor. In this case, the component declared in the parent GenericPostProcessorConfig configuration overrides the component with the same name declared in the child PostProcessorConfig one.

The resulting configuration contains the following components:

  •  presentationPostProcessor from PostProcessorConfig
  •  basePostProcessor from GenericPostProcessorConfig

Filtering

When importing a configuration, you can filter out certain components, for instance, sub-child configurations (if any). See the two examples below:

Example 1

There are two configurations, each containing several named components. ChildAnnotatorConfig is imported to ParentAnnotatorConfig with @Filter disabled.

import com.workfusion.vds.sdk.api.hypermodel.annotation.Import;
import com.workfusion.vds.sdk.api.hypermodel.annotation.ModelConfiguration;
import com.workfusion.vds.sdk.api.hypermodel.annotation.Named;
import com.workfusion.vds.sdk.api.nlp.annotator.Annotator;

@ModelConfiguration
class ChildAnnotatorConfig {

@Named("annotatorA")
public Annotator testAnnotatorA() {
return new AnnotatorA();
}

@Named("annotatorB")
public Annotator testAnnotatorB() {
return new AnnotatorB();
}

}

@ModelConfiguration
@Import(configurations = {@Import.Configuration(ChildAnnotatorConfig.class)})
class ParentAnnotatorConfig {

@Named("annotatorC")
public Annotator testAnnotatorC() {
return new AnnotatorC();
}

}

The output is a merge of the child and parent configurations and contains the following components:

  • Optional annotatorA
  • Fixed annotatorB
  • Fixed annotatorC

Example 2

There are two configurations, each containing several named components. ChildAnnotatorConfig is imported to ParentAnnotatorConfig with enabled @Filter. To enable the filter, use @Filter in the @Import annotation.

import com.workfusion.vds.sdk.api.hypermodel.annotation.Filter;
import com.workfusion.vds.sdk.api.hypermodel.annotation.Import;
import com.workfusion.vds.sdk.api.hypermodel.annotation.ModelConfiguration;
import com.workfusion.vds.sdk.api.hypermodel.annotation.Named;
import com.workfusion.vds.sdk.api.nlp.annotator.Annotator;

@ModelConfiguration
class ChildAnnotatorConfig {

@Named("annotatorA")
public Annotator testAnnotatorA() {
return new AnnotatorA();
}

@Named("annotatorB")
public Annotator testAnnotatorB() {
return new AnnotatorB();
}

}

@ModelConfiguration
@Import(configurations = {
@Import.Configuration(value = ChildAnnotatorConfig.class, exclude = {@Filter(type = AnnotatorB.class)}),
})
class ParentAnnotatorConfig {

@Named("annotatorC")
public Annotator testAnnotatorC() {
return new AnnotatorC();
}

}

The resulting configuration contains the following components:

  • Fixed AnnotatorC
  • AnnotatorA or AnnotatorB

Advanced configuration components

Apart from standard components like Annotators, Feature Extractors, and Post-Processors, a model can contain fundamental components for advanced configuration. These components may require a deeper understanding of AutoML SDK.

caution

Any of the following components can be declared only once. Otherwise, errors may occur.

Advanced components include:

  • LiblinearClassifier, Vowpal Wabbit Classifier
  • PipelineConfiguration

LiblinearClassifier and Vowpal Wabbit Classifier

LiblinearClassifier and VWClassifier are utility classes to store possible training arguments of Liblinear and Vowpal Wabbit.

@Named("mlConfig")
public LiblinearClassifier mlConfig(){
return new LiblinearClassifier.Builder()
.solver(Solver.L2R_L2LOSS_SVC)
.quietMode()
.build();
}
warning

Only one classifier at a time can be used in a configuration. Otherwise, errors may occur.

For more information, refer to the LIBSVM and Vowpal Wabbit documentation.

Algorithm extensions

AutoML SDK provides extensions for LiblinearClassifier and some Python-based classifiers, such as AdaBoostClassifier, LinearSupportVectorClassifier, LogisticRegression, RandomForestClassifier. Extensions allow setting value ranges for specific algorithm parameters to select the best ones for model training.

Here's the list of extensions:

  • LiblinearParamGridClassifier
  • AdaBoostParamGridClassifier
  • LinearSupportVectorParamGridClassifier
  • LogisticRegressionParamGridClassifier
  • RandomForestParamGridClassifier

To use an extension, add the mlConfig annotation to your AutoML SDK configuration. Here's an example of using the LiblinearParamGridClassifier extension:

@Named("mlConfig")
public Classifier mlConfig() {
return new LiblinearParamGridClassifier.Builder()
.solver(LiblinearClassifier.Solver.L2R_L2LOSS_SVC)
.quietMode()
.cost(new RealMultipliedRange(Math.pow(2, -3), Math.pow(2, 6), 2))
.solverTypes(ImmutableList.of(
LiblinearClassifier.Solver.L2R_L2LOSS_SVC,
LiblinearClassifier.Solver.L2R_L1LOSS_SVC_DUAL,
LiblinearClassifier.Solver.L1R_L2LOSS_SVC))
.build();
}

Also, see this example of using LinearSupportVectorParamGridClassifier:

@Named("mlConfig")
public Classifier mlConfig() {
return new LinearSupportVectorParamGridClassifier.Builder()
.maxIterationsRange(new DiscreteMultipliedRange(2, 8, 2))
.seed(123)
.build();
}

ParamGridClassifier implementations have extra utilities, such as DiscreteMultipliedRange, DiscreteRange, RealMultipliedRange, RealRange to specify the ranges of parameters for different data types (Integer, Double, and so on) and steps to generate arithmetic or geometric sequence.

Below is an example of using RealMultipliedRange that produces the [1/8, 1/4, 1/2, 1, 2, 4, 8, 16, 32, 64] range:

new RealMultipliedRange(Math.pow(2, -3), Math.pow(2, 6), 2)

Here's an example of using DiscreteRange that produces the [100, 200, 300, 500] range:

new DiscreteRange(100, 500, 100)
warning

It is recommended to use ParamGridClassifier extensions only for local model training, not for production. The selection of algorithm parameters is a time-consuming operation that can dramatically affect model training time.

PipelineConfiguration

PipelineConfiguration is a set of parameters for building a pipeline. The defined parameters remain unchanged across all configurations created for experiments.

The following pipelineConfiguration example sets the NORMALIZE_SCORE and CASE_SENSITIVE parameters to true.

@Named("pipelineConfiguration")
public PipelineConfiguration pipelineConfiguration() {
return new PipelineConfiguration.Builder()
.parameter(GenericPipelineConfiguration.NORMALIZE_SCORE, true)
.parameter(GenericPipelineConfiguration.CASE_SENSITIVE, true)
.build();
}

For more information, refer to the PipelineConfiguration and GenericPipelineConfiguration documentation.