Ejemplo n.º 1
0
class BufferedModel(Model):
    """
    A Model that reads inputs from a differentiable input buffer
    and writes outputs to a differentiable output buffer. At each step
    of computation, the model must read something from the input
    buffer, interact with the neural data structure, and write something
    to the output buffer.
    """

    def __init__(self, input_size, read_size, output_size,
                 controller_type=LinearSimpleStructController, struct_type=Stack,
                 reg_weight=1., **kwargs):
        """
        Constructor for the VanillaModel object.

        :type input_size: int
        :param input_size: The size of the vectors that will be input to
            this Model

        :type read_size: int
        :param read_size: The size of the vectors that will be placed on
            the neural data structure

        :type output_size: int
        :param output_size: The size of the vectors that will be output
            from this Model

        :type struct_type: type
        :param struct_type: The type of neural data structure that this
            Model will operate

        :type controller_type: type
        :param controller_type: The type of the Controller that will perform
            the neural network computations
        """
        super(BufferedModel, self).__init__(read_size, struct_type)
        self._input_size = input_size
        self._output_size = output_size
        self._read_size = read_size

        self._read = None
        self._e_in = None

        self._controller = controller_type(input_size, read_size, output_size,
                                     n_args=4, discourage_pop=True, **kwargs)
        self._buffer_in = None
        self._buffer_out = None

        if reg_weight == 0:
            self._reg_tracker = None
        else:
            self._reg_tracker = InterfaceRegTracker(reg_weight)

    def _init_buffer(self, batch_size, xs):
        """
        Initializes the input and output buffers. The input buffer will
        contain a specified collection of values. The output buffer will
        be empty.

        :type batch_size: int
        :param batch_size: The number of trials in each mini-batch where
            this Model is used

        :type xs: Variable
        :param xs: An array of values that will be placed on the input
            buffer. The dimensions should be [batch size, t, read size],
            where t is the maximum length of a string represented in xs

        :return: None
        """
        self._e_in = Variable(torch.zeros(batch_size))

        self._buffer_in = InputBuffer(batch_size, self._input_size)
        self._buffer_out = OutputBuffer(batch_size, self._input_size)

        self._buffer_in.init_contents(xs.permute(1, 0, 2))
        self._buffer_in.set_reg_tracker(self._reg_tracker, Operation.pop)
        self._buffer_out.set_reg_tracker(self._reg_tracker, Operation.push)

    """ Neural Network Computation """

    def forward(self):
        """
        Computes the output of the neural network given an input. The
        controller should push a value onto the neural data structure and
        pop one or more values from the neural data structure, and
        produce an output based on this information and recurrent state
        if available.

        :return: The output of the neural network
        """
        x = self._buffer_in(self._e_in)

        output, (v, u, d, e_in, e_out) = self._controller(x, self._read)
        self._e_in = e_in
        self._read = self._struct(v, u, d)

        self._buffer_out(output, e_out)

    """ Public Accessors """

    def read_output(self):
        """
        Returns the next symbol from the output buffer.

        :rtype: Variable
        :return: The value read from the output buffer after popping
            with strength 1
        """
        self._buffer_out.pop(1.)
        return self._buffer_out.read(1.)

    """ Reporting """

    def trace(self, trace_x, num_steps):
        """
        Draws a graphic representation of the neural data structure
        instructions produced by the Model's Controller at each time
        step for a single input.

        :type trace_x: Variable
        :param trace_x: An input string

        :type num_steps: int
        :param num_steps: The number of computation steps to perform on
            the input

        :return: None
        """
        self.eval()
        self.init_model(1, trace_x)

        self._controller.start_log(num_steps)
        for j in range(num_steps):
            self.forward()
        self._controller.stop_log()

        x_labels = ["x_" + str(i) for i in range(self._input_size)]
        y_labels = ["y_" + str(i) for i in range(self._output_size)]
        i_labels = ["Pop", "Push", "Input", "Output"]
        v_labels = ["v_" + str(i) for i in range(self._read_size)]
        labels = x_labels + y_labels + i_labels + v_labels

        import matplotlib.pyplot as plt
        plt.imshow(self._controller.log_data, cmap="hot", interpolation="nearest")
        plt.title("Trace")
        plt.yticks(list(range(len(labels))), labels)
        plt.xlabel("Time")
        plt.ylabel("Value")
        plt.show()

    def trace_step(self, trace_x, num_steps, step=True):
        """
        Steps through the neural network's computation. The controller will
        read an input and produce an output. At each time step, a
        summary of the controller's state and actions will be printed to
        the console.

        :type trace_x: Variable
        :param trace_x: A single input string

        :type num_steps: int
        :param num_steps: The number of computation steps to perform

        :type step: bool
        :param step: If True, the user will need to press Enter in the
            console after each computation step

        :return: None
        """
        if trace_x.data.shape[0] != 1:
            raise ValueError("You can only trace one input at a time!")

        self.eval()
        self.init_model(1, trace_x)

        x_end = self._input_size
        y_end = x_end + self._output_size
        push = y_end + 1
        e_in = push + 1
        e_out = e_in + 1
        v_start = e_out + 1

        self._controller.start_log(num_steps)
        for j in range(num_steps):
            print("\n-- Step {} of {} --".format(j, num_steps))

            self.forward()

            i = self._controller.log_data[:x_end, j]
            o = self._controller.log_data[x_end:y_end, j].round(decimals=4)
            u = self._controller.log_data[y_end, j].round(decimals=4)
            d = self._controller.log_data[push, j].round(decimals=4)
            e_in = self._controller.log_data[e_in, j].round(decimals=4)
            e_out = self._controller.log_data[e_out, j].round(decimals=4)
            v = self._controller.log_data[v_start:, j].round(decimals=4)
            r = self._struct.read(1).data.numpy()[0].round(decimals=4)

            print("\nInput: " + str(i))
            print("Input Strength: " + str(e_in))
            print("Output: " + str(o))
            print("Output Strength: " + str(e_out))

            print("\nPop Strength: " + str(u))

            print("\nPush Vector: " + str(v))
            print("Push Strength: " + str(d))

            print("\nRead Vector: " + str(r))
            print("Struct Contents: ")
            self._struct.print_summary(0)

            if step:
                input("\nPress Enter to continue\n")
        self._controller.stop_log()

    def get_and_reset_reg_loss(self):
        """If there is a regularization tracker, return the loss term from it."""

        if self._reg_tracker is None:
            return super(BufferedModel, self).get_and_reset_reg_loss()

        loss = self._reg_tracker.loss
        self._reg_tracker.reset()
        return loss

    def print_experiment_start(self):
        """Overriden to print buffered-specific params."""
        super(BufferedModel, self).print_experiment_start()
        print("Reg Weight: " + str(self._reg_tracker.reg_weight))
