(C) PLOS One This story was originally published by PLOS One and is unaltered. . . . . . . . . . . pyhgf: A neural network library for predictive coding [1] ['Nicolas Legrand', 'Interacting Minds Centre', 'Aarhus University', 'Aarhus', 'Lilian Weber', 'Department Of Psychiatry', 'University Of Oxford', 'Oxford', 'United Kingdom', 'Peter Thestrup Waade'] Date: 2026-09 pyhgf is a Python library for the creation, manipulation, and inference over dynamic neural networks for predictive coding with a focus on the generalised hierarchical Gaussian filter [27–29]. Models and theories that imply such networks are becoming ubiquitous in computational neuroscience, and researchers interested in fitting behavioural data to these models require the flexibility of a regular neural network library together with the modularity of a probabilistic framework to perform inference on parameters of interest. In the pyhgf package, we provide the user with an API that provides methods for smoothly interacting with the following two levels of modelling: By using these interfaces, the user is able to customize the computational structure of artificial agents to fit a broad range of applications, both in experimental cognitive neuroscience and artificial intelligence. Here, we start by reviewing the core principles on which dynamic neural networks are built in pyhgf, and how this differs from other network libraries. 2.1 Computational framework The design and software implementation of dynamic neural networks for predictive coding have been shaped by a set of requirements. These networks are made of nodes that can store any number of variables. Some variables might be found in other nodes as well, and some might be unique. Nodes are connected with each other through directed edges, and there can exist multiple types of connections in the same graph, denoting different interactions between the nodes. Computation steps in the graph typically occur locally between adjacent nodes for prediction and prediction errors. Multiple types of computation can be defined. The computation steps can be triggered either reactively, by observing events in the surroundings of a node and reacting to them, or they can be scheduled by pre-allocating a sequence of steps that will propagate the information through the graph. Finally, all these components should be transparent to the network itself when performing a given computation, allowing it to meet the demands of self-monitoring and self-organisation principles. To observe the set of constraints above, computations should follow a strict functional programming framework, meaning that they should be in-place programmatically pure functions operating on the components of the network. Functional programming is natively supported in Rust and also enforced by JAX [35] to leverage just-in-time (JIT) compilation and automatic differentiation, therefore departing from object-oriented programming (the definition of classes populated with attributes and methods) that is a central feature of Python. This comes with limitations in the way toolboxes’ APIs can be developed (see, for example, how this can be handled in [41]). To fully meet the dynamic aspects mentioned previously, the update functions should ideally receive and return all of the following components defining a network: A list of attributes - the attributes are dictionaries of parameters of a given node A set of lists of edges - the edges are the directed connections between the nodes. All the possible edge types are grouped into a set. A set of update functions. Each function defines a computation and can be parametrised by the index of the triggering node. Possible computations are, for example, prediction, posterior update, or prediction error between two nodes. Unless using a reactive computation scheme, the function should also have access to an ordered sequence of update functions that apply to individual nodes. By defining these four components, and by creating functions that can receive and return all of them, the user can generate arbitrarily sized and structured dynamic neural networks for predictive coding (see Fig 1). The first two items define what is usually called a graph, with the addition that it can be directed and multilayered. The last two items shape what is central to predictive coding: the schedule or reactive nature of the propagation of information through the network. Because all of these components are transparent during message-passing computations, learning algorithms can be developed to act on them as a way of inference. Acting on the attributes corresponds to standard inference or other learning algorithms like reinforcement learning. Acting on the size of the networks is comparable to structure learning. Acting on the edges can relate to causal inference, and acting on the update functions or their sequence can implement principles from meta-learning (see 5 for more details on possible applications). The hard constraint on transparency of the network component during message passing makes this framework difficult to implement in other graph/neural network libraries (e.g., see [17,18]). Most of these constraints can be met by using a pure JAX implementation [35] while remaining compatible with transformations like JIT and automatic differentiation. However, some advanced use cases of dynamic reshaping and edge manipulation might result in degraded performance or incompatibility with certain transformations. When using Rust [36] as the backend, all constraints can be met with no cost in terms of performance. PNG larger image TIFF original image Download: Fig 1. The four components of a dynamic network for predictive coding. pyhgf represents any dynamic network using the combination of four variables: attributes, edges, update functions, and update sequences. This modularity allows dissociating update steps and connectivity structures and makes these variables part of the inference process. The creation of a network is read from left to right: 1. Attributes. Nodes in the network contain parameters (e.g., sufficient statistics about probability distributions and coupling weights). 2. Edges. Nodes can have multiple connection types with each other (e.g., value and volatility coupling). The network’s structure is represented in an m-dimensional adjacency list that encodes the directed connections with other nodes. Here, dotted and filled lines represent different types of connectivity. 3. Updates. Update functions are deterministic transformations operating locally that can access and modify the four sets of variables at run time. 4. Update sequences. The update sequence shapes belief propagation. It defines the order in which nodes should be updated when a new observation is presented to the input node(s). By default, prediction propagates from the leaves to the roots of the network, while the interleaved sequence of prediction errors and posterior updates follow the inverted path. Updates can also be triggered reactively in which case the propagation starts with the activation of a proximal node. https://doi.org/10.1371/journal.pcbi.1014340.g001 A dynamic network, as implemented in pyhgf is thus defined as the combination of four variables (see Fig 1). Let, for example, be a neural network with k nodes. This network handles in a tuple four parameters of interest: (1) The variable represents the nodes’ attributes. Attributes can be used to register local information, like the sufficient statistics of a probability distribution as well as the coupling weights with other nodes. This variable can also be arbitrarily extended to include other fixed parameters or results from other update steps. In a convolutional neural network, would, for example, encode the activation strength. Most standard learning models optimize attributes that belong to this parameter space. The second key parameter, tightly linked to the first one, is the adjacency list that controls the shape of the network. Each item in this set registers the directed connection between node k and other nodes. Networks that exhibit different connectivity structures propagate information differently. The set of directed connections can be multivariate (a node can have different types of connections with other nodes), such as in multilayer networks [42]. For example, the nodalised hierarchical Gaussian filter [29] assumes two kinds of coupling between nodes: value and volatility coupling. Every edge , therefore, contains m = 2 sets of node indices in this case, m being the adjacency dimension. By comparison, in a standard recurrent neural network, this variable would define the shape of the layers and their connectivity. Critically, in the proposed framework, this variable is transparent to the update function and can be subject to inference and updates. The third central component is the set of n in-place update functions defining a message passing step operating on the network’s parameter set such as: (2) In a convolutional neural network, this set of functions would include the linear product of input and weights, as well as the activation functions. In the generalized HGF [29], this includes three kinds of steps: a prediction (based on previous values and any parent nodes), an update step (based on input from child nodes and the prediction), and the computation of a prediction error. The specific computations in each case depend on the type of coupling between parent and child nodes. Note that the function is parametrized by a target node k to which it applies. This allows for defined local computation where only information from a subset of adjacent nodes is used, such as in particular mean field approximations. Finally, a fourth component is introduced to control the scheduling of these update steps over time as . This ordered list describes a sequence of functions parametrized on individual nodes. The update order shapes belief propagation. This component is rarely expressed in the form of a parameter in most conventional applications of neural networks, as well as in the previous implementation of the HGF. This sequence is instead scripted outside the network’s closure and, therefore, not accessible during inference or optimisation. In the case of predictive coding neural networks, however, finer control over belief propagation might be requested by the user, of a kind that also offers flexibility in the modification of belief propagation dynamically. When using the HGF as implemented in pyhgf, this scheduling can be generated at runtime from the network structure , assuming an ideal belief propagation pattern with a cascade of prediction from the leaves to the roots of the network, and another cascade of prediction error / posterior update pair from the roots to the leaves. The proposed framework is intended to provide the minimal layout required to create dynamic neural networks for predictive coding. It allows users to create and manipulate the scheduling of updates through a network of nodes while keeping the four components of the network available for inference. Contrary to other neural networks that rely on matrix multiplication for learning, our networks implement local computations that are run sequentially to propagate beliefs along connectivity paths. This also offers a clear dissociation between components that can be developed separately. It is, for example, possible to create alternative message-passing algorithms without having to develop an entire library to simulate the networks, and it is possible to implement existing predictive coding frameworks so users can easily apply them to behavioural data. pyhgf natively support the generalized hierarchical Gaussian filter [29], a recent development of the HGF [27,28] into a nodalised version for predictive coding. In this framework, for example, every node in the network represents a probability distribution of a belief about a latent space in the environment. Beliefs are updated through precision-weighted prediction errors coming from nodes in a lower level of the hierarchy and propagated to higher-level nodes. The exact update functions have been derived in their closed form and can work with arbitrary network architectures [29], which makes this model an excellent application of dynamic neural networks as described here. The relatively widespread use of the HGF in computational psychiatry, and the need for advanced Bayesian modelling tools around it, are also good opportunities to extend the original Matlab toolbox [34] by enhancing the modularity and extensibility of the library. [END] --- [1] Url: https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1014340 Published and (C) by PLOS One Content appears here under this condition or license: Creative Commons - Attribution BY 4.0. via Magical.Fish Gopher News Feeds: gopher://magical.fish/1/feeds/news/plosone/