You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opennlp.apache.org by jz...@apache.org on 2023/10/31 13:10:54 UTC
(opennlp) branch main updated: OPENNLP-1384: The document categorizer can read labels from a model's config.json (#553)
This is an automated email from the ASF dual-hosted git repository.
jzemerick pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opennlp.git
The following commit(s) were added to refs/heads/main by this push:
new e652c8e3 OPENNLP-1384: The document categorizer can read labels from a model's config.json (#553)
e652c8e3 is described below
commit e652c8e3af5044ed08c212aca65205a83c0e080b
Author: Jeff Zemerick <13...@users.noreply.github.com>
AuthorDate: Tue Oct 31 09:10:48 2023 -0400
OPENNLP-1384: The document categorizer can read labels from a model's config.json (#553)
* OPENNLP-1384: The document categorizer can read labels from a model's config.json
* OPENNLP-1384: Adding new line to NOTICE and making map readonly.
---
NOTICE | 6 ++
opennlp-dl/pom.xml | 5 ++
.../dl/doccat/DocumentCategorizerConfig.java | 35 ++++++++++
.../opennlp/dl/doccat/DocumentCategorizerDL.java | 79 ++++++++++++++++------
.../dl/doccat/DocumentCategorizerDLEval.java | 66 ++++++++++++++----
pom.xml | 1 +
6 files changed, 157 insertions(+), 35 deletions(-)
diff --git a/NOTICE b/NOTICE
index a0a2c3eb..5897a68a 100644
--- a/NOTICE
+++ b/NOTICE
@@ -93,3 +93,9 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+============================================================================
+
+jackson-databind
+https://github.com/FasterXML/jackson-databind
+The Apache Software License, Version 2.0
diff --git a/opennlp-dl/pom.xml b/opennlp-dl/pom.xml
index dafff563..9fec4798 100644
--- a/opennlp-dl/pom.xml
+++ b/opennlp-dl/pom.xml
@@ -41,6 +41,11 @@
<artifactId>onnxruntime</artifactId>
<version>${onnxruntime.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
diff --git a/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerConfig.java b/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerConfig.java
new file mode 100644
index 00000000..8e6d04e2
--- /dev/null
+++ b/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerConfig.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package opennlp.dl.doccat;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class DocumentCategorizerConfig {
+
+ private Map<String, String> id2label;
+
+ public Map<String, String> getId2label() {
+ return Collections.unmodifiableMap(id2label);
+ }
+
+ public void setId2label(Map<String, String> id2label) {
+ this.id2label = id2label;
+ }
+
+}
diff --git a/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerDL.java b/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerDL.java
index b4f5caa5..a06d4b09 100644
--- a/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerDL.java
+++ b/opennlp-dl/src/main/java/opennlp/dl/doccat/DocumentCategorizerDL.java
@@ -20,6 +20,7 @@ package opennlp.dl.doccat;
import java.io.File;
import java.io.IOException;
import java.nio.LongBuffer;
+import java.nio.file.Files;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -35,6 +36,8 @@ import ai.onnxruntime.OnnxTensor;
import ai.onnxruntime.OrtEnvironment;
import ai.onnxruntime.OrtException;
import ai.onnxruntime.OrtSession;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -96,6 +99,41 @@ public class DocumentCategorizerDL extends AbstractDL implements DocumentCategor
}
+ /**
+ * Instantiates a {@link DocumentCategorizer document categorizer} using ONNX models.
+ *
+ * @param model The ONNX model file.
+ * @param vocabulary The model file's vocabulary file.
+ * @param config The model's config file. The file will be used to determine the classification categories.
+ * @param classificationScoringStrategy Implementation of {@link ClassificationScoringStrategy} used
+ * to calculate the classification scores given the score of each
+ * individual document part.
+ * @param inferenceOptions {@link InferenceOptions} to control the inference.
+ *
+ * @throws OrtException Thrown if the {@code model} cannot be loaded.
+ * @throws IOException Thrown if errors occurred loading the {@code model} or {@code vocabulary}.
+ */
+ public DocumentCategorizerDL(File model, File vocabulary, File config,
+ ClassificationScoringStrategy classificationScoringStrategy,
+ InferenceOptions inferenceOptions)
+ throws IOException, OrtException {
+
+ this.env = OrtEnvironment.getEnvironment();
+
+ final OrtSession.SessionOptions sessionOptions = new OrtSession.SessionOptions();
+ if (inferenceOptions.isGpu()) {
+ sessionOptions.addCUDA(inferenceOptions.getGpuDeviceId());
+ }
+
+ this.session = env.createSession(model.getPath(), sessionOptions);
+ this.vocab = loadVocab(vocabulary);
+ this.tokenizer = new WordpieceTokenizer(vocab.keySet());
+ this.categories = readCategoriesFromFile(config);
+ this.classificationScoringStrategy = classificationScoringStrategy;
+ this.inferenceOptions = inferenceOptions;
+
+ }
+
@Override
public double[] categorize(String[] strings) {
@@ -222,28 +260,6 @@ public class DocumentCategorizerDL extends AbstractDL implements DocumentCategor
}
- private Tokens oldTokenize(String text) {
-
- final String[] tokens = tokenizer.tokenize(text);
-
- final int[] ids = new int[tokens.length];
-
- for (int x = 0; x < tokens.length; x++) {
- ids[x] = vocab.get(tokens[x]);
- }
-
- final long[] lids = Arrays.stream(ids).mapToLong(i -> i).toArray();
-
- final long[] mask = new long[ids.length];
- Arrays.fill(mask, 1);
-
- final long[] types = new long[ids.length];
- Arrays.fill(types, 0);
-
- return new Tokens(tokens, lids, mask, types);
-
- }
-
private List<Tokens> tokenize(final String text) {
final List<Tokens> t = new LinkedList<>();
@@ -329,4 +345,23 @@ public class DocumentCategorizerDL extends AbstractDL implements DocumentCategor
.orElse(-1);
}
+ private Map<Integer, String> readCategoriesFromFile(File config) throws IOException {
+
+ final String json = new String(Files.readAllBytes(config.toPath()));
+
+ final ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ final DocumentCategorizerConfig documentCategorizerConfig =
+ objectMapper.readValue(json, DocumentCategorizerConfig.class);
+
+ final Map<Integer, String> categories = new HashMap<>();
+ for (final String key : documentCategorizerConfig.getId2label().keySet()) {
+ categories.put(Integer.valueOf(key), documentCategorizerConfig.getId2label().get(key));
+ }
+
+ return categories;
+
+ }
+
}
diff --git a/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerDLEval.java b/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerDLEval.java
index 385e08f1..506b0bc5 100644
--- a/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerDLEval.java
+++ b/opennlp-dl/src/test/java/opennlp/dl/doccat/DocumentCategorizerDLEval.java
@@ -41,6 +41,19 @@ public class DocumentCategorizerDLEval extends AbstractDLTest {
private static final Logger logger = LoggerFactory.getLogger(DocumentCategorizerDLEval.class);
+ final String text = "We try hard to identify the sources and licenses of all media such as text," +
+ " images or sounds used in our encyclopedia articles. Still, we cannot guarantee that all " +
+ "media are used or marked correctly: for example, if an image description page states " +
+ "that an image was in the public domain, you should still check yourself whether that claim " +
+ "appears correct and decide for yourself whether your use of the image would be fine under " +
+ "the laws applicable to you. Wikipedia is primarily subject to U.S. law; re-users outside " +
+ "the U.S. should be aware that they are subject to the laws of their country, which almost " +
+ "certainly are different. Images published under the GFDL or one of the Creative Commons " +
+ "Licenses are unlikely to pose problems, as these are specific licenses with precise terms " +
+ "worldwide. Public domain images may need to be re-evaluated by a re-user because it depends " +
+ "on each country's copyright laws what is in the public domain there. There is no guarantee " +
+ "that something in the public domain in the U.S. was also in the public domain in your country.";
+
@Test
public void categorize() throws IOException, OrtException {
@@ -54,19 +67,6 @@ public class DocumentCategorizerDLEval extends AbstractDLTest {
new AverageClassificationScoringStrategy(),
new InferenceOptions());
- final String text = "We try hard to identify the sources and licenses of all media such as text, images" +
- " or sounds used in our encyclopedia articles. Still, we cannot guarantee that all media are used " +
- "or marked correctly: for example, if an image description page states that an image was in the " +
- "public domain, you should still check yourself whether that claim appears correct and decide for " +
- "yourself whether your use of the image would be fine under the laws applicable to you. Wikipedia " +
- "is primarily subject to U.S. law; re-users outside the U.S. should be aware that they are subject " +
- "to the laws of their country, which almost certainly are different. Images published under the " +
- "GFDL or one of the Creative Commons Licenses are unlikely to pose problems, as these are specific " +
- "licenses with precise terms worldwide. Public domain images may need to be re-evaluated by a " +
- "re-user because it depends on each country's copyright laws what is in the public domain there. " +
- "There is no guarantee that something in the public domain in the U.S. was also in the public " +
- "domain in your country.";
-
final double[] result = documentCategorizerDL.categorize(new String[]{text});
// Sort the result for easier comparison.
@@ -92,6 +92,46 @@ public class DocumentCategorizerDLEval extends AbstractDLTest {
}
+ @Test
+ public void categorizeWithAutomaticLabels() throws IOException, OrtException {
+
+ final File model = new File(getOpennlpDataDir(),
+ "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.onnx");
+ final File vocab = new File(getOpennlpDataDir(),
+ "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.vocab");
+ final File config = new File(getOpennlpDataDir(),
+ "onnx/doccat/nlptown_bert-base-multilingual-uncased-sentiment.json");
+
+ final DocumentCategorizerDL documentCategorizerDL =
+ new DocumentCategorizerDL(model, vocab, config,
+ new AverageClassificationScoringStrategy(),
+ new InferenceOptions());
+
+ final double[] result = documentCategorizerDL.categorize(new String[]{text});
+
+ // Sort the result for easier comparison.
+ final double[] sortedResult = Arrays.stream(result)
+ .boxed()
+ .sorted(Collections.reverseOrder()).mapToDouble(Double::doubleValue).toArray();
+
+ final double[] expected = new double[]
+ {0.3391093313694,
+ 0.2611352801322937,
+ 0.24420668184757233,
+ 0.11939861625432968,
+ 0.03615010157227516};
+
+ logger.debug("Actual: {}", Arrays.toString(sortedResult));
+ logger.debug("Expected: {}", Arrays.toString(expected));
+
+ Assertions.assertArrayEquals(expected, sortedResult, 0.000001);
+ Assertions.assertEquals(5, result.length);
+
+ final String category = documentCategorizerDL.getBestCategory(result);
+ Assertions.assertEquals("2 stars", category);
+
+ }
+
@Disabled("This test will should only be run if a GPU device is present.")
@Test
public void categorizeWithGpu() throws Exception {
diff --git a/pom.xml b/pom.xml
index 434426d7..a8e107ed 100644
--- a/pom.xml
+++ b/pom.xml
@@ -167,6 +167,7 @@
<java.version>17</java.version>
<maven.version>3.3.9</maven.version>
<enforcer.plugin.version>3.3.0</enforcer.plugin.version>
+ <jackson.version>2.15.3</jackson.version>
<jersey.version>2.39.1</jersey.version>
<junit.version>5.9.2</junit.version>
<uimaj.version>3.4.1</uimaj.version>