public RNNLM(RNNLMConfiguration conf) throws IOException {

        this.conf = conf;

        // For files
        if (conf.vocab != null) {
            vocab = conf.vocab;
            conf.vocabSize = vocab.size();
        }
        else if (conf.trainFile != null) {
            vocab = new Vocabulary();
            vocab.loadRawText(conf.trainFile);
            conf.vocabSize = vocab.size();
        }

        inputLayer = new Layer(inputLayerSize());
        recurrentLayer = new Layer(hiddenLayerSize());
        hiddenLayer = new Layer(hiddenLayerSize());
        outputLayer = new Layer(outputLayerSize());

        inputSynapse = new Synapse(inputLayerSize(), hiddenLayerSize());
        hiddenSynapse = new Synapse(hiddenLayerSize(), outputLayerSize());
        recurrentSynapse = new Synapse(hiddenLayerSize(), hiddenLayerSize());

        bpttHiddenLayers = new Layer[(conf.bptt+conf.bpttBlock+1)];
        for (int i = 0; i < bpttHiddenLayers.length; ++i) {
            bpttHiddenLayers[i] = new Layer(hiddenLayerSize());
        }

        bpttInputSynapse = new Synapse(inputLayer.size, hiddenLayer.size);
        bpttRecurrentSynapse = new Synapse(recurrentLayer.size, hiddenLayer.size);
        bpttInputSynapse.zero();
        bpttRecurrentSynapse.zero();

        history = new int[conf.maxNgramOrder];
        bpttHistory = new int[conf.bptt + conf.bpttBlock + 1];

        wordVector = new DenseMatrix64F(outputLayerSize(), 1);
        saver = new LMSaver();

        // Weights
        if (conf.sameInitialWeights) {
            Arrays.fill(inputSynapse.weights.getData(), 0.1);
            Arrays.fill(recurrentSynapse.weights.getData(), 0.1);
            Arrays.fill(hiddenSynapse.weights.getData(), 0.1);
        }
    }