Skip to main content

Empirical Init

This package provides a way of automatically initializing weights in pytorch neural networks using a hacky empirical method. Why do we need it? Well, there are other ways of normalizing weights. But batch norm is terrible, and layer norm is a non-linearity, which is kind of funky. Also, we not only need to keep activations from diverging, we need to keep the gradients from diverging too, and it would be really funky to apply a non-linearity to our gradients. The maximum update parametrization of Greg Yang and Edward Hu provides a recipe for how to scale all the gradients and activations so that the following three pillars are upheld:

  • Non-divergent activations: Activations in all layers should be approximately O(1)
  • Non-divergent gradients: Gradients in all layers should be approximately O(1)
  • Maximum stable update: The change in activations for learning rate equal to 1 should be approximately O(1). (But in practice we don't want updates quite this large so we'll use a smaller learning rate like 1e-3 or something.)

Their technique for achieving this is to represent the neural network as a tensor program and then do a whole lot of math to figure out how the activations and gradients and updates will flow through the network. But all that sounds like work. Know what's easier and no work at all? Just running your neural network! You already have it coded up, running it is a single function call. Then instead of computing all these things, we can just measure them.

Usage

Empirical init works by wrapping all modules in a helper module that scales the activations and gradients by tunable amounts. The wrapper class is called Normed, and you can certainly wrap your submodules manually. But the easiest way to wrap all submodules is to use the decorator @wrap_all_leaf_modules to modify __init__(). This will wrap every leaf module under your module that has any trainable parameters.

import torch.nn as nn
from empirical_init import wrap_all_leaf_modules

...

class MyModule(nn.Module):
  @wrap_all_leaf_modules
  def __init__(self, device="cpu"):
    super().__init__()
    ...

Normed has the tunable scalings registered as buffers, so they won't count as trainable but they'll still be in the state dict when you go to save your module. However, these scalings must actually be tuned to the correct values. This can be done with a call to empirical_init like so:

import torch
from empirical_init import get_wrapped_submodules, empirical_init

...

def dummy_input(batchsz):
  return torch.randn(batchsz, 100)
def dummy_loss(model_output):
  return model_output.mean()

my_module = MyModule()
empirical_init(
  get_wrapped_submodules(my_module), my_module,
  dummy_input, dummy_loss)

This will print out a bunch of helpful debug information about the tuning process. In particular, the magnitudes of activations and gradients going in and out of each wrapped submodule will be printed. After the call completes, all the scaling factors should be properly tuned.

Note that the number of calls made by empirical_init to your network scales with the number of layers in your network. So if your network takes a while to run or it has a lot of layers, empirical_init could take a while to terminate. Try it on a small fast network first if it's your first time using this package.

The dummy functions are there to provide realistic-looking data and gradients for your network to consume. The dummy input function should generate random input data of the provided batch size. The dummy loss function should produce a loss when passed the output of the network. A good rule of thumb is to have the dummy input function call torch.randn() to produce input of the right shape, and the dummy loss function should be the same as your actual loss function, but with randomized labels.

Metadata

Release files for empirical-init 0.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for empirical-init 0.0.2
File Size Uploaded Provenance
empirical_init-0.0.2.tar.gz 8.9 kB Without provenance Details

Release files / empirical_init-0.0.2.tar.gz

Download URL empirical_init-0.0.2.tar.gz
Size 8.9 kB
Tags Source
SHA-256 checksum
How to use checksums
580ca6c043c4a74e598ac0a2390fc2447d98c9bc9f65e97cf1d864f6bba832ee
BLAKE2b-256 checksum
How to use checksums
5c5bcfc7514bf79f5f1c5afac99f4662d49d77a5d2b4c214e72f912cb9a0a677
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.7.2

Security for empirical-init 0.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.2 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page