package edu.stanford.nlp.pipeline;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.neural.rnn.RNNCoreAnnotations;
import edu.stanford.nlp.sentiment.CollapseUnaryTransformer;
import edu.stanford.nlp.sentiment.SentimentCoreAnnotations;
import edu.stanford.nlp.sentiment.SentimentCostAndGradient;
import edu.stanford.nlp.sentiment.SentimentModel;
import edu.stanford.nlp.sentiment.SentimentUtils;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeCoreAnnotations;
import edu.stanford.nlp.util.CoreMap;
/**
* This annotator attaches a binarized tree with sentiment annotations
* to each sentence. It requires there to already be binarized trees
* attached to the sentence, which is best done in the
* ParserAnnotator.
* <br>
* The tree will be attached to each sentence in the
* SentencesAnnotation via the SentimentCoreAnnotations.AnnotatedTree
* annotation. The class name for the top level class is also set
* using the SentimentCoreAnnotations.ClassName annotation.
* <br>
* The reason the decision was made to do the binarization in the
* ParserAnnotator is because it may require specific options set in
* the parser. An alternative would be to do the binarization here,
* which would require at a minimum the HeadFinder used in the parser.
*
* @author John Bauer
*/
public class SentimentAnnotator implements Annotator {
static final String DEFAULT_MODEL = "edu/stanford/nlp/models/sentiment/sentiment.ser.gz";
String modelPath;
SentimentModel model;
CollapseUnaryTransformer transformer = new CollapseUnaryTransformer();
public SentimentAnnotator(String name, Properties props) {
this.modelPath = props.getProperty(name + ".model", DEFAULT_MODEL);
if (modelPath == null) {
throw new IllegalArgumentException("No model specified for Sentiment annotator");
}
this.model = SentimentModel.loadSerialized(modelPath);
}
public Set<Requirement> requirementsSatisfied() {
return Collections.emptySet();
}
public Set<Requirement> requires() {
return PARSE_TAG_BINARIZED_TREES;
}
public void annotate(Annotation annotation) {
if (annotation.containsKey(CoreAnnotations.SentencesAnnotation.class)) {
// TODO: parallelize
List<CoreMap> sentences = annotation.get(CoreAnnotations.SentencesAnnotation.class);
for (CoreMap sentence : sentences) {
Tree binarized = sentence.get(TreeCoreAnnotations.BinarizedTreeAnnotation.class);
if (binarized == null) {
throw new AssertionError("Binarized sentences not built by parser");
}
Tree collapsedUnary = transformer.transformTree(binarized);
SentimentCostAndGradient scorer = new SentimentCostAndGradient(model, null);
scorer.forwardPropagateTree(collapsedUnary);
sentence.set(SentimentCoreAnnotations.AnnotatedTree.class, collapsedUnary);
int sentiment = RNNCoreAnnotations.getPredictedClass(collapsedUnary);
sentence.set(SentimentCoreAnnotations.ClassName.class, SentimentUtils.sentimentString(model, sentiment));
}
} else {
throw new RuntimeException("unable to find sentences in: " + annotation);
}
}
}