├── 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 | | Summary |
6 | Format |
7 |
8 |
9 | | Scalars |
10 | 1 csv-file. One column per scalar summary tag. |
11 |
12 |
13 | | Images |
14 | Multiple PNG-images structured in folderes depending on the name of the summary tags. |
15 |
16 |
17 | | Audio |
18 | Not yet supported. |
19 |
20 |
21 | | Histograms |
22 | Not yet supported. |
23 |
24 |
25 | | Distributions |
26 | Not yet supported. |
27 |
28 |
29 | | Tensors |
30 | Not yet supported. |
31 |
32 |
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 |
--------------------------------------------------------------------------------