├── LICENSE ├── README.md └── exportTensorFlowLog.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 anderskm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # exportTensorFlowLog 2 | Export TensorFlow logs to common easy to read formats (csv-files, png-images, ...) 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
SummaryFormat
Scalars1 csv-file. One column per scalar summary tag.
ImagesMultiple PNG-images structured in folderes depending on the name of the summary tags.
AudioNot yet supported.
HistogramsNot yet supported.
DistributionsNot yet supported.
TensorsNot yet supported.
33 | 34 | Tested on TensorFlow version 0.11.0, 1.1.0 and 1.3.0 and Python 2.7 and 3.6. 35 | 36 | ## Usage 37 | 38 | ``` 39 | python readLogs.py 40 | 41 | Inputs: 42 | - Path to TensorFlow logfile. 43 | - Path to output folder. 44 | - (Optional) Comma separated list of summaries to save in output-folder. Default: scalars, histograms, images, audio, compressedHistograms 45 | ``` 46 | -------------------------------------------------------------------------------- /exportTensorFlowLog.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import time 3 | import csv 4 | import sys 5 | import os 6 | import collections 7 | 8 | # Import the event accumulator from Tensorboard. Location varies between Tensorflow versions. Try each known location until one works. 9 | eventAccumulatorImported = False; 10 | # TF version < 1.1.0 11 | if (not eventAccumulatorImported): 12 | try: 13 | from tensorflow.python.summary import event_accumulator 14 | eventAccumulatorImported = True; 15 | except ImportError: 16 | eventAccumulatorImported = False; 17 | # TF version = 1.1.0 18 | if (not eventAccumulatorImported): 19 | try: 20 | from tensorflow.tensorboard.backend.event_processing import event_accumulator 21 | eventAccumulatorImported = True; 22 | except ImportError: 23 | eventAccumulatorImported = False; 24 | # TF version >= 1.3.0 25 | if (not eventAccumulatorImported): 26 | try: 27 | from tensorboard.backend.event_processing import event_accumulator 28 | eventAccumulatorImported = True; 29 | except ImportError: 30 | eventAccumulatorImported = False; 31 | # TF version = Unknown 32 | if (not eventAccumulatorImported): 33 | raise ImportError('Could not locate and import Tensorflow event accumulator.') 34 | 35 | summariesDefault = ['scalars','histograms','images','audio','compressedHistograms']; 36 | 37 | class Timer(object): 38 | # Source: https://stackoverflow.com/a/5849861 39 | def __init__(self, name=None): 40 | self.name = name 41 | 42 | def __enter__(self): 43 | self.tstart = time.time() 44 | 45 | def __exit__(self, type, value, traceback): 46 | if self.name: 47 | print('[%s]' % self.name) 48 | print('Elapsed: %s' % (time.time() - self.tstart)) 49 | 50 | def exitWithUsage(): 51 | print(' '); 52 | print('Usage:'); 53 | print(' python readLogs.py '); 54 | print('Inputs:'); 55 | print(' - Path to TensorFlow logfile.'); 56 | print(' - Path to output folder.'); 57 | print(' - (Optional) Comma separated list of summaries to save in output-folder. Default: ' + ', '.join(summariesDefault)); 58 | print(' '); 59 | sys.exit(); 60 | 61 | if (len(sys.argv) < 3): 62 | exitWithUsage(); 63 | 64 | inputLogFile = sys.argv[1]; 65 | outputFolder = sys.argv[2]; 66 | 67 | if (len(sys.argv) < 4): 68 | summaries = summariesDefault; 69 | else: 70 | if (sys.argv[3] == 'all'): 71 | summaries = summariesDefault; 72 | else: 73 | summaries = sys.argv[3].split(','); 74 | 75 | print(' '); 76 | print('> Log file: ' + inputLogFile); 77 | print('> Output folder: ' + outputFolder); 78 | print('> Summaries: ' + ', '.join(summaries)); 79 | 80 | if any(x not in summariesDefault for x in summaries): 81 | print('Unknown summary! See usage for acceptable summaries.'); 82 | exitWithUsage(); 83 | 84 | 85 | print(' '); 86 | print('Setting up event accumulator...'); 87 | with Timer(): 88 | ea = event_accumulator.EventAccumulator(inputLogFile, 89 | size_guidance={ 90 | event_accumulator.COMPRESSED_HISTOGRAMS: 0, # 0 = grab all 91 | event_accumulator.IMAGES: 0, 92 | event_accumulator.AUDIO: 0, 93 | event_accumulator.SCALARS: 0, 94 | event_accumulator.HISTOGRAMS: 0, 95 | }) 96 | 97 | print(' '); 98 | print('Loading events from file*...'); 99 | print('* This might take a while. Sit back, relax and enjoy a cup of coffee :-)'); 100 | with Timer(): 101 | ea.Reload() # loads events from file 102 | 103 | print(' '); 104 | print('Log summary:'); 105 | tags = ea.Tags(); 106 | for t in tags: 107 | tagSum = [] 108 | if (isinstance(tags[t],collections.Sequence)): 109 | tagSum = str(len(tags[t])) + ' summaries'; 110 | else: 111 | tagSum = str(tags[t]); 112 | print(' ' + t + ': ' + tagSum); 113 | 114 | if not os.path.isdir(outputFolder): 115 | os.makedirs(outputFolder); 116 | 117 | if ('audio' in summaries): 118 | print(' '); 119 | print('Exporting audio...'); 120 | with Timer(): 121 | print(' Audio is not yet supported!'); 122 | 123 | if ('compressedHistograms' in summaries): 124 | print(' '); 125 | print('Exporting compressedHistograms...'); 126 | with Timer(): 127 | print(' Compressed histograms are not yet supported!'); 128 | 129 | 130 | if ('histograms' in summaries): 131 | print(' '); 132 | print('Exporting histograms...'); 133 | with Timer(): 134 | print(' Histograms are not yet supported!'); 135 | 136 | if ('images' in summaries): 137 | print(' '); 138 | print('Exporting images...'); 139 | imageDir = outputFolder + 'images' 140 | print('Image dir: ' + imageDir); 141 | with Timer(): 142 | imageTags = tags['images']; 143 | for imageTag in imageTags: 144 | images = ea.Images(imageTag); 145 | imageTagDir = imageDir + '/' + imageTag; 146 | if not os.path.isdir(imageTagDir): 147 | os.makedirs(imageTagDir); 148 | for image in images: 149 | imageFilename = imageTagDir + '/' + str(image.step) + '.png'; 150 | with open(imageFilename,'wb') as f: 151 | f.write(image.encoded_image_string); 152 | 153 | if ('scalars' in summaries): 154 | print(' '); 155 | csvFileName = os.path.join(outputFolder,'scalars.csv'); 156 | print('Exporting scalars to csv-file...'); 157 | print(' CSV-path: ' + csvFileName); 158 | scalarTags = tags['scalars']; 159 | with Timer(): 160 | with open(csvFileName,'w') as csvfile: 161 | logWriter = csv.writer(csvfile, delimiter=','); 162 | 163 | # Write headers to columns 164 | headers = ['wall_time','step']; 165 | for s in scalarTags: 166 | headers.append(s); 167 | logWriter.writerow(headers); 168 | 169 | vals = ea.Scalars(scalarTags[0]); 170 | for i in range(len(vals)): 171 | v = vals[i]; 172 | data = [v.wall_time, v.step]; 173 | for s in scalarTags: 174 | scalarTag = ea.Scalars(s); 175 | S = scalarTag[i]; 176 | data.append(S.value); 177 | logWriter.writerow(data); 178 | 179 | print(' '); 180 | print('Bye bye...'); 181 | 182 | --------------------------------------------------------------------------------