As Wikipedia puts it, a quine is a computer program that takes no input and produces a copy of its own source code as its only output. A neural quine is the analogous concept for neural networks : a network that outputs its own weights. Something like this :
Initially, I modeled the whole thing as a regression problem with multiple outputs. The idea was simple: treat the WHOLE neural network as a function
The loss could then be written as:
and in principle, I could train the network using gradient descent or even Newton’s method if I computed the full Jacobian:
If we introduce a scaling factor
The Jacobian now includes the scaling :
And the Newton-style update is updated accordingly:
This allows you to control the "strength" of the quine with
Apparently, this topic was explored wayyy back in Neural Network Quine, 2018 (I really should have read this first 😭). This paper proposes a clever alternative : make the network weights queryable
What The Paper Suggestss (Indexed Version)
Model does something like this :
That would mean :
- We feed an index
$(i, j)$ - The model returns a single parameter
$W_{ij}$ - We must loop over all indices to reconstruct
$\theta$
This formulation describes an indexed neural quine. In that case, the full parameter vector would be reconstructed as :
which requires
What I Actually Built (Non-Indexed Version)
Instead, my model is defined as:
Where :
-
$d = 8$ (input dimension) -
$P$ = total number of parameters -
$\theta \in \mathbb{R}^P$ is the flattened parameter vector
We choose a fixed probe vector :
And train the network so that :
This means a single forward pass generates the entire parameter vector.
The Fixed-Point Equation
Training solves the nonlinear fixed-point condition:
This means the parameters define a function that, when evaluated at a specific input
Input Dimension vs Parameter Dimension
The input does not need to be size
The model learns this mapping :
Where:
-
$d$ = input dimension -
$P$ = total number of parameters
So a small latent vector input_probes as well
Even with queryable inputs, the zero-quine problem remains. To bypass it, I followed Evan Fletcher’s blog (should've read this before too 😭 ... it's pretty good):
We can forcibly avoid the zero quine by adding a parameter-free normalization layer after the trained dense layer. Both instance normalization and batch normalization (with all learned & running parameters disabled – no extra weights!) produce imperfect, but non-trivial, quines with relatively low error.
The reason why this works is because even though the weights CAN be zero, the gradients never are. See APPENDIX for a proof attempt
# Clone the repo and go to root folder of repo
mkdir neural-quines
cd neural-quines
git clone https://github.com/Vishvam10/neural-quines
export PYTHONPATH=$(pwd)
# Jacobian
cd nnquine/jacobian
python train.py
python evaluate.py
# Non-Jacobian
cd nnquine/non_jacobian
python train.py
python evaluate.pyIf you wish to contribute, kindly lint and format the code before raising a PR :
# Kindly lint and format the code if you plan to contribute
ruff check --config pyproject.toml
ruff check --select I --fix . --config pyproject.toml
ruff format --config pyproject.toml-
The zero-quine problem
- If all weights are zero, the network trivially satisfies
$F(0) = 0$ . - Newton’s method or gradient descent will often converge to this trivial solution if the initialization isn’t perfect.
- If all weights are zero, the network trivially satisfies
-
Jacobian scales poorly
- For a network with
$P$ parameters, the Jacobian$J$ is$P \times P$ . - Constructing, storing, and solving linear systems with
$J - I$ becomes expensive and numerically unstable for even modest networks.
- For a network with
-
Nonlinear interactions and ill-conditioning
- Neural quines are highly coupled : changing one weight affects multiple outputs. So, Newton’s method oscillates or overcorrects
Newton’s method for solving the fixed-point equation
is locally stable only if
Instability occurs when any eigenvalue of
Let
Define
The normalized output is
We compute the Jacobian
Using the identity
Differentiate with respect to
Since
we get
Compute the first derivative:
So the first term becomes
Now substitute the derivative of
If
then
The second term vanishes, giving
where
Now this is not 0. So, when the weights are updated, we get non-zero weights

