Skip to content
This repository was archived by the owner on Nov 28, 2025. It is now read-only.

fix tfrecord compress on hdfs - #108

Closed
bigbear2017 wants to merge 1 commit into
tensorflow:masterfrom
bigbear2017:master
Closed

bigbear2017 wants to merge 1 commit into
tensorflow:masterfrom
bigbear2017:master

Conversation

@bigbear2017

Copy link
Copy Markdown

Default code doesn't support gzip or other compression type on hdfs. This
has been fixed in this pull request. Simply using following gzip compression,
it can reduce 6-7 times less space.

    TFRecordFileOutputFormat.setCompressOutput(job, true);
    TFRecordFileOutputFormat.setOutputCompressorClass(job, GzipCodec.class);

@googlebot

Copy link
Copy Markdown

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here (e.g. I signed it!) and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

@bigbear2017

Copy link
Copy Markdown
Author

I signed it!

@googlebot

Copy link
Copy Markdown

CLAs look good, thanks!

@jhseu

jhseu commented Nov 13, 2018

Copy link
Copy Markdown
Contributor

The underlying TFRecords file format supports compression, and I'm worried that the difference in format here will confuse users. Could we use that instead?

@bigbear2017

Copy link
Copy Markdown
Author

The underlying TFRecords file format supports compression, and I'm worried that the difference in format here will confuse users. Could we use that instead?

please refer to this issue:
#61

Now, the compression doesn't work on spark or hadoop MR. If you write data local, it's OK. You can compress TF records. The compression is done by python not TF. To me, there is no confusion. With this PR, you can read compressed data generated by Spark or hadoop in python. This has been tested in our system.

@sahilbadyal

Copy link
Copy Markdown

@bigbear2017 Do we have to add options to compress the TFRecord files ?

@bigbear2017

Copy link
Copy Markdown
Author

@sahilbadyal
Just add the following code to your job.
TFRecordFileOutputFormat.setCompressOutput(job, true);
TFRecordFileOutputFormat.setOutputCompressorClass(job, GzipCodec.class);

@sahilbadyal

Copy link
Copy Markdown

@bigbear2017 Sorry for not asking the question right. I am using Pyspark

@fhoering

fhoering commented Mar 14, 2019 •

Copy link
Copy Markdown
Contributor

Why is this this PR closed ? It has not been merged.
We have exactly the same issue. We need to write compressed TFRecords from Spark to HDFS. Compressing them manually is yet another step to do. In Python TFRecordWriter supports this with TFRecordCompressionType
Why not reusing the settings from FileOutputFormat as proposed here ? As it uses the Hadoop RecordWriter API it seems the standard way to do.