Ejemplo n.º 2
0
class BufferedController(AbstractController):
    """
    A Controller that reads inputs from a differentiable input buffer
    and writes outputs to a differentiable output buffer. At each step
    of computation, the controller must read something from the input
    buffer, interact with the neural data structure, and write something
    to the output buffer.
    """
    def __init__(self,
                 input_size,
                 read_size,
                 output_size,
                 network_type=LinearSimpleStructNetwork,
                 struct_type=Stack):
        """
        Constructor for the VanillaController object.

        :type input_size: int
        :param input_size: The size of the vectors that will be input to
            this Controller

        :type read_size: int
        :param read_size: The size of the vectors that will be placed on
            the neural data structure

        :type output_size: int
        :param output_size: The size of the vectors that will be output
            from this Controller

        :type struct_type: type
        :param struct_type: The type of neural data structure that this
            Controller will operate

        :type network_type: type
        :param network_type: The type of the Network that will perform
            the neural network computations
        """
        super(BufferedController, self).__init__(read_size, struct_type)
        self._input_size = input_size
        self._output_size = output_size
        self._read_size = read_size

        self._read = None
        self._e_in = None

        self._network = network_type(input_size,
                                     read_size,
                                     output_size,
                                     n_args=4,
                                     discourage_pop=True)
        self._buffer_in = None
        self._buffer_out = None

        # TODO:
        #   * To disable regularization, can set this to None.
        #   * The weight of the regularization should a Model and Task
        # parameter.
        self._reg_tracker = InterfaceRegTracker(1.)

        return

    def _init_buffer(self, batch_size, xs):
        """
        Initializes the input and output buffers. The input buffer will
        contain a specified collection of values. The output buffer will
        be empty.

        :type batch_size: int
        :param batch_size: The number of trials in each mini-batch where
            this Controller is used

        :type xs: Variable
        :param xs: An array of values that will be placed on the input
            buffer. The dimensions should be [batch size, t, read size],
            where t is the maximum length of a string represented in xs

        :return: None
        """
        self._e_in = Variable(torch.zeros(batch_size))

        self._buffer_in = InputBuffer(batch_size, self._input_size)
        self._buffer_out = OutputBuffer(batch_size, self._input_size)

        self._buffer_in.init_contents(xs.permute(1, 0, 2))
        self._buffer_in.set_reg_tracker(self._reg_tracker, Operation.pop)
        self._buffer_out.set_reg_tracker(self._reg_tracker, Operation.push)

    """ Neural Network Computation """

    def forward(self):
        """
        Computes the output of the neural network given an input. The
        network should push a value onto the neural data structure and
        pop one or more values from the neural data structure, and
        produce an output based on this information and recurrent state
        if available.

        :return: The output of the neural network
        """
        x = self._buffer_in(self._e_in)

        output, (v, u, d, e_in, e_out) = self._network(x, self._read)
        self._e_in = e_in
        self._read = self._struct(v, u, d)

        self._buffer_out(output, e_out)

    """ Public Accessors """

    def read_output(self):
        """
        Returns the next symbol from the output buffer.

        :rtype: Variable
        :return: The value read from the output buffer after popping
            with strength 1
        """
        self._buffer_out.pop(1.)
        return self._buffer_out.read(1.)

    """ Analytical Tools """

    def trace(self, trace_x, num_steps):
        """
        Draws a graphic representation of the neural data structure
        instructions produced by the Controller's Network at each time
        step for a single input.

        :type trace_x: Variable
        :param trace_x: An input string

        :type num_steps: int
        :param num_steps: The number of computation steps to perform on
            the input

        :return: None
        """
        self.eval()
        self.init_controller(1, trace_x)

        self._network.start_log(num_steps)
        for j in xrange(num_steps):
            self.forward()
        self._network.stop_log()

        x_labels = ["x_" + str(i) for i in xrange(self._input_size)]
        y_labels = ["y_" + str(i) for i in xrange(self._output_size)]
        i_labels = ["Pop", "Push", "Input", "Output"]
        v_labels = ["v_" + str(i) for i in xrange(self._read_size)]
        labels = x_labels + y_labels + i_labels + v_labels

        plt.imshow(self._network.log_data,
                   cmap="Greys",
                   interpolation="nearest")
        plt.title("Trace")
        plt.yticks(range(len(labels)), labels)
        plt.xlabel("Time")
        plt.ylabel("Value")
        plt.show()

    def get_and_reset_reg_loss(self):
        if self._reg_tracker is None:
            return 0.
        return self._reg_tracker.get_and_reset()
