     }
 
     public init(
-        bpe: BytePairEncoder,
+        bpe: BytePairEncoder? = nil,
         variant: TextUnsupervisedVariant = TextUnsupervisedVariant.wikiText2,
         trainingBatchSize: Int = 8, validationBatchSize: Int = 4, sequenceLength: Int = 1024,
         trainingDocumentCount: Int = 4, validationDocumentCount: Int = 4

        return rows
    }

    private static func embedding(for string: String, bpe: BytePairEncoder) -> [Int] {
        let tokens = bpe.encode(token: string, variant: .gpt2)
        // TODO(michellecasbon): Decide how to prevent OOV or choose a better ID (probably not 0).

        return ids
    }

    /// Returns a LanguageModelDataset by processing files specified by 'variantDetails' which
    /// resides in 'directory'.
    ///
    /// Download the files if not present. If bpe is nil which means skip bype pair encoding,
    /// then download the encoded file instead.
    ///
    /// - Parameter name: name of the dataset. Ususally 'train' or 'test'.
    /// - Parameter directory: directory that files are read from.
    /// - Parameter bpe: byte pair encoder used for encoding text.
    /// - Parameter variantDetails: an object containing information of filename, location, etc.
    /// - Parameter batchSize: number of sequences in a batch.
    /// - Parameter sequenceLength: number of characters in a sequence.
    /// - Parameter documentCount: number of documents to proceed. (Refer func readCSV() to see how
    ///   a text file is chunked into documents.)
    private static func loadDirectory(
        named name: String, in directory: URL, bpe: BytePairEncoder?,
        variantDetails: TextUnsupervisedVariantDetails, batchSize: Int, sequenceLength: Int,
        documentCount: Int = 4
    ) throws -> LanguageModelDataset<[[Int]]> {
        precondition(bpe != nil || variantDetails.encodedFileName != nil,
                     "bpe must be provided when encodedFileName is nil.")
        downloadIfNotPresent(to: directory, variantDetails: variantDetails, downloadEncodedFile: bpe == nil)

        var encodedDocs: [[Int]] = []
        if let bpe = bpe {
            let path = directory.appendingPathComponent("\(variantDetails.filename)/\(name).csv")
            let documentsFull = try readCSV(in: path)
            let documents = Array(documentsFull[0..<min(documentCount, documentsFull.count)])
            encodedDocs = documents.map { embedding(for: $0, bpe: bpe) }
        } else {
            let pathPrefix = directory.appendingPathComponent("\(variantDetails.encodedFileName!)/\(name)").path
            for i in 0..<documentCount {
                encodedDocs += [
                  try readEncoded(in: URL(fileURLWithPath: "\(pathPrefix)/doc_\(i).txt"))
                ]
            }
        }

        return LanguageModelDataset(
            batchSize: batchSize,
            sequenceLength: sequenceLength,
            numericalizedTexts: encodedDocs,
            lengths: encodedDocs.map { $0.count },
            dropLast: true
        )
    }

    private static func loadTraining(
        localStorageDirectory: URL, bpe: BytePairEncoder?,
        variantDetails: TextUnsupervisedVariantDetails, batchSize: Int, sequenceLength: Int,
        documentCount: Int
    )
