<p dir="auto">Love the library btw. This seems to be an issue with pydot from what I can tell.</p>
<p dir="auto"><code class="notranslate">from keras.utils.visualize_util import plot</code></p>
<p dir="auto">AttributeError                            Traceback (most recent call last)<br>
 in ()<br>
17 from PIL import Image<br>
18 import matplotlib.pyplot as plt<br>
---&gt; 19 from keras.utils.visualize_util import plot<br>
20 get_ipython().magic(u'matplotlib inline')<br>
21</p>
<p dir="auto">/Users/fonz/anaconda/lib/python2.7/site-packages/keras/utils/visualize_util.py in ()<br>
5     # fall back on pydot if necessary<br>
6     import pydot<br>
----&gt; 7 if not pydot.find_graphviz():<br>
8     raise RuntimeError('Failed to import pydot. You must install pydot'<br>
9                        ' and graphviz for <code class="notranslate">pydotprint</code> to work.')</p>
<p dir="auto">AttributeError: 'module' object has no attribute 'find_graphviz'</p>
<p dir="auto">Hello!<br>
I am using latest tensorflow with GPU support and latest Keras.<br>
I am trying to write parallel data augmentation using <code class="notranslate">keras.utils.Sequence</code>, but have two problems:</p>
<ol dir="auto">
<li><code class="notranslate">fit_generator</code> creates too many workers (I have parameter <code class="notranslate">workers=2</code>, but it generates 4 additional workers);</li>
<li>Using <code class="notranslate">Sequence</code> is extremely slow (with generator and a lot of augmentations I spend two minutes on epoch, with multiprocessing and <code class="notranslate">Sequence</code> - more than 10 minutes.</li>
</ol>
<p dir="auto">Here is my <code class="notranslate">Sequence</code> and <code class="notranslate">fit_generator</code>:</p>
<p dir="auto">`class ParallelDataGenerator(Sequence):<br>
"""Generate images for training/validation/testing (parallel version)."""</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="def __init__(self, dname: str, start: int, stop: int, batch_size: int, augmentate: bool):
    self.batch_size = batch_size
    self.augmentate = augmentate
    self.idxs = [i for i in range(start, stop)]
    self.imgs_in = [cv2.imread(os.path.join(dname, 'in', str(i) + '_in.png'),
                               cv2.IMREAD_GRAYSCALE).astype(np.float32) for i in range(start, stop)]
    self.imgs_gt = [cv2.imread(os.path.join(dname, 'gt', str(i) + '_in.png'),
                               cv2.IMREAD_GRAYSCALE).astype(np.float32) for i in range(start, stop)]
    self.idxs = [i for i in range(0, stop - start)]

def __len__(self):
    return int(np.ceil(float(len(self.idxs)) / float(self.batch_size)))

def on_epoch_end(self):
    shuffle(self.idxs)

def __getitem__(self, idx):
    print(idx, os.getpid())
    start = idx * self.batch_size
    stop = start + self.batch_size
    if stop &gt;= len(self.idxs):
        stop = len(self.idxs)

    imgs_in = []
    imgs_gt = []
    for i in range(start, stop):
        img_in = np.copy(self.imgs_in[self.idxs[i]])
        img_gt = np.copy(self.imgs_gt[self.idxs[i]])
        if self.augmentate:
            img_in, img_gt = random_effect_img(img_in, img_gt)
        imgs_in.append(normalize_in(img_in))
        imgs_gt.append(normalize_gt(img_gt))
    imgs_in = np.array(imgs_in)
    imgs_in.shape = (imgs_in.shape[0], imgs_in.shape[1], imgs_in.shape[2], 1)
    imgs_gt = np.array(imgs_gt)
    imgs_gt.shape = imgs_in.shape
    return imgs_in, imgs_gt`"><pre class="notranslate"><code class="notranslate">def __init__(self, dname: str, start: int, stop: int, batch_size: int, augmentate: bool):
    self.batch_size = batch_size
    self.augmentate = augmentate
    self.idxs = [i for i in range(start, stop)]
    self.imgs_in = [cv2.imread(os.path.join(dname, 'in', str(i) + '_in.png'),
                               cv2.IMREAD_GRAYSCALE).astype(np.float32) for i in range(start, stop)]
    self.imgs_gt = [cv2.imread(os.path.join(dname, 'gt', str(i) + '_in.png'),
                               cv2.IMREAD_GRAYSCALE).astype(np.float32) for i in range(start, stop)]
    self.idxs = [i for i in range(0, stop - start)]

def __len__(self):
    return int(np.ceil(float(len(self.idxs)) / float(self.batch_size)))

def on_epoch_end(self):
    shuffle(self.idxs)

def __getitem__(self, idx):
    print(idx, os.getpid())
    start = idx * self.batch_size
    stop = start + self.batch_size
    if stop &gt;= len(self.idxs):
        stop = len(self.idxs)

    imgs_in = []
    imgs_gt = []
    for i in range(start, stop):
        img_in = np.copy(self.imgs_in[self.idxs[i]])
        img_gt = np.copy(self.imgs_gt[self.idxs[i]])
        if self.augmentate:
            img_in, img_gt = random_effect_img(img_in, img_gt)
        imgs_in.append(normalize_in(img_in))
        imgs_gt.append(normalize_gt(img_gt))
    imgs_in = np.array(imgs_in)
    imgs_in.shape = (imgs_in.shape[0], imgs_in.shape[1], imgs_in.shape[2], 1)
    imgs_gt = np.array(imgs_gt)
    imgs_gt.shape = imgs_in.shape
    return imgs_in, imgs_gt`
</code></pre></div>
<p dir="auto"><code class="notranslate">    model.fit_generator( train_generator, steps_per_epoch=(train_stop - train_start) / args.batchsize, epochs=args.epochs, validation_data=validation_generator, validation_steps=(validation_stop - validation_start) / args.batchsize, callbacks=callbacks, use_multiprocessing=True, workers=2, max_queue_size=10 )</code></p>