'Run the attack on a batch of images and labels.'

def attack_batch(self, imgs, labs):

    def compare(x, y):
        if (not isinstance(x, (float, int, np.int64))):
            x = np.copy(x)
            if self.TARGETED:
                x[y] -= self.CONFIDENCE
            else:
                x[y] += self.CONFIDENCE
            x = np.argmax(x)
        if self.TARGETED:
            return (x == y)
        else:
            return (x != y)
    batch_size = self.batch_size
    oimgs = np.clip(imgs, self.clip_min, self.clip_max)
    imgs = ((imgs - self.clip_min) / (self.clip_max - self.clip_min))
    imgs = np.clip(imgs, 0, 1)
    imgs = ((imgs * 2) - 1)
    imgs = np.arctanh((imgs * 0.999999))
    lower_bound = np.zeros(batch_size)
    CONST = (np.ones(batch_size) * self.initial_const)
    upper_bound = (np.ones(batch_size) * 10000000000.0)
    o_bestl2 = ([10000000000.0] * batch_size)
    o_bestscore = ([(-1)] * batch_size)
    o_bestattack = np.copy(oimgs)
    for outer_step in range(self.BINARY_SEARCH_STEPS):
        self.sess.run(self.init)
        batch = imgs[:batch_size]
        batchlab = labs[:batch_size]
        bestl2 = ([10000000000.0] * batch_size)
        bestscore = ([(-1)] * batch_size)
        if (self.repeat and (outer_step == (self.BINARY_SEARCH_STEPS - 1))):
            CONST = upper_bound
        self.sess.run(self.setup, {self.assign_timg: batch, self.assign_tlab: batchlab, self.assign_const: CONST})
        prev = 1000000.0
        for iteration in range(self.MAX_ITERATIONS):
            (_, l, l2s, scores, nimg) = self.sess.run([self.train, self.loss, self.l2dist, self.output, self.newimg])
            if (self.ABORT_EARLY and ((iteration % (self.MAX_ITERATIONS // 10)) == 0)):
                if (l > (prev * 0.9999)):
                    break
                prev = l
            for (e, (l2, sc, ii)) in enumerate(zip(l2s, scores, nimg)):
                lab = np.argmax(batchlab[e])
                if ((l2 < bestl2[e]) and compare(sc, lab)):
                    bestl2[e] = l2
                    bestscore[e] = np.argmax(sc)
                if ((l2 < o_bestl2[e]) and compare(sc, lab)):
                    o_bestl2[e] = l2
                    o_bestscore[e] = np.argmax(sc)
                    o_bestattack[e] = ii
        for e in range(batch_size):
            if (compare(bestscore[e], np.argmax(batchlab[e])) and (bestscore[e] != (-1))):
                upper_bound[e] = min(upper_bound[e], CONST[e])
                if (upper_bound[e] < 1000000000.0):
                    CONST[e] = ((lower_bound[e] + upper_bound[e]) / 2)
            else:
                lower_bound[e] = max(lower_bound[e], CONST[e])
                if (upper_bound[e] < 1000000000.0):
                    CONST[e] = ((lower_bound[e] + upper_bound[e]) / 2)
                else:
                    CONST[e] *= 10
    o_bestl2 = np.array(o_bestl2)
    return o_bestattack
