public ArrayList<String> predictIOB(ArrayList<Sentence> sentences, boolean showSegmentConfidence)
      throws JNETException {

    if (trained == false || model == null) {
      throw new JNETException(
          "no model available. Train or load trained model first.");
    }

    System.out.println("  * predicting with crf model...");

    Pipe myPipe = model.getInputPipe();

    // iterate through sentences and predict `em as IOB Output
    ArrayList<String> iobList = new ArrayList<String>();
    for (int i = 0; i < sentences.size(); i++) {
      Sentence sentence = sentences.get(i);
      Instance inst = new Instance(sentence, "", "", "", myPipe);
      Sequence input = (Sequence) inst.getData();
      Sequence output = model.viterbiPath(input).output();

      ArrayList<Unit> units = sentence.getUnits();

      if (output.size() != sentence.getUnits().size()) {
        throw new JNETException("Wrong number of labels predicted.");
      }

      // calculate performance on segments
      double[] conf = null;
      if (showSegmentConfidence) { 
        conf = getSegmentConfidence(input, output);
      }
      
      // now add the label to the unit object
      // and write in IOB ArrayList
      for (int j = 0; j < sentence.getUnits().size(); j++) {
        Unit unit = sentence.get(j);
        
        unit.setLabel((String) output.get(j));
        String iobString = units.get(j).getRep() + "\t" + (String) output.get(j);
        
        if (showSegmentConfidence) {
          unit.setConfidence(conf[j]);
          iobString += "\t" + conf[j];
        }
        
        iobList.add(iobString);
      }

      iobList.add("O" + "\t" + "O"); // O<tab>O at sentence end
    }
    return iobList;
  }