@@ -32,20 +32,29 @@ public class TFRecordFileOutputFormat extends FileOutputFormat<BytesWritable, Nu
@Override public RecordWriter<BytesWritable, NullWritable> getRecordWriter(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relevant imports are missing:
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.io.compress.GzipCodec;
import org.apache.hadoop.util.ReflectionUtils;

import java.io.DataOutputStream;

FileSystem fs = file.getFileSystem(conf);
final DataOutputStream fsdos = isCompressed ?
new DataOutputStream(codec.createOutputStream(fs.create(file, true, bufferSize))) :
fs.create(file, true, bufferSize);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fs.create(file, true, bufferSize) could be factorized in a variable

@fhoering

fhoering commented Mar 14, 2019 •

Copy link
Copy Markdown
Contributor

I tested the fix. It is working (with minor changes, need to add the right imports) and can be imported from Python by setting
tf.io.TFRecordCompressionType = tf.io.TFRecordCompressionType.GZIP

Unit tests are still working
Maybe a new test can be added for the gzip case

@jhseu

jhseu commented Mar 14, 2019

Copy link
Copy Markdown
Contributor

I'm ok with a pull request that sets the TFRecordCompressionType. I'm just worried about using different compression formats. The TFRecord compression is integrated into the file format, and this PR gzips the file which ends up being a different format. Happy to accept a pull request that can set the option in TFRecords.

@fhoering

fhoering commented Mar 15, 2019 •

Copy link
Copy Markdown
Contributor

@jhseu

Can you give more details on

the TFRecord compression is integrated into the file format

What do you mean by ?

and this PR gzips the file which ends up being a different format

gzip is standardized. So it always will be the gzip format.

From how I understand it (please correct me if I'm wrong)

  • TFRecord is a protobuf with schema Example or SequenceExample
  • Protobuf doesn't have integrated gzip compression
  • If GZIP compression is integrated in the TfRecordWriter Python API it means that there is (somehow) a c++ Gzip outstream class on top of the encoded protobuf
  • Here we are in the Java world, TFRecordWriter is writing the Java protobuf Example/SequenceExample
  • We need to somehow gzip the protobuf output stream before writing to disk
  • So it ends up applying a Java GzipOutputStream on top of that
  • This is exactly what is proposed here

About the settings, it ends up setting this to the Spark/PySpark job which also seems fine to me.

spark.hadoop.mapreduce.output.fileoutputformat.compress:true
spark.hadoop.mapreduce.output.fileoutputformat.compress.codec:
org.apache.hadoop.io.compress.GzipCodec

Indeed it might not work in some cases as Python api might not support it but it gives enough flexibility for other codecs.
Adding yet another config like tfrecordcompressiontype=Gzip will also be confusing.

At the end on my side I would like to have something that works (and I don't want to maintain my own fork). So any implementation is fine for me.
As indicated I would also provide a new PR. But what is proposed here (fixing using + units tests) looks fine to me.

@jhseu

jhseu commented Mar 15, 2019

Copy link
Copy Markdown
Contributor

TFRecord is a format that is essentially a sequence of records stored as bytes. Those can be anything, but are typically tf.Example protos.

The TFRecord has custom compression settings that are different than just gzipping the file, which you can set in the options:
https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/io/TFRecordOptions?hl=en

I'm worried about offering an incompatible, but similar compression setting here. If we could make it compatible, then that's fine.

@jhseu

jhseu commented Mar 15, 2019

Copy link
Copy Markdown
Contributor

@fhoering

Copy link
Copy Markdown
Contributor

In my opinion what is important is that TfRecords that are written here can be read by Pythons TFRecordReader.
And this is the case for GZIP compression. I have tested it.
I could be a first commit. This will already be fine for 90% of the users.

And when someone wants to implement all options of ZLIB he can do this in a second step. I would argue user rather want to use a newer compression lib than doing that.

@jhseu

jhseu commented Mar 15, 2019

Copy link
Copy Markdown
Contributor

It would also need to work with tf.data.

@fhoering

Copy link
Copy Markdown
Contributor

So maybe adding a new setting 'tfrecord.compressiontype=Gzip' is better because it restrains the number of possibilities and can be extended to what has been implemented in TfRecordOptions

@fhoering

fhoering commented Mar 25, 2019 •

Copy link
Copy Markdown
Contributor

I tried this:

tf.data.TFRecordDataset(files, compression_type="GZIP") 

It is working.

As suggested I can provide a new PR with the same code + a unit test.
If this is not enough can you please clearly give a timeline on when you will be implementing this on your side or at least give some clear guidelines on what needs to be done or clearly say it will never be done (and close the ticket #61)

@jhseu

jhseu commented Mar 25, 2019

Copy link
Copy Markdown
Contributor

@fhoering
Hmm, yeah, it seems I misunderstood the format, and that does seem like it should work after reading through the code more closely. Feel free to send a PR, preferably with a unit test if you can get one to work (if not, it's fine).

@jhseu jhseu reopened this Mar 25, 2019
@fhoering

Copy link
Copy Markdown
Contributor

@bigbear2017

Copy link
Copy Markdown
Author

hmmm.... I thought I would have a merge in this project. T.T

@bigbear2017

Copy link
Copy Markdown
Author

anyway, it is good that this has been fixed. : )

@jhseu

jhseu commented Mar 27, 2019

Copy link
Copy Markdown
Contributor

Thanks @bigbear2017 for starting this effort! The test that checked that tf.data reads it correctly alleviated my concern about merging this kind of change in.

@jhseu jhseu closed this Mar 27, 2019
@qiaoguan

qiaoguan commented Sep 6, 2019

Copy link
Copy Markdown

Execuse me, i user spark to transform the original format to TFrecord format, it works , but the tfrecord file is too large , i want to compress it, what should i do?

import org.tensorflow.hadoop.io.TFRecordFileOutputFormat
import org.tensorflow.hadoop.shaded.protobuf.ByteString
import org.apache.hadoop.io.compress.CompressionCodec
import org.apache.hadoop.io.compress.GzipCodec

val tfrecord_sample_dir = sample_dir + localArgs.yyyyMMdd + "/" + localArgs.loc+"_tfrecord"
FileSystem.get(sc.hadoopConfiguration).delete(new Path(tfrecord_sample_dir), true)
tfrecord_sample.saveAsNewAPIHadoopFileTFRecordFileOutputFormat

where tfrecord_sample is a RDD[(BytesWritable, NullWriteable)] format, BytesWritable is a tfrecord example format。 i see saveAsHadoopFile function provide a way to compress the original data, but i do not know how to use it, anyone can help?
/**

Output the RDD to any Hadoop-supported file system, using a Hadoop OutputFormat class
supporting the key and value types K and V in this RDD. Compress the result with the
supplied codec.
*/
def saveAsHadoopFile[F <: OutputFormat[K, V]](
path: String,
codec: Class[_ <: CompressionCodec])(implicit fm: ClassTag[F]): Unit = self.withScope {
val runtimeClass = fm.runtimeClass
saveAsHadoopFile(path, keyClass, valueClass, runtimeClass.asInstanceOf[Class[F]], codec)
}
i try to use
tfrecord_sample.saveAsHadoopFile[TFRecordFileOutputFormat](tfrecord_sample_dir, GzipCodec)
like this , but it doesn't work

@nnnnwang

Copy link
Copy Markdown

hello,when i use follow code to compress the tfrecord as gzip format,it seems doesn't work. There is no different between the output file size whether add the "option("codec","org.apache.hadoop.io.compress.GzipCodec")" or not

write.mode("overwrite")
.format("tfrecords")
.option("recordType","Example")
.option("codec", "org.apache.hadoop.io.compress.GzipCodec")
.save(outputFilePath)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants