diff --git a/.gitignore b/.gitignore
index 2be136df..7899427d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/config
.DS_Store
data
*/data
@@ -13,7 +14,6 @@ target/
.projectFilesBackup
*.class
annotation-cache/
-/config
*.lc
*.lex
*~
diff --git a/build.sbt b/build.sbt
index 0257233b..e928aeca 100644
--- a/build.sbt
+++ b/build.sbt
@@ -57,7 +57,8 @@ lazy val commonSettings = Seq(
name := "saul-project",
resolvers ++= Seq(
Resolver.mavenLocal,
- "CogcompSoftware" at "http://cogcomp.cs.illinois.edu/m2repo/"
+ "CogcompSoftware" at "http://cogcomp.cs.illinois.edu/m2repo/",
+ "Sonatype Releases" at "https://oss.sonatype.org/content/repositories/releases/"
),
javaOptions ++= List("-Xmx11g"),
libraryDependencies ++= Seq(
@@ -66,7 +67,9 @@ lazy val commonSettings = Seq(
"com.gurobi" % "gurobi" % "6.0",
"org.apache.commons" % "commons-math3" % "3.0",
"org.scalatest" % "scalatest_2.11" % "2.2.4",
- "ch.qos.logback" % "logback-classic" % "1.1.7"
+ "ch.qos.logback" % "logback-classic" % "1.1.7",
+ "org.scalanlp" %% "breeze-viz" % "0.12",
+ "edu.illinois.cs.cogcomp" % "illinois-sl" % "1.3.6" withSources
),
fork := true,
connectInput in run := true,
diff --git a/config/DCD.config b/config/DCD.config
new file mode 100644
index 00000000..77fd5f6e
--- /dev/null
+++ b/config/DCD.config
@@ -0,0 +1,26 @@
+# {L2LossSSVM, StructuredPerceptron}
+# LEARNING_MODEL = L2LossSSVM
+LEARNING_MODEL = StructuredPerceptron
+MAX_NUM_ITER = 20
+# {DCDSolver, ParallelDCDSolver, DEMIParallelDCDSolver};
+L2_LOSS_SSVM_SOLVER_TYPE = DCDSolver
+
+NUMBER_OF_THREADS = 1
+C_FOR_STRUCTURE = 1.0
+TRAINMINI = false
+TRAINMINI_SIZE = 1000
+STOP_CONDITION = 0.0001
+CHECK_INFERENCE_OPT = false
+# MAX_NUM_ITER = 250
+PROGRESS_REPORT_ITER = 10
+INNER_STOP_CONDITION = 0.00001
+MAX_ITER_INNER = 250
+MAX_ITER_INNER_FINAL = 2500
+TOTAL_NUMBER_FEATURE = -1
+CLEAN_CACHE = true
+CLEAN_CACHE_ITER = 5
+DEMIDCD_NUMBER_OF_UPDATES_BEFORE_UPDATE_BUFFER = 100
+DEMIDCD_NUMBER_OF_INF_PARSE_BEFORE_UPDATE_WV = 10
+LEARNING_RATE = 0.01
+DECAY_LEARNING_RATE = false
+NUMBER_OF_FEATURE_BITS = 26
diff --git a/saul-core/doc/INSTALLATION.md b/saul-core/doc/INSTALLATION.md
index 03c2affd..c6cbbd48 100644
--- a/saul-core/doc/INSTALLATION.md
+++ b/saul-core/doc/INSTALLATION.md
@@ -81,3 +81,4 @@ We suggest using [IntelliJ IDEA](https://www.jetbrains.com/idea/download/).
If you are interested in contributing to the Saul project, either by your ideas or codes, you are welcome
to create pull requests here.
+
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ClassifierUtils.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ClassifierUtils.scala
index f211d057..1cdf3a81 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ClassifierUtils.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ClassifierUtils.scala
@@ -137,8 +137,13 @@ object ClassifierUtils extends Logging {
logger.info(evalSeparator)
testResults
}
- }
+ def apply1[T <: AnyRef, H <: AnyRef](insts: Iterable[T], cls: ConstrainedClassifier[T, H]): Results = {
+ println(evalSeparator)
+ println("Evaluating " + cls.getClassSimpleNameForClassifier)
+ cls.test(insts)
+ }
+ }
object ForgetAll {
def apply(c: Learnable[_]*): Unit = {
c.foreach((x: Learnable[_]) => x.forget())
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ConstrainedClassifier.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ConstrainedClassifier.scala
index 337956f6..7c66a9bf 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ConstrainedClassifier.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/ConstrainedClassifier.scala
@@ -10,6 +10,7 @@ import edu.illinois.cs.cogcomp.lbjava.classify.{ Classifier, FeatureVector, Test
import edu.illinois.cs.cogcomp.infer.ilp.{ GurobiHook, ILPSolver, OJalgoHook }
import edu.illinois.cs.cogcomp.lbjava.infer.{ BalasHook, FirstOrderConstraint, InferenceManager }
import edu.illinois.cs.cogcomp.lbjava.learn.Learner
+import edu.illinois.cs.cogcomp.saul.classifier.SL_model.LossAugmentedNormalizer
import edu.illinois.cs.cogcomp.saul.classifier.infer.InferenceCondition
import edu.illinois.cs.cogcomp.saul.constraint.LfsConstraint
import edu.illinois.cs.cogcomp.saul.datamodel.edge.Edge
@@ -17,6 +18,8 @@ import edu.illinois.cs.cogcomp.saul.lbjrelated.{ LBJClassifierEquivalent, LBJLea
import edu.illinois.cs.cogcomp.saul.parser.IterableToLBJavaParser
import edu.illinois.cs.cogcomp.saul.test.TestWithStorage
import edu.illinois.cs.cogcomp.saul.util.Logging
+
+import scala.collection.mutable
import scala.reflect.ClassTag
/** The input to a ConstrainedClassifier is of type `T`. However given an input, the inference is based upon the
@@ -31,7 +34,7 @@ abstract class ConstrainedClassifier[T <: AnyRef, HEAD <: AnyRef](val onClassifi
implicit val headType: ClassTag[HEAD]
) extends LBJClassifierEquivalent with Logging {
- type LEFT = T
+ final type LEFT = T
type RIGHT = HEAD
def className: String = this.getClass.getName
@@ -69,26 +72,30 @@ abstract class ConstrainedClassifier[T <: AnyRef, HEAD <: AnyRef](val onClassifi
val l = pathToHead.get.forward.neighborsOf(x).toSet.toList
if (l.isEmpty) {
- logger.error("Warning: Failed to find head")
+ // logger.error("Warning: Failed to find head")
None
} else if (l.size != 1) {
- logger.warn("Find too many heads")
+ // logger.warn("Find too many heads")
Some(l.head)
} else {
- logger.info(s"Found head ${l.head} for child $x")
+ /// logger.info(s"Found head ${l.head} for child $x")
Some(l.head)
}
}
}
- def getCandidates(head: HEAD): Seq[T] = {
+ // def getMultiCandidates(head: Seq[HEAD]): Seq[LEFT] = {
+ // head.flatMap(h => getCandidates(h)).distinct
+ // }
+
+ def getCandidates(head: HEAD): Seq[LEFT] = {
if (tType.equals(headType) || pathToHead.isEmpty) {
head.asInstanceOf[T] :: Nil
} else {
val l = pathToHead.get.backward.neighborsOf(head)
if (l.isEmpty) {
- logger.error("Failed to find part")
+ // logger.error("Failed to find part")
Seq.empty[T]
} else {
l.filter(filter(_, head)).toSeq
@@ -103,7 +110,7 @@ abstract class ConstrainedClassifier[T <: AnyRef, HEAD <: AnyRef](val onClassifi
var inference = InferenceManager.get(name, head)
if (inference == null) {
inference = infer(head)
- logger.warn(s"Inference ${name} has not been cached; running inference . . . ")
+ // logger.warn(s"Inference ${name} has not been cached; running inference . . . ")
InferenceManager.put(name, inference)
}
inference.valueOf(cls, t)
@@ -113,6 +120,16 @@ abstract class ConstrainedClassifier[T <: AnyRef, HEAD <: AnyRef](val onClassifi
}
}
+ def lossAugmentedInfer(h: HEAD, offset: Int): mutable.ListBuffer[String] = {
+ var v = mutable.ListBuffer[String]()
+ getCandidates(h).foreach {
+ (example) =>
+ // val g1 = onClassifier.scores(example)
+ v += buildWithConstraint(subjectTo.createInferenceCondition[T](getSolverInstance(), new LossAugmentedNormalizer(offset, onClassifier.classifier, example)).convertToType[T], onClassifier.classifier)(example)
+ }
+ v
+ }
+
def buildWithConstraint(inferenceCondition: InferenceCondition[T, HEAD])(t: T): String = {
buildWithConstraint(inferenceCondition, onClassifier.classifier)(t)
}
@@ -141,7 +158,8 @@ abstract class ConstrainedClassifier[T <: AnyRef, HEAD <: AnyRef](val onClassifi
.orElse({
onClassifier match {
case clf: Learnable[T] => Some(clf.node)
- case _ => logger.error("pathToHead is not provided and the onClassifier is not a Learnable!"); None
+ case _ => None
+ // logger.error("pathToHead is not provided and the onClassifier is not a Learnable!"); None
}
})
.map(node => node.getTestingInstances)
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/JointTrainSparseNetwork.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/JointTrainSparseNetwork.scala
index 4ac33f82..62924d19 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/JointTrainSparseNetwork.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/JointTrainSparseNetwork.scala
@@ -18,16 +18,16 @@ object JointTrainSparseNetwork {
val logger: Logger = LoggerFactory.getLogger(this.getClass)
var difference = 0
- def apply[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], init: Boolean)(implicit headTag: ClassTag[HEAD]) = {
- train[HEAD](node, cls, 1, init)
+ def apply[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], init: Boolean,lossAugmented: Boolean)(implicit headTag: ClassTag[HEAD]) = {
+ train[HEAD](node, cls, 1, init,lossAugmented)
}
- def apply[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], it: Int, init: Boolean)(implicit headTag: ClassTag[HEAD]) = {
- train[HEAD](node, cls, it, init)
+ def apply[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], it: Int, init: Boolean, lossAugmented: Boolean=false)(implicit headTag: ClassTag[HEAD]) = {
+ train[HEAD](node, cls, it, init, lossAugmented)
}
@scala.annotation.tailrec
- def train[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], it: Int, init: Boolean)(implicit headTag: ClassTag[HEAD]): Unit = {
+ def train[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], it: Int, init: Boolean, lossAugmented: Boolean=false)(implicit headTag: ClassTag[HEAD]): Unit = {
// forall members in collection of the head (dm.t) do
logger.info("Training iteration: " + it)
if (init) ClassifierUtils.InitializeClassifiers(node, cls: _*)
@@ -43,19 +43,24 @@ object JointTrainSparseNetwork {
if (idx % 5000 == 0)
logger.info(s"Training: $idx examples inferred.")
- cls.foreach {
- case classifier: ConstrainedClassifier[_, HEAD] =>
- val typedClassifier = classifier.asInstanceOf[ConstrainedClassifier[_, HEAD]]
- val oracle = typedClassifier.onClassifier.getLabeler
+ if (lossAugmented)
+ cls.foreach{ cls_i =>
+ cls_i.onClassifier.classifier.setLossFlag()
+ cls_i.onClassifier.classifier.setCandidates(cls_i.getCandidates(h).size * cls.size)
+ }
- typedClassifier.getCandidates(h) foreach {
+ cls.foreach {
+ currentClassifier: ConstrainedClassifier[_, HEAD] =>
+ val oracle = currentClassifier.onClassifier.getLabeler
+ val baseClassifier = currentClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner]
+ currentClassifier.getCandidates(h) foreach {
candidate =>
{
def trainOnce() = {
- val result = typedClassifier.classifier.discreteValue(candidate)
+
+ val result = currentClassifier.classifier.discreteValue(candidate)
val trueLabel = oracle.discreteValue(candidate)
- val ilearner = typedClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner]
- val lLexicon = typedClassifier.onClassifier.getLabelLexicon
+ val lLexicon = currentClassifier.onClassifier.getLabelLexicon
var LTU_actual: Int = 0
var LTU_predicted: Int = 0
for (i <- 0 until lLexicon.size()) {
@@ -69,26 +74,26 @@ object JointTrainSparseNetwork {
// and the LTU of the predicted class should be demoted.
if (!result.equals(trueLabel)) //equals("true") && trueLabel.equals("false") )
{
- val a = typedClassifier.onClassifier.getExampleArray(candidate)
+ val a = currentClassifier.onClassifier.getExampleArray(candidate)
val a0 = a(0).asInstanceOf[Array[Int]] //exampleFeatures
val a1 = a(1).asInstanceOf[Array[Double]] // exampleValues
val exampleLabels = a(2).asInstanceOf[Array[Int]]
val label = exampleLabels(0)
- var N = ilearner.getNetwork.size
+ var N = baseClassifier.getNetwork.size
- if (label >= N || ilearner.getNetwork.get(label) == null) {
- val conjugateLabels = ilearner.isUsingConjunctiveLabels | ilearner.getLabelLexicon.lookupKey(label).isConjunctive
- ilearner.setConjunctiveLabels(conjugateLabels)
+ if (label >= N || baseClassifier.getNetwork.get(label) == null) {
+ val conjugateLabels = baseClassifier.isUsingConjunctiveLabels | baseClassifier.getLabelLexicon.lookupKey(label).isConjunctive
+ baseClassifier.setConjunctiveLabels(conjugateLabels)
- val ltu: LinearThresholdUnit = ilearner.getBaseLTU
- ltu.initialize(ilearner.getNumExamples, ilearner.getNumFeatures)
- ilearner.getNetwork.set(label, ltu)
+ val ltu: LinearThresholdUnit = baseClassifier.getBaseLTU.clone().asInstanceOf[LinearThresholdUnit]
+ ltu.initialize(baseClassifier.getNumExamples, baseClassifier.getNumFeatures)
+ baseClassifier.getNetwork.set(label, ltu)
N = label + 1
}
// test push
- val ltu_actual = ilearner.getLTU(LTU_actual).asInstanceOf[LinearThresholdUnit]
- val ltu_predicted = ilearner.getLTU(LTU_predicted).asInstanceOf[LinearThresholdUnit]
+ val ltu_actual = baseClassifier.getLTU(LTU_actual).asInstanceOf[LinearThresholdUnit]
+ val ltu_predicted = baseClassifier.getLTU(LTU_predicted).asInstanceOf[LinearThresholdUnit]
if (ltu_actual != null)
ltu_actual.promote(a0, a1, 0.1)
@@ -100,8 +105,13 @@ object JointTrainSparseNetwork {
trainOnce()
}
}
+
}
}
+ if (lossAugmented)
+ cls.foreach{ cls_i =>
+ cls_i.onClassifier.classifier.unsetLossFlag()
+ }
}
train(node, cls, it - 1, false)
}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Initialize.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Initialize.scala
new file mode 100644
index 00000000..b08bc001
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Initialize.scala
@@ -0,0 +1,72 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.lbjava.learn.{ LinearThresholdUnit, SparseNetworkLearner }
+import edu.illinois.cs.cogcomp.saul.classifier.infer.InitSparseNetwork
+import edu.illinois.cs.cogcomp.saul.datamodel.node.Node
+import edu.illinois.cs.cogcomp.sl.util.WeightVector
+
+import scala.collection.mutable.ListBuffer
+
+/** Created by Parisa on 4/1/16.
+ * Here we only make the lbjava lexicons for each onClassifier
+ * (i.e. the base classifier of each constraint classifier) based on the features of IInstances
+ */
+object Initialize {
+
+ def apply[HEAD <: AnyRef](node: Node[HEAD], model: SaulSLModel[HEAD], usePreTrained: Boolean = false): SaulSLModel[HEAD] = {
+
+ var wvLength = 0
+ var fullWeightList: ListBuffer[Array[Float]] = ListBuffer()
+
+ /*this means we are not reading any model into the SparseNetworks but
+ we forget all the models and go over the data to build the right size
+ for the lexicon and the right number of the ltu s*/
+
+ if (!usePreTrained)
+ model.Factors.foreach {
+ cf => InitSparseNetwork(node, cf)
+ }
+ /*In this step or we have built the lexicon by going over the data in the above block or
+we use the loaded lexicons in the case of uesPreTrained == true, the goal is to build
+ a global weight vector using all classifiers and initialize it accordingly to have a fixed size*/
+
+ model.Factors.foreach(
+ x => {
+ val sparseNet = x.onClassifier.classifier.asInstanceOf[SparseNetworkLearner]
+ val lexiconSize = (sparseNet.getLexicon.size())
+
+ for (i <- 0 until sparseNet.getNetwork.size()) {
+
+ val trainedWeighs = x.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector
+ val fullWeights = Array.fill[Float](lexiconSize)(0)
+
+ if (usePreTrained) { //if we are going to initialize we get the loaded weights otherwise the weights are filled with zeros
+
+ for (j <- 0 until lexiconSize)
+ fullWeights(j) = trainedWeighs.getWeight(j).asInstanceOf[Float]
+
+ }
+ fullWeightList = fullWeightList :+ fullWeights
+
+ wvLength = wvLength + lexiconSize
+ }
+
+ println("lexicon size: " + sparseNet.getLexicon.size(), "* label lexicon size:", sparseNet.getLabelLexicon.size())
+ }
+ )
+ // wv = Concatenate_(over factors)Concatenate_(over ltu) => size(wv)=sum_(over factors)sum_(over ltu)(size(ltu_i))
+
+ val myWeight = Array(fullWeightList.flatten: _*)
+ val wv = new WeightVector(myWeight) // wv this is one unified weight vector of all initialized LTUs
+ val m = new SaulSLModel[HEAD](model.Factors.toList, fullWeightList) // lt is the list of individual weight vectors
+ m.wv = wv
+ m
+ /*This weigh vector is a a flat vector containing one block of weights per each ltu*/
+ } //end f apply
+} // end of object
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/LossAugmentedNormalizer.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/LossAugmentedNormalizer.scala
new file mode 100644
index 00000000..663ca717
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/LossAugmentedNormalizer.scala
@@ -0,0 +1,36 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.lbjava.classify.ScoreSet
+import edu.illinois.cs.cogcomp.lbjava.learn.{ Learner, Normalizer, SparseNetworkLearner }
+
+/** Created by Parisa on 4/18/16.
+ */
+class LossAugmentedNormalizer(cand_num: Int, c: Learner, example: AnyRef) extends Normalizer {
+ /** Simply returns the argument.
+ *
+ * @param scores The set of scores to normalize.
+ * @return The normalized set of scores.
+ */
+ def normalize(scores: ScoreSet): ScoreSet = {
+ if (cand_num == 0)
+ print("There is no relevant component of this type in the head to be classified.")
+ val cf = c.asInstanceOf[SparseNetworkLearner]
+ val gold = cf.getLabeler.discreteValue(example)
+ val lLexicon = cf.getLabelLexicon
+
+ val resultS: ScoreSet = cf.scores(example) //new ScoreSet
+ for (i <- 0 until lLexicon.size()) {
+ if (lLexicon.lookupKey(i).valueEquals(gold))
+ resultS.put(lLexicon.lookupKey(i).getStringValue, resultS.getScore(lLexicon.lookupKey(i).getStringValue).score - (1 / (cand_num)))
+ else
+ resultS.put(lLexicon.lookupKey(i).getStringValue, resultS.getScore(lLexicon.lookupKey(i).getStringValue).score + (1 / (cand_num)))
+ }
+ resultS
+ }
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/README.md b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/README.md
new file mode 100644
index 00000000..0f7a512c
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/README.md
@@ -0,0 +1,62 @@
+
+The `SL_model` package aims at providing the possibility of designing structured output prediction models, based on generalized linear models such as structured SVMs and structured Perceptrons.
+For implementating any structured learning problem in SL, we need to implement the following classes, [see here.](http://cogcomp.cs.illinois.edu/software/illinois-sl/)
+
+The input structure, x. This should implement the IInstance interface.
+
+The output structure, y. This should implement the IStructure interface.
+
+A procedure to compute the feature vector Φ(x,y). For this you need to extend the AbstractFeatureGenerator class and override its getFeatureVector method.
+
+A procedure InferenceSolver to perform the loss-augmented inference,
+
+argmaxy′wTΦ(x,y′)+Δ(y,y′)
+
+For this you need to extend the AbstractInferenceSolver class.
+
+At test time, we need to solve
+
+argmaxy′wTΦ(x,y′)
+We will call this the MAP inference problem. For this we can just set Δ(y,y′) to zero in the loss-augmented inference solver.
+
+
+
+Now here in Saul-SL, what we do is that the way we define our model is based on Saul's conceptual abstraction rather than the SL abstraction. In other words Saul user writes the program in terms of Classifiers and Constraints and the above mentioned modules are provided by Saul.
+-The input structure is the collection of the input components of each individual classifier.
+
+-The output structure is the collection of the labels
+
+-The feature vector is the concatenation of the vectors generated by (input-feature * output-label) for each individual classifier and a global join feature function is built automatically based on those join features of the independent classifiers.
+
+-The inference is done using the constraints that express the correlations between the Classifiers.
+
+This model implements the idea of collective classification in the framework of structured output prediction models and provides the possibility of using global first order constraints and domain knowledge easily in the structured learning model.
+
+The underlying inference is performed using ILP techniques.
+
+###The ER example
+
+The explanation of the ER problem can be found in the [EntityRelation example](/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/README.md).
+To solve this problem and extract the relations and entities jointly using SL's structured output prediction models, we use the same problem specification of this problem that is used for other configurations in Saul. This specification includes defining the
+[ER data model](/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationDataModel.scala),
+ [classifiers](/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationClassifiers.scala) and [constraints](/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstraints.scala).
+ The only different part is the end ER application is to simply call `StructuredLearning("NodeType_Name", "ListOfConstrainedClassifiers_Name")`, where `NodeTyeName` is a node type in our dataModel and indicates the type of examples that our model receives.
+ In fact, this specifies the type of most global object that is used as an independent example. The evaluation of the model also is done by calling def `Evaluate("NodeType_Name", "ListOfConstrainedClassifiers_Name",myModelName, modelPath)`. This is the
+ [end ER application](/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationApp_SL.scala) that uses SL to train and test.
+
+###Saul-SL provided components for developer's information
+
+
+ A __Saul IInstance__ (`Saul_SL_Instance`), is simply a node in the data model graph. We call is a head because it is a global object and will be the head of a potential inference module later. Normally, we will have a classifier that applies on the head node and also other local classifiers that are applied on other nodes which are connected to the head node.
+ A __Saul Structure__ (`Saul_SL_Label_Structure`), is simply a list of labels collected fro the labels of all the engaged classifiers in the structured model.
+ __Feature Generation__ (`SL_FeatureGenerator`), The global feature function is made by adding up (and concatenation) of the join feature functions of all involved classifiers. The SparseNetwork structure is used for keeping the information of the classifiers and the LTU keeping the vectors of weights.
+ __Saul Inference__ (`Saul_SL_Inference`), simply receives the list of constrained classifiers, one of these is a classifier which applies on the head object and the others are parts of the objective function and all of these share a set of constraints. Hence, inference is easily done by calling LBJava on the list of constrained classifiers.
+ __Saul Loss__ this is simply the normalized aggregation (average) of the hamming loss of the classifiers assigned labels, this is by default equally weighted but can be extended to input weights.
+ __Loss augmented Inference__ the score of each classifier is augmented by its loss, before the inference is performed in LBJava. This is done by using a method (that we have added) in LBJava's Learner, called `scoresAugmented`. For this modified score to be returned we set a flag called lossFlag before calling inference and after inference this flag is unset.
+
+
+
+
+
+
+
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SL_FeatureGenerator.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SL_FeatureGenerator.scala
new file mode 100644
index 00000000..77af2478
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SL_FeatureGenerator.scala
@@ -0,0 +1,71 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.lbjava.learn.SparseNetworkLearner
+import edu.illinois.cs.cogcomp.sl.core.{ AbstractFeatureGenerator, IInstance, IStructure }
+import edu.illinois.cs.cogcomp.sl.util.{ FeatureVectorBuffer, IFeatureVector }
+
+/** Created by Parisa on 12/8/15.
+ */
+class SL_FeatureGenerator[HEAD <: AnyRef](model: SaulSLModel[HEAD]) extends AbstractFeatureGenerator {
+ override def getFeatureVector(x: IInstance, y: IStructure): IFeatureVector = {
+
+ val myX = x.asInstanceOf[Saul_SL_Instance[HEAD]]
+ val myY = y.asInstanceOf[Saul_SL_Label_Structure[HEAD]]
+ val fv = new FeatureVectorBuffer()
+ var ltuNum = 0
+ var factorOffset = 0
+ var labelCount = 0
+
+ //The features vectors are generated per classifier with local indexes and then the indexes are adjusted globally
+
+ model.Factors.zipWithIndex.foreach {
+
+ case (cf, indF) =>
+ val candis: Seq[_] = cf.getCandidates(myX.head)
+ val sparseNet = cf.onClassifier.classifier.asInstanceOf[SparseNetworkLearner]
+ val fvLocal = new FeatureVectorBuffer()
+
+ candis.foreach {
+ (ci) =>
+ var localOffset = 0
+ //This block is the conversion from Lbjava to SL feature vectors
+ val a = sparseNet.getExampleArray(ci, false)
+ var a0 = a(0).asInstanceOf[Array[Int]]
+ var a1 = a(1).asInstanceOf[Array[Double]]
+ val fvTemp = new FeatureVectorBuffer(a0, a1)
+ val lab = myY.labels(labelCount)
+ labelCount = labelCount + 1
+ //keep the features for the on label (at netI index) and repeat a zero feature vector for the off labels
+ for (netI <- 0 until sparseNet.getNetwork.size()) {
+ if (netI != 0)
+ localOffset = localOffset + model.LTUWeightTemplates(ltuNum + netI - 1).length
+ // else localOffset = 0
+ if (!sparseNet.getLabelLexicon.lookupKey(netI).valueEquals(lab)) {
+ a1 = Array()
+ a0 = Array()
+ fvLocal.addFeature(new FeatureVectorBuffer(a0, a1), localOffset)
+ } else
+ fvLocal.addFeature(fvTemp, localOffset)
+ //val p = fvLocal.toFeatureVector
+
+ }
+ }
+ ltuNum = ltuNum + sparseNet.getNetwork.size()
+
+ if (indF > 0)
+ factorOffset = factorOffset + model.Factors(indF - 1).onClassifier.classifier.getLexicon.size() * model.Factors(indF - 1).onClassifier.getLabelLexicon.size()
+
+ fv.addFeature(fvLocal, factorOffset)
+ }
+
+ fv.toFeatureVector()
+
+ }
+
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SL_IOManager.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SL_IOManager.scala
new file mode 100644
index 00000000..99369fe9
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SL_IOManager.scala
@@ -0,0 +1,38 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import edu.illinois.cs.cogcomp.saul.datamodel.node.Node
+import edu.illinois.cs.cogcomp.sl.core.SLProblem
+import edu.illinois.cs.cogcomp.sl.util.Lexiconer
+
+import scala.reflect.ClassTag
+
+/** Created by Parisa on 12/4/15.
+ */
+object SL_IOManager {
+ val lexm: Lexiconer = new Lexiconer()
+ def makeSLProblem[HEAD <: AnyRef](node: Node[HEAD], list: List[ConstrainedClassifier[_, HEAD]], testing: Boolean = false)(implicit t: ClassTag[HEAD]): SLProblem = {
+ var sp: SLProblem = new SLProblem()
+ var allHeads: Iterable[HEAD] = Iterable[HEAD]()
+ if (testing) {
+ allHeads = node.getTestingInstances
+ } else {
+ allHeads = node.getTrainingInstances
+ }
+
+ allHeads.foreach(x =>
+ {
+ // val l: java.util.List[ConstrainedClassifier[_,HEAD]] =list.asJava
+ val ins = new Saul_SL_Instance(x)
+ val outs = new Saul_SL_Label_Structure(list, x)
+ sp.addExample(ins, outs)
+ })
+ sp
+ }
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SUtils.java b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SUtils.java
new file mode 100755
index 00000000..04f7a2a0
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SUtils.java
@@ -0,0 +1,54 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model;
+
+import edu.illinois.cs.cogcomp.sl.util.FeatureVectorBuffer;
+import org.apache.commons.lang.ArrayUtils;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class SUtils {
+ /**
+ * A static method for smartly adding features to the LexManager, and creating a FeatureVector
+ * at the same time.
+ *
+ * @param feats
+ * @return
+ */
+ public static FeatureVectorBuffer makeFeatures(List feats) {
+ ArrayList idxList = new ArrayList();
+ ArrayList valList = new ArrayList();
+
+ for (String feat : feats) {
+
+ if (!SL_IOManager.lexm().containFeature(feat)) {
+ System.out.println("Flag of preview: "+ SL_IOManager.lexm().getNumOfFeature());
+ System.out.println("before Flag of feature set: "+ SL_IOManager.lexm().isAllowNewFeatures()+"\n");
+ if(SL_IOManager.lexm().isAllowNewFeatures())
+ //Todo see the error of the following line
+ // RunnerPLPL.lexm().previewFeature(feat);
+ System.out.println("After preview flag: "+SL_IOManager.lexm().getNumOfFeature());
+ System.out.println("Flag of after feature set: "+ SL_IOManager.lexm().isAllowNewFeatures()+"\n");
+ SL_IOManager.lexm().addFeature(feat);
+ }
+ if (SL_IOManager.lexm().containFeature(feat)) {
+
+ int fid = SL_IOManager.lexm().getFeatureId(feat);
+ idxList.add(fid);
+ valList.add(1.);
+ }
+ }
+
+ int[] idx = ArrayUtils.toPrimitive(idxList.toArray(new Integer[0]));
+ double[] val = ArrayUtils.toPrimitive(valList.toArray(new Double[0]));
+ //Todo check waht is going on in the next two lines
+ return new FeatureVectorBuffer(idx, val);
+ }
+
+
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SaulSLModel.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SaulSLModel.scala
new file mode 100644
index 00000000..b61edbe8
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SaulSLModel.scala
@@ -0,0 +1,34 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import java.io.{BufferedOutputStream, FileOutputStream, ObjectOutputStream}
+
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import edu.illinois.cs.cogcomp.sl.core.{SLModel, SLParameters}
+
+import scala.collection.mutable.ListBuffer
+
+/** Created by Parisa on 4/1/16.
+ */
+class SaulSLModel[HEAD <: AnyRef](cls: List[ConstrainedClassifier[_, HEAD]], listBuffer: ListBuffer[Array[Float]] = ListBuffer()) extends SLModel with Serializable {
+ val LTUWeightTemplates: ListBuffer[Array[Float]] = listBuffer
+ val Factors: ListBuffer[ConstrainedClassifier[_, HEAD]] = ListBuffer()
+ cls.foreach {
+ (c: ConstrainedClassifier[_, HEAD]) =>
+ Factors += (c)
+ }
+
+ override def saveModel(fileName: String): Unit = {
+ numFeatuerBit = SLParameters.HASHING_MASK
+ val oos: ObjectOutputStream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)))
+ oos.writeObject(this.wv)
+ oos.close
+ // logger.info("Done!")
+ }
+
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SaulSLTest.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SaulSLTest.scala
new file mode 100644
index 00000000..4b27d2eb
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/SaulSLTest.scala
@@ -0,0 +1,38 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import edu.illinois.cs.cogcomp.saul.datamodel.node.Node
+import edu.illinois.cs.cogcomp.sl.core.IStructure
+
+import scala.collection.JavaConversions._
+import scala.reflect.ClassTag
+
+/** Created by Parisa on 4/1/16.
+ */
+
+object SaulSLTest {
+
+ def evaluate[HEAD <: AnyRef](goldIstructure: List[IStructure], predictedIstructure: List[IStructure], model: SaulSLModel[HEAD]) = {
+ model.Factors.foreach {
+ x =>
+ {
+ }
+ }
+ }
+ def apply[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], model: SaulSLModel[HEAD], inference: Saul_SL_Inference[HEAD])(implicit t: ClassTag[HEAD]): Unit = {
+ val sp = SL_IOManager.makeSLProblem(node, cls, true)
+ var a: List[IStructure] = List[IStructure]()
+ sp.instanceList.toList.foreach {
+ ins =>
+ a = model.infSolver.getBestStructure(model.wv, ins) :: a
+ }
+ evaluate(a, sp.goldStructureList.toList, model)
+ }
+
+}
\ No newline at end of file
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Inference.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Inference.scala
new file mode 100644
index 00000000..4e907ddf
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Inference.scala
@@ -0,0 +1,136 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.lbjava.learn.{ LinearThresholdUnit, SparseNetworkLearner }
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import edu.illinois.cs.cogcomp.sl.core.{ AbstractInferenceSolver, IInstance, IStructure }
+import edu.illinois.cs.cogcomp.sl.util.WeightVector
+
+import scala.Array._
+import scala.collection.mutable.ListBuffer
+import scala.reflect.ClassTag
+
+/** Created by Parisa on 12/8/15.
+ */
+class Saul_SL_Inference[HEAD <: AnyRef](factors: List[ConstrainedClassifier[_, HEAD]], ltuTemplates: ListBuffer[Array[Float]])(implicit t: ClassTag[HEAD]) extends AbstractInferenceSolver {
+ val a = factors
+
+ override def getBestStructure(weight: WeightVector, ins: IInstance): IStructure = {
+
+ //updates the weights of all factors in a
+ updateWeights(weight)
+
+ // Now make the predictions using the updated constrained classifiers
+ val myStruct = makePredictions(ins)
+ myStruct
+ }
+
+ override def getLoss(ins: IInstance, gold: IStructure, pred: IStructure): Float = {
+ var TotalLoss: Float = 0
+ val myGold = gold.asInstanceOf[Saul_SL_Label_Structure[HEAD]]
+ val myPred = pred.asInstanceOf[Saul_SL_Label_Structure[HEAD]]
+ var count = 0
+ // println(ins.asInstanceOf[Saul_SL_Instance[HEAD]].head)
+ a.foreach {
+ x =>
+ var localLoss = 0
+ // val oracle: Classifier = x.onClassifier.getLabeler()
+ val candidates = x.getCandidates(ins.asInstanceOf[Saul_SL_Instance[HEAD]].head)
+ candidates.foreach {
+ ci =>
+ if (myGold.labels(count) != (myPred.labels(count)))
+ localLoss = localLoss + 1
+ count = count + 1
+ }
+ if (candidates.size != 0)
+ TotalLoss = TotalLoss + localLoss / candidates.size
+ }
+ TotalLoss = TotalLoss / factors.size
+ println("Loss=" + TotalLoss)
+ TotalLoss
+ }
+
+ override def getLossAugmentedBestStructure(weight: WeightVector, ins: IInstance, goldStructure: IStructure): IStructure = {
+
+ val myIns = ins.asInstanceOf[Saul_SL_Instance[HEAD]]
+ val FactorsNum = a.size
+
+ //set the weights of the classifiers with the trained weight so far
+ updateWeights(weight)
+
+ // augment all factors with loss for finding mvc
+ a.foreach {
+ cf =>
+ cf.onClassifier.classifier.setLossFlag()
+ cf.onClassifier.classifier.setCandidates(cf.getCandidates(myIns.head).size * FactorsNum)
+ }
+ // Now make the predictions using the loss augmented inference
+ val myStruct = makePredictions(ins)
+
+ //make the classifier to use its normal inference without considering loss in the future calls
+ a.map(x => x.onClassifier.classifier.unsetLossFlag())
+ myStruct
+ }
+
+ //This module receives a global weight vector and distribute it among factors (i.e. classifiers)
+
+ def updateWeights(weight: WeightVector): Unit =
+ {
+ var ltu_count = 0
+ var offset = 0
+ a.foreach {
+ cf =>
+ for (i <- 0 until cf.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.size()) {
+ val ltuSize = ltuTemplates(ltu_count).size //cf.onClassifier.asInstanceOf[SparseNetworkLBP].net.get(i).asInstanceOf[LinearThresholdUnit].getParameters.asInstanceOf[LinearThresholdUnit.Parameters].weightVector
+ // print("w", ltu_count, " size:\t", ltuSize.size)
+ val myLTUJointlyTrainedWeight = weight.getWeightArray.slice(offset, offset + ltuSize)
+ // var count = 0
+ // for (count <- cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector.size() until ltuSize.size)
+ // myLTUJointlyTrainedWeight = myLTUJointlyTrainedWeight :+ 0.asInstanceOf[Float]
+ // if (cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector.size()!= ltuSize.size) {
+ // println("size mismatch!", cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector.size(), ",", ltuSize.size)
+ // }
+ val exampleFeatureIndexes = ofDim[Int](myLTUJointlyTrainedWeight.length)
+ val weightVector = cf.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getLTU(i).asInstanceOf[LinearThresholdUnit].getWeightVector
+ weightVector.clear()
+
+ // val exampleFeatureIndexes = cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getLexicon.getMap.values.toArray.map(_.asInstanceOf[Int])//.toArray//.toArray().asInstanceOf[Array[Int]]
+ for (featureIndex <- myLTUJointlyTrainedWeight.indices) {
+ exampleFeatureIndexes(featureIndex) = featureIndex
+ weightVector.setWeight(featureIndex, myLTUJointlyTrainedWeight(featureIndex))
+ //cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getLexicon.;
+ }
+
+ //.getParameters.asInstanceOf[LinearThresholdUnit.Parameters]
+ // cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getLTU(i).getWeightVector.scaledAdd(exampleFeatureIndexes, Utils.converFarrayToD(myLTUJointlyTrainedWeight), 1.0)
+ offset = offset + ltuTemplates(ltu_count).length
+ ltu_count = ltu_count + 1
+ }
+ }
+ }
+
+ // Uses the current status of the factors and makes the necessary predictions
+ def makePredictions(ins: IInstance): Saul_SL_Label_Structure[HEAD] = {
+ val myIns = ins.asInstanceOf[Saul_SL_Instance[HEAD]]
+ val myStruct: Saul_SL_Label_Structure[HEAD] = new Saul_SL_Label_Structure[HEAD](factors.toList, myIns.head)
+
+ var labelCount = 0
+ a.foreach {
+ cf =>
+ cf.getCandidates(myIns.head).foreach {
+ x =>
+ //print(cf.onClassifier.classifier.name.substring(80) + "\t")
+ //print("gt:" + cf.onClassifier.classifier.getLabeler.discreteValue(x))
+ myStruct.labels(labelCount) = cf.classifier.discreteValue(x) //.onClassifier.classifier.discreteValue(x)
+ //println("\tmvc:" + myStruct.labels(labelCount))
+ labelCount = labelCount + 1
+ }
+ }
+ myStruct
+ }
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Instance.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Instance.scala
new file mode 100644
index 00000000..0b054ccc
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Instance.scala
@@ -0,0 +1,16 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.sl.core.IInstance
+
+/** Created by Parisa on 12/10/15.
+ */
+case class Saul_SL_Instance[HEAD <: AnyRef](x: HEAD) extends IInstance {
+ val head: HEAD = x
+}
+
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Label_Structure.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Label_Structure.scala
new file mode 100644
index 00000000..826358e6
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Saul_SL_Label_Structure.scala
@@ -0,0 +1,36 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.lbjava.classify.Classifier
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import edu.illinois.cs.cogcomp.sl.core.IStructure
+
+import scala.collection.JavaConversions._
+import scala.collection.mutable.ListBuffer
+
+/** Created by Parisa on 12/10/15.
+ */
+class Saul_SL_Label_Structure[HEAD <: AnyRef](l: List[ConstrainedClassifier[_, HEAD]], x: HEAD) extends IStructure {
+
+ var labels: ListBuffer[String] = ListBuffer()
+ val head = x
+ l.foreach { (c: ConstrainedClassifier[_, HEAD]) =>
+ {
+ val oracle: Classifier = c.onClassifier.classifier.getLabeler()
+ val candis: Seq[_] = c.getCandidates(x)
+ candis.foreach {
+ ci =>
+ labels.add(oracle.discreteValue(ci))
+
+ }
+ }
+ }
+ def equals(a: Saul_SL_Label_Structure[HEAD]): Boolean = {
+ a.labels.equals(labels)
+ }
+}
\ No newline at end of file
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/StructuredLearning.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/StructuredLearning.scala
new file mode 100644
index 00000000..66c699e1
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/StructuredLearning.scala
@@ -0,0 +1,64 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+
+import edu.illinois.cs.cogcomp.saul.classifier.{ ClassifierUtils, ConstrainedClassifier }
+import edu.illinois.cs.cogcomp.saul.datamodel.node.Node
+import edu.illinois.cs.cogcomp.sl.core._
+import edu.illinois.cs.cogcomp.sl.learner._
+
+import scala.collection.JavaConversions._
+import scala.reflect._
+
+/** Created by Parisa on 12/3/15.
+ */
+object StructuredLearning {
+ def apply[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], usePreTrained: Boolean = false)(implicit headTag: ClassTag[HEAD]) =
+ {
+ trainSSVM[HEAD](node, cls, usePreTrained)
+ }
+
+ def trainSSVM[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_, HEAD]], usePreTrained: Boolean)(implicit t: ClassTag[HEAD]): SaulSLModel[HEAD] = {
+ val sp = SL_IOManager.makeSLProblem(node, cls)
+ val model = Initialize(node, new SaulSLModel(cls), usePreTrained)
+
+ model.infSolver = new Saul_SL_Inference[HEAD](model.Factors.toList, model.LTUWeightTemplates)
+ val para = new SLParameters
+ // para.STOP_CONDITION = 0.0001f
+ // para.INNER_STOP_CONDITION= 0.0001f
+ // para.C_FOR_STRUCTURE = 1
+ // para.CHECK_INFERENCE_OPT = false
+
+ model.featureGenerator = new SL_FeatureGenerator(model)
+ para.loadConfigFile("./config/DCD.config")
+ model.para = para
+ val learner = LearnerFactory.getLearner(model.infSolver, model.featureGenerator, para);
+ model.wv = learner.train(sp, model.wv)
+ model.saveModel("SL_ER_Model.txt")
+ return model
+ }
+
+ def Eval1[T <: AnyRef, H <: AnyRef](cf: ConstrainedClassifier[T, H], sp: SLProblem) = {
+
+ val testExamples: Seq[T] = sp.instanceList.map(x => cf.getCandidates(x.asInstanceOf[Saul_SL_Instance[H]].head)).flatten.distinct
+ ClassifierUtils.TestClassifiers.apply1(testExamples, cf)
+ }
+ def Evaluate[HEAD <: AnyRef](node: Node[HEAD], cls: List[ConstrainedClassifier[_ <: AnyRef, HEAD]], myModel: SaulSLModel[HEAD], modelPath: String)(implicit t: ClassTag[HEAD]): Unit = {
+
+ val sp: SLProblem = SL_IOManager.makeSLProblem[HEAD](node, cls, testing = true)
+ println("Before weight update:")
+ val results1 = for (cf <- myModel.Factors.toList.asInstanceOf[List[ConstrainedClassifier[_ <: AnyRef, HEAD]]]) yield {
+ Eval1(cf, sp)
+ }
+ println("after weight update:")
+ myModel.infSolver.asInstanceOf[Saul_SL_Inference[HEAD]].updateWeights(myModel.wv)
+ val results = for (cf <- myModel.Factors.toList.asInstanceOf[List[ConstrainedClassifier[_ <: AnyRef, HEAD]]]) yield {
+ Eval1(cf, sp)
+ }
+ }
+}
+
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Utils.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Utils.scala
new file mode 100644
index 00000000..4d6f7c90
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/Utils.scala
@@ -0,0 +1,19 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+import Array._
+/** Created by Parisa on 4/1/16.
+ */
+object Utils {
+ def converFarrayToD(a: Array[Float]): Array[Double] = {
+ var d: Array[Double] = ofDim[Double](a.length)
+ for (i <- 0 until a.length) {
+ d.update(i, Float.float2double(a(i)))
+ }
+ d
+ }
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/lossAugmentedClassifier.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/lossAugmentedClassifier.scala
new file mode 100644
index 00000000..620eff6c
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SL_model/lossAugmentedClassifier.scala
@@ -0,0 +1,48 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saul.classifier.SL_model
+import java.io.PrintStream
+
+import edu.illinois.cs.cogcomp.lbjava.classify.{ FeatureVector, ScoreSet }
+import edu.illinois.cs.cogcomp.lbjava.learn.{ Learner, SparseNetworkLearner }
+
+/** Created by Parisa on 4/1/16.
+ */
+class lossAugmentedClassifier[T <: AnyRef](c: Learner, cand_num: Int = 1) extends Learner("lossAugmentedClassifier") {
+ override def getInputType: String = { "dummy" }
+
+ override def allowableValues: Array[String] = c.allowableValues() //{ Array[String]("false", "true") }
+
+ override def equals(o: Any): Boolean = { getClass == o.getClass }
+
+ /** The reason for true to be -1 is because the internal optimization by default finds the maximizer, while in this
+ * problem we are looking for a minimizer
+ */
+ override def scores(example: AnyRef): ScoreSet = {
+ if (cand_num == 0)
+ print("There is no relevant component of this type in the head to be classified.")
+ val cf = c.asInstanceOf[SparseNetworkLearner]
+ val gold = cf.getLabeler.discreteValue(example)
+ val lLexicon = cf.getLabelLexicon
+ val resultS: ScoreSet = c.scores(example) //new ScoreSet
+ for (i <- 0 until lLexicon.size()) {
+ if (lLexicon.lookupKey(i).valueEquals(gold))
+ resultS.put(lLexicon.lookupKey(i).getStringValue, resultS.getScore(lLexicon.lookupKey(i).getStringValue).score - (1 / (cand_num)))
+ else
+ resultS.put(lLexicon.lookupKey(i).getStringValue, resultS.getScore(lLexicon.lookupKey(i).getStringValue).score + (1 / (cand_num)))
+ }
+ resultS
+ }
+
+ override def write(printStream: PrintStream): Unit = ???
+
+ override def scores(ints: Array[Int], doubles: Array[Double]): ScoreSet = ???
+
+ override def classify(ints: Array[Int], doubles: Array[Double]): FeatureVector = ???
+
+ override def learn(ints: Array[Int], doubles: Array[Double], ints1: Array[Int], doubles1: Array[Double]): Unit = ???
+}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SimpleSparseNetwork.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SimpleSparseNetwork.scala
new file mode 100644
index 00000000..4484fc07
--- /dev/null
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/SimpleSparseNetwork.scala
@@ -0,0 +1,98 @@
+package edu.illinois.cs.cogcomp.saul.classifier
+
+/** Created by Parisa on 11/2/16.
+ */
+
+import edu.illinois.cs.cogcomp.lbjava.learn.{ LinearThresholdUnit, SparseNetworkLearner }
+import edu.illinois.cs.cogcomp.saul.datamodel.node.Node
+import org.slf4j.{ Logger, LoggerFactory }
+
+import scala.reflect.ClassTag
+
+object SimpleSparseNetwork {
+
+ val logger: Logger = LoggerFactory.getLogger(this.getClass)
+ var difference = 0
+ def apply[HEAD <: AnyRef](node: Node[HEAD], cls: Learnable[HEAD], init: Boolean)(implicit headTag: ClassTag[HEAD]) = {
+ train[HEAD](node, cls, 1, init)
+ }
+
+ def apply[HEAD <: AnyRef](node: Node[HEAD], cls: Learnable[HEAD], it: Int, init: Boolean)(implicit headTag: ClassTag[HEAD]) = {
+ train[HEAD](node, cls, it, init)
+ }
+
+ @scala.annotation.tailrec
+ def train[HEAD <: AnyRef](node: Node[HEAD], currentClassifier: Learnable[HEAD], it: Int, init: Boolean)(implicit headTag: ClassTag[HEAD]): Unit = {
+ // forall members in collection of the head (dm.t) do
+ logger.info("Training iteration: " + it)
+ if (it == 0) {
+ // Done
+ println("difference=", difference)
+ } else {
+ val allHeads = node.getTrainingInstances
+ difference = 0
+ allHeads.zipWithIndex.foreach {
+ case (candidate, idx) =>
+
+ // if (idx % 5000 == 0)
+ logger.info(s"Training: $idx examples inferred.")
+ val oracle = currentClassifier.getLabeler
+ val baseClassifier = currentClassifier.classifier.asInstanceOf[SparseNetworkLearner]
+
+ {
+ def trainOnce() = {
+ val result = currentClassifier.classifier.discreteValue(candidate)
+ val trueLabel = oracle.discreteValue(candidate)
+ val lLexicon = currentClassifier.getLabelLexicon
+ var LTU_actual: Int = 0
+ var LTU_predicted: Int = 0
+ for (i <- 0 until lLexicon.size()) {
+ if (lLexicon.lookupKey(i).valueEquals(result))
+ LTU_predicted = i
+ if (lLexicon.lookupKey(i).valueEquals(trueLabel))
+ LTU_actual = i
+ }
+
+ // The idea is that when the prediction is wrong the LTU of the actual class should be promoted
+ // and the LTU of the predicted class should be demoted.
+ if (!result.equals(trueLabel)) //equals("true") && trueLabel.equals("false") )
+ {
+ val a = currentClassifier.getExampleArray(candidate)
+ val a0 = a(0).asInstanceOf[Array[Int]] //exampleFeatures
+ val a1 = a(1).asInstanceOf[Array[Double]] // exampleValues
+ val exampleLabels = a(2).asInstanceOf[Array[Int]]
+ val labelValues = a(3).asInstanceOf[Array[Double]]
+ val label = exampleLabels(0)
+ var N = baseClassifier.getNetwork.size
+
+ if (label >= N || baseClassifier.getNetwork.get(label) == null) {
+ val conjugateLabels = baseClassifier.isUsingConjunctiveLabels | baseClassifier.getLabelLexicon.lookupKey(label).isConjunctive
+ baseClassifier.setConjunctiveLabels(conjugateLabels)
+
+ val ltu: LinearThresholdUnit = baseClassifier.getBaseLTU.clone.asInstanceOf[LinearThresholdUnit]
+ ltu.initialize(baseClassifier.getNumExamples, baseClassifier.getNumFeatures)
+ baseClassifier.getNetwork.set(label, ltu)
+ N = label + 1
+ }
+
+ // test push
+ val ltu_actual = baseClassifier.getLTU(LTU_actual).asInstanceOf[LinearThresholdUnit]
+ val ltu_predicted = baseClassifier.getLTU(LTU_predicted).asInstanceOf[LinearThresholdUnit]
+
+ if (ltu_actual != null)
+ ltu_actual.promote(a0, a1, 0.1)
+ if (ltu_predicted != null)
+ ltu_predicted.demote(a0, a1, 0.1)
+ }
+ }
+
+ trainOnce()
+ }
+ }
+ train(node, currentClassifier, it - 1, false)
+ }
+
+ }
+
+}
+
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InferenceCondition.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InferenceCondition.scala
index 26d7c7c5..e0d967e8 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InferenceCondition.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InferenceCondition.scala
@@ -6,22 +6,25 @@
*/
package edu.illinois.cs.cogcomp.saul.classifier.infer
-import edu.illinois.cs.cogcomp.infer.ilp.ILPSolver
import edu.illinois.cs.cogcomp.lbjava.infer.ParameterizedConstraint
import edu.illinois.cs.cogcomp.saul.constraint.LfsConstraint
+import edu.illinois.cs.cogcomp.infer.ilp.ILPSolver
+import edu.illinois.cs.cogcomp.lbjava.learn.{ IdentityNormalizer, Learner, Normalizer }
-import scala.reflect.ClassTag
-
-abstract class InferenceCondition[INPUT <: AnyRef, HEAD <: AnyRef](solver: ILPSolver) {
+abstract class InferenceCondition[INPUT <: AnyRef, HEAD <: AnyRef](solver: ILPSolver, normalize: Normalizer = new IdentityNormalizer) {
def subjectTo: LfsConstraint[HEAD]
def transfer(t: HEAD): JointTemplate[HEAD] = {
- new JointTemplate[HEAD](t, solver) {
+ new JointTemplate[HEAD](t, solver, normalize) {
// TODO: Define this function
override def getSubjectToInstance: ParameterizedConstraint = {
subjectTo.transfer
}
+ //verbosity = 1
// TODO: override other functions that needed here
+ override def getNormalizer(c: Learner): Normalizer = {
+ normalize
+ }
}
}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InitSparseNetwork.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InitSparseNetwork.scala
index a9df6c4c..94c04cef 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InitSparseNetwork.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/InitSparseNetwork.scala
@@ -14,10 +14,11 @@ import edu.illinois.cs.cogcomp.saul.datamodel.node.Node
*/
object InitSparseNetwork {
def apply[HEAD <: AnyRef](node: Node[HEAD], cClassifier: ConstrainedClassifier[_, HEAD]) = {
+
val allHeads = node.getTrainingInstances
//this means we are not reading any model into the SparseNetworks
// but we forget all the models and go over the data to build the right
- // size for the lexicon and the right number of the ltu s
+ // size for the lexicon and the right number of ltu s
cClassifier.onClassifier.classifier.forget()
val iLearner = cClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner]
allHeads.foreach {
@@ -33,7 +34,7 @@ object InitSparseNetwork {
if (label >= N || iLearner.getNetwork.get(label) == null) {
val isConjunctiveLabels = iLearner.isUsingConjunctiveLabels | iLearner.getLabelLexicon.lookupKey(label).isConjunctive
iLearner.setConjunctiveLabels(isConjunctiveLabels)
- val ltu: LinearThresholdUnit = iLearner.getBaseLTU
+ val ltu: LinearThresholdUnit = iLearner.getBaseLTU.clone().asInstanceOf[LinearThresholdUnit]
ltu.initialize(iLearner.getNumExamples, iLearner.getNumFeatures)
iLearner.getNetwork.set(label, ltu)
}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/JointTemplate.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/JointTemplate.scala
index 21a754fc..355de0fe 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/JointTemplate.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/classifier/infer/JointTemplate.scala
@@ -10,20 +10,22 @@ import edu.illinois.cs.cogcomp.infer.ilp.ILPSolver
import edu.illinois.cs.cogcomp.lbjava.infer.{ ParameterizedConstraint, ILPInference }
import edu.illinois.cs.cogcomp.lbjava.learn.{ IdentityNormalizer, Normalizer, Learner }
-abstract class JointTemplate[T](head: T, solver: ILPSolver) extends ILPInference(head, solver) {
+abstract class JointTemplate[T](head: T, solver: ILPSolver, norm: Normalizer = new IdentityNormalizer) extends ILPInference(head, solver) {
constraint = this.getSubjectToInstance.makeConstraint(head)
override def getHeadType: String = {
"T"
}
+ verbosity = 2
+
override def getHeadFinderTypes: Array[String] = {
Array[String](null, null)
}
- override def getNormalizer(c: Learner): Normalizer = {
- new IdentityNormalizer
- }
+ override def getNormalizer(c: Learner): Normalizer //= {
+ // new IdentityNormalizer
+ //}
def getSubjectToInstance: ParameterizedConstraint
}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/constraint/LfsConstraint.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/constraint/LfsConstraint.scala
index 0a85942e..d0e17837 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/constraint/LfsConstraint.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/constraint/LfsConstraint.scala
@@ -6,14 +6,12 @@
*/
package edu.illinois.cs.cogcomp.saul.constraint
-import edu.illinois.cs.cogcomp.infer.ilp.ILPSolver
-import edu.illinois.cs.cogcomp.lbjava.infer.{ ParameterizedConstraint, FirstOrderConstraint }
+import edu.illinois.cs.cogcomp.lbjava.infer.{ FirstOrderConstraint, ParameterizedConstraint }
import edu.illinois.cs.cogcomp.saul.classifier.infer.InferenceCondition
-
-import scala.reflect.ClassTag
+import edu.illinois.cs.cogcomp.infer.ilp.ILPSolver
+import edu.illinois.cs.cogcomp.lbjava.learn.{ IdentityNormalizer, Normalizer }
abstract class LfsConstraint[T <: AnyRef] {
-
def makeConstrainDef(x: T): FirstOrderConstraint
def evalDiscreteValue(t: T): String = {
@@ -40,8 +38,8 @@ abstract class LfsConstraint[T <: AnyRef] {
val lc = this
- def createInferenceCondition[C <: AnyRef](solver: ILPSolver): InferenceCondition[C, T] = {
- new InferenceCondition[C, T](solver) {
+ def createInferenceCondition[C <: AnyRef](solver: ILPSolver, normalizer: Normalizer = new IdentityNormalizer): InferenceCondition[C, T] = {
+ new InferenceCondition[C, T](solver, normalizer) {
override def subjectTo: LfsConstraint[T] = lc
}
}
diff --git a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/datamodel/node/Node.scala b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/datamodel/node/Node.scala
index 46f6b4b8..a9eb3364 100644
--- a/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/datamodel/node/Node.scala
+++ b/saul-core/src/main/scala/edu/illinois/cs/cogcomp/saul/datamodel/node/Node.scala
@@ -17,6 +17,7 @@ import java.util.concurrent.atomic.AtomicInteger
import scala.collection.mutable
import scala.collection.mutable.{ ArrayBuffer, ListBuffer, HashMap => MutableHashMap, LinkedHashSet => MutableSet, Map => MutableMap }
+
import scala.reflect.ClassTag
trait NodeProperty[T <: AnyRef] extends Property[T] {
diff --git a/saul-core/src/test/scala/ssvm/binaryConstraints.scala b/saul-core/src/test/scala/ssvm/binaryConstraints.scala
new file mode 100644
index 00000000..0e76932c
--- /dev/null
+++ b/saul-core/src/test/scala/ssvm/binaryConstraints.scala
@@ -0,0 +1,20 @@
+package ssvm
+
+/** Created by Parisa on 10/21/16.
+ */
+
+import edu.illinois.cs.cogcomp.infer.ilp.OJalgoHook
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import ssvm.randomClassifiers.bClassifier
+
+object binaryConstraints {
+
+ val binaryConstraint = ConstrainedClassifier.constraint[String] {
+
+ x: String => bClassifier on x is "-1"
+ }
+}
+object binaryConstrainedClassifier extends ConstrainedClassifier[String, String](bClassifier) {
+ def subjectTo = binaryConstraints.binaryConstraint
+ override val solver = new OJalgoHook
+}
\ No newline at end of file
diff --git a/saul-core/src/test/scala/ssvm/randomDataApp.scala b/saul-core/src/test/scala/ssvm/randomDataApp.scala
new file mode 100644
index 00000000..6666fe43
--- /dev/null
+++ b/saul-core/src/test/scala/ssvm/randomDataApp.scala
@@ -0,0 +1,43 @@
+package ssvm
+import ssvm.randomClassifiers.bClassifier
+
+/** Created by Parisa on 10/13/16.
+ */
+object randomDataApp extends App {
+
+ import randomDataModel._
+ for (i <- 1 to 100) {
+ randomNode.addInstance(i.toString)
+ }
+ val ex = randomNode.getAllInstances
+ val graphCacheFile = "models/temp.model"
+ randomDataModel.deriveInstances()
+ randomDataModel.write(graphCacheFile)
+
+ bClassifier.learn(30)
+ bClassifier.test(ex)
+
+ binaryConstrainedClassifier.test(ex)
+
+ // val w = bClassifier.classifier.getLTU(1).asInstanceOf[LinearThresholdUnit].getWeightVector
+ //
+ // val p2 = (randomNode() prop randomProperty) zip (randomNode() prop randomLabel)
+ //
+ // val x2 = DenseVector(p2.filter(x => x._2.equals("1")).map(x => x._1(0)).toArray)
+ // val y2 = DenseVector(p2.filter(x => x._2.equals("1")).map(x => x._1(1)).toArray)
+ // val x_minus = DenseVector(p2.filter(x => x._2.equals("-1")).map(x => x._1(0)).toArray)
+ // val y_minus = DenseVector(p2.filter(x => x._2.equals("-1")).map(x => x._1(1)).toArray)
+ //
+ // val f = Figure()
+ // val p = f.subplot(0)
+ // p.ylim(-3.0, 3)
+ // p.xlim(-3, 3)
+ // val x = linspace(0.0, 1.0)
+ // p += plot(x2, y2, '.')
+ // p += plot(x_minus, y_minus, '.')
+ // p += plot(DenseVector(0, w.getWeight(0)), DenseVector(0, w.getWeight(1)))
+ // p += plot(DenseVector(10 * w.getWeight(1), (-10) * w.getWeight(1)), DenseVector(-10 * w.getWeight(0), 10 * w.getWeight(0)))
+ // p.xlabel = "x axis"
+ // p.ylabel = "y axis"
+ // f.saveas("lines.png")
+}
diff --git a/saul-core/src/test/scala/ssvm/randomDataModel.scala b/saul-core/src/test/scala/ssvm/randomDataModel.scala
new file mode 100644
index 00000000..fe72f050
--- /dev/null
+++ b/saul-core/src/test/scala/ssvm/randomDataModel.scala
@@ -0,0 +1,34 @@
+package ssvm
+
+import edu.illinois.cs.cogcomp.saul.datamodel.DataModel
+
+import scala.math._
+
+/** Created by Parisa on 10/14/16.
+ */
+object randomDataModel extends DataModel {
+ val randomNode = node[String]
+ val th = Pi / 3
+ val c = cos(th)
+ val s = sin(th)
+ val r = scala.util.Random
+ r.setSeed(0)
+
+ val randomLabel = property(randomNode, cache = true) {
+ x: String =>
+ (2 * (if (r.nextGaussian() > 0) 1 else 0) - 1).toString
+ }
+ val binaryLabel = property(randomNode, cache = true) {
+ x: String =>
+ if (randomLabel == "-1") false
+ else true
+ }
+
+ val randomProperty = property(randomNode, cache = true) {
+ x: String =>
+ val p = List(2 * r.nextGaussian().toDouble, 0.5 * r.nextGaussian().toDouble)
+ val p1new = p(1) + randomLabel(x).toDouble
+ val p2 = List(c * p1new - s * p(1), c * p1new + s * p(1))
+ p2
+ }
+}
diff --git a/saul-core/src/test/scala/ssvm/randomclassifiers.scala b/saul-core/src/test/scala/ssvm/randomclassifiers.scala
new file mode 100644
index 00000000..7c4da843
--- /dev/null
+++ b/saul-core/src/test/scala/ssvm/randomclassifiers.scala
@@ -0,0 +1,16 @@
+package ssvm
+
+import edu.illinois.cs.cogcomp.lbjava.learn.SparseAveragedPerceptron
+import edu.illinois.cs.cogcomp.saul.classifier.Learnable
+
+/** Created by Parisa on 10/14/16.
+ */
+object randomClassifiers {
+ import randomDataModel._
+ object bClassifier extends Learnable[String](randomNode) {
+ def label = binaryLabel
+ override def feature = using(randomProperty)
+ override lazy val classifier = new SparseAveragedPerceptron()
+ override val useCache = true
+ }
+}
diff --git a/saul-examples/src/main/java/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeReader.java b/saul-examples/src/main/java/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeReader.java
new file mode 100644
index 00000000..6f1e0d47
--- /dev/null
+++ b/saul-examples/src/main/java/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeReader.java
@@ -0,0 +1,27 @@
+package edu.illinois.cs.cogcomp.saulexamples.Badge;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BadgeReader {
+ public List badges;
+ // int currentBadge;
+
+ public BadgeReader(String dataFile) {
+ badges = new ArrayList();
+
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(dataFile)));
+
+ String str;
+ while ((str = br.readLine()) != null) {
+ badges.add(str);
+ }
+
+ br.close();
+ }catch (Exception e) {}
+ }
+}
\ No newline at end of file
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeClassifiers.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeClassifiers.scala
new file mode 100644
index 00000000..344599ab
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeClassifiers.scala
@@ -0,0 +1,33 @@
+package edu.illinois.cs.cogcomp.saulexamples.Badge
+
+import edu.illinois.cs.cogcomp.lbjava.learn.{ SparseNetworkLearner, SparsePerceptron }
+
+/** Created by Parisa on 9/13/16.
+ */
+
+object BadgeClassifiers {
+ import BadgeDataModel._
+ import edu.illinois.cs.cogcomp.saul.classifier.Learnable
+ object BadgeClassifier extends Learnable[String](badge) {
+ def label = BadgeLabel
+ override lazy val classifier = new SparsePerceptron()
+ override def feature = using(BadgeFeature1)
+ }
+ object BadgeOppositClassifier extends Learnable[String](badge) {
+ def label = BadgeOppositLabel
+ override lazy val classifier = new SparsePerceptron()
+ override def feature = using(BadgeFeature1)
+ }
+
+ object BadgeClassifierMulti extends Learnable[String](badge) {
+ def label = BadgeLabel
+ override lazy val classifier = new SparseNetworkLearner()
+ override def feature = using(BadgeFeature1)
+ }
+
+ object BadgeOppositClassifierMulti extends Learnable[String](badge) {
+ def label = BadgeOppositLabel
+ override lazy val classifier = new SparseNetworkLearner()
+ override def feature = using(BadgeFeature1)
+ }
+}
\ No newline at end of file
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeConstraintClassifiers.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeConstraintClassifiers.scala
new file mode 100644
index 00000000..b613d94d
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeConstraintClassifiers.scala
@@ -0,0 +1,37 @@
+package edu.illinois.cs.cogcomp.saulexamples.Badge
+
+import edu.illinois.cs.cogcomp.infer.ilp.OJalgoHook
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import edu.illinois.cs.cogcomp.saul.constraint.ConstraintTypeConversion._
+import edu.illinois.cs.cogcomp.saulexamples.Badge.BadgeClassifiers.{ BadgeOppositClassifierMulti, BadgeClassifierMulti, BadgeClassifier, BadgeOppositClassifier }
+import edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData.BinaryConstraints
+/** Created by Parisa on 11/1/16.
+ */
+object BadgeConstraintClassifiers {
+
+ val binaryConstraint = ConstrainedClassifier.constraint[String] {
+ x: String =>
+ (BadgeClassifier on x is "negative") ==> (BadgeOppositClassifier on x is "positive")
+ }
+
+ object badgeConstrainedClassifier extends ConstrainedClassifier[String, String](BadgeClassifier) {
+ def subjectTo = BinaryConstraints.binaryConstraint
+ override val solver = new OJalgoHook
+ }
+
+ object oppositBadgeConstrainedClassifier extends ConstrainedClassifier[String, String](BadgeOppositClassifier) {
+ def subjectTo = BinaryConstraints.binaryConstraint
+ override val solver = new OJalgoHook
+ }
+
+ object badgeConstrainedClassifierMulti extends ConstrainedClassifier[String, String](BadgeClassifierMulti) {
+ def subjectTo = BinaryConstraints.binaryConstraint
+ override val solver = new OJalgoHook
+ }
+
+ object oppositBadgeConstrainedClassifierMulti extends ConstrainedClassifier[String, String](BadgeOppositClassifierMulti) {
+ def subjectTo = BinaryConstraints.binaryConstraint
+ override val solver = new OJalgoHook
+ }
+
+}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeDataModel.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeDataModel.scala
new file mode 100644
index 00000000..70d7a1bf
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BadgeDataModel.scala
@@ -0,0 +1,40 @@
+package edu.illinois.cs.cogcomp.saulexamples.Badge
+
+import edu.illinois.cs.cogcomp.saul.datamodel.DataModel
+
+/** Created by Parisa on 9/13/16.
+ */
+object BadgeDataModel extends DataModel {
+
+ val badge = node[String]
+
+ val BadgeFeature1 = property(badge) {
+ x: String =>
+ {
+ val tokens = x.split(" ")
+ tokens(1).charAt(1).toString
+ }
+ }
+
+ val BadgeLabel = property(badge)("true", "false") {
+ x: String =>
+ {
+ val tokens = x.split(" ")
+ if (tokens(0).equals("+"))
+ "true"
+ else
+ "false"
+ }
+ }
+
+ val BadgeOppositLabel = property(badge)("true", "false") {
+ x: String =>
+ {
+ val tokens = x.split(" ")
+ if (tokens(0).equals("+"))
+ "false"
+ else
+ "true"
+ }
+ }
+}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BagesApp.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BagesApp.scala
new file mode 100644
index 00000000..d0d37dcc
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/Badge/BagesApp.scala
@@ -0,0 +1,80 @@
+package edu.illinois.cs.cogcomp.saulexamples.Badge
+
+/** Created by Parisa on 9/13/16.
+ */
+
+import edu.illinois.cs.cogcomp.saul.classifier.SL_model.StructuredLearning
+import edu.illinois.cs.cogcomp.saul.classifier.{ClassifierUtils, JointTrain, JointTrainSparseNetwork}
+import edu.illinois.cs.cogcomp.saulexamples.Badge.BadgeClassifiers.{BadgeOppositClassifier, BadgeClassifier}
+import edu.illinois.cs.cogcomp.saulexamples.Badge.BadgeConstraintClassifiers.{badgeConstrainedClassifier, badgeConstrainedClassifierMulti, oppositBadgeConstrainedClassifier, oppositBadgeConstrainedClassifierMulti}
+import edu.illinois.cs.cogcomp.saulexamples.Badge.BadgeDataModel._
+
+import scala.collection.JavaConversions._
+object BadgesApp {
+
+ val allNamesTrain = new BadgeReader("data/badges/badges.train").badges
+ val allNamesTest = new BadgeReader("data/badges/badges.test").badges
+
+ badge.populate(allNamesTrain)
+ badge.populate(allNamesTest, false)
+
+ val cls = List(badgeConstrainedClassifierMulti, oppositBadgeConstrainedClassifierMulti)
+
+ object BadgeExperimentType extends Enumeration {
+ val JoinTrainSparsePerceptron, JointTrainSparseNetwork, JointTrainSparseNetworkLossAugmented, JoinTrainSL = Value
+ }
+
+ def main(args: Array[String]): Unit = {
+ /** Choose the experiment you're interested in by changing the following line */
+ val testType = BadgeExperimentType.JointTrainSparseNetworkLossAugmented
+
+ testType match {
+ case BadgeExperimentType.JoinTrainSparsePerceptron => JoinTrainSparsePerceptron()
+ case BadgeExperimentType.JointTrainSparseNetwork => JoinTrainSparseNetwork()
+ case BadgeExperimentType.JointTrainSparseNetworkLossAugmented => LossAugmentedJoinTrainSparseNetwork()
+ case BadgeExperimentType.JoinTrainSL => JoinTrainSL()
+ }
+ }
+
+ /*Test the join training with SparsePerceptron*/
+ def JoinTrainSparsePerceptron(): Unit = {
+ BadgeClassifier.test()
+ BadgeOppositClassifier.test()
+ JointTrain.train(BadgeDataModel.badge, List(badgeConstrainedClassifier, oppositBadgeConstrainedClassifier), 5)
+ oppositBadgeConstrainedClassifier.test()
+ badgeConstrainedClassifier.test()
+ BadgeClassifier.test()
+ }
+
+ /*Test the joinTraining with SparseNetwork*/
+ def JoinTrainSparseNetwork(): Unit = {
+
+ JointTrainSparseNetwork.train(badge, cls, 5, init = true)
+
+ badgeConstrainedClassifierMulti.test()
+ oppositBadgeConstrainedClassifierMulti.test()
+ }
+
+ /*Test the joinTraining with SparseNetwork and doing loss augmented inference*/
+ def LossAugmentedJoinTrainSparseNetwork(): Unit = {
+
+ JointTrainSparseNetwork.train(badge, cls, 5, init = true,lossAugmented = true)
+
+ badgeConstrainedClassifierMulti.test()
+ oppositBadgeConstrainedClassifierMulti.test()
+ }
+
+ /*Test the joinTraining with Structured output prediction in SL*/
+ def JoinTrainSL(): Unit = {
+
+ ClassifierUtils.InitializeClassifiers(badge, cls: _*)
+ val m = StructuredLearning(badge, cls, usePreTrained = false)
+
+ badgeConstrainedClassifierMulti.test()
+ oppositBadgeConstrainedClassifier.test()
+
+ StructuredLearning.Evaluate(badge, cls, m, "")
+
+ }
+
+}
\ No newline at end of file
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/BinaryConstraints.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/BinaryConstraints.scala
new file mode 100644
index 00000000..0dae89a0
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/BinaryConstraints.scala
@@ -0,0 +1,31 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData
+
+import edu.illinois.cs.cogcomp.infer.ilp.OJalgoHook
+import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
+import edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData.RandomClassifiers.{ OppositClassifier, BinaryClassifier }
+import edu.illinois.cs.cogcomp.saul.constraint.ConstraintTypeConversion._
+/** Created by Parisa on 10/28/16.
+ */
+object BinaryConstraints {
+ val binaryConstraint = ConstrainedClassifier.constraint[String] {
+ x: String =>
+ (BinaryClassifier on x is "-1") ==> (OppositClassifier on x is "1")
+ }
+
+ object binaryConstrainedClassifier extends ConstrainedClassifier[String, String](BinaryClassifier) {
+ def subjectTo = BinaryConstraints.binaryConstraint
+ override val solver = new OJalgoHook
+ }
+
+ object oppositBinaryConstrainedClassifier extends ConstrainedClassifier[String, String](OppositClassifier) {
+ def subjectTo = BinaryConstraints.binaryConstraint
+ override val solver = new OJalgoHook
+ }
+}
+
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomApp.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomApp.scala
new file mode 100644
index 00000000..77b5972c
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomApp.scala
@@ -0,0 +1,43 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData
+
+import edu.illinois.cs.cogcomp.lbjava.learn.SparsePerceptron
+import edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData.BinaryConstraints.{ binaryConstrainedClassifier, oppositBinaryConstrainedClassifier }
+import edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData.RandomClassifiers.{ BinaryClassifier, OppositClassifier }
+
+object RandomApp extends App {
+
+ import RandomDataModel._
+ for (i <- 1 to 100) {
+ randomNode.addInstance(i.toString)
+ }
+ val examples = randomNode.getAllInstances
+ BinaryClassifier.classifier.asInstanceOf[SparsePerceptron].setInitialWeight(0.01)
+ OppositClassifier.classifier.asInstanceOf[SparsePerceptron].setInitialWeight(0.02)
+
+ // val graphCacheFile = "models/temp.model"
+ //RandomDataModel.deriveInstances()
+ // RandomDataModel.write(graphCacheFile)
+ //BinaryClassifier.learn(30)
+ BinaryClassifier.test(examples)
+ //OppositClassifier.learn(30)
+ //OppositClassifier.test(examples)
+ //binaryConstrainedClassifier.test(examples)
+ val ccl = List(binaryConstrainedClassifier, oppositBinaryConstrainedClassifier)
+
+ // JointTrain.train(randomNode,ccl ,10)
+
+ //binaryConstrainedClassifier.classifier.asInstanceOf[SparsePerceptron].setInitialWeight(0.01)
+
+ BinaryClassifier.test(examples)
+
+ OppositClassifier.test(examples)
+ binaryConstrainedClassifier.test(examples)
+ oppositBinaryConstrainedClassifier.test(examples)
+
+}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomDataApp.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomDataApp.scala
deleted file mode 100644
index 4ec2402a..00000000
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomDataApp.scala
+++ /dev/null
@@ -1,22 +0,0 @@
-/** This software is released under the University of Illinois/Research and Academic Use License. See
- * the LICENSE file in the root folder for details. Copyright (c) 2016
- *
- * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
- * http://cogcomp.cs.illinois.edu/
- */
-package edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData
-import edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData.RandomClassifiers.BinaryClassifier
-
-object RandomDataApp extends App {
-
- import RandomDataModel._
- for (i <- 1 to 100) {
- randomNode.addInstance(i.toString)
- }
- val examples = randomNode.getAllInstances
- val graphCacheFile = "models/temp.model"
- RandomDataModel.deriveInstances()
- RandomDataModel.write(graphCacheFile)
- BinaryClassifier.learn(30)
- BinaryClassifier.test(examples)
-}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomDataModel.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomDataModel.scala
index 9dee0917..9b47e37b 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomDataModel.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/RandomDataModel.scala
@@ -18,7 +18,7 @@ object RandomDataModel extends DataModel {
val r = scala.util.Random
r.setSeed(0)
- val randomLabel = property(randomNode, cache = true) {
+ val randomLabel = property(randomNode, cache = true)("1", "-1") {
x: String =>
(2 * (if (r.nextGaussian() > 0) 1 else 0) - 1).toString
}
@@ -29,4 +29,9 @@ object RandomDataModel extends DataModel {
val p1new = p(1) + randomLabel(x).toDouble
List(c * p1new - s * p(1), c * p1new + s * p(1))
}
+
+ val oppositRandomLabel = property(randomNode, cache = true)("1", "-1") {
+ x: String =>
+ if (randomLabel(x).equals("1")) "-1" else "1"
+ }
}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/Randomclassifiers.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/Randomclassifiers.scala
index 4eb3c50c..14255dc0 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/Randomclassifiers.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/BasicClassifierWithRandomData/Randomclassifiers.scala
@@ -6,7 +6,7 @@
*/
package edu.illinois.cs.cogcomp.saulexamples.BasicClassifierWithRandomData
-import edu.illinois.cs.cogcomp.lbjava.learn.SparseNetworkLearner
+import edu.illinois.cs.cogcomp.lbjava.learn.SparsePerceptron
import edu.illinois.cs.cogcomp.saul.classifier.Learnable
object RandomClassifiers {
@@ -14,7 +14,14 @@ object RandomClassifiers {
object BinaryClassifier extends Learnable[String](randomNode) {
def label = randomLabel
override def feature = using(randomProperty)
- override lazy val classifier = new SparseNetworkLearner()
- override val useCache = true
+ override lazy val classifier = new SparsePerceptron()
+ //override val useCache = true
+ }
+
+ object OppositClassifier extends Learnable[String](randomNode) {
+ def label = oppositRandomLabel
+ override def feature = using(randomProperty)
+ override lazy val classifier = new SparsePerceptron()
+ //override val useCache = true
}
}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/KnowEngDataModel.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/KnowEngDataModel.scala
index 8bb56eb3..bc591cf5 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/KnowEngDataModel.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/KnowEngDataModel.scala
@@ -81,7 +81,9 @@ object KnowEngDataModel extends DataModel {
}
val drugResponse = property(patientDrug) {
- x: PatientDrug => x.response.doubleValue()
+ x: PatientDrug =>
+ val temp = x.response.doubleValue()
+ if (temp > 100) "+" else "-"
}
val genesGroupedPerPathway = genes().map(x => x.KEGG.map(y => (x.GeneName, y))).flatten.groupBy(_._2).map(x => (x._1, x._2.map(t1 => t1._1)))
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/myApp.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/myApp.scala
index 5c5ca870..1804bb5b 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/myApp.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/DrugResponse/myApp.scala
@@ -63,7 +63,7 @@ object myApp extends Logging {
val genesGroupedPerPathway = genes().map(x => x.KEGG.map(y => (x.GeneName, y))).flatten.groupBy(_._2).map(x => (x._1, x._2.map(t1 => t1._1)))
- patientDrug().filter(x => drugResponse(x) > 12)
+ //patientDrug().filter(x => drugResponse(x) > 12)
(patients() ~> -pgPatient ~> pgGenes) prop gene_KEGG
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EmailSpam/SpamClassifiers.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EmailSpam/SpamClassifiers.scala
index 986228f9..0ba5c3db 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EmailSpam/SpamClassifiers.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EmailSpam/SpamClassifiers.scala
@@ -10,7 +10,7 @@ import edu.illinois.cs.cogcomp.lbjava.learn.SupportVectorMachine
import edu.illinois.cs.cogcomp.saul.classifier.Learnable
import edu.illinois.cs.cogcomp.saul.learn.SaulWekaWrapper
import edu.illinois.cs.cogcomp.saulexamples.nlp.EmailSpam.SpamDataModel._
-import weka.classifiers.bayes.NaiveBayes
+import weka.classifiers.`lazy`.IBk
object SpamClassifiers {
object SpamClassifier extends Learnable(email) {
@@ -33,7 +33,7 @@ object SpamClassifiers {
}
object SpamClassifierWeka extends Learnable(email) {
def label = spamLabel
- override lazy val classifier = new SaulWekaWrapper(new NaiveBayes())
+ override lazy val classifier = new SaulWekaWrapper(new IBk(3))
override def feature = using(words)
}
}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationApp_SL.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationApp_SL.scala
new file mode 100644
index 00000000..e329adef
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationApp_SL.scala
@@ -0,0 +1,43 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation
+
+import edu.illinois.cs.cogcomp.saul.classifier.JointTrainSparseNetwork
+import edu.illinois.cs.cogcomp.saul.classifier.SL_model.StructuredLearning
+import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.datastruct.ConllRelation
+import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationClassifiers._
+import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationConstrainedClassifiers._
+
+/** Created by Parisa on 12/8/15.
+ */
+object EntityRelationApp_SL extends App {
+ import EntityRelationDataModel._
+
+ EntityRelationDataModel.populateWithConll() //.populateWithConll()
+
+ // ClassifierUtils.LoadClassifier(EntityRelationApp.jarModelPath, PersonClassifier, OrganizationClassifier, LocationClassifier, WorksForClassifier, LivesInClassifier)
+
+ val cls_base = List(PersonClassifier, OrganizationClassifier, LocationClassifier, LivesInClassifier, WorksForClassifier)
+
+ //ClassifierUtils.TrainClassifiers(10, cls_base)
+ //ClassifierUtils.TestClassifiers(cls_base: _*)
+
+ val cls = List(PerConstrainedClassifier, OrgConstrainedClassifier, LocConstrainedClassifier,
+ LivesIn_PerOrg_relationConstrainedClassifier, WorksFor_PerOrg_ConstrainedClassifier)
+
+ JointTrainSparseNetwork.train[ConllRelation](pairs, cls, 5, true)
+
+ //ClassifierUtils.TestClassifiers(cls: _*)
+
+ val m = StructuredLearning(pairs, cls, usePreTrained = false)
+
+ println("Structured evaluation.\n")
+
+ // StructuredLearning.Evaluate(pairs, cls, m, "")
+ //ClassifierUtils.TestClassifiers(cls_base:_*)
+}
+
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationClassifiers.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationClassifiers.scala
index b7292bf5..68db918c 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationClassifiers.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationClassifiers.scala
@@ -74,4 +74,3 @@ object EntityRelationClassifiers {
override lazy val classifier = new SparseNetworkLearner()
}
}
-
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstrainedClassifiers.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstrainedClassifiers.scala
index 445b8f60..119bb16b 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstrainedClassifiers.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstrainedClassifiers.scala
@@ -16,33 +16,33 @@ object EntityRelationConstrainedClassifiers {
val erSolver = new OJalgoHook
object OrgConstrainedClassifier extends ConstrainedClassifier[ConllRawToken, ConllRelation](OrganizationClassifier) {
- def subjectTo = relationArgumentConstraints
+ def subjectTo = dummyConst //relationArgumentConstraints
override val pathToHead = Some(-EntityRelationDataModel.pairTo2ndArg)
override def filter(t: ConllRawToken, h: ConllRelation): Boolean = t.wordId == h.wordId2
override val solver = erSolver
}
object PerConstrainedClassifier extends ConstrainedClassifier[ConllRawToken, ConllRelation](PersonClassifier) {
- def subjectTo = relationArgumentConstraints
+ def subjectTo = dummyConst // relationArgumentConstraints
override val pathToHead = Some(-EntityRelationDataModel.pairTo1stArg)
override def filter(t: ConllRawToken, h: ConllRelation): Boolean = t.wordId == h.wordId1
override val solver = erSolver
}
object LocConstrainedClassifier extends ConstrainedClassifier[ConllRawToken, ConllRelation](LocationClassifier) {
- def subjectTo = relationArgumentConstraints
+ def subjectTo = dummyConst // relationArgumentConstraints
override val pathToHead = Some(-EntityRelationDataModel.pairTo2ndArg)
override def filter(t: ConllRawToken, h: ConllRelation): Boolean = t.wordId == h.wordId2
override val solver = erSolver
}
object WorksFor_PerOrg_ConstrainedClassifier extends ConstrainedClassifier[ConllRelation, ConllRelation](WorksForClassifier) {
- def subjectTo = relationArgumentConstraints
- override val solver = new OJalgoHook
+ def subjectTo = dummyConst //relationArgumentConstraints
+ override val solver = erSolver
}
object LivesIn_PerOrg_relationConstrainedClassifier extends ConstrainedClassifier[ConllRelation, ConllRelation](LivesInClassifier) {
- def subjectTo = relationArgumentConstraints
+ def subjectTo = dummyConst // relationArgumentConstraints
override val solver = erSolver
}
}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstraints.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstraints.scala
index 637dff0a..0a03a3d0 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstraints.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationConstraints.scala
@@ -6,13 +6,20 @@
*/
package edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation
+import edu.illinois.cs.cogcomp.lbjava.infer.{ FirstOrderConstant, FirstOrderConstraint }
import edu.illinois.cs.cogcomp.saul.classifier.ConstrainedClassifier
import edu.illinois.cs.cogcomp.saul.constraint.ConstraintTypeConversion._
-import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.datastruct.{ ConllRawSentence, ConllRelation }
-import EntityRelationClassifiers._
+import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.datastruct.ConllRelation
+import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationClassifiers._
object EntityRelationConstraints {
+ val dummyConst = ConstrainedClassifier.constraint[ConllRelation] {
+ x =>
+ val a: FirstOrderConstraint = new FirstOrderConstant(true)
+ a
+ }
+
// if x is works-for relation, it shouldn't be lives-in relation.
val relationArgumentConstraints = ConstrainedClassifier.constraint[ConllRelation] { x: ConllRelation =>
worksForConstraint(x) and livesInConstraint(x) and worksForImpliesNotLivesIn(x)
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationDataModel.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationDataModel.scala
index 2c378477..3a2d3932 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationDataModel.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationDataModel.scala
@@ -8,9 +8,12 @@ package edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation
import edu.illinois.cs.cogcomp.saul.datamodel.DataModel
import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.datastruct.{ ConllRawSentence, ConllRawToken, ConllRelation }
+import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.reader.Conll04_Reader
import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationClassifiers._
import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationSensors._
+import scala.collection.JavaConversions._
+
object EntityRelationDataModel extends DataModel {
/** Nodes & Edges */
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/README.md b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/README.md
index eeb4779e..1da3daac 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/README.md
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/README.md
@@ -224,18 +224,7 @@ And the summary of performances for independent relation classifiers:
==============================================
```
-
-
-## Testing the Entity Classifier interactively
-
-For a quick demo of the Entity Type Classifier, you can run the following command in the project's root folder:
-
-```shell
-sbt "project saulExamples" "runMain edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationApp"
-```
-
## Using it in your code
-
Add Sual as your dependency in your maven:
```xml
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/preTest.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/preTest.scala
new file mode 100644
index 00000000..a150f5ca
--- /dev/null
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/preTest.scala
@@ -0,0 +1,164 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation
+
+import edu.illinois.cs.cogcomp.infer.ilp.OJalgoHook
+import edu.illinois.cs.cogcomp.lbjava.infer.FirstOrderConstant
+import edu.illinois.cs.cogcomp.lbjava.learn.{ LinearThresholdUnit, SparseNetworkLearner }
+import edu.illinois.cs.cogcomp.saul.classifier.SL_model._
+import edu.illinois.cs.cogcomp.saul.classifier.{ ClassifierUtils, ConstrainedClassifier, Learnable }
+import edu.illinois.cs.cogcomp.saul.datamodel.DataModel
+import edu.illinois.cs.cogcomp.saul.datamodel.property.Property
+import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.datastruct.ConllRelation
+import edu.illinois.cs.cogcomp.sl.core.SLParameters
+import edu.illinois.cs.cogcomp.sl.learner.LearnerFactory
+
+/** Created by Parisa on 9/27/16.
+ */
+object preTest extends App {
+
+ object testModel extends DataModel {
+ val tokens = node[String]
+ // val pairs = edge(tokens, tokens)
+ val testLabel = property(tokens) { x: String => x.equals("candidate") }
+ val word = property(tokens) { x: String => x }
+ val biWord = property(tokens) { x: String => x + "-" + x }
+ }
+
+ // Testing the original functions with real classifiers
+ // "integration test" should "work" in {
+ // Initialize toy model
+
+ import testModel._
+
+ object TestClassifier extends Learnable(tokens) {
+ def label: Property[String] = testLabel
+
+ override def feature = using(word)
+
+ override lazy val classifier = new SparseNetworkLearner()
+ }
+
+ object TestBiClassifier extends Learnable(tokens) {
+ def label: Property[String] = testLabel
+
+ override def feature = using(word, biWord)
+
+ override lazy val classifier = new SparseNetworkLearner()
+ }
+
+ object TestConstraintClassifier extends ConstrainedClassifier[String, String](TestClassifier) {
+ def subjectTo = ConstrainedClassifier.constraint { _ => new FirstOrderConstant(true) }
+
+ // override val pathToHead = Some(-pairs)
+ //override def filter(t: String, h: String): Boolean = t.equals(h)
+ override val solver = new OJalgoHook
+ }
+
+ object TestBiConstraintClassifier extends ConstrainedClassifier[String, String](TestBiClassifier) {
+ def subjectTo = ConstrainedClassifier.constraint { _ => new FirstOrderConstant(true) }
+
+ // override val pathToHead = Some(-pairs)
+ //override def filter(t: String, h: String): Boolean = t.equals(h)
+ override val solver = new OJalgoHook
+ }
+
+ val words_train = List("this", "is", "a", "candidate")
+ val words_test = List("this", "was", "not", "true")
+ tokens.populate(words_train)
+ tokens.populate(words_test, train = false)
+
+ val cls = List(TestConstraintClassifier, TestBiConstraintClassifier)
+ val cls_base = List(TestClassifier, TestBiClassifier)
+ val model = Initialize(tokens, new SaulSLModel(cls), usePreTrained = false)
+
+ // JointTrainSparseNetwork(tokens, cls, 3, true)
+ // This should combine the weights
+ // val m = StructuredLearning(tokens, cls, initialize = false)
+
+ val SLProblem = SL_IOManager.makeSLProblem(tokens, cls)
+
+ println("lables:", SLProblem.goldStructureList.size())
+ println("examples", SLProblem.instanceList.size())
+
+ println("factors:", model.Factors.size)
+ println("ltus:", model.LTUWeightTemplates.size)
+ model.wv.getLength
+ model.wv.getWeightArray.filter(p => (p > 0.00)).isEmpty
+
+ val xGold = SLProblem.instanceList.get(0)
+ val yGold = SLProblem.goldStructureList.get(0)
+ model.featureGenerator = new SL_FeatureGenerator(model)
+
+ model.featureGenerator.getFeatureVector(xGold, yGold).getValues.sum //should be(3.0)
+
+ ClassifierUtils.TrainClassifiers(5, cls_base: _*)
+ val InitializedModel = Initialize(tokens, new SaulSLModel(cls), usePreTrained = true)
+ // "Structured output learning (SL) initialization with trained models" should "work." in
+
+ println("Factors:", InitializedModel.Factors.size)
+ println("LTUs:", InitializedModel.LTUWeightTemplates.size)
+ println("modellength:", InitializedModel.wv.getLength)
+ println("weightArray:", InitializedModel.wv.getWeightArray)
+ InitializedModel.Factors.size //should be(2)
+ InitializedModel.LTUWeightTemplates.size //should be(4)
+ InitializedModel.wv.getLength //should be(24)
+
+ InitializedModel.Factors.foreach(
+ x => {
+ val classifierWeightVector0 = x.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getLTU(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+ val baseWeightVector0 = cls_base(0).classifier.asInstanceOf[SparseNetworkLearner].getLTU(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+
+ classifierWeightVector0 //should be(baseWeightVector0)
+
+ val classifierWeightVector1 = x.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getLTU(1).asInstanceOf[LinearThresholdUnit].getWeightVector
+ val baseWeightVector1 = cls_base(1).classifier.asInstanceOf[SparseNetworkLearner].getLTU(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+
+ classifierWeightVector1 //should be(baseWeightVector1)
+ }
+ )
+ //InitializedModel.wv.getWeightArray.filter(p => (p > 0.00)).isEmpty should be(true)
+
+ val para = new SLParameters
+ para.loadConfigFile("../config/DCD.config")
+ model.para = para
+ model.infSolver = new Saul_SL_Inference[String](model.Factors.toList, model.LTUWeightTemplates)
+ val learner = LearnerFactory.getLearner(model.infSolver, model.featureGenerator, para)
+
+ //"Structured output learning's loss" should " be calculate correctly." in {
+
+ val yTest = new Saul_SL_Label_Structure[String](cls, yGold.asInstanceOf[Saul_SL_Label_Structure[String]].head.asInstanceOf[String])
+ yTest.labels = for (
+ l <- yGold.asInstanceOf[Saul_SL_Label_Structure[ConllRelation]].labels
+ ) yield "true"
+
+ val yTest2 = new Saul_SL_Label_Structure[String](cls, yGold.asInstanceOf[Saul_SL_Label_Structure[String]].head.asInstanceOf[String])
+ yTest2.labels(0) = "true"
+ yTest2.labels(1) = "false"
+ print(model.infSolver.getLoss(xGold, yGold, yTest2), "here")
+
+ print(model.infSolver.getLoss(xGold, yGold, yGold), "here") //should be(0.00)
+ println(model.infSolver.getLoss(xGold, yGold, yTest), "here") //>= (0.8) //should be(true)
+ // }
+
+ val weight = learner.train(SLProblem, model.wv)
+ // "Structured output learning" should " have a correctly working inference module." in {
+ val yPredicted = model.infSolver.getBestStructure(model.wv, xGold)
+ val yMostViolated = model.infSolver.getLossAugmentedBestStructure(model.wv, xGold, yGold)
+ println(model.infSolver.getLoss(xGold, yGold, yPredicted), "here") // should be(0.00)
+ // model.infSolver.getLoss(xGold, yPredicted, yMostViolated) should be(0.00)
+ // (yPredicted.asInstanceOf[Saul_SL_Label_Structure[ConllRelation]].equals(yMostViolated.
+ // asInstanceOf[Saul_SL_Label_Structure[ConllRelation]])) should be(true)
+ // }
+
+ // "Structured output learning (SL)" should "really work in Saul." in {
+
+ //}
+
+ // }
+
+}
diff --git a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/POSTagger/POSTaggerApps.scala b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/POSTagger/POSTaggerApps.scala
index effc856b..f25390fb 100644
--- a/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/POSTagger/POSTaggerApps.scala
+++ b/saul-examples/src/main/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/POSTagger/POSTaggerApps.scala
@@ -19,7 +19,6 @@ import edu.illinois.cs.cogcomp.saul.parser.IterableToLBJavaParser
import edu.illinois.cs.cogcomp.saulexamples.nlp.POSTagger.POSClassifiers._
import edu.illinois.cs.cogcomp.saulexamples.nlp.POSTagger.POSDataModel._
import edu.illinois.cs.cogcomp.saulexamples.nlp.CommonSensors
-
import scala.collection.JavaConversions._
import scala.io.StdIn
diff --git a/saul-examples/src/test/resources/EntityMentionRelation/conll04_small.corp b/saul-examples/src/test/resources/EntityMentionRelation/conll04_small.corp
new file mode 100644
index 00000000..f3cc8501
--- /dev/null
+++ b/saul-examples/src/test/resources/EntityMentionRelation/conll04_small.corp
@@ -0,0 +1,706 @@
+0 Other 0 O JJ Palestinian O O O
+0 O 1 O NNP Uprising O O O
+0 O 2 O NNP Affects O O O
+0 Other 3 O NNP Israeli O O O
+0 O 4 O NNP Artists O O O
+
+
+1 O 0 O IN By O O O
+1 Peop 1 O NNP/NNP RONI/RABIN O O O
+
+
+2 Org 0 O NNP/NNP Associated/Press O O O
+2 O 1 O NNP Writer O O O
+
+
+3 O 0 O DT The O O O
+3 O 1 O JJ long O O O
+3 Other 2 O JJ Palestinian O O O
+3 O 3 O NN uprising O O O
+3 O 4 O VBZ has O O O
+3 O 5 O VBN brought O O O
+3 O 6 O NN bitterness O O O
+3 O 7 O TO to O O O
+3 Other 8 O JJ Israeli O O O
+3 O 9 O NN humor O O O
+3 O 10 O , COMMA O O O
+3 O 11 O CC and O O O
+3 O 12 O DT the O O O
+3 O 13 O NN comedian O O O
+3 O 14 O POS 's O O O
+3 O 15 O NN opener O O O
+3 O 16 O VBD was O O O
+3 O 17 O RB not O O O
+3 O 18 O VBN meant O O O
+3 O 19 O TO to O O O
+3 O 20 O VB put O O O
+3 O 21 O PP$ his O O O
+3 O 22 O NN audience O O O
+3 O 23 O IN at O O O
+3 O 24 O NN ease O O O
+3 O 25 O . . O O O
+
+
+4 O 0 O `` ` O O O
+4 O 1 O `` ` O O O
+4 O 2 O NNS Soldiers O O O
+4 O 3 O IN in O O O
+4 O 4 O NN uniform O O O
+4 O 5 O VBP get O O O
+4 O 6 O IN in O O O
+4 O 7 O IN with O O O
+4 O 8 O DT a O O O
+4 O 9 O NN discount O O O
+4 O 10 O , COMMA O O O
+4 O 11 O '' ' O O O
+4 O 12 O '' ' O O O
+4 Peop 13 O NNP/NNP Yonathan/Geffen O O O
+4 O 14 O VBD said O O O
+4 O 15 O , COMMA O O O
+4 O 16 O CC and O O O
+4 O 17 O IN after O O O
+4 O 18 O DT a O O O
+4 O 19 O NN pause O O O
+4 O 20 O : : O O O
+4 O 21 O `` ` O O O
+4 O 22 O `` ` O O O
+4 O 23 O NNS Soldiers O O O
+4 O 24 O IN with O O O
+4 O 25 O NNS clubs O O O
+4 O 26 O VBP get O O O
+4 O 27 O IN in O O O
+4 O 28 O NN free. O O O
+4 O 29 O '' ' O O O
+4 O 30 O '' ' O O O
+
+
+5 O 0 O PRP He O O O
+5 O 1 O VBD referred O O O
+5 O 2 O TO to O O O
+5 O 3 O NNS beatings O O O
+5 O 4 O IN by O O O
+5 O 5 O NNS soldiers O O O
+5 O 6 O IN of O O O
+5 O 7 O NNS protesters O O O
+5 O 8 O IN in O O O
+5 O 9 O DT the O O O
+5 O 10 O VBD occupied O O O
+5 Loc 11 O NNP/NNP West/Bank O O O
+5 O 12 O CC and O O O
+5 Loc 13 O NNP/NNP Gaza/Strip O O O
+5 O 14 O , COMMA O O O
+5 O 15 O WRB where O O O
+5 O 16 O RBR more O O O
+5 O 17 O IN than O O O
+5 O 18 O CD 300 O O O
+5 Other 19 O NNPS Palestinians O O O
+5 O 20 O VBP have O O O
+5 O 21 O VBN been O O O
+5 O 22 O VBN killed O O O
+5 O 23 O CC and O O O
+5 O 24 O NNS thousands O O O
+5 O 25 O VBN wounded O O O
+5 O 26 O . . O O O
+
+
+6 O 0 O PDT Such O O O
+6 O 1 O DT a O O O
+6 O 2 O NN joke O O O
+6 O 3 O MD would O O O
+6 O 4 O VB have O O O
+6 O 5 O VBN been O O O
+6 O 6 O JJ unthinkable O O O
+6 O 7 O IN before O O O
+6 O 8 O DT the O O O
+6 O 9 O NN rebellion O O O
+6 O 10 O VBD began O O O
+6 Other 11 O NNP/CD/,/CD Dec./8/COMMA/1987 O O O
+6 O 12 O . . O O O
+
+
+7 O 0 O IN In O O O
+7 O 1 O NN night O O O
+7 O 2 O NNS clubs O O O
+7 O 3 O , COMMA O O O
+7 O 4 O NNS theaters O O O
+7 O 5 O CC and O O O
+7 O 6 O NNS galleries O O O
+7 O 7 O , COMMA O O O
+7 O 8 O NNS artists O O O
+7 O 9 O IN of O O O
+7 O 10 O JJ various O O O
+7 O 11 O NNS kinds O O O
+7 O 12 O VB grapple O O O
+7 O 13 O IN with O O O
+7 O 14 O NNS questions O O O
+7 O 15 O IN about O O O
+7 O 16 O DT the O O O
+7 O 17 O NN violence O O O
+7 O 18 O IN of O O O
+7 O 19 O NN occupation O O O
+7 O 20 O CC and O O O
+7 O 21 O DT the O O O
+7 O 22 O JJ brutalizing O O O
+7 O 23 O NN effect O O O
+7 O 24 O IN on O O O
+7 Other 25 O JJ Israeli O O O
+7 O 26 O NN society O O O
+7 O 27 O IN of O O O
+7 O 28 O DT the O O O
+7 O 29 O NN army O O O
+7 O 30 O POS 's O O O
+7 O 31 O NN handling O O O
+7 O 32 O IN of O O O
+7 O 33 O DT the O O O
+7 O 34 O NN uprising O O O
+7 O 35 O . . O O O
+
+
+8 O 0 O DT A O O O
+8 O 1 O NN satire O O O
+8 O 2 O IN by O O O
+8 O 3 O NN nightclub O O O
+8 O 4 O JJ performer O O O
+8 Peop 5 O NNP/NNP Dudu/Topaz O O O
+8 O 6 O VBZ takes O O O
+8 O 7 O DT the O O O
+8 O 8 O NN form O O O
+8 O 9 O IN of O O O
+8 O 10 O DT an O O O
+8 O 11 O NN army O O O
+8 O 12 O NN radio O O O
+8 O 13 O VBP report O O O
+8 O 14 O IN of O O O
+8 O 15 O DT an O O O
+8 O 16 O NN incident O O O
+8 O 17 O VBD said O O O
+8 O 18 O TO to O O O
+8 O 19 O VB have O O O
+8 O 20 O VBN begun O O O
+8 O 21 O WRB when O O O
+8 O 22 O DT a O O O
+8 O 23 O JJ young O O O
+8 Other 24 O NN Palestinian O O O
+8 O 25 O VBN urinated O O O
+8 O 26 O IN on O O O
+8 O 27 O DT a O O O
+8 O 28 O NN soldier O O O
+8 O 29 O POS 's O O O
+8 O 30 O NN leg O O O
+8 O 31 O . . O O O
+
+
+9 Peop 0 O NNP Topaz O O O
+9 O 1 O VBD was O O O
+9 O 2 O VBN barred O O O
+9 O 3 O IN from O O O
+9 O 4 O DT a O O O
+9 O 5 O NN radio O O O
+9 O 6 O VBP talk O O O
+9 O 7 O VBP show O O O
+9 O 8 O IN for O O O
+9 Other 9 O CD/NNS two/weeks O O O
+9 O 10 O IN for O O O
+9 O 11 O NNS comments O O O
+9 O 12 O JJ critical O O O
+9 O 13 O IN of O O O
+9 O 14 O DT the O O O
+9 O 15 O NN army O O O
+9 O 16 O . . O O O
+
+
+10 Loc 0 O NNP Israel O O O
+10 O 1 O NN television O O O
+10 O 2 O VBD rejected O O O
+10 O 3 O DT a O O O
+10 O 4 O NN skit O O O
+10 O 5 O IN by O O O
+10 O 6 O NN comedian O O O
+10 Peop 7 O NNP/NNP Tuvia/Tzafir O O O
+10 O 8 O IN that O O O
+10 O 9 O VBN attacked O O O
+10 O 10 O JJ public O O O
+10 O 11 O NN apathy O O O
+10 O 12 O IN by O O O
+10 O 13 O VBG depicting O O O
+10 O 14 O DT an O O O
+10 Other 15 O JJ Israeli O O O
+10 O 16 O NN family O O O
+10 O 17 O VBG watching O O O
+10 O 18 O NN TV O O O
+10 O 19 O IN while O O O
+10 O 20 O DT a O O O
+10 O 21 O NN fire O O O
+10 O 22 O VBD raged O O O
+10 O 23 O IN outside O O O
+10 O 24 O . . O O O
+
+7 0 Live_In
+
+11 O 0 O NNS Lyrics O O O
+11 O 1 O IN in O O O
+11 O 2 O `` ` O O O
+11 O 3 O `` ` O O O
+11 Other 4 O NNP/IN/NNP Coexistence/With/Love O O O
+11 O 5 O , COMMA O O O
+11 O 6 O '' ' O O O
+11 O 7 O '' ' O O O
+11 O 8 O DT a O O O
+11 O 9 O JJ new O O O
+11 O 10 O NN album O O O
+11 O 11 O IN by O O O
+11 O 12 O NN vocalist O O O
+11 Peop 13 O NNP/NNP Astar/Shamir O O O
+11 O 14 O , COMMA O O O
+11 O 15 O VBP accuse O O O
+11 O 16 O DT the O O O
+11 O 17 O NN government O O O
+11 O 18 O IN of O O O
+11 O 19 O VBG failing O O O
+11 O 20 O TO to O O O
+11 O 21 O VB explore O O O
+11 O 22 O NNS options O O O
+11 O 23 O IN for O O O
+11 O 24 O NN peace O O O
+11 O 25 O IN while O O O
+11 O 26 O JJ young O O O
+11 O 27 O NNS soldiers O O O
+11 O 28 O VBP do O O O
+11 O 29 O DT the O O O
+11 O 30 O JJ dirty O O O
+11 O 31 O NN work O O O
+11 O 32 O IN of O O O
+11 O 33 O NN occupation O O O
+11 O 34 O . . O O O
+
+
+12 O 0 O IN As O O O
+12 O 1 O CD one O O O
+12 O 2 O IN of O O O
+12 O 3 O PP$ her O O O
+12 O 4 O NNS songs O O O
+12 O 5 O , COMMA O O O
+12 O 6 O `` ` O O O
+12 O 7 O `` ` O O O
+12 Other 8 O DT/NNP/IN/DT/NN A/Moment/Before/the/Storm O O O
+12 O 9 O , COMMA O O O
+12 O 10 O '' ' O O O
+12 O 11 O '' ' O O O
+12 O 12 O VBZ puts O O O
+12 O 13 O PRP it O O O
+12 O 14 O : : O O O
+12 O 15 O `` ` O O O
+12 O 16 O `` ` O O O
+12 O 17 O PP$ My O O O
+12 O 18 O NN brother O O O
+12 O 19 O NN isn O O O
+12 O 20 O NN 't O O O
+12 O 21 O DT a O O O
+12 O 22 O JJ cruel O O O
+12 O 23 O NN soldier O O O
+12 O 24 O , COMMA O O O
+12 O 25 O CC but O O O
+12 O 26 O PRP he O O O
+12 O 27 O VBZ 's O O O
+12 O 28 O NN cold O O O
+12 O 29 O IN in O O O
+12 O 30 O PP$ his O O O
+12 O 31 O NN soul O O O
+12 O 32 O . . O O O
+
+
+13 O 0 O RB Early O O O
+13 O 1 O JJ last O O O
+13 O 2 O NN year O O O
+13 O 3 O , COMMA O O O
+13 O 4 O NN army O O O
+13 O 5 O NN radio O O O
+13 O 6 O VBD banned O O O
+13 O 7 O NN pop O O O
+13 O 8 O NN singer O O O
+13 Peop 9 O NNP/NNP Si/Hyman O O O
+13 O 10 O POS 's O O O
+13 O 11 O NN song O O O
+13 O 12 O `` ` O O O
+13 O 13 O `` ` O O O
+13 Other 14 O NN/CC/NNP Shooting/and/Crying O O O
+13 O 15 O '' ' O O O
+13 O 16 O '' ' O O O
+13 O 17 O IN about O O O
+13 O 18 O NNS soldiers O O O
+13 O 19 O WP who O O O
+13 O 20 O VBD used O O O
+13 O 21 O DT a O O O
+13 O 22 O NN bulldozer O O O
+13 O 23 O TO to O O O
+13 O 24 O VB bury O O O
+13 O 25 O CD four O O O
+13 O 26 O JJ young O O O
+13 Other 27 O NNPS Palestinians O O O
+13 O 28 O JJ alive O O O
+13 O 29 O IN in O O O
+13 O 30 O DT a O O O
+13 Loc 31 O NNP/NNP West/Bank O O O
+13 O 32 O NN village O O O
+13 O 33 O . . O O O
+
+
+14 Peop 0 O NNP Hyman O O O
+14 O 1 O VBZ asks O O O
+14 O 2 O IN in O O O
+14 O 3 O DT the O O O
+14 O 4 O NN chorus O O O
+14 O 5 O , COMMA O O O
+14 O 6 O VBG alluding O O O
+14 O 7 O TO to O O O
+14 O 8 O DT the O O O
+14 Org 9 O JJ Nazi O O O
+14 O 10 O NN extermination O O O
+14 O 11 O IN of O O O
+14 Other 12 O CD/CD 6/million O O O
+14 Other 13 O NNPS Jews O O O
+14 O 14 O . . O O O
+
+
+15 O 0 O IN In O O O
+15 O 1 O DT a O O O
+15 Loc 2 O NNP Jaffa O O O
+15 O 3 O NN nightclub O O O
+15 O 4 O , COMMA O O O
+15 Peop 5 O NNP Tzafir O O O
+15 O 6 O VBZ performs O O O
+15 O 7 O DT a O O O
+15 O 8 O NN skit O O O
+15 O 9 O VBG accusing O O O
+15 O 10 O NNP Prime O O O
+15 Peop 11 O NNP/NNP Yitzhak/Shamir O O O
+15 O 12 O IN of O O O
+15 O 13 O VBG ignoring O O O
+15 O 14 O NNS opportunities O O O
+15 O 15 O IN for O O O
+15 O 16 O NN peace O O O
+15 O 17 O . . O O O
+
+
+16 Other 0 O NNPS Palestinians O O O
+16 O 1 O VBP have O O O
+16 O 2 O VBN incorporated O O O
+16 O 3 O NNS themes O O O
+16 O 4 O IN of O O O
+16 O 5 O DT the O O O
+16 O 6 O NN uprising O O O
+16 O 7 O IN into O O O
+16 O 8 O NNS songs O O O
+16 O 9 O CC and O O O
+16 O 10 O NNS plays O O O
+16 O 11 O . . O O O
+
+
+17 O 0 O DT An O O O
+17 O 1 O NN art O O O
+17 O 2 O NN exhibit O O O
+17 O 3 O IN at O O O
+17 O 4 O DT the O O O
+17 Org 5 O NNP/NNP Hakawati/Theatre O O O
+17 O 6 O IN in O O O
+17 Other 7 O JJ Arab O O O
+17 O 8 O JJ east O O O
+17 Loc 9 O NNP Jerusalem O O O
+17 O 10 O VBD was O O O
+17 O 11 O DT a O O O
+17 O 12 O NN series O O O
+17 O 13 O IN of O O O
+17 O 14 O NNS portraits O O O
+17 O 15 O IN of O O O
+17 Other 16 O NNPS Palestinians O O O
+17 O 17 O VBN killed O O O
+17 O 18 O IN in O O O
+17 O 19 O DT the O O O
+17 O 20 O NN rebellion O O O
+17 O 21 O . . O O O
+
+5 9 OrgBased_In
+
+18 O 0 O DT The O O O
+18 O 1 O JJ new O O O
+18 O 2 O NN play O O O
+18 O 3 O `` ` O O O
+18 O 4 O `` ` O O O
+18 Other 5 O VBG/IN/DT/NN Waiting/for/the/Savior O O O
+18 O 6 O POS ' O O O
+18 O 7 O '' ' O O O
+18 O 8 O VBZ depicts O O O
+18 O 9 O JJ buffoon-like O O O
+18 Other 10 O JJ Israeli O O O
+18 O 11 O NNS soldiers O O O
+18 O 12 O VBG harassing O O O
+18 Other 13 O NNPS Palestinians O O O
+18 O 14 O VBG going O O O
+18 O 15 O IN about O O O
+18 O 16 O PP$ their O O O
+18 O 17 O NN daily O O O
+18 O 18 O NNS lives O O O
+18 O 19 O . . O O O
+
+
+19 O 0 O `` ` O O O
+19 O 1 O `` ` O O O
+19 O 2 O NN Everything O O O
+19 O 3 O VBZ is O O O
+19 O 4 O JJ political O O O
+19 O 5 O , COMMA O O O
+19 O 6 O '' ' O O O
+19 O 7 O '' ' O O O
+19 O 8 O VBD said O O O
+19 Peop 9 O NNP/NNP Jamal/Ghosheh O O O
+19 O 10 O , COMMA O O O
+19 O 11 O NN director O O O
+19 O 12 O IN of O O O
+19 O 13 O DT the O O O
+19 O 14 O FW theatre O O O
+19 O 15 O . . O O O
+
+
+20 O 0 O IN For O O O
+20 Other 1 O JJ Israeli O O O
+20 O 2 O NNS performers O O O
+20 O 3 O , COMMA O O O
+20 O 4 O WP who O O O
+20 O 5 O VBP do O O O
+20 O 6 O JJ active O O O
+20 O 7 O CC and O O O
+20 O 8 O JJ reserve O O O
+20 O 9 O NN army O O O
+20 O 10 O NN duty O O O
+20 O 11 O IN like O O O
+20 O 12 O NN everyone O O O
+20 O 13 O JJ else O O O
+20 O 14 O , COMMA O O O
+20 O 15 O PRP it O O O
+20 O 16 O VBZ is O O O
+20 O 17 O RBR more O O O
+20 O 18 O VBN complicated O O O
+20 O 19 O . . O O O
+
+
+21 O 0 O DT The O O O
+21 O 1 O NN comedian O O O
+21 O 2 O , COMMA O O O
+21 O 3 O WP$ whose O O O
+21 O 4 O NN father O O O
+21 O 5 O VBD came O O O
+21 O 6 O RB here O O O
+21 O 7 O IN from O O O
+21 O 8 O DT the O O O
+21 Loc 9 O NNP/NNP Soviet/Union O O O
+21 O 10 O , COMMA O O O
+21 O 11 O VBD said O O O
+21 O 12 O IN in O O O
+21 O 13 O DT an O O O
+21 O 14 O NN interview O O O
+21 O 15 O : : O O O
+21 O 16 O `` ` O O O
+21 O 17 O `` ` O O O
+21 O 18 O DT This O O O
+21 O 19 O VBZ is O O O
+21 O 20 O RB not O O O
+21 O 21 O DT the O O O
+21 O 22 O NN country O O O
+21 O 23 O PRP I O O O
+21 O 24 O VBD wanted O O O
+21 O 25 O . . O O O
+
+
+22 Other 0 O JJ Italian O O O
+22 O 1 O NNS Police O O O
+22 O 2 O VB Find O O O
+22 Other 3 O NN/CD $10/Million O O O
+22 O 4 O IN in O O O
+22 O 5 O NNP Fake O O O
+22 Loc 6 O NNP U.S. O O O
+22 O 7 O NNS Bills O O O
+
+
+23 Loc 0 O NNP PERUGIA O O O
+23 O 1 O , COMMA O O O
+23 Loc 2 O NNP Italy O O O
+23 O 3 O -LRB- -LRB- O O O
+23 Org 4 O NNP AP O O O
+23 O 5 O -RRB- -RRB- O O O
+
+0 2 Located_In
+4 0 OrgBased_In
+4 2 OrgBased_In
+
+24 O 0 O NNS Police O O O
+24 O 1 O VBD arrested O O O
+24 O 2 O CD 10 O O O
+24 O 3 O NNS people O O O
+24 O 4 O CC and O O O
+24 O 5 O VBD confiscated O O O
+24 Other 6 O NN/CD $10/million O O O
+24 O 7 O IN in O O O
+24 O 8 O JJ counterfeit O O O
+24 Loc 9 O NNP U.S. O O O
+24 O 10 O NN currency O O O
+24 O 11 O , COMMA O O O
+24 O 12 O DT an O O O
+24 Other 13 O JJ Italian O O O
+24 O 14 O NN news O O O
+24 O 15 O NN agency O O O
+24 O 16 O VBD reported O O O
+24 O 17 O . . O O O
+
+
+25 O 0 O DT The O O O
+25 O 1 O NNS bills O O O
+25 O 2 O VBD were O O O
+25 O 3 O RB reportedly O O O
+25 O 4 O VBN distributed O O O
+25 O 5 O IN through O O O
+25 O 6 O JJ central O O O
+25 Loc 7 O NNP Italy O O O
+25 O 8 O IN after O O O
+25 O 9 O VBG being O O O
+25 O 10 O VBN manufactured O O O
+25 O 11 O IN in O O O
+25 Loc 12 O NNP Rome O O O
+25 O 13 O , COMMA O O O
+25 O 14 O WRB where O O O
+25 O 15 O NNS police O O O
+25 O 16 O VBD seized O O O
+25 O 17 O DT a O O O
+25 O 18 O NN printing O O O
+25 O 19 O NN press O O O
+25 O 20 O . . O O O
+
+
+26 O 0 O NNS Officials O O O
+26 O 1 O IN in O O O
+26 Loc 2 O NNP Perugia O O O
+26 O 3 O IN in O O O
+26 Loc 4 O NNP Umbria O O O
+26 O 5 O NN province O O O
+26 O 6 O VBD said O O O
+26 O 7 O CD five O O O
+26 O 8 O NNS people O O O
+26 O 9 O VBD were O O O
+26 O 10 O VBN arrested O O O
+26 O 11 O RB there O O O
+26 O 12 O NNP Tuesday O O O
+26 O 13 O NN night O O O
+26 O 14 O IN after O O O
+26 O 15 O NNS police O O O
+26 O 16 O VBD stopped O O O
+26 O 17 O PP$ their O O O
+26 O 18 O NN car O O O
+26 O 19 O CC and O O O
+26 O 20 O VBD found O O O
+26 Other 21 O NN/CD $1/million O O O
+26 O 22 O IN in O O O
+26 O 23 O JJ bogus O O O
+26 O 24 O NNS bills O O O
+26 O 25 O IN in O O O
+26 O 26 O DT the O O O
+26 O 27 O NN trunk O O O
+26 O 28 O . . O O O
+
+2 4 Located_In
+
+27 O 0 O DT The O O O
+27 Org 1 O NNP ANSA O O O
+27 O 2 O NN news O O O
+27 O 3 O NN agency O O O
+27 O 4 O VBD said O O O
+27 O 5 O DT the O O O
+27 O 6 O NN operation O O O
+27 O 7 O VBD involved O O O
+27 O 8 O NN police O O O
+27 O 9 O IN in O O O
+27 Loc 10 O NNP Umbria O O O
+27 O 11 O CC and O O O
+27 Loc 12 O NNP Lazio O O O
+27 O 13 O NNS provinces O O O
+27 O 14 O IN in O O O
+27 O 15 O JJ central O O O
+27 Loc 16 O NNP Italy O O O
+27 O 17 O CC and O O O
+27 Loc 18 O NNP Campania O O O
+27 O 19 O NN province O O O
+27 O 20 O IN in O O O
+27 O 21 O DT the O O O
+27 O 22 O NN south O O O
+27 O 23 O , COMMA O O O
+27 O 24 O IN without O O O
+27 O 25 O VBG specifying O O O
+27 O 26 O JJ exact O O O
+27 O 27 O NN arrest O O O
+27 O 28 O NNS locations O O O
+27 O 29 O . . O O O
+
+10 16 Located_In
+12 16 Located_In
+18 16 Located_In
+
+28 Loc 0 O NNP Rome O O O
+28 O 1 O VBZ is O O O
+28 O 2 O IN in O O O
+28 Loc 3 O NNP Lazio O O O
+28 O 4 O NN province O O O
+28 O 5 O CC and O O O
+28 Loc 6 O NNP Naples O O O
+28 O 7 O IN in O O O
+28 Loc 8 O NNP Campania O O O
+28 O 9 O . . O O O
+
+0 3 Located_In
+6 8 Located_In
+
+29 O 0 O NNS Police O O O
+29 O 1 O VBD began O O O
+29 O 2 O VBG investigating O O O
+29 O 3 O IN after O O O
+29 O 4 O VBG getting O O O
+29 O 5 O NNS reports O O O
+29 O 6 O IN that O O O
+29 O 7 O DT an O O O
+29 O 8 O RB unusually O O O
+29 O 9 O JJ large O O O
+29 O 10 O NN number O O O
+29 O 11 O IN of O O O
+29 Loc 12 O NNP U.S. O O O
+29 O 13 O NNS dollars O O O
+29 O 14 O VBD was O O O
+29 O 15 O VBG being O O O
+29 O 16 O VBN used O O O
+29 O 17 O TO to O O O
+29 O 18 O VB pay O O O
+29 O 19 O IN for O O O
+29 O 20 O NNS goods O O O
+29 O 21 O CC and O O O
+29 O 22 O NNS services O O O
+29 O 23 O IN in O O O
+29 O 24 O NN tourist O O O
+29 O 25 O NNS centers O O O
+29 O 26 O . . O O O
+
+
+30 Other 0 O NNP/NNP WASHINGTON/TODAY O O O
+30 O 1 O : : O O O
+30 Peop 2 O NNP Reagan O O O
+30 O 3 O VBZ Takes O O O
+30 O 4 O NNP High O O O
+30 O 5 O NNP Road O O O
+30 O 6 O IN in O O O
+30 O 7 O NNP Farewell O O O
+30 O 8 O NNP Speech O O O
+
+
+31 O 0 O IN By O O O
+31 Peop 1 O NNP/NNP/NNP W./DALE/NELSON O O O
+
+
+32 Org 0 O NNP/NNP Associated/Press O O O
+32 O 1 O NNP Writer O O O
+
+
diff --git a/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/datamodel/GraphQueriesTest.scala b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/datamodel/GraphQueriesTest.scala
index 11317192..2787df6f 100644
--- a/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/datamodel/GraphQueriesTest.scala
+++ b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/datamodel/GraphQueriesTest.scala
@@ -118,5 +118,9 @@ class GraphQueriesTest extends FlatSpec with Matchers {
query3.counts.size should be(2)
query3.counts("a") should be(3)
query3.counts("e") should be(1)
+
+ // "finding the nodes in a window in the neighbohood" should "find the neighbors in a window" in {
+ //
firstNames.getWithWindow(firstNames.getAllInstances.head, -2, 2).toSet should be(Set(None, Some("Dave"), Some("John"), Some("Mark")))
+ // lastNames.getWithWindow(lastNames.getAllInstances.head, -2, 2).toSet should be(Set(None, Some("Dave"), Some("John"), Some("Mark")))
}
}
}
diff --git a/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/Badge/weightTest.scala b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/Badge/weightTest.scala
new file mode 100644
index 00000000..4201ee5f
--- /dev/null
+++ b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/Badge/weightTest.scala
@@ -0,0 +1,248 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saulexamples.nlp.Badge
+
+import edu.illinois.cs.cogcomp.lbjava.learn.{LinearThresholdUnit, SparseNetworkLearner}
+import edu.illinois.cs.cogcomp.saulexamples.Badge.BadgeClassifiers.{BadgeClassifierMulti, BadgeOppositClassifierMulti}
+import edu.illinois.cs.cogcomp.saulexamples.Badge.BadgeDataModel._
+import edu.illinois.cs.cogcomp.saulexamples.Badge.BadgeReader
+import edu.illinois.cs.cogcomp.sl.util.WeightVector
+import org.scalatest.{FlatSpec, Matchers}
+
+import scala.Array._
+import scala.collection.JavaConversions._
+import scala.collection.mutable.ListBuffer
+
+class weightTest extends FlatSpec with Matchers {
+
+ val allNamesTrain = new BadgeReader("/Users/Parisa/iSoftware/Github_forked/ParisaVersion/ParisaPublicVersion/saul/data/badges/badges.train").badges
+ val allNamesTest = new BadgeReader("/Users/Parisa/iSoftware/Github_forked/ParisaVersion/ParisaPublicVersion/saul/data/badges/badges.test").badges
+
+ badge.populate(allNamesTrain)
+ badge.populate(allNamesTest,false)
+ BadgeClassifierMulti.learn(2)
+ BadgeOppositClassifierMulti.learn(2)
+ BadgeClassifierMulti.test()
+ BadgeOppositClassifierMulti.test()
+ var fullWeightList: ListBuffer[Array[Float]] = ListBuffer()
+ var wvLength = 0
+ "update weight" should "work" in {
+ List(BadgeClassifierMulti,BadgeOppositClassifierMulti).foreach{
+ x => {
+ val sparseNet = x.classifier.asInstanceOf[SparseNetworkLearner]
+ val lexiconSize = (sparseNet.getLexicon.size())
+
+ for (i <- 0 until sparseNet.getNetwork.size()) {
+ val fullWeights = Array.fill[Float](lexiconSize)(0)
+ val trainedWeighs = x.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector
+ println("joint before ", trainedWeighs,", s=", trainedWeighs.size())
+
+ for (j <- 0 until lexiconSize)
+ fullWeights(j) = trainedWeighs.getWeight(j).asInstanceOf[Float]
+
+ fullWeightList = fullWeightList :+ fullWeights
+
+ wvLength = wvLength + lexiconSize
+ }
+
+ println("lexicon size: " + sparseNet.getLexicon.size(), "* label lexicon size:", sparseNet.getLabelLexicon.size())
+ }
+ }
+
+ // wv = Concatenate_(over factors)Concatenate_(over ltu) => size(wv)=sum_(over factors)sum_(over ltu)(size(ltu_i))
+
+ val myWeight = Array(fullWeightList.flatten: _*)
+ val wv = new WeightVector(myWeight) // wv this is one unified weight vector of all initialized LTUs
+ wvLength should be (72)
+
+ BadgeClassifierMulti.test()
+
+ var ltu_count = 0
+ var offset = 0
+ List(BadgeClassifierMulti,BadgeOppositClassifierMulti).foreach {
+ cf =>
+ for (i <- 0 until cf.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.size()) {
+ val ltuSize = cf.classifier.asInstanceOf[SparseNetworkLearner].getLexicon.size()//.net.get(i).asInstanceOf[LinearThresholdUnit].getParameters.asInstanceOf[LinearThresholdUnit.Parameters].weightVector
+ // print("w", ltu_count, " size:\t", ltuSize.size)
+ val myLTUJointlyTrainedWeight = wv.getWeightArray.slice(offset, offset + ltuSize)
+ // var count = 0
+ // for (count <- cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector.size() until ltuSize.size)
+ // myLTUJointlyTrainedWeight = myLTUJointlyTrainedWeight :+ 0.asInstanceOf[Float]
+ // if (cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector.size()!= ltuSize.size) {
+ // println("size mismatch!", cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector.size(), ",", ltuSize.size)
+ // }
+ val exampleFeatureIndexes = ofDim[Int](myLTUJointlyTrainedWeight.length)
+ val weightVector = cf.classifier.asInstanceOf[SparseNetworkLearner].getLTU(i).asInstanceOf[LinearThresholdUnit].getWeightVector
+ weightVector.clear()
+
+ // val exampleFeatureIndexes = cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getLexicon.getMap.values.toArray.map(_.asInstanceOf[Int])//.toArray//.toArray().asInstanceOf[Array[Int]]
+ for (featureIndex <- myLTUJointlyTrainedWeight.indices) {
+ exampleFeatureIndexes(featureIndex) = featureIndex
+ weightVector.setWeight(featureIndex, myLTUJointlyTrainedWeight(featureIndex))
+ //cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getLexicon.;
+ }
+
+ //.getParameters.asInstanceOf[LinearThresholdUnit.Parameters]
+ // cf.onClassifier.classifier.asInstanceOf[SparseNetworkLBP].getLTU(i).getWeightVector.scaledAdd(exampleFeatureIndexes, Utils.converFarrayToD(myLTUJointlyTrainedWeight), 1.0)
+ offset = offset + ltuSize//ltuTemplates(ltu_count).length
+ ltu_count = ltu_count + 1
+ val trainedWeighs2 = cf.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.get(i).asInstanceOf[LinearThresholdUnit].getWeightVector
+ println("after joint ", trainedWeighs2, ", s=", trainedWeighs2.size())
+ }
+ }
+
+ BadgeClassifierMulti.test()
+
+
+ }
+
+// "weights initializer" should "join multiple weight vectors" in {
+// var lt: ListBuffer[Array[Float]] = ListBuffer()
+// var wvLength = 0
+// // Add 3 factors (size 3, 4, 7)
+// val length1 = 3
+// val length2 = 4
+// val length3 = 7
+// val t1: Array[Float] = Array(4.0f, 6.0f, 8.0f)
+// wvLength = wvLength + length1
+// val t2: Array[Float] = Array(-8.0f, -6.0f, -4.0f, 0.0f)
+// wvLength = wvLength + length2
+// val t3: Array[Float] = Array(14.0f, 16.0f, 18.0f, 24.0f, 35.5f, 78.32f, 567.865f)
+// wvLength = wvLength + length3
+//
+// // Append the individual vectors to the buffer
+// lt = lt :+ t1
+// lt = lt :+ t2
+// lt = lt :+ t3
+//
+// // Create the complete weight vector
+// val myWeight = Array(lt.flatten: _*)
+// val wv = new WeightVector(myWeight)
+// wv.getWeightArray should be(Array(4.0f, 6.0f, 8.0f, -8.0f, -6.0f, -4.0f, 0.0f, 14.0f, 16.0f, 18.0f, 24.0f, 35.5f, 78.32f, 567.865f))
+// }
+//
+// "weight update" should "distribute the joint weight vector" in {
+// var lt: ListBuffer[Array[Float]] = ListBuffer()
+// var wvLength = 0
+// // Add 3 factors (size 3, 4, 7)
+// val t1: Array[Float] = Array(4.0f, 6.0f, 8.0f)
+// wvLength = wvLength + t1.length
+// val t2: Array[Float] = Array(-8.0f, -6.0f, -4.0f, 0.0f)
+// wvLength = wvLength + t2.length
+// val t3: Array[Float] = Array(14.0f, 16.0f, 18.0f, 24.0f, 35.5f, 78.32f, 567.865f)
+// wvLength = wvLength + t3.length
+//
+// // Append the individual vectors to the buffer
+// lt = lt :+ t1
+// lt = lt :+ t2
+// lt = lt :+ t3
+//
+// // Create the complete weight vector
+// val myWeight = Array(lt.flatten: _*)
+// val wv = new WeightVector(myWeight)
+//
+// var offset = 0
+// val factorWeight1 = wv.getWeightArray.slice(offset, offset + t1.length)
+// factorWeight1 should be(Array(4.0f, 6.0f, 8.0f))
+// offset = offset + t1.length
+//
+// val factorWeight2 = wv.getWeightArray.slice(offset, offset + t2.length)
+// factorWeight2 should be(Array(-8.0f, -6.0f, -4.0f, 0.0f))
+// offset = offset + t2.length
+//
+// val factorWeight3 = wv.getWeightArray.slice(offset, offset + t3.length)
+// factorWeight3 should be(Array(14.0f, 16.0f, 18.0f, 24.0f, 35.5f, 78.32f, 567.865f))
+// }
+// "featureVector operations" should "work" in {
+// val fvGlobal = new FeatureVectorBuffer()
+// val fv = new FeatureVectorBuffer()
+// val a0: Array[Int] = Array(1, 2, 3)
+// val a1: Array[Double] = Array(0.1, 0.2, 0.3)
+// val fvTemp = new FeatureVectorBuffer(a0, a1)
+// fvGlobal.addFeature(fvTemp)
+// fvTemp.toFeatureVector.getIndices should be(Array(1, 2, 3))
+// fvGlobal.addFeature(fvTemp, 3)
+// fvGlobal.addFeature(fvTemp, 3)
+// fvGlobal.shift(1)
+// fvGlobal.toFeatureVector.getIndices should be(Array(2, 3, 4, 5, 6, 7))
+// }
+//
+//
+// // Testing the original functions with real classifiers
+// "integration test" should "work" in {
+// // Initialize toy model
+// import testModel._
+// object TestClassifier extends Learnable(tokens) {
+// def label = testLabel
+//
+// override def feature = using(word)
+//
+// override lazy val classifier = new SparseNetworkLearner()
+// }
+// object TestBiClassifier extends Learnable(tokens) {
+// def label = testLabel
+//
+// override def feature = using(word, biWord)
+//
+// override lazy val classifier = new SparseNetworkLearner()
+// }
+// object TestConstraintClassifier extends ConstrainedClassifier[String, String](TestClassifier) {
+// def subjectTo = ConstrainedClassifier.constraint { _ => new FirstOrderConstant(true) }
+//
+// //override val pathToHead = Some(-iEdge)
+// // override def filter(t: String, h: String): Boolean = t.equals(h)
+// override val solver = new OJalgoHook
+// }
+// object TestBiConstraintClassifier extends ConstrainedClassifier[String, String](TestBiClassifier) {
+// def subjectTo = ConstrainedClassifier.constraint { _ => new FirstOrderConstant(true) }
+//
+// // override val pathToHead = Some(-iEdge)
+// //override def filter(t: String, h: String): Boolean = t.equals(h)
+// override val solver = new OJalgoHook
+// }
+//
+// val words = List("this", "is", "a", "test")
+// tokens.populate(words)
+//
+// val cls = List(TestConstraintClassifier, TestBiConstraintClassifier)
+// // This should combine the weights
+// val m = StructuredLearning(tokens, cls)
+//
+// val clNet1 = TestConstraintClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner]
+// val clNet2 = TestBiConstraintClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner]
+// val wv1 = clNet1.getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+// val wv2 = clNet2.getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+//
+// m.Factors.size should be(2)
+//
+// wv1.size() should be(4)
+// wv2.size() should be(8)
+// // Combined size should be 12
+// m.wv.getLength should be(12)
+//
+// // This should distribute the weights
+// m.infSolver.asInstanceOf[Saul_SL_Inference[String]].updateWeights(m.wv)
+//
+// val wv1After = clNet1.getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+// val wv2After = clNet2.getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+//
+// //Everything should be the same
+// wv1After.size() should be(4)
+// wv2After.size() should be(8)
+// // Combined size should be 12
+// m.wv.getLength should be(12)
+// }
+//
+// object testModel extends DataModel {
+// val tokens = node[String]
+// val iEdge = edge(tokens, tokens)
+// val testLabel = property(tokens) { x: String => x.equals("candidate") }
+// val word = property(tokens) { x: String => x }
+// val biWord = property(tokens) { x: String => x + "-" + x }
+// }
+
+}
diff --git a/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationSLTests.scala b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationSLTests.scala
new file mode 100644
index 00000000..e4f7c77d
--- /dev/null
+++ b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationSLTests.scala
@@ -0,0 +1,99 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation
+
+import edu.illinois.cs.cogcomp.saul.classifier.ClassifierUtils
+import edu.illinois.cs.cogcomp.saul.classifier.SL_model._
+import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.datastruct.ConllRelation
+import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationClassifiers._
+import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationConstrainedClassifiers._
+import edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation.EntityRelationDataModel._
+import edu.illinois.cs.cogcomp.sl.core.SLParameters
+import org.scalatest.{ FlatSpec, Matchers }
+
+/** Created by Parisa on 6/10/16.
+ */
+class EntityRelationSLTests extends FlatSpec with Matchers {
+
+ /*this lines of setting are used in all the tests below them*/
+
+ populateWithConllSmallSet()
+
+ val cls = List(PerConstrainedClassifier, OrgConstrainedClassifier, LocConstrainedClassifier, LivesIn_PerOrg_relationConstrainedClassifier, WorksFor_PerOrg_ConstrainedClassifier)
+ val cls_base = List(PersonClassifier, OrganizationClassifier, LocationClassifier, WorksForClassifier, LivesInClassifier)
+
+ val SLProblem = SL_IOManager.makeSLProblem(pairs, cls)
+ val para = new SLParameters
+ para.loadConfigFile("../config/DCD.config")
+
+ val xGold = SLProblem.instanceList.get(0)
+ val yGold = SLProblem.goldStructureList.get(0)
+
+ /*Tests*/
+
+ "Structured output learning (SL)" should "get correct number of instances." in {
+ SLProblem.goldStructureList.size() should be(24)
+ SLProblem.instanceList.size() should be(24)
+ }
+
+ "Structured output learning (SL) initialization" should "work." in {
+ val model = Initialize(pairs, new SaulSLModel(cls), usePreTrained = false)
+ model.Factors.size should be(5)
+ model.LTUWeightTemplates.size should be(10)
+ model.wv.getLength should be(1144)
+ model.wv.getWeightArray.filter(p => (p > 0.00)).isEmpty should be(true)
+ }
+ "Structured output learning (SL) without initialization using trained models" should "work." in {
+ ClassifierUtils.LoadClassifier(EntityRelationApp.jarModelPath, cls_base: _*)
+ val model = Initialize(pairs, new SaulSLModel(cls), usePreTrained = true)
+ model.Factors.size should be(5)
+ model.LTUWeightTemplates.size should be(10)
+ model.wv.getLength should be(171582)
+ (model.wv.getWeightArray.filter(p => (p > 0.00)).length < 20000) should be(true)
+ // model.featureGenerator.getFeatureVector(xGold, yGold).getValues.sum should be(96.0)
+ }
+
+ // val a = sparseNet.getExampleArray(ci, false)
+ // var a0 = a(0).asInstanceOf[Array[Int]]
+ // var a1 = a(1).asInstanceOf[Array[Double]]
+ // val fvTemp = new FeatureVectorBuffer(a0, a1)
+
+ "Structured output learning (SL) Feature extraction" should "work." in {
+ // val model = Initialize(pairs, new SaulSLModel(cls), usePreTrained = false)
+
+ }
+
+ "Structured output learning's loss" should " be calculate correctly." in {
+ val model = Initialize(pairs, new SaulSLModel(cls), usePreTrained = false)
+ model.para = para
+ model.infSolver = new Saul_SL_Inference[ConllRelation](model.Factors.toList, model.LTUWeightTemplates)
+ //val learner = LearnerFactory.getLearner(model.infSolver, model.featureGenerator, para)
+
+ val yTest = new Saul_SL_Label_Structure[ConllRelation](cls, yGold.asInstanceOf[Saul_SL_Label_Structure[ConllRelation]].head.asInstanceOf[ConllRelation])
+ yTest.labels = for (
+ l <- yGold.asInstanceOf[Saul_SL_Label_Structure[ConllRelation]].labels
+ ) yield "true"
+
+ model.infSolver.getLoss(xGold, yGold, yGold) should be(0.00)
+ model.infSolver.getLoss(xGold, yGold, yTest) >= (0.8) should be(true)
+ }
+
+ // val weight = learner.train(SLProblem, model.wv)
+ "Structured output learning" should " have a correctly working inference module." in {
+ // val model = Initialize(pairs, new SaulSLModel(cls), usePreTrained = false)
+ // val yPredicted = model.infSolver.getBestStructure(model.wv, xGold)
+ // val yMostViolated = model.infSolver.getLossAugmentedBestStructure(model.wv, xGold, yGold)
+ // // model.infSolver.getLoss(xGold, yGold, yPredicted) should be(0.00)
+ // // model.infSolver.getLoss(xGold, yPredicted, yMostViolated) should be(0.00)
+ // (yPredicted.asInstanceOf[Saul_SL_Label_Structure[ConllRelation]].equals(yMostViolated.
+ // asInstanceOf[Saul_SL_Label_Structure[ConllRelation]])) should be(true)
+ }
+
+ "Structured output learning (SL)" should "really work in Saul." in {
+
+ }
+}
diff --git a/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationTests.scala b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationTests.scala
index 298fe7eb..cf1adec0 100644
--- a/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationTests.scala
+++ b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/EntityRelationTests.scala
@@ -92,14 +92,19 @@ class EntityRelationTests extends FlatSpec with Matchers {
ClassifierUtils.TrainClassifiers(1, cls_base)
- PerConstrainedClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector.size() should be(1660)
+ PerConstrainedClassifier.onClassifier.classifier.getLabelLexicon.size() should be(2)
+ PerConstrainedClassifier.onClassifier.classifier.getLexicon.size() should be(1661)
+
+ PerConstrainedClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector.size() should be(1661)
val jointTrainIteration = 1
JointTrainSparseNetwork.train[ConllRelation](
pairs, cls, jointTrainIteration, init = true
)
- PerConstrainedClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector.size() should be(50)
+ PerConstrainedClassifier.onClassifier.classifier.getLabelLexicon.size() should be(2)
+ PerConstrainedClassifier.onClassifier.classifier.getLexicon.size() should be(84)
+ PerConstrainedClassifier.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getNetwork.get(0).asInstanceOf[LinearThresholdUnit].getWeightVector.size() should be(84)
}
}
\ No newline at end of file
diff --git a/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/SLTest2.scala b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/SLTest2.scala
new file mode 100644
index 00000000..29ff7f40
--- /dev/null
+++ b/saul-examples/src/test/scala/edu/illinois/cs/cogcomp/saulexamples/nlp/EntityRelation/SLTest2.scala
@@ -0,0 +1,166 @@
+/** This software is released under the University of Illinois/Research and Academic Use License. See
+ * the LICENSE file in the root folder for details. Copyright (c) 2016
+ *
+ * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign
+ * http://cogcomp.cs.illinois.edu/
+ */
+package edu.illinois.cs.cogcomp.saulexamples.nlp.EntityRelation
+
+import edu.illinois.cs.cogcomp.infer.ilp.OJalgoHook
+import edu.illinois.cs.cogcomp.lbjava.infer.FirstOrderConstant
+import edu.illinois.cs.cogcomp.lbjava.learn.{ LinearThresholdUnit, SparseNetworkLearner }
+import edu.illinois.cs.cogcomp.saul.classifier.SL_model._
+import edu.illinois.cs.cogcomp.saul.classifier.{ JointTrainSparseNetwork, ClassifierUtils, ConstrainedClassifier, Learnable }
+import edu.illinois.cs.cogcomp.saul.datamodel.DataModel
+import edu.illinois.cs.cogcomp.saul.datamodel.property.Property
+import edu.illinois.cs.cogcomp.saulexamples.EntityMentionRelation.datastruct.ConllRelation
+import edu.illinois.cs.cogcomp.sl.core.SLParameters
+import edu.illinois.cs.cogcomp.sl.learner.LearnerFactory
+import org.scalatest.{ FlatSpec, Matchers }
+
+/** Created by Parisa on 7/2/16.
+ */
+class SLTest2 extends FlatSpec with Matchers {
+
+ object testModel extends DataModel {
+ val tokens = node[String]
+ // val pairs = edge(tokens, tokens)
+ val testLabel = property(tokens) { x: String => x.equals("candidate") }
+ val word = property(tokens) { x: String => x }
+ val biWord = property(tokens) { x: String => x + "-" + x }
+ }
+
+ // Testing the original functions with real classifiers
+ // "integration test" should "work" in {
+ // Initialize toy model
+
+ import testModel._
+
+ object TestClassifier extends Learnable(tokens) {
+ def label: Property[String] = testLabel
+
+ override def feature = using(word)
+
+ override lazy val classifier = new SparseNetworkLearner()
+ }
+
+ object TestBiClassifier extends Learnable(tokens) {
+ def label: Property[String] = testLabel
+
+ override def feature = using(word, biWord)
+
+ override lazy val classifier = new SparseNetworkLearner()
+ }
+
+ object TestConstraintClassifier extends ConstrainedClassifier[String, String](TestClassifier) {
+ def subjectTo = ConstrainedClassifier.constraint { _ => new FirstOrderConstant(true) }
+
+ // override val pathToHead = Some(-pairs)
+ //override def filter(t: String, h: String): Boolean = t.equals(h)
+ override val solver = new OJalgoHook
+ }
+
+ object TestBiConstraintClassifier extends ConstrainedClassifier[String, String](TestBiClassifier) {
+ def subjectTo = ConstrainedClassifier.constraint { _ => new FirstOrderConstant(true) }
+
+ // override val pathToHead = Some(-pairs)
+ //override def filter(t: String, h: String): Boolean = t.equals(h)
+ override val solver = new OJalgoHook
+ }
+
+ val words_train = List("this", "is", "a", "candidate")
+ val words_test = List("this", "was", "not", "true")
+ tokens.populate(words_train)
+ tokens.populate(words_test, train = false)
+
+ val cls = List(TestConstraintClassifier, TestBiConstraintClassifier)
+ val cls_base = List(TestClassifier, TestBiClassifier)
+ val model = Initialize(tokens, new SaulSLModel(cls), usePreTrained = true)
+
+ JointTrainSparseNetwork(tokens, cls, 3, true)
+ // This should combine the weights
+ // val m = StructuredLearning(tokens, cls, initialize = false)
+
+ val SLProblem = SL_IOManager.makeSLProblem(tokens, cls)
+ "Structured output learning (SL)" should "get correct number of instances." in {
+ SLProblem.goldStructureList.size() should be(4)
+ SLProblem.instanceList.size() should be(4)
+ }
+
+ "Structured output learning (SL) initialization with zero" should "work." in {
+ model.Factors.size should be(2)
+ model.LTUWeightTemplates.size should be(4)
+ model.wv.getLength should be(24)
+ model.wv.getWeightArray.filter(p => (p > 0.00)).isEmpty should be(true)
+ }
+
+ val xGold = SLProblem.instanceList.get(0)
+ val yGold = SLProblem.goldStructureList.get(0)
+ model.featureGenerator = new SL_FeatureGenerator(model)
+
+ "Structured output learning (SL) Feature extraction" should "work." in {
+ model.featureGenerator.getFeatureVector(xGold, yGold).getValues.sum should be(3.0)
+ }
+
+ ClassifierUtils.TrainClassifiers(5, cls_base: _*)
+ val InitializedModel = Initialize(tokens, new SaulSLModel(cls), usePreTrained = true)
+ "Structured output learning (SL) initialization with trained models" should "work." in {
+ println("Factors:", InitializedModel.Factors.size)
+ println("LTUs:", InitializedModel.LTUWeightTemplates.size)
+ println("modellength:", InitializedModel.wv.getLength)
+ println("weightArray:", InitializedModel.wv.getWeightArray)
+ InitializedModel.Factors.size should be(2)
+ InitializedModel.LTUWeightTemplates.size should be(4)
+ InitializedModel.wv.getLength should be(24)
+
+ InitializedModel.Factors.foreach(
+ x => {
+ val classifierWeightVector0 = x.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getLTU(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+ val baseWeightVector0 = cls_base(0).classifier.asInstanceOf[SparseNetworkLearner].getLTU(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+
+ classifierWeightVector0 should be(baseWeightVector0)
+
+ val classifierWeightVector1 = x.onClassifier.classifier.asInstanceOf[SparseNetworkLearner].getLTU(1).asInstanceOf[LinearThresholdUnit].getWeightVector
+ val baseWeightVector1 = cls_base(1).classifier.asInstanceOf[SparseNetworkLearner].getLTU(0).asInstanceOf[LinearThresholdUnit].getWeightVector
+
+ classifierWeightVector1 should be(baseWeightVector1)
+ }
+ )
+ //InitializedModel.wv.getWeightArray.filter(p => (p > 0.00)).isEmpty should be(true)
+
+ }
+
+ val para = new SLParameters
+ para.loadConfigFile("../config/DCD.config")
+ model.para = para
+ model.infSolver = new Saul_SL_Inference[String](model.Factors.toList, model.LTUWeightTemplates)
+ val learner = LearnerFactory.getLearner(model.infSolver, model.featureGenerator, para)
+
+ "Structured output learning's loss" should " be calculate correctly." in {
+
+ val yTest = new Saul_SL_Label_Structure[String](cls, yGold.asInstanceOf[Saul_SL_Label_Structure[String]].head.asInstanceOf[String])
+ yTest.labels = for (
+ l <- yGold.asInstanceOf[Saul_SL_Label_Structure[ConllRelation]].labels
+ ) yield "true"
+
+ model.infSolver.getLoss(xGold, yGold, yGold) should be(0.00)
+ model.infSolver.getLoss(xGold, yGold, yTest) >= (0.8) should be(true)
+ }
+
+ // val weight = learner.train(SLProblem, model.wv)
+ // "Structured output learning" should " have a correctly working inference module." in {
+ // val yPredicted = model.infSolver.getBestStructure(model.wv, xGold)
+ // val yMostViolated = model.infSolver.getLossAugmentedBestStructure(model.wv, xGold, yGold)
+ // model.infSolver.getLoss(xGold, yGold, yPredicted) should be(0.00)
+ // model.infSolver.getLoss(xGold, yPredicted, yMostViolated) should be(0.00)
+ // (yPredicted.asInstanceOf[Saul_SL_Label_Structure[ConllRelation]].equals(yMostViolated.
+ // asInstanceOf[Saul_SL_Label_Structure[ConllRelation]])) should be(true)
+ // }
+
+ "Structured output learning (SL)" should "really work in Saul." in {
+
+ }
+
+ // }
+}
+