'FrameProcessor' object is not callable

Issue

I tried implementing a Deep Reinforcement Learning Network but I get the same error every time I try to run it,

class Atari(object):
    """Wrapper for the environment provided by gym"""
    def __init__(self, envName, no_op_steps=10, agent_history_length=4):
        self.env = gym.make(envName)
        self.process_frame = FrameProcessor()
        self.state = None
        self.last_lives = 0
        self.no_op_steps = no_op_steps
        self.agent_history_length = agent_history_length

    def reset(self, sess, evaluation=False):
        """
        Args:
            sess: A Tensorflow session object
            evaluation: A boolean saying whether the agent is evaluating or training
        Resets the environment and stacks four frames ontop of each other to
        create the first state
        """
        frame = self.env.reset()
        self.last_lives = 0
        terminal_life_lost = True # Set to true so that the agent starts
                                  # with a 'FIRE' action when evaluating
        if evaluation:
            for _ in range(random.randint(1, self.no_op_steps)):
                frame, _, _, _ = self.env.step(1) # Action 'Fire'
        processed_frame = self.process_frame(sess, frame)   # (★★★)
        self.state = np.repeat(processed_frame, self.agent_history_length, axis=2)

        return terminal_life_lost

The line where I am getting the error is at `processed_frame = self.process_frame(sess, frame)

class FrameProcessor(object):
    """Resizes and converts RGB Atari frames to grayscale"""
    def __init__(self, frame_height=84, frame_width=84):
        self.frame_height = frame_height
        self.frame_width = frame_width
        self.frame = tf.compat.v1.placeholder(shape=[210, 160, 3], dtype=tf.uint8)
        self.processed = tf.image.rgb_to_grayscale(self.frame)
        self.processed = tf.image.crop_to_bounding_box(self.processed, 34, 0, 160, 160)
        self.processed = tf.image.resize(self.processed,
                                               [self.frame_height, self.frame_width],
                                               method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
        def __call__(self, session, frame):
            return session.run(self.processed, feed_dict={self.frame:frame})

Solution

(See my comment under OP for context)

The error message "FrameProcessor" object is not callable means what it says on the tin: there is an object of type "FrameProcessor", and your code is trying to call this object despite the fact that this object cannot be called.

(Remember that to call something is to treat it as a function and to try to run this function, much like how you might call a parent at a grocery store and tell them to buy you a snack.)

Where does your code try to call this FrameProcessor object? Well, you yourself pointed out the line:

processed_frame = self.process_frame(sess, frame).

In Python, any time you write an expression of the form something(arg1, arg2, ...), the Python interpreter treats the expression as a function call, which, from your error message, we know we’re not allowed to do if the something happens to be a FrameProcessor.

And we know from the earlier line self.process_frame = FrameProcessor() that self.process_frame is a FrameProcessor. So the problem is that you’re trying to call self.process_frame like a function when it really oughtn’t be called in that way.

So, how can this be fixed?

Look up the documentation for FrameProcessor, wherever that happens to be, so that you can know how FrameProcessors ought to be used. With that knowledge, you can revise the lines processed_frame = self.process_frame(sess, frame) and maybe self.process_frame = FrameProcessor() to match the intended usage, whatever that may be. At that point it’s just a matter of reading and applying the relevant documentation.

EDIT:

Looking at the code for FrameProcessor, it seems the issue is caused by an extra indent before __call__ is defined. Indents determine scope in Python, and the extra indent is causing __call__ to be defined in the local scope of the __init__ function. That means that __call__ has no meaning outside the body of __init__, which is not what we want. Try removing the extra indent before __call__ and see if that solves the issue.

Answered By – Asker

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published