Ejemplo n.º 3
0
class BufferedModel(Model):
    """
    A Model that reads inputs from a differentiable input buffer
    and writes outputs to a differentiable output buffer. At each step
    of computation, the model must read something from the input
    buffer, interact with the neural data structure, and write something
    to the output buffer.
    """

    def __init__(self, input_size, read_size, output_size,
                 controller_type=LinearSimpleStructController, struct_type=Stack,
                 reg_weight=1., **kwargs):
        """
        Constructor for the VanillaModel object.

        :type input_size: int
        :param input_size: The size of the vectors that will be input to
            this Model

        :type read_size: int
        :param read_size: The size of the vectors that will be placed on
            the neural data structure

        :type output_size: int
        :param output_size: The size of the vectors that will be output
            from this Model

        :type struct_type: type
        :param struct_type: The type of neural data structure that this
            Model will operate

        :type controller_type: type
        :param controller_type: The type of the Controller that will perform
            the neural network computations
        """
        super(BufferedModel, self).__init__(read_size, struct_type)
        self._input_size = input_size
        self._output_size = output_size
        self._read_size = read_size

        self._read = None
        self._e_in = None

        self._controller = controller_type(input_size, read_size, output_size,
                                     n_args=4, discourage_pop=True, **kwargs)
        self._buffer_in = None
        self._buffer_out = None

        if reg_weight == 0:
            self._reg_tracker = None
        else:
            self._reg_tracker = InterfaceRegTracker(reg_weight)

    def _init_buffer(self, batch_size, xs):
        """
        Initializes the input and output buffers. The input buffer will
        contain a specified collection of values. The output buffer will
        be empty.

        :type batch_size: int
        :param batch_size: The number of trials in each mini-batch where
            this Model is used

        :type xs: Variable
        :param xs: An array of values that will be placed on the input
            buffer. The dimensions should be [batch size, t, read size],
            where t is the maximum length of a string represented in xs

        :return: None
        """
        self._e_in = Variable(torch.zeros(batch_size))

        self._buffer_in = InputBuffer(batch_size, self._input_size)
        self._buffer_out = OutputBuffer(batch_size, self._input_size)

        self._buffer_in.init_contents(xs.permute(1, 0, 2))
        self._buffer_in.set_reg_tracker(self._reg_tracker, Operation.pop)
        self._buffer_out.set_reg_tracker(self._reg_tracker, Operation.push)

    """ Neural Network Computation """

    def forward(self):
        """
        Computes the output of the neural network given an input. The
        controller should push a value onto the neural data structure and
        pop one or more values from the neural data structure, and
        produce an output based on this information and recurrent state
        if available.

        :return: The output of the neural network
        """
        x = self._buffer_in(self._e_in)

        output, (v, u, d, e_in, e_out) = self._controller(x, self._read)
        self._e_in = e_in
        self._read = self._struct(v, u, d)

        self._buffer_out(output, e_out)

    """ Public Accessors """

    def read_output(self):
        """
        Returns the next symbol from the output buffer.

        :rtype: Variable
        :return: The value read from the output buffer after popping
            with strength 1
        """
        self._buffer_out.pop(1.)
        return self._buffer_out.read(1.)

    """ Reporting """

    def trace(self, trace_x, num_steps):
        """
        Draws a graphic representation of the neural data structure
        instructions produced by the Model's Controller at each time
        step for a single input.

        :type trace_x: Variable
        :param trace_x: An input string

        :type num_steps: int
        :param num_steps: The number of computation steps to perform on
            the input

        :return: None
        """
        self.eval()
        self.init_model(1, trace_x)

        self._controller.start_log(num_steps)
        for j in xrange(num_steps):
            self.forward()
        self._controller.stop_log()

        x_labels = ["x_" + str(i) for i in xrange(self._input_size)]
        y_labels = ["y_" + str(i) for i in xrange(self._output_size)]
        i_labels = ["Pop", "Push", "Input", "Output"]
        v_labels = ["v_" + str(i) for i in xrange(self._read_size)]
        labels = x_labels + y_labels + i_labels + v_labels

        plt.imshow(self._controller.log_data, cmap="hot", interpolation="nearest")
        plt.title("Trace")
        plt.yticks(range(len(labels)), labels)
        plt.xlabel("Time")
        plt.ylabel("Value")
        plt.show()

    def trace_step(self, trace_x, num_steps, step=True):
        """
        Steps through the neural network's computation. The controller will
        read an input and produce an output. At each time step, a
        summary of the controller's state and actions will be printed to
        the console.

        :type trace_x: Variable
        :param trace_x: A single input string

        :type num_steps: int
        :param num_steps: The number of computation steps to perform

        :type step: bool
        :param step: If True, the user will need to press Enter in the
            console after each computation step

        :return: None
        """
        if trace_x.data.shape[0] != 1:
            raise ValueError("You can only trace one input at a time!")

        self.eval()
        self.init_model(1, trace_x)

        x_end = self._input_size
        y_end = x_end + self._output_size
        push = y_end + 1
        e_in = push + 1
        e_out = e_in + 1
        v_start = e_out + 1

        self._controller.start_log(num_steps)
        for j in xrange(num_steps):
            print "\n-- Step {} of {} --".format(j, num_steps)

            self.forward()

            i = self._controller.log_data[:x_end, j]
            o = self._controller.log_data[x_end:y_end, j].round(decimals=4)
            u = self._controller.log_data[y_end, j].round(decimals=4)
            d = self._controller.log_data[push, j].round(decimals=4)
            e_in = self._controller.log_data[e_in, j].round(decimals=4)
            e_out = self._controller.log_data[e_out, j].round(decimals=4)
            v = self._controller.log_data[v_start:, j].round(decimals=4)
            r = self._struct.read(1).data.numpy()[0].round(decimals=4)

            print "\nInput: " + str(i)
            print "Input Strength: " + str(e_in)
            print "Output: " + str(o)
            print "Output Strength: " + str(e_out)

            print "\nPop Strength: " + str(u)

            print "\nPush Vector: " + str(v)
            print "Push Strength: " + str(d)

            print "\nRead Vector: " + str(r)
            print "Struct Contents: "
            self._struct.print_summary(0)

            if step:
                raw_input("\nPress Enter to continue\n")
        self._controller.stop_log()

    def get_and_reset_reg_loss(self):
        """If there is a regularization tracker, return the loss term from it."""

        if self._reg_tracker is None:
            return super(BufferedModel, self).get_and_reset_reg_loss()

        loss = self._reg_tracker.loss
        self._reg_tracker.reset()
        return loss

    def print_experiment_start(self):
        """Overriden to print buffered-specific params."""
        super(BufferedModel, self).print_experiment_start()
        print "Reg Weight: " + str(self._reg_tracker.reg_weight)