def dense_transformer_parameters(layers: int, hidden: int, ffn: int, vocab: int) -> int:
    if min(layers, hidden, ffn, vocab) <= 0:
        raise ValueError("all dimensions must be positive")
    embedding = vocab * hidden
    attention = layers * 4 * hidden * hidden
    feed_forward = layers * 2 * hidden * ffn
    norms = layers * 2 * hidden
    return embedding + attention + feed_forward + norms


def training_flops(parameters: int, tokens: int) -> int:
    if parameters <= 0 or tokens <= 0:
        raise ValueError("parameters and tokens must be positive")
    return 6 * parameters * tokens


def weight_memory_bytes(parameters: int, bits: int) -> int:
    if parameters <= 0 or bits not in {4, 8, 16, 32}:
        raise ValueError("bits must be one of 4, 8, 16 or 32")
    return (parameters * bits + 7) // 8
