Repository: popsim-consortium/demes-python (language: python)

Issue:
allow Graph.description field to be missing/None.
See https://github.com/popsim-consortium/demes-spec/issues/42


Discussion / hints:

Fix patch:
diff --git a/demes/convert/moments_.py b/demes/convert/moments_.py
index 17a5b207..e48e5012 100644
--- a/demes/convert/moments_.py
+++ b/demes/convert/moments_.py
@@ -155,7 +155,7 @@ def augment_with_ancient_samples(g, sampled_demes, sample_times):
             sampled_demes[ii] = sd_frozen
             g.deme(
                 id=sd_frozen,
-                epochs=[Epoch(start_time=st, end_time=0, initial_size=1)],
+                epochs=[Epoch(start_time=st, end_time=0, start_size=1)],
                 ancestors=[sd],
             )
     return g, sampled_demes, frozen_demes
@@ -259,7 +259,7 @@ def get_integration_parameters(g, demes_present, frozen_list, Ne=None):
             if len(preds) == 0:
                 root_deme = deme_id
                 break
-        Ne = g[root_deme].epochs[0].initial_size
+        Ne = g[root_deme].epochs[0].start_size
 
     for interval, live_demes in sorted(demes_present.items())[::-1]:
         # get intergration time for interval
@@ -338,37 +338,33 @@ def sizes_at_time(g, deme_id, time_interval):
     size_function = epoch.size_function
 
     if size_function == "constant":
-        start_size = end_size = epoch.initial_size
+        start_size = end_size = epoch.start_size
 
     if epoch.start_time == time_interval[0]:
-        start_size = epoch.initial_size
+        start_size = epoch.start_size
     else:
         if size_function == "exponential":
-            start_size = epoch.initial_size * np.exp(
-                np.log(epoch.final_size / epoch.initial_size)
+            start_size = epoch.start_size * np.exp(
+                np.log(epoch.end_size / epoch.start_size)
                 * (epoch.start_time - time_interval[0])
                 / epoch.time_span
             )
         elif size_function == "linear":
             frac = (epoch.start_time - time_interval[0]) / epoch.time_span
-            start_size = epoch.initial_size + frac * (
-                epoch.final_size - epoch.initial_size
-            )
+            start_size = epoch.start_size + frac * (epoch.end_size - epoch.start_size)
 
     if epoch.end_time == time_interval[1]:
-        end_size = epoch.final_size
+        end_size = epoch.end_size
     else:
         if size_function == "exponential":
-            end_size = epoch.initial_size * np.exp(
-                np.log(epoch.final_size / epoch.initial_size)
+            end_size = epoch.start_size * np.exp(
+                np.log(epoch.end_size / epoch.start_size)
                 * (epoch.start_time - time_interval[1])
                 / epoch.time_span
             )
         elif size_function == "linear":
             frac = (epoch.start_time - time_interval[1]) / epoch.time_span
-            end_size = epoch.initial_size + frac * (
-                epoch.final_size - epoch.initial_size
-            )
+            end_size = epoch.start_size + frac * (epoch.end_size - epoch.start_size)
 
     return start_size, end_size, size_function
 
diff --git a/demes/convert/msprime_.py b/demes/convert/msprime_.py
index 7e730d06..f755dafb 100644
--- a/demes/convert/msprime_.py
+++ b/demes/convert/msprime_.py
@@ -33,8 +33,8 @@ def to_msprime(graph: demes.Graph):
     pop_id = {deme.id: j for j, deme in enumerate(graph.demes)}
 
     def growth_rate(epoch: demes.Epoch) -> float:
-        initial_size = typing.cast(float, epoch.final_size)
-        final_size = typing.cast(float, epoch.initial_size)
+        initial_size = typing.cast(float, epoch.end_size)
+        final_size = typing.cast(float, epoch.start_size)
         if initial_size == final_size:
             growth_rate = 0.0
         else:
@@ -61,7 +61,7 @@ def growth_rate(epoch: demes.Epoch) -> float:
             initial_size = Ne_invalid
             _growth_rate = 0.0
         else:
-            initial_size = typing.cast(float, deme.epochs[-1].final_size)
+            initial_size = typing.cast(float, deme.epochs[-1].end_size)
             _growth_rate = growth_rate(deme.epochs[-1])
         population_configurations.append(
             msprime.PopulationConfiguration(
@@ -89,7 +89,7 @@ def growth_rate(epoch: demes.Epoch) -> float:
                 demographic_events.append(
                     msprime.PopulationParametersChange(
                         time=epoch.end_time,
-                        initial_size=epoch.final_size,
+                        initial_size=epoch.end_size,
                         growth_rate=growth_rate(epoch),
                         population_id=pop_id[deme.id],
                     )
@@ -240,7 +240,7 @@ def from_msprime(
                         gtmp["demes"][pop_name] = {
                             "ancestors": [],
                             "proportions": [],
-                            "epochs": [demes.Epoch(initial_size=1)],
+                            "epochs": [demes.Epoch(start_size=1)],
                         }
                     pop_param_changes.add(pop_name)
 
@@ -257,7 +257,7 @@ def from_msprime(
                     gtmp["demes"][parent] = {
                         "ancestors": [],
                         "proportions": [],
-                        "epochs": [demes.Epoch(initial_size=1)],
+                        "epochs": [demes.Epoch(start_size=1)],
                     }
 
             if math.isclose(sum(proportions), 1):
@@ -266,7 +266,7 @@ def from_msprime(
                 # Set attributes after deme creation, to avoid internal
                 # checks about the ancestors' existence time intervals.
                 gtmp["demes"][child]["epochs"] = [
-                    demes.Epoch(start_time=ddb_epoch.start_time, initial_size=1)
+                    demes.Epoch(start_time=ddb_epoch.start_time, start_size=1)
                 ]
                 gtmp["demes"][child]["ancestors"] = ancestors
                 gtmp["demes"][child]["proportions"] = proportions
@@ -296,14 +296,14 @@ def from_msprime(
             last_epoch = epochs[deme_id][-1]
             last_epoch.end_time = ddb_epoch.start_time
             if last_epoch.start_time == ddb_epoch.end_time:
-                last_epoch.initial_size = pop.end_size
-            last_epoch.final_size = pop.start_size
+                last_epoch.start_size = pop.end_size
+            last_epoch.end_size = pop.start_size
 
             if name[j] in pop_param_changes:
                 # Add new epoch, to be fixed in the next ddb_epoch iteration.
                 epochs[deme_id].append(
                     demes.Epoch(
-                        start_time=ddb_epoch.start_time, end_time=0, initial_size=1
+                        start_time=ddb_epoch.start_time, end_time=0, start_size=1
                     )
                 )
 
@@ -337,8 +337,8 @@ def from_msprime(
             epochs[deme_id][0] = demes.Epoch(
                 start_time=epoch.start_time,
                 end_time=epoch.end_time,
-                initial_size=epoch.final_size,
-                final_size=epoch.final_size,
+                start_size=epoch.end_size,
+                end_size=epoch.end_size,
             )
 
     # Create a fresh demes graph, now that we have complete epoch information
@@ -357,8 +357,8 @@ def from_msprime(
                 demes.Epoch(
                     start_time=epoch.start_time,
                     end_time=epoch.end_time,
-                    initial_size=epoch.initial_size,
-                    final_size=epoch.final_size,
+                    start_size=epoch.start_size,
+                    end_size=epoch.end_size,
                 )
                 for epoch in epochs[deme_id]
             ],
diff --git a/demes/demes.py b/demes/demes.py
index 266d841e..13b61505 100644
--- a/demes/demes.py
+++ b/demes/demes.py
@@ -125,9 +125,9 @@ class Epoch:
 
     :ivar start_time: The start time of the epoch.
     :ivar end_time: The end time of the epoch (must be specified).
-    :ivar initial_size: Population size at ``start_time``.
-    :ivar final_size: Population size at ``end_time``.
-        If ``initial_size != final_size``, the population size changes
+    :ivar start_size: Population size at ``start_time``.
+    :ivar end_size: Population size at ``end_time``.
+        If ``start_size != end_size``, the population size changes
         monotonically between the start and end times.
     :ivar size_function: The size change function. Common options are constant,
         exponential, or linear, though any string is valid. Warning: downstream
@@ -144,11 +144,11 @@ class Epoch:
         default=None,
         validator=attr.validators.optional([int_or_float, non_negative, finite]),
     )
-    initial_size: Optional[Size] = attr.ib(
+    start_size: Optional[Size] = attr.ib(
         default=None,
         validator=attr.validators.optional([int_or_float, positive, finite]),
     )
-    final_size: Optional[Size] = attr.ib(
+    end_size: Optional[Size] = attr.ib(
         default=None,
         validator=attr.validators.optional([int_or_float, positive, finite]),
     )
@@ -168,8 +168,8 @@ class Epoch:
     )
 
     def __attrs_post_init__(self):
-        if self.initial_size is None and self.final_size is None:
-            raise ValueError("must set either initial_size or final_size")
+        if self.start_size is None and self.end_size is None:
+            raise ValueError("must set either start_size or end_size")
         if (
             self.start_time is not None
             and self.end_time is not None
@@ -178,20 +178,18 @@ def __attrs_post_init__(self):
             raise ValueError("must have start_time > end_time")
         if (
             self.start_time is not None
-            and self.initial_size is not None
-            and self.final_size is not None
+            and self.start_size is not None
+            and self.end_size is not None
         ):
-            if math.isinf(self.start_time) and self.initial_size != self.final_size:
+            if math.isinf(self.start_time) and self.start_size != self.end_size:
                 raise ValueError("if start time is inf, must be a constant size epoch")
         if (
             self.size_function == "constant"
-            and self.initial_size is not None
-            and self.final_size is not None
-            and self.initial_size != self.final_size
+            and self.start_size is not None
+            and self.end_size is not None
+            and self.start_size != self.end_size
         ):
-            raise ValueError(
-                "initial_size != final_size, but size_function is constant"
-            )
+            raise ValueError("start_size != end_size, but size_function is constant")
 
     @property
     def time_span(self):
@@ -211,7 +209,7 @@ def assert_close(
         Returns true if the epoch and ``other`` epoch implement essentially
         the same epoch and raises AssertionError otherwise.
         Compares values of the following attributes:
-        ``start_time``, ``end_time``, ``initial_size``, ``final_size``,
+        ``start_time``, ``end_time``, ``start_size``, ``end_size``,
         ``size_function``, ``selfing_rate``, ``cloning_rate``.
 
         :param other: The epoch to compare against.
@@ -237,14 +235,14 @@ def assert_close(
             self.end_time, other.end_time, rel_tol=rel_tol, abs_tol=abs_tol
         ), f"Failed for end_time {self.end_time} != {other.end_time} (other)."
         assert isclose(
-            self.initial_size, other.initial_size, rel_tol=rel_tol, abs_tol=abs_tol
+            self.start_size, other.start_size, rel_tol=rel_tol, abs_tol=abs_tol
         ), (
-            f"Failed for initial_size "
-            f"{self.initial_size} != {other.initial_size} (other)."
+            f"Failed for start_size "
+            f"{self.start_size} != {other.start_size} (other)."
         )
         assert isclose(
-            self.final_size, other.final_size, rel_tol=rel_tol, abs_tol=abs_tol
-        ), f"Failed for final_size {self.final_size} != {other.final_size} (other)."
+            self.end_size, other.end_size, rel_tol=rel_tol, abs_tol=abs_tol
+        ), f"Failed for end_size {self.end_size} != {other.end_size} (other)."
         assert self.size_function == other.size_function
         assert isclose(
             self.selfing_rate, other.selfing_rate, rel_tol=rel_tol, abs_tol=abs_tol
@@ -1138,6 +1136,7 @@ class Graph:
     function uses this API internally.
 
     :ivar str description: A human readable description of the demography.
+        May be ``None``.
     :ivar str time_units: The units of time used for the demography. This is
         commonly ``years`` or ``generations``, but can be any string.
         This field is intended to be useful for documenting a demography,
@@ -1164,8 +1163,11 @@ class Graph:
     :vartype defaults: dict
     """
 
-    description: str = attr.ib(
-        validator=[attr.validators.instance_of(str), nonzero_len]
+    description: Optional[str] = attr.ib(
+        default=None,
+        validator=attr.validators.optional(
+            [attr.validators.instance_of(str), nonzero_len]
+        ),
     )
     time_units: str = attr.ib(validator=[attr.validators.instance_of(str), nonzero_len])
     generation_time: Optional[Time] = attr.ib(
@@ -1332,8 +1334,8 @@ def deme(
         epochs=None,
         start_time=None,
         end_time=None,
-        initial_size=None,
-        final_size=None,
+        start_size=None,
+        end_size=None,
         defaults={},
     ) -> Deme:
         """
@@ -1362,15 +1364,15 @@ def deme(
         :param float end_time: The time at which this deme stops existing,
             in units of ``time_units`` before the present.
             If not specified, defaults to ``0.0`` (the present).
-        :param initial_size: The initial population size of the deme.
+        :param start_size: The initial population size of the deme.
             This must be provided.
-        :param final_size: The final population size of the deme. If ``None``,
-            the deme has a constant ``initial_size`` population size.
+        :param end_size: The final population size of the deme. If ``None``,
+            the deme has a constant ``start_size`` population size.
         :param epochs: Epochs that define population sizes, selfing rates, and
             cloning rates, for the deme over various time periods.
             If not specified, a single epoch will be created for the deme that
-            spans from ``start_time`` to ``end_time``, using the ``initial_size``,
-            ``final_size``, ``selfing_rate`` and ``cloning_rate`` provided.
+            spans from ``start_time`` to ``end_time``, using the ``start_size``,
+            ``end_size``, ``selfing_rate`` and ``cloning_rate`` provided.
         :param defaults: Default attributes for epochs, including cloning_rate
             and selfing_rate.
         :return: Newly created deme.
@@ -1381,10 +1383,10 @@ def deme(
             raise ValueError(f"deme {id} already exists in this graph")
         if epochs is None:
             raise ValueError(f"deme {id} must have at least one specified epoch")
-        if initial_size is None and epochs is not None:
-            initial_size = epochs[0].initial_size
-        if initial_size is None:
-            raise ValueError(f"must set initial_size for deme {id}")
+        if start_size is None and epochs is not None:
+            start_size = epochs[0].start_size
+        if start_size is None:
+            raise ValueError(f"must set start_size for deme {id}")
         if ancestors is None:
             ancestors = []
         if not isinstance(ancestors, list):
@@ -1457,12 +1459,12 @@ def deme(
                 )
             # for each subsequent epoch, fill in start size, final size,
             # and size function as necessary based on last epoch
-            if epochs[i].initial_size is None:
-                epochs[i].initial_size = epochs[i - 1].final_size
-            if epochs[i].final_size is None:
-                epochs[i].final_size = epochs[i].initial_size
+            if epochs[i].start_size is None:
+                epochs[i].start_size = epochs[i - 1].end_size
+            if epochs[i].end_size is None:
+                epochs[i].end_size = epochs[i].start_size
             if epochs[i].size_function is None:
-                if epochs[i].initial_size == epochs[i].final_size:
+                if epochs[i].start_size == epochs[i].end_size:
                     epochs[i].size_function = "constant"
                 else:
                     epochs[i].size_function = "exponential"
@@ -1847,8 +1849,8 @@ def simplify_epochs(data):
                         del epoch["start_time"]
                     if epoch["size_function"] in ("constant", "exponential"):
                         del epoch["size_function"]
-                    if epoch["initial_size"] == epoch["final_size"]:
-                        del epoch["final_size"]
+                    if epoch["start_size"] == epoch["end_size"]:
+                        del epoch["end_size"]
 
             for deme in data["demes"]:
                 del deme["start_time"]
diff --git a/docs/api.rst b/docs/api.rst
index 5ffb74da..1c05df7b 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -32,12 +32,12 @@ pulses via the methods available on this class.
         time_units="years",
         generation_time=25,
     )
-    g.deme("ancestral", epochs=[demes.Epoch(end_time=220e3, initial_size=7300)])
-    g.deme("AMH", ancestors=["ancestral"], epochs=[demes.Epoch(end_time=140e3, initial_size=12300)])
-    g.deme("OOA", ancestors=["AMH"], epochs=[demes.Epoch(end_time=21.2e3, initial_size=2100)])
-    g.deme("YRI", ancestors=["AMH"], epochs=[demes.Epoch(initial_size=12300, end_time=0)])
-    g.deme("CEU", ancestors=["OOA"], epochs=[demes.Epoch(initial_size=1000, final_size=29725, end_time=0)])
-    g.deme("CHB", ancestors=["OOA"], epochs=[demes.Epoch(initial_size=510, final_size=54090, end_time=0)])
+    g.deme("ancestral", epochs=[demes.Epoch(end_time=220e3, start_size=7300)])
+    g.deme("AMH", ancestors=["ancestral"], epochs=[demes.Epoch(end_time=140e3, start_size=12300)])
+    g.deme("OOA", ancestors=["AMH"], epochs=[demes.Epoch(end_time=21.2e3, start_size=2100)])
+    g.deme("YRI", ancestors=["AMH"], epochs=[demes.Epoch(start_size=12300, end_time=0)])
+    g.deme("CEU", ancestors=["OOA"], epochs=[demes.Epoch(start_size=1000, end_size=29725, end_time=0)])
+    g.deme("CHB", ancestors=["OOA"], epochs=[demes.Epoch(start_size=510, end_size=54090, end_time=0)])
     g.symmetric_migration(demes=["YRI", "OOA"], rate=25e-5)
     g.symmetric_migration(demes=["YRI", "CEU"], rate=3e-5)
     g.symmetric_migration(demes=["YRI", "CHB"], rate=1.9e-5)
@@ -65,7 +65,7 @@ with migration between adjacent demes, can be done with the following code.
     )
 
     for j in range(M):
-        g.deme(f"deme{j}", epochs=[demes.Epoch(initial_size=1000, end_time=0)])
+        g.deme(f"deme{j}", epochs=[demes.Epoch(start_size=1000, end_time=0)])
         if j > 0:
             g.symmetric_migration(demes=[f"deme{j - 1}", f"deme{j}"], rate=1e-5)
     g.symmetric_migration(demes=[f"deme{M - 1}", "deme0"], rate=1e-5)
diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index 68ff50f5..687d5d50 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -78,8 +78,8 @@ Defining epochs
 A ``deme`` can be made to have more interesting demographic history, such as
 size changes or non-constant size functions. This is done by defining
 ``epochs`` that span the time that a deme exists. When defining an epoch,
-we specify its ``start_time`` and ``end_time``, along with its ``initial_size``
-and ``final_size`` (or just ``initial_size`` if the population size is constant
+we specify its ``start_time`` and ``end_time``, along with its ``start_size``
+and ``end_size`` (or just ``start_size`` if the population size is constant
 over that epoch).
 
 For example, the same minimal demography :ref:`above <minimal-demography>`
@@ -91,7 +91,7 @@ the deme:
    demes:
      constant_size_deme:
        epochs:
-       - initial_size: 1000
+       - start_size: 1000
          end_time: 0
 
 By default, the first listed ``epoch`` has a ``start_time`` of :math:`\infty`
@@ -110,8 +110,8 @@ in order, from most ancient to most recent.
    :linenos:
 
 We also see, again, that for constant size epochs we only need to specify
-the ``initial_size``, and if no ``initial_size`` is given, the ``epoch`` inherits
-the ``final_size`` of the previous epoch.
+the ``start_size``, and if no ``start_size`` is given, the ``epoch`` inherits
+the ``end_size`` of the previous epoch.
 
 In the previous example, we have a ``deme`` that expands from an effective population
 size of 10,000 to 20,000 250 thousand years ago, goes through a bottleneck
@@ -120,7 +120,7 @@ bottleneck size of 1,500 to 40,000 from 30 thousand years ago until present
 time.
 
 .. note::
-   If no ``size_function`` is given, when the ``initial_size`` and ``final_size``
+   If no ``size_function`` is given, when the ``start_size`` and ``end_size``
    are different, the default size function is exponential. However, other
    size functions, such as linear, are permitted and can be specified.
 
@@ -135,9 +135,9 @@ interact (for illustration, not realism), we could write:
 
    demes:
      deme1:
-       initial_size: 1000
+       start_size: 1000
      deme2:
-       initial_size: 2000
+       start_size: 2000
 
 Population branches and splits
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -151,11 +151,11 @@ deme, we would specify that its ``ancestor`` is its parental deme. For example,
    demes:
      parental_deme:
        description: The parental deme, that exists for all time.
-       initial_size: 1000
+       start_size: 1000
      child_deme:
        description: The child deme, that exists from the branching time.
        ancestors: parental_deme
-       initial_size: 500
+       start_size: 500
        start_time: 100
 
 Here, the child deme split off from the parental deme 100 time units ago,
@@ -172,20 +172,20 @@ is written as
    demes:
      parental_deme:
        description: The parental deme, that splits into three demes.
-       initial_size: 1000
+       start_size: 1000
        end_time: 200
      child1:
        description: The first child deme.
        ancestors: parental_deme
-       initial_size: 500
+       start_size: 500
      child2:
        description: The second child deme.
        ancestors: parental_deme
-       initial_size: 800
+       start_size: 800
      child3:
        description: The third child deme.
        ancestors: parental_deme
-       initial_size: 600
+       start_size: 600
 
 Here, the parental deme exists until time 200, and each child deme exists
 from time 200 to present time.
@@ -225,9 +225,9 @@ over time:
 
    demes:
      deme1:
-       initial_size: 1000
+       start_size: 1000
      deme2:
-       initial_size: 1000
+       start_size: 1000
    migrations:
      symmetric:
        - demes: deme1, deme2
@@ -291,16 +291,16 @@ demes listed in ``ancestors``.
 
    demes:
      parental1:
-       initial_size: 1000
+       start_size: 1000
        end_time: 100
      parental2:
-       initial_size: 2000
+       start_size: 2000
        end_time: 100
      merged_deme:
        ancestors: parental1, parental2
        proportions: 0.7, 0.3
-       initial_size: 3000
-       final_size: 5000
+       start_size: 3000
+       end_size: 5000
 
 Here, two demes merge to form a single deme 100 time units ago, which
 then grows exponentially from 3,000 to 5,000 at present time.
diff --git a/docs/tutorial_examples/browning_america.yml b/docs/tutorial_examples/browning_america.yml
index 8912d448..a8e20f12 100644
--- a/docs/tutorial_examples/browning_america.yml
+++ b/docs/tutorial_examples/browning_america.yml
@@ -8,38 +8,38 @@ demes:
     description: Equilibrium/root population
     epochs:
     - end_time: 5920
-      initial_size: 7310
+      start_size: 7310
   - id: AMH
     description: Anatomically modern humans
     ancestors: [ancestral]
     epochs:
     - end_time: 2040
-      initial_size: 14474
+      start_size: 14474
   - id: OOA
     description: Bottleneck out-of-Africa population
     ancestors: [AMH]
     epochs:
     - end_time: 920
-      initial_size: 1861
+      start_size: 1861
   - id: AFR
     description: African population
     ancestors: [AMH]
     epochs:
-    - initial_size: 14474
+    - start_size: 14474
       end_time: 0
   - id: EUR
     description: European population
     ancestors: [OOA]
     epochs:
-    - initial_size: 1000
-      final_size: 34039
+    - start_size: 1000
+      end_size: 34039
       end_time: 0
   - id: EAS
     description: East Asian population
     ancestors: [OOA]
     epochs:
-    - initial_size: 510
-      final_size: 45852
+    - start_size: 510
+      end_size: 45852
       end_time: 0
   - id: ADMIX
     description: Admixed America
@@ -47,8 +47,8 @@ demes:
     proportions: [0.167, 0.333, 0.5]
     epochs:
     - start_time: 12
-      initial_size: 30000
-      final_size: 54664
+      start_size: 30000
+      end_size: 54664
       end_time: 0
 migrations:
   symmetric:
diff --git a/docs/tutorial_examples/isolation_with_migration.yml b/docs/tutorial_examples/isolation_with_migration.yml
index 3ce3f842..263ac913 100644
--- a/docs/tutorial_examples/isolation_with_migration.yml
+++ b/docs/tutorial_examples/isolation_with_migration.yml
@@ -5,21 +5,21 @@ demes:
   root:
     description: Parental deme
     epochs:
-    - initial_size: 10000
+    - start_size: 10000
       end_time: 1200
   deme1:
     description: First child deme
     ancestors: root
     epochs:
-    - initial_size: 2000
-      final_size: 30000
+    - start_size: 2000
+      end_size: 30000
       end_time: 0
   deme2:
     description: Second child deme
     ancestors: root
     epochs:
-    - initial_size: 8000
-      final_size: 15000
+    - start_size: 8000
+      end_size: 15000
       end_time: 0
 migrations:
   symmetric:
diff --git a/docs/tutorial_examples/minimal.yml b/docs/tutorial_examples/minimal.yml
index d63a5609..8b262425 100644
--- a/docs/tutorial_examples/minimal.yml
+++ b/docs/tutorial_examples/minimal.yml
@@ -3,5 +3,5 @@ time_units: generations
 demes:
   constant_size_deme:
     epochs:
-    - initial_size: 1000
+    - start_size: 1000
       end_time: 0
diff --git a/docs/tutorial_examples/one_pop_epochs.yml b/docs/tutorial_examples/one_pop_epochs.yml
index 4d872ff2..9a03f774 100644
--- a/docs/tutorial_examples/one_pop_epochs.yml
+++ b/docs/tutorial_examples/one_pop_epochs.yml
@@ -5,13 +5,13 @@ generation_time: 25
 demes:
   our_population:
     description: A deme with multiple epochs.
-    initial_size: 10000
+    start_size: 10000
     epochs:
-    - initial_size: 10000
+    - start_size: 10000
       end_time: 250000
-    - initial_size: 20000
+    - start_size: 20000
       end_time: 60000
-    - initial_size: 1500
+    - start_size: 1500
       end_time: 30000
-    - final_size: 40000
+    - end_size: 40000
       end_time: 0
diff --git a/examples/bottleneck.yml b/examples/bottleneck.yml
index 1c3b4f4f..6985cc3e 100644
--- a/examples/bottleneck.yml
+++ b/examples/bottleneck.yml
@@ -5,10 +5,10 @@ demes:
   - id: our_population
     description: Bottleneck population using epochs
     epochs:
-    - initial_size: 1e4
+    - start_size: 1e4
       start_time: 10000
       end_time: 500
-    - initial_size: 1e2
+    - start_size: 1e2
       end_time: 100
-    - initial_size: 1e4
+    - start_size: 1e4
       end_time: 0
diff --git a/examples/browning_america.yml b/examples/browning_america.yml
index 8912d448..a8e20f12 100644
--- a/examples/browning_america.yml
+++ b/examples/browning_america.yml
@@ -8,38 +8,38 @@ demes:
     description: Equilibrium/root population
     epochs:
     - end_time: 5920
-      initial_size: 7310
+      start_size: 7310
   - id: AMH
     description: Anatomically modern humans
     ancestors: [ancestral]
     epochs:
     - end_time: 2040
-      initial_size: 14474
+      start_size: 14474
   - id: OOA
     description: Bottleneck out-of-Africa population
     ancestors: [AMH]
     epochs:
     - end_time: 920
-      initial_size: 1861
+      start_size: 1861
   - id: AFR
     description: African population
     ancestors: [AMH]
     epochs:
-    - initial_size: 14474
+    - start_size: 14474
       end_time: 0
   - id: EUR
     description: European population
     ancestors: [OOA]
     epochs:
-    - initial_size: 1000
-      final_size: 34039
+    - start_size: 1000
+      end_size: 34039
       end_time: 0
   - id: EAS
     description: East Asian population
     ancestors: [OOA]
     epochs:
-    - initial_size: 510
-      final_size: 45852
+    - start_size: 510
+      end_size: 45852
       end_time: 0
   - id: ADMIX
     description: Admixed America
@@ -47,8 +47,8 @@ demes:
     proportions: [0.167, 0.333, 0.5]
     epochs:
     - start_time: 12
-      initial_size: 30000
-      final_size: 54664
+      start_size: 30000
+      end_size: 54664
       end_time: 0
 migrations:
   symmetric:
diff --git a/examples/cloning_example.yml b/examples/cloning_example.yml
index 17795b3e..3612a7cc 100644
--- a/examples/cloning_example.yml
+++ b/examples/cloning_example.yml
@@ -8,26 +8,26 @@ demes:
     description: Root population
     epochs:
     - end_time: 1000
-      initial_size: 1e3
+      start_size: 1e3
   - id: pop1
     description: Population with epochs and changing cloning rates
     ancestors: [root]
     defaults:
       cloning_rate: 0.2
     epochs:
-    - initial_size: 1e4
+    - start_size: 1e4
       end_time: 500
-    - initial_size: 1e2
+    - start_size: 1e2
       end_time: 100
-    - initial_size: 1e4
+    - start_size: 1e4
       end_time: 0
       cloning_rate: 0.5
   - id: pop2
     description: Population with epochs and changing cloning rates
     ancestors: [root]
     epochs:
-    - initial_size: 1e4
+    - start_size: 1e4
       end_time: 500
-    - initial_size: 1e2
+    - start_size: 1e2
       end_time: 0
       cloning_rate: 1.0
diff --git a/examples/gutenkunst_ooa.yml b/examples/gutenkunst_ooa.yml
index dd4eecae..2988360b 100644
--- a/examples/gutenkunst_ooa.yml
+++ b/examples/gutenkunst_ooa.yml
@@ -13,38 +13,38 @@ demes:
     description: Equilibrium/root population
     epochs:
     - end_time: 220e3
-      initial_size: 7300
+      start_size: 7300
   - id: AMH
     description: Anatomically modern humans
     ancestors: [ancestral]
     epochs:
     - end_time: 140e3
-      initial_size: 12300
+      start_size: 12300
   - id: OOA
     description: Bottleneck out-of-Africa population
     ancestors: [AMH]
     epochs:
     - end_time: 21.2e3
-      initial_size: 2100
+      start_size: 2100
   - id: YRI
     description: Yoruba in Ibadan, Nigeria
     ancestors: [AMH]
     epochs:
-    - initial_size: 12300
+    - start_size: 12300
       end_time: 0
   - id: CEU
     description: Utah Residents (CEPH) with Northern and Western European Ancestry
     ancestors: [OOA]
     epochs:
-    - initial_size: 1000
-      final_size: 29725
+    - start_size: 1000
+      end_size: 29725
       end_time: 0
   - id: CHB
     description: Han Chinese in Beijing, China
     ancestors: [OOA]
     epochs:
-    - initial_size: 510
-      final_size: 54090
+    - start_size: 510
+      end_size: 54090
       end_time: 0
 migrations:
   symmetric:
diff --git a/examples/jacobs_papuans.yml b/examples/jacobs_papuans.yml
index 4341f673..347977b0 100644
--- a/examples/jacobs_papuans.yml
+++ b/examples/jacobs_papuans.yml
@@ -13,80 +13,80 @@ demes:
   - id: YRI
     epochs:
     - end_time: 20225.0
-      initial_size: 32671.0
+      start_size: 32671.0
     - end_time: 2218.0
-      initial_size: 41563.0
+      start_size: 41563.0
     - end_time: 0
-      initial_size: 48433.0
+      start_size: 48433.0
   - id: DenA
     ancestors: [YRI]
     start_time: 20225.0
     epochs:
     - end_time: 15090.0
-      initial_size: 13249.0
+      start_size: 13249.0
     - end_time: 12500.0
-      initial_size: 100.0
+      start_size: 100.0
     - end_time: 9750.0
-      initial_size: 100.0
+      start_size: 100.0
     - end_time: 0
-      initial_size: 5083.0
+      start_size: 5083.0
   - id: NeaA
     ancestors: [DenA]
     start_time: 15090.0
     epochs:
     - end_time: 3375.0
-      initial_size: 13249.0
+      start_size: 13249.0
     - end_time: 0
-      initial_size: 826.0
+      start_size: 826.0
   - id: Den2
     ancestors: [DenA]
     epochs:
     - start_time: 12500.0
-      initial_size: 13249.0
+      start_size: 13249.0
       end_time: 0
   - id: Den1
     ancestors: [DenA]
     epochs:
     - start_time: 9750.0
-      initial_size: 13249.0
+      start_size: 13249.0
       end_time: 0
   - id: Nea1
     ancestors: [NeaA]
     epochs:
     - start_time: 3375.0
-      initial_size: 13249.0
+      start_size: 13249.0
       end_time: 0
   - id: Ghost
     ancestors: [YRI]
     start_time: 2218.0
     epochs:
     - end_time: 2119.0
-      initial_size: 1394.0
+      start_size: 1394.0
     - end_time: 0
-      initial_size: 8516.0
+      start_size: 8516.0
   - id: Papuan
     ancestors: [Ghost]
     start_time: 1784.0
     epochs:
     - end_time: 1685.0
-      initial_size: 243.0
+      start_size: 243.0
     - end_time: 0
-      initial_size: 8834.0
+      start_size: 8834.0
   - id: CHB
     ancestors: [Ghost]
     start_time: 1758.0
     epochs:
     - end_time: 1659.0
-      initial_size: 2231.0
+      start_size: 2231.0
     - end_time: 1293.0
-      initial_size: 12971.0
+      start_size: 12971.0
     - end_time: 0
-      initial_size: 9025.0
+      start_size: 9025.0
   - id: CEU
     ancestors: [CHB]
     epochs:
     - start_time: 1293.0
-      initial_size: 6962.0
+      start_size: 6962.0
       end_time: 0
 migrations:
   symmetric:
diff --git a/examples/linear_growth.yml b/examples/linear_growth.yml
index de88f4ff..171d07e7 100644
--- a/examples/linear_growth.yml
+++ b/examples/linear_growth.yml
@@ -6,12 +6,12 @@ demes:
   - id: my_pop
     description: Multi-epoch population
     epochs:
-    - initial_size: 1e4
+    - start_size: 1e4
       end_time: 1000
-    - initial_size: 1e3
-      final_size: 1e4
+    - start_size: 1e3
+      end_size: 1e4
       end_time: 100
       size_function: linear
-    - initial_size: 1e4
-      final_size: 1e2
+    - start_size: 1e4
+      end_size: 1e2
       end_time: 0
diff --git a/examples/offshoots.yml b/examples/offshoots.yml
index d34768b2..4f8d6f3d 100644
--- a/examples/offshoots.yml
+++ b/examples/offshoots.yml
@@ -6,21 +6,21 @@ demes:
   - id: ancestral
     description: Main population
     epochs:
-    - initial_size: 1000
+    - start_size: 1000
       end_time: 0
   - id: offshoot1
     description: More recent offshoot population
     ancestors: [ancestral]
     epochs:
     - start_time: 500
-      initial_size: 100
+      start_size: 100
       end_time: 0
   - id: offshoot2
     description: More ancient offshoot population
     ancestors: [ancestral]
     epochs:
     - start_time: 1000
-      initial_size: 200
+      start_size: 200
       end_time: 0
 migrations:
   asymmetric:
diff --git a/examples/selfing_example.yml b/examples/selfing_example.yml
index a4c3616c..b91566fe 100644
--- a/examples/selfing_example.yml
+++ b/examples/selfing_example.yml
@@ -9,7 +9,7 @@ demes:
   defaults:
     selfing_rate: 0.1
   epochs:
-  - initial_size: 1e3
+  - start_size: 1e3
     end_time: 1000
 - id: pop1
   description: Population with epochs and changing selfing rates
@@ -17,20 +17,20 @@ demes:
   defaults:
     selfing_rate: 0.2
   epochs:
-  - initial_size: 1e4
+  - start_size: 1e4
     end_time: 500
-  - initial_size: 1e2
+  - start_size: 1e2
     end_time: 100
-  - initial_size: 1e4
+  - start_size: 1e4
     end_time: 0
     selfing_rate: 0.5
 - id: pop2
   description: Population with epochs and changing selfing rates
   ancestors: [root]
   epochs:
-  - initial_size: 1e4
+  - start_size: 1e4
     end_time: 500
     selfing_rate: 0.9
-  - initial_size: 1e2
+  - start_size: 1e2
     end_time: 0
     selfing_rate: 1.0
diff --git a/examples/zigzag.yml b/examples/zigzag.yml
index 9c505cac..e9f282fb 100644
--- a/examples/zigzag.yml
+++ b/examples/zigzag.yml
@@ -10,22 +10,22 @@ demes:
       in this case).
     epochs:
     - end_time: 34133.31
-      initial_size: 1431
+      start_size: 1431
     - start_time: 34133.31
       end_time: 8533.33
-      final_size: 14312
+      end_size: 14312
     - start_time: 8533.33
       end_time: 2133.33
-      final_size: 1431
+      end_size: 1431
     - start_time: 2133.33
       end_time: 533.33
-      final_size: 14312
+      end_size: 14312
     - start_time: 533.33
       end_time: 133.33
-      final_size: 1431
+      end_size: 1431
     - start_time: 133.33
       end_time: 33.333
-      final_size: 14312
+      end_size: 14312
     - start_time: 33.333
       end_time: 0
-      final_size: 14312
+      end_size: 14312
diff --git a/schema/graph.json b/schema/graph.json
index 8a1f050a..7feec3f9 100644
--- a/schema/graph.json
+++ b/schema/graph.json
@@ -32,10 +32,10 @@
         "epoch": {
             "type": "object",
             "properties": {
-                "initial_size": {
+                "start_size": {
                     "$ref": "#/definitions/size"
                 },
-                "final_size": {
+                "end_size": {
                     "$ref": "#/definitions/size"
                 },
                 "size_function": {
@@ -56,7 +56,7 @@
                     "default": 0
                 }
             },
-            "required": ["initial_size", "final_size", "size_function", "start_time", "end_time"]
+            "required": ["start_size", "end_size", "size_function", "start_time", "end_time"]
         },
         "deme": {
             "type": "object",


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
index a7635517..69dd3d78 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -81,13 +81,13 @@ def epochs_lists(draw, start_time=math.inf, max_epochs=5):
     epochs = []
 
     for end_time in times[1:]:
-        initial_size = draw(
+        start_size = draw(
             st.floats(min_value=0, exclude_min=True, allow_infinity=False)
         )
         if math.isinf(start_time):
-            final_size = initial_size
+            end_size = start_size
         else:
-            final_size = draw(
+            end_size = draw(
                 st.floats(min_value=0, exclude_min=True, allow_infinity=False)
             )
         cloning_rate = draw(st.floats(min_value=0, max_value=1))
@@ -97,8 +97,8 @@ def epochs_lists(draw, start_time=math.inf, max_epochs=5):
             demes.Epoch(
                 start_time=start_time,
                 end_time=end_time,
-                initial_size=initial_size,
-                final_size=final_size,
+                start_size=start_size,
+                end_size=end_size,
                 cloning_rate=cloning_rate,
                 selfing_rate=selfing_rate,
             )
diff --git a/tests/test_demes.py b/tests/test_demes.py
index acd20aac..91a0bfac 100644
--- a/tests/test_demes.py
+++ b/tests/test_demes.py
@@ -25,99 +25,95 @@ class TestEpoch(unittest.TestCase):
     def test_bad_time(self):
         for time in ("0", "inf", {}, [], float("NaN")):
             with self.assertRaises(TypeError):
-                Epoch(start_time=time, end_time=0, initial_size=1)
+                Epoch(start_time=time, end_time=0, start_size=1)
             with self.assertRaises(TypeError):
-                Epoch(start_time=100, end_time=time, initial_size=1)
+                Epoch(start_time=100, end_time=time, start_size=1)
 
         for start_time in (-10000, -1, -1e-9):
             with self.assertRaises(ValueError):
-                Epoch(start_time=start_time, end_time=0, initial_size=1)
+                Epoch(start_time=start_time, end_time=0, start_size=1)
         for end_time in (-10000, -1, -1e-9, float("inf")):
             with self.assertRaises(ValueError):
-                Epoch(start_time=100, end_time=end_time, initial_size=1)
+                Epoch(start_time=100, end_time=end_time, start_size=1)
 
     def test_bad_time_span(self):
         with self.assertRaises(ValueError):
-            Epoch(start_time=1, end_time=1, initial_size=1)
+            Epoch(start_time=1, end_time=1, start_size=1)
         with self.assertRaises(ValueError):
-            Epoch(start_time=1, end_time=2, initial_size=1)
+            Epoch(start_time=1, end_time=2, start_size=1)
 
     def test_bad_size(self):
         for size in ("0", "100", {}, [], float("NaN")):
             with self.assertRaises(TypeError):
-                Epoch(start_time=1, end_time=0, initial_size=size)
+                Epoch(start_time=1, end_time=0, start_size=size)
             with self.assertRaises(TypeError):
-                Epoch(start_time=1, end_time=0, initial_size=1, final_size=size)
+                Epoch(start_time=1, end_time=0, start_size=1, end_size=size)
 
         for size in (-10000, -1, -1e-9, 0, float("inf")):
             with self.assertRaises(ValueError):
-                Epoch(start_time=1, end_time=0, initial_size=size)
+                Epoch(start_time=1, end_time=0, start_size=size)
             with self.assertRaises(ValueError):
-                Epoch(start_time=1, end_time=0, initial_size=1, final_size=size)
+                Epoch(start_time=1, end_time=0, start_size=1, end_size=size)
 
     def test_missing_size(self):
         with self.assertRaises(ValueError):
             Epoch(start_time=1, end_time=0)
 
     def test_valid_epochs(self):
-        Epoch(end_time=0, initial_size=1)
-        Epoch(end_time=0, final_size=1)
-        Epoch(start_time=float("inf"), end_time=0, initial_size=1)
-        Epoch(start_time=float("inf"), end_time=10, initial_size=1)
-        Epoch(start_time=100, end_time=99, initial_size=1)
-        Epoch(end_time=0, initial_size=1, final_size=1)
-        Epoch(end_time=0, initial_size=1, final_size=100)
-        Epoch(end_time=0, initial_size=100, final_size=1)
-        Epoch(start_time=20, end_time=10, initial_size=1, final_size=100)
+        Epoch(end_time=0, start_size=1)
+        Epoch(end_time=0, end_size=1)
+        Epoch(start_time=float("inf"), end_time=0, start_size=1)
+        Epoch(start_time=float("inf"), end_time=10, start_size=1)
+        Epoch(start_time=100, end_time=99, start_size=1)
+        Epoch(end_time=0, start_size=1, end_size=1)
+        Epoch(end_time=0, start_size=1, end_size=100)
+        Epoch(end_time=0, start_size=100, end_size=1)
+        Epoch(start_time=20, end_time=10, start_size=1, end_size=100)
         for rate in (0, 1, 0.5, 1e-5):
-            Epoch(end_time=0, initial_size=1, selfing_rate=rate)
-            Epoch(end_time=0, initial_size=1, cloning_rate=rate)
-            Epoch(end_time=0, initial_size=1, selfing_rate=rate, cloning_rate=rate)
-        Epoch(end_time=0, initial_size=1, size_function="constant")
-        Epoch(end_time=0, final_size=1, size_function="constant")
-        Epoch(end_time=0, initial_size=1, final_size=1, size_function="constant")
+            Epoch(end_time=0, start_size=1, selfing_rate=rate)
+            Epoch(end_time=0, start_size=1, cloning_rate=rate)
+            Epoch(end_time=0, start_size=1, selfing_rate=rate, cloning_rate=rate)
+        Epoch(end_time=0, start_size=1, size_function="constant")
+        Epoch(end_time=0, end_size=1, size_function="constant")
+        Epoch(end_time=0, start_size=1, end_size=1, size_function="constant")
         for fn in ("linear", "exponential", "N(t) = 6 * log(t)"):
-            Epoch(end_time=0, initial_size=1, final_size=10, size_function=fn)
-            Epoch(end_time=0, initial_size=1, size_function=fn)
-            Epoch(end_time=0, final_size=10, size_function=fn)
+            Epoch(end_time=0, start_size=1, end_size=10, size_function=fn)
+            Epoch(end_time=0, start_size=1, size_function=fn)
+            Epoch(end_time=0, end_size=10, size_function=fn)
 
     def test_time_span(self):
-        e = Epoch(start_time=float("inf"), end_time=0, initial_size=1)
+        e = Epoch(start_time=float("inf"), end_time=0, start_size=1)
         self.assertEqual(e.time_span, float("inf"))
-        e = Epoch(start_time=100, end_time=20, initial_size=1)
+        e = Epoch(start_time=100, end_time=20, start_size=1)
         self.assertEqual(e.time_span, 80)
 
     def test_inf_start_time_constant_epoch(self):
         with self.assertRaises(ValueError):
-            Epoch(start_time=float("inf"), end_time=0, initial_size=10, final_size=20)
+            Epoch(start_time=float("inf"), end_time=0, start_size=10, end_size=20)
 
     def test_isclose(self):
         eps = 1e-50
-        e1 = Epoch(end_time=0, initial_size=1)
+        e1 = Epoch(end_time=0, start_size=1)
         self.assertTrue(e1.isclose(e1))
-        self.assertTrue(e1.isclose(Epoch(end_time=0 + eps, initial_size=1)))
-        self.assertTrue(e1.isclose(Epoch(end_time=0, initial_size=1 + eps)))
+        self.assertTrue(e1.isclose(Epoch(end_time=0 + eps, start_size=1)))
+        self.assertTrue(e1.isclose(Epoch(end_time=0, start_size=1 + eps)))
 
-        self.assertFalse(e1.isclose(Epoch(end_time=1e-9, initial_size=1)))
-        self.assertFalse(e1.isclose(Epoch(end_time=0, initial_size=1 + 1e-9)))
-        self.assertFalse(e1.isclose(Epoch(start_time=10, end_time=0, initial_size=1)))
-        self.assertFalse(e1.isclose(Epoch(end_time=0, initial_size=1, final_size=2)))
+        self.assertFalse(e1.isclose(Epoch(end_time=1e-9, start_size=1)))
+        self.assertFalse(e1.isclose(Epoch(end_time=0, start_size=1 + 1e-9)))
+        self.assertFalse(e1.isclose(Epoch(start_time=10, end_time=0, start_size=1)))
+        self.assertFalse(e1.isclose(Epoch(end_time=0, start_size=1, end_size=2)))
         self.assertFalse(
-            Epoch(end_time=0, initial_size=1, final_size=2).isclose(
+            Epoch(end_time=0, start_size=1, end_size=2).isclose(
                 Epoch(
                     end_time=0,
-                    initial_size=1,
-                    final_size=2,
+                    start_size=1,
+                    end_size=2,
                     size_function="exponential",
                 )
             )
         )
-        self.assertFalse(
-            e1.isclose(Epoch(end_time=0, initial_size=1, selfing_rate=0.1))
-        )
-        self.assertFalse(
-            e1.isclose(Epoch(end_time=0, initial_size=1, cloning_rate=0.1))
-        )
+        self.assertFalse(e1.isclose(Epoch(end_time=0, start_size=1, selfing_rate=0.1)))
+        self.assertFalse(e1.isclose(Epoch(end_time=0, start_size=1, cloning_rate=0.1)))
         self.assertFalse(e1.isclose(None))
         self.assertFalse(e1.isclose(123))
         self.assertFalse(e1.isclose("foo"))
@@ -125,29 +121,29 @@ def test_isclose(self):
     def test_bad_selfing_rate(self):
         for rate in ("0", "1e-4", "inf", [], {}, float("NaN")):
             with self.assertRaises(TypeError):
-                Epoch(start_time=100, end_time=0, initial_size=1, selfing_rate=rate)
+                Epoch(start_time=100, end_time=0, start_size=1, selfing_rate=rate)
 
         for rate in (-10000, 10000, -1, -1e-9, 1.2, float("inf")):
             with self.assertRaises(ValueError):
-                Epoch(start_time=100, end_time=0, initial_size=1, selfing_rate=rate)
+                Epoch(start_time=100, end_time=0, start_size=1, selfing_rate=rate)
 
     def test_bad_cloning_rate(self):
         for rate in ("0", "1e-4", "inf", [], {}, float("NaN")):
             with self.assertRaises(TypeError):
-                Epoch(start_time=100, end_time=0, initial_size=1, cloning_rate=rate)
+                Epoch(start_time=100, end_time=0, start_size=1, cloning_rate=rate)
 
         for rate in (-10000, 10000, -1, -1e-9, 1.2, float("inf")):
             with self.assertRaises(ValueError):
-                Epoch(start_time=100, end_time=0, initial_size=1, cloning_rate=rate)
+                Epoch(start_time=100, end_time=0, start_size=1, cloning_rate=rate)
 
     def test_bad_size_function(self):
         for fn in (0, 1e5, [], {}, float("NaN")):
             with self.assertRaises(TypeError):
-                Epoch(end_time=0, initial_size=1, final_size=10, size_function=fn)
+                Epoch(end_time=0, start_size=1, end_size=10, size_function=fn)
 
         for fn in ("", "constant"):
             with self.assertRaises(ValueError):
-                Epoch(end_time=0, initial_size=1, final_size=10, size_function=fn)
+                Epoch(end_time=0, start_size=1, end_size=10, size_function=fn)
 
 
 class TestMigration(unittest.TestCase):
@@ -767,7 +763,7 @@ def test_properties(self):
             description="b",
             ancestors=["c"],
             proportions=[1],
-            epochs=[Epoch(start_time=float("inf"), end_time=0, initial_size=1)],
+            epochs=[Epoch(start_time=float("inf"), end_time=0, start_size=1)],
             defaults={},
         )
         self.assertEqual(deme.start_time, float("inf"))
@@ -781,9 +777,9 @@ def test_properties(self):
             ancestors=["c"],
             proportions=[1],
             epochs=[
-                Epoch(start_time=100, end_time=50, initial_size=1),
-                Epoch(start_time=50, end_time=20, initial_size=100),
-                Epoch(start_time=20, end_time=1, initial_size=200),
+                Epoch(start_time=100, end_time=50, start_size=1),
+                Epoch(start_time=50, end_time=20, start_size=100),
+                Epoch(start_time=20, end_time=1, start_size=200),
             ],
             defaults={},
         )
@@ -795,7 +791,7 @@ def test_properties(self):
             description=None,
             ancestors=["c"],
             proportions=[1],
-            epochs=[Epoch(start_time=float("inf"), end_time=0, initial_size=1)],
+            epochs=[Epoch(start_time=float("inf"), end_time=0, start_size=1)],
             defaults={},
         )
         self.assertEqual(deme.description, None)
@@ -808,7 +804,7 @@ def test_bad_id(self):
                     description="b",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=float("inf"), end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=float("inf"), end_time=0, start_size=1)],
                     defaults={},
                 )
         for id in ["", "501", "pop-1", "pop.2", "pop 3"]:
@@ -818,7 +814,7 @@ def test_bad_id(self):
                     description="b",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=float("inf"), end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=float("inf"), end_time=0, start_size=1)],
                     defaults={},
                 )
 
@@ -830,7 +826,7 @@ def test_bad_description(self):
                     description=description,
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=float("inf"), end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=float("inf"), end_time=0, start_size=1)],
                 )
         with self.assertRaises(ValueError):
             Deme(
@@ -838,7 +834,7 @@ def test_bad_description(self):
                 description="",
                 ancestors=[],
                 proportions=[],
-                epochs=[Epoch(start_time=float("inf"), end_time=0, initial_size=1)],
+                epochs=[Epoch(start_time=float("inf"), end_time=0, start_size=1)],
                 defaults={},
             )
 
@@ -850,7 +846,7 @@ def test_bad_ancestors(self):
                     description="b",
                     ancestors=ancestors,
                     proportions=[1],
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
         for id in (None, 0, float("inf"), 1e3, {}, []):
@@ -860,7 +856,7 @@ def test_bad_ancestors(self):
                     description="b",
                     ancestors=[id],
                     proportions=[1],
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
         for id in ["", "501", "pop-1", "pop.2", "pop 3"]:
@@ -870,7 +866,7 @@ def test_bad_ancestors(self):
                     description="b",
                     ancestors=[id],
                     proportions=[1],
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
 
@@ -880,7 +876,7 @@ def test_bad_ancestors(self):
                 description="b",
                 ancestors=["a", "c"],
                 proportions=[0.5, 0.5],
-                epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                 defaults={},
             )
         with self.assertRaises(ValueError):
@@ -890,7 +886,7 @@ def test_bad_ancestors(self):
                 description="test",
                 ancestors=["x", "x"],
                 proportions=[0.5, 0.5],
-                epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                 defaults={},
             )
 
@@ -902,7 +898,7 @@ def test_bad_proportions(self):
                     description="test",
                     ancestors=[],
                     proportions=proportions,
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
         for proportion in (None, "inf", "100", {}, [], float("NaN")):
@@ -912,7 +908,7 @@ def test_bad_proportions(self):
                     description="test",
                     ancestors=["b"],
                     proportions=[proportion],
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
 
@@ -928,7 +924,7 @@ def test_bad_proportions(self):
                     description="test",
                     ancestors=["x", "y"],
                     proportions=proportions,
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
 
@@ -939,7 +935,7 @@ def test_bad_proportions(self):
                     description="test",
                     ancestors=["b", "c"],
                     proportions=[0.5, proportion],
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
             with self.assertRaises(ValueError):
@@ -948,7 +944,7 @@ def test_bad_proportions(self):
                     description="test",
                     ancestors=["b", "c"],
                     proportions=[proportion, 0.5],
-                    epochs=[Epoch(start_time=10, end_time=0, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=0, start_size=1)],
                     defaults={},
                 )
 
@@ -961,8 +957,8 @@ def test_epochs_out_of_order(self):
                     ancestors=["c"],
                     proportions=[1],
                     epochs=[
-                        Epoch(start_time=10, end_time=5, initial_size=1),
-                        Epoch(start_time=5, end_time=time, initial_size=100),
+                        Epoch(start_time=10, end_time=5, start_size=1),
+                        Epoch(start_time=5, end_time=time, start_size=100),
                     ],
                     defaults={},
                 )
@@ -976,8 +972,8 @@ def test_epochs_are_a_partition(self):
                     ancestors=["c"],
                     proportions=[1],
                     epochs=[
-                        Epoch(start_time=start_time, end_time=end_time, initial_size=1),
-                        Epoch(start_time=50, end_time=0, initial_size=2),
+                        Epoch(start_time=start_time, end_time=end_time, start_size=1),
+                        Epoch(start_time=50, end_time=0, start_size=2),
                     ],
                     defaults={},
                 )
@@ -1010,9 +1006,7 @@ def test_time_span(self):
                 description="b",
                 ancestors=["c"],
                 proportions=[1],
-                epochs=[
-                    Epoch(start_time=start_time, end_time=end_time, initial_size=1)
-                ],
+                epochs=[Epoch(start_time=start_time, end_time=end_time, start_size=1)],
                 defaults={},
             )
             self.assertEqual(deme.time_span, start_time - end_time)
@@ -1022,7 +1016,7 @@ def test_time_span(self):
                 description="b",
                 ancestors=["c"],
                 proportions=[1],
-                epochs=[Epoch(start_time=100, end_time=100, initial_size=1)],
+                epochs=[Epoch(start_time=100, end_time=100, start_size=1)],
                 defaults={},
             )
 
@@ -1032,7 +1026,7 @@ def test_isclose(self):
             description="foo deme",
             ancestors=[],
             proportions=[],
-            epochs=[Epoch(start_time=10, end_time=5, initial_size=1)],
+            epochs=[Epoch(start_time=10, end_time=5, start_size=1)],
             defaults={},
         )
         self.assertTrue(d1.isclose(d1))
@@ -1043,7 +1037,7 @@ def test_isclose(self):
                     description="foo deme",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=10, end_time=5, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=5, start_size=1)],
                     defaults={},
                 )
             )
@@ -1056,7 +1050,7 @@ def test_isclose(self):
                     description="bar deme",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=10, end_time=5, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=5, start_size=1)],
                     defaults={},
                 )
             )
@@ -1073,7 +1067,7 @@ def test_isclose(self):
                     description="foo deme",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=10, end_time=5, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=5, start_size=1)],
                     defaults={},
                 )
             )
@@ -1085,7 +1079,7 @@ def test_isclose(self):
                     description="foo deme",
                     ancestors=["x"],
                     proportions=[1],
-                    epochs=[Epoch(start_time=10, end_time=5, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=5, start_size=1)],
                     defaults={},
                 )
             )
@@ -1097,7 +1091,7 @@ def test_isclose(self):
                     description="foo deme",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=9, end_time=5, initial_size=1)],
+                    epochs=[Epoch(start_time=9, end_time=5, start_size=1)],
                     defaults={},
                 )
             )
@@ -1109,7 +1103,7 @@ def test_isclose(self):
                     description="foo deme",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=10, end_time=9, initial_size=1)],
+                    epochs=[Epoch(start_time=10, end_time=9, start_size=1)],
                     defaults={},
                 )
             )
@@ -1122,7 +1116,7 @@ def test_isclose(self):
                     description="foo deme",
                     ancestors=[],
                     proportions=[],
-                    epochs=[Epoch(start_time=10, end_time=5, initial_size=9)],
+                    epochs=[Epoch(start_time=10, end_time=5, start_size=9)],
                     defaults={},
                 )
             )
@@ -1135,9 +1129,7 @@ def test_isclose(self):
                     ancestors=[],
                     proportions=[],
                     epochs=[
-                        Epoch(
-                            start_time=10, end_time=5, initial_size=1, selfing_rate=0.1
-                        )
+                        Epoch(start_time=10, end_time=5, start_size=1, selfing_rate=0.1)
                     ],
                     defaults={},
                 )
@@ -1151,9 +1143,7 @@ def test_isclose(self):
                     ancestors=[],
                     proportions=[],
                     epochs=[
-                        Epoch(
-                            start_time=10, end_time=5, initial_size=1, cloning_rate=0.1
-                        )
+                        Epoch(start_time=10, end_time=5, start_size=1, cloning_rate=0.1)
                     ],
                     defaults={},
                 )
@@ -1181,8 +1171,13 @@ def test_bad_generation_time(self):
                     generation_time=generation_time,
                 )
 
+    def test_description(self):
+        Graph(description="test", time_units="generations")
+        Graph(description=None, time_units="generations")
+        Graph(time_units="generations")
+
     def test_bad_description(self):
-        for description in (None, [], {}, 0, 1e5, float("inf")):
+        for description in ([], {}, 0, 1e5, float("inf")):
             with self.assertRaises(TypeError):
                 Graph(
                     description=description,
@@ -1318,8 +1313,8 @@ def test_in_generations(self):
 
     def test_bad_migration_time(self):
         dg = demes.Graph(description="test bad migration", time_units="generations")
-        dg.deme("deme1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        dg.deme("deme2", epochs=[Epoch(end_time=100, initial_size=1000)])
+        dg.deme("deme1", epochs=[Epoch(start_size=1000, end_time=0)])
+        dg.deme("deme2", epochs=[Epoch(end_time=100, start_size=1000)])
         with self.assertRaises(ValueError):
             dg.migration(
                 source="deme1", dest="deme2", rate=0.01, start_time=1000, end_time=0
@@ -1327,8 +1322,8 @@ def test_bad_migration_time(self):
 
     def test_overlapping_migrations(self):
         dg = demes.Graph(description="test", time_units="generations")
-        dg.deme("A", epochs=[Epoch(initial_size=1, end_time=0)])
-        dg.deme("B", epochs=[Epoch(initial_size=1, end_time=0)])
+        dg.deme("A", epochs=[Epoch(start_size=1, end_time=0)])
+        dg.deme("B", epochs=[Epoch(start_size=1, end_time=0)])
         dg.migration(source="A", dest="B", rate=0.01)
         with self.assertRaises(ValueError):
             dg.migration(source="A", dest="B", start_time=10, rate=0.02)
@@ -1346,26 +1341,26 @@ def test_overlapping_migrations(self):
 
     def test_bad_pulse_time(self):
         dg = demes.Graph(description="test bad pulse time", time_units="generations")
-        dg.deme("deme1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        dg.deme("deme2", epochs=[Epoch(end_time=100, initial_size=1000)])
+        dg.deme("deme1", epochs=[Epoch(start_size=1000, end_time=0)])
+        dg.deme("deme2", epochs=[Epoch(end_time=100, start_size=1000)])
         with self.assertRaises(ValueError):
             dg.pulse(source="deme1", dest="deme2", proportion=0.1, time=10)
 
     def test_bad_deme(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("b", epochs=[Epoch(initial_size=1, end_time=0)])
+        dg.deme("b", epochs=[Epoch(start_size=1, end_time=0)])
         with self.assertRaises(ValueError):
             # no epochs given
             dg.deme("a")
         with self.assertRaises(ValueError):
-            # no initial_size
+            # no start_size
             dg.deme("a", epochs=[Epoch(end_time=1)])
         with self.assertRaises(TypeError):
             # ancestors must be a list
             dg.deme(
                 "a",
                 ancestors="b",
-                epochs=[Epoch(initial_size=1, start_time=10, end_time=0)],
+                epochs=[Epoch(start_size=1, start_time=10, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # ancestor c doesn't exist
@@ -1373,73 +1368,73 @@ def test_bad_deme(self):
                 "a",
                 ancestors=["b", "c"],
                 proportions=[0.5, 0.5],
-                epochs=[Epoch(initial_size=1, end_time=0)],
+                epochs=[Epoch(start_size=1, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # end_time and final epoch end_time are different
             dg.deme(
                 "a",
-                initial_size=100,
+                start_size=100,
                 ancestors=["b"],
                 end_time=0,
                 epochs=[
-                    Epoch(initial_size=1, start_time=20, end_time=10),
-                    Epoch(start_time=10, end_time=5, initial_size=2),
+                    Epoch(start_size=1, start_time=20, end_time=10),
+                    Epoch(start_time=10, end_time=5, start_size=2),
                 ],
             )
         with self.assertRaises(ValueError):
             # start_time is more recent than an epoch's start_time
             dg.deme(
                 "a",
-                initial_size=100,
+                start_size=100,
                 ancestors=["b"],
                 start_time=15,
                 end_time=0,
                 epochs=[
-                    Epoch(initial_size=1, start_time=20, end_time=10),
-                    Epoch(start_time=10, end_time=0, initial_size=2),
+                    Epoch(start_size=1, start_time=20, end_time=10),
+                    Epoch(start_time=10, end_time=0, start_size=2),
                 ],
             )
 
     def test_duplicate_deme(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=1, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=1, end_time=0)])
         with self.assertRaises(ValueError):
-            dg.deme("a", epochs=[Epoch(initial_size=1, end_time=0)])
+            dg.deme("a", epochs=[Epoch(start_size=1, end_time=0)])
 
     def test_ancestor_not_in_graph(self):
         dg = demes.Graph(description="a", time_units="generations")
         with self.assertRaises(ValueError):
-            dg.deme("a", ancestors=["b"], epochs=[Epoch(initial_size=1)])
+            dg.deme("a", ancestors=["b"], epochs=[Epoch(start_size=1)])
 
     def test_duplicate_ancestors(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, end_time=50)])
+        dg.deme("a", epochs=[Epoch(start_size=100, end_time=50)])
         with self.assertRaises(ValueError):
             dg.deme(
                 "b",
                 ancestors=["a", "a"],
                 proportions=[0.5, 0.5],
-                epochs=[Epoch(initial_size=100, start_time=100)],
+                epochs=[Epoch(start_size=100, start_time=100)],
             )
 
     def test_bad_start_time_wrt_ancestors(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, start_time=100, end_time=50)])
-        dg.deme("b", epochs=[Epoch(initial_size=100, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=100, start_time=100, end_time=50)])
+        dg.deme("b", epochs=[Epoch(start_size=100, end_time=0)])
         with self.assertRaises(ValueError):
             # start_time too old
             dg.deme(
                 "c",
                 ancestors=["a"],
-                epochs=[Epoch(initial_size=100, start_time=200, end_time=0)],
+                epochs=[Epoch(start_size=100, start_time=200, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # start_time too young
             dg.deme(
                 "c",
                 ancestors=["a"],
-                epochs=[Epoch(initial_size=100, start_time=20, end_time=0)],
+                epochs=[Epoch(start_size=100, start_time=20, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # start_time too old
@@ -1447,7 +1442,7 @@ def test_bad_start_time_wrt_ancestors(self):
                 "c",
                 ancestors=["a", "b"],
                 proportions=[0.5, 0.5],
-                epochs=[Epoch(start_time=200, initial_size=100, end_time=0)],
+                epochs=[Epoch(start_time=200, start_size=100, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # start_time too young
@@ -1455,7 +1450,7 @@ def test_bad_start_time_wrt_ancestors(self):
                 "c",
                 ancestors=["a", "b"],
                 proportions=[0.5, 0.5],
-                epochs=[Epoch(initial_size=100, start_time=20, end_time=0)],
+                epochs=[Epoch(start_size=100, start_time=20, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # start_time not provided
@@ -1463,19 +1458,19 @@ def test_bad_start_time_wrt_ancestors(self):
                 "c",
                 ancestors=["a", "b"],
                 proportions=[0.5, 0.5],
-                epochs=[Epoch(initial_size=100, end_time=0)],
+                epochs=[Epoch(start_size=100, end_time=0)],
             )
 
     def test_proportions_default(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, end_time=50)])
-        dg.deme("b", epochs=[Epoch(initial_size=100, end_time=50)])
+        dg.deme("a", epochs=[Epoch(start_size=100, end_time=50)])
+        dg.deme("b", epochs=[Epoch(start_size=100, end_time=50)])
         with self.assertRaises(ValueError):
             # proportions missing
             dg.deme(
                 "c",
                 ancestors=["a", "b"],
-                epochs=[Epoch(initial_size=100, start_time=100, end_time=0)],
+                epochs=[Epoch(start_size=100, start_time=100, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # proportions wrong length
@@ -1483,7 +1478,7 @@ def test_proportions_default(self):
                 "c",
                 ancestors=["a", "b"],
                 proportions=[1],
-                epochs=[Epoch(initial_size=100, start_time=100, end_time=0)],
+                epochs=[Epoch(start_size=100, start_time=100, end_time=0)],
             )
         with self.assertRaises(ValueError):
             # proportions wrong length
@@ -1491,9 +1486,9 @@ def test_proportions_default(self):
                 "c",
                 ancestors=["a", "b"],
                 proportions=[1 / 3, 1 / 3, 1 / 3],
-                epochs=[Epoch(initial_size=100, start_time=100, end_time=0)],
+                epochs=[Epoch(start_size=100, start_time=100, end_time=0)],
             )
-        dg.deme("c", ancestors=["b"], epochs=[Epoch(initial_size=100, end_time=0)])
+        dg.deme("c", ancestors=["b"], epochs=[Epoch(start_size=100, end_time=0)])
         self.assertEqual(len(dg["c"].proportions), 1)
         self.assertEqual(dg["c"].proportions[0], 1.0)
 
@@ -1503,7 +1498,7 @@ def test_bad_epochs(self):
             dg.deme(
                 "a",
                 end_time=50,
-                epochs=[Epoch(initial_size=1, start_time=float("inf"), end_time=0)],
+                epochs=[Epoch(start_size=1, start_time=float("inf"), end_time=0)],
             )
 
     def test_bad_migration(self):
@@ -1514,7 +1509,7 @@ def test_bad_migration(self):
             dg.symmetric_migration(demes=["a"], rate=0.1)
         with self.assertRaises(ValueError):
             dg.migration(source="a", dest="b", rate=0.1)
-        dg.deme("a", epochs=[Epoch(initial_size=100, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=100, end_time=0)])
         with self.assertRaises(ValueError):
             dg.migration(source="a", dest="b", rate=0.1)
         with self.assertRaises(ValueError):
@@ -1522,7 +1517,7 @@ def test_bad_migration(self):
 
     def test_bad_pulse(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=100, end_time=0)])
         with self.assertRaises(ValueError):
             dg.pulse(source="a", dest="b", proportion=0.1, time=10)
         with self.assertRaises(ValueError):
@@ -1531,7 +1526,7 @@ def test_bad_pulse(self):
     def test_pulse_same_time(self):
         g1 = Graph(description="test", time_units="generations")
         for j in range(4):
-            g1.deme(f"d{j}", epochs=[Epoch(initial_size=1000, end_time=0)])
+            g1.deme(f"d{j}", epochs=[Epoch(start_size=1000, end_time=0)])
 
         T = 100  # time of pulses
 
@@ -1587,7 +1582,7 @@ def test_isclose(self):
             time_units="generations",
         )
         g2 = copy.deepcopy(g1)
-        g1.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g1.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
         self.assertTrue(g1.isclose(g1))
         self.assertTrue(g1.isclose(demes.loads(demes.dumps(g1))))
 
@@ -1596,7 +1591,7 @@ def test_isclose(self):
             description="some other description",
             time_units="generations",
         )
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
         self.assertTrue(g1.isclose(g3))
 
         # Don't care about doi for equality.
@@ -1605,16 +1600,16 @@ def test_isclose(self):
             time_units="generations",
             doi=["https://example.com/foo.bar"],
         )
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
         self.assertTrue(g1.isclose(g3))
 
         # The order in which demes are added shouldn't matter.
         g3 = copy.deepcopy(g2)
         g4 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g4.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g4.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
+        g4.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
+        g4.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
         self.assertTrue(g3.isclose(g4))
 
         # The order in which migrations are added shouldn't matter.
@@ -1637,80 +1632,80 @@ def test_isclose(self):
 
         self.assertFalse(g1 == g2)
         g3 = copy.deepcopy(g2)
-        g3.deme("dX", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("dX", epochs=[Epoch(start_size=1000, end_time=0)])
         self.assertFalse(g1.isclose(g3))
 
         g3 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1001, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1001, end_time=0)])
         self.assertFalse(g1.isclose(g3))
 
         g3 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         self.assertFalse(g1.isclose(g3))
 
         g3 = copy.deepcopy(g1)
         g4 = copy.deepcopy(g1)
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, start_time=50, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, start_time=50, end_time=0)])
         g4.deme(
             "d2",
             ancestors=["d1"],
-            epochs=[Epoch(initial_size=1000, start_time=50, end_time=0)],
+            epochs=[Epoch(start_size=1000, start_time=50, end_time=0)],
         )
         self.assertFalse(g3.isclose(g4))
 
         g3 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g4 = copy.deepcopy(g2)
-        g4.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g4.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g4.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g4.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g4.migration(source="d2", dest="d1", rate=1e-5)
         self.assertFalse(g3.isclose(g4))
 
         g3 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g3.migration(source="d1", dest="d2", rate=1e-5)
         g4 = copy.deepcopy(g2)
-        g4.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g4.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g4.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g4.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g4.migration(source="d2", dest="d1", rate=1e-5)
         self.assertFalse(g3.isclose(g4))
 
         g3 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g3.migration(source="d2", dest="d1", rate=1e-5)
         g4 = copy.deepcopy(g2)
-        g4.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g4.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g4.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g4.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g4.symmetric_migration(demes=["d2", "d1"], rate=1e-5)
         self.assertFalse(g3.isclose(g4))
 
         g3 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g4 = copy.deepcopy(g2)
-        g4.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g4.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g4.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g4.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g4.pulse(source="d1", dest="d2", proportion=0.01, time=100)
         self.assertFalse(g3.isclose(g4))
 
         g3 = copy.deepcopy(g2)
-        g3.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g3.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g3.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g3.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g3.pulse(source="d2", dest="d1", proportion=0.01, time=100)
         g4 = copy.deepcopy(g2)
-        g4.deme("d1", epochs=[Epoch(initial_size=1000, end_time=0)])
-        g4.deme("d2", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g4.deme("d1", epochs=[Epoch(start_size=1000, end_time=0)])
+        g4.deme("d2", epochs=[Epoch(start_size=1000, end_time=0)])
         g4.pulse(source="d1", dest="d2", proportion=0.01, time=100)
         self.assertFalse(g3.isclose(g4))
 
     def test_validate(self):
         g1 = demes.Graph(description="test", time_units="generations")
-        g1.deme("a", epochs=[Epoch(initial_size=1, end_time=100)])
-        g1.deme("b", epochs=[Epoch(initial_size=1, start_time=50, end_time=0)])
+        g1.deme("a", epochs=[Epoch(start_size=1, end_time=100)])
+        g1.deme("b", epochs=[Epoch(start_size=1, start_time=50, end_time=0)])
         g1.validate()
 
         #
@@ -1733,7 +1728,7 @@ def test_validate(self):
 
         # add an overlapping epoch
         g2 = copy.deepcopy(g1)
-        g2["a"].epochs.append(Epoch(start_time=200, end_time=0, initial_size=1))
+        g2["a"].epochs.append(Epoch(start_time=200, end_time=0, start_size=1))
         with self.assertRaises(ValueError):
             g2.validate()
 
@@ -1747,9 +1742,9 @@ def test_validate(self):
 
     def test_newly_created_objects_return(self):
         g = demes.Graph(description="test", time_units="generations")
-        d1 = g.deme("a", epochs=[Epoch(initial_size=1, end_time=0)])
+        d1 = g.deme("a", epochs=[Epoch(start_size=1, end_time=0)])
         self.assertIsInstance(d1, Deme)
-        d2 = g.deme("b", epochs=[Epoch(initial_size=1, start_time=50, end_time=0)])
+        d2 = g.deme("b", epochs=[Epoch(start_size=1, start_time=50, end_time=0)])
         self.assertIsInstance(d2, Deme)
 
         mig = g.migration(source="a", dest="b", rate=1e-4, end_time=25)
@@ -1767,8 +1762,8 @@ def test_deme_end_time(self):
         g.deme(
             "a",
             epochs=[
-                Epoch(end_time=100, initial_size=10),
-                Epoch(initial_size=20, end_time=0),
+                Epoch(end_time=100, start_size=10),
+                Epoch(start_size=20, end_time=0),
             ],
         )
         with self.assertRaises(ValueError):
@@ -1776,14 +1771,14 @@ def test_deme_end_time(self):
                 "a",
                 end_time=10,
                 epochs=[
-                    Epoch(end_time=100, initial_size=10),
-                    Epoch(initial_size=20, end_time=0),
+                    Epoch(end_time=100, start_size=10),
+                    Epoch(start_size=20, end_time=0),
                 ],
             )
         with self.assertRaises(ValueError):
-            g.deme("b", epochs=[Epoch(initial_size=100, start_time=100, end_time=100)])
+            g.deme("b", epochs=[Epoch(start_size=100, start_time=100, end_time=100)])
         with self.assertRaises(ValueError):
-            g.deme("b", epochs=[Epoch(initial_size=100, start_time=100, end_time=200)])
+            g.deme("b", epochs=[Epoch(start_size=100, start_time=100, end_time=200)])
 
     def test_ambiguous_epoch_times(self):
         g = demes.Graph(description="test", time_units="generations")
@@ -1791,8 +1786,8 @@ def test_ambiguous_epoch_times(self):
             g.deme(
                 "a",
                 epochs=[
-                    Epoch(start_time=100, initial_size=10),
-                    Epoch(end_time=0, initial_size=100),
+                    Epoch(start_time=100, start_size=10),
+                    Epoch(end_time=0, start_size=100),
                 ],
             )
 
@@ -1800,31 +1795,31 @@ def test_ambiguous_epoch_times(self):
 class TestGraphToDict(unittest.TestCase):
     def test_finite_start_time(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, start_time=100, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=100, start_time=100, end_time=0)])
         d = dg.asdict()
         self.assertTrue(d["demes"][0]["epochs"][0]["start_time"] == dg["a"].start_time)
 
     def test_deme_selfing_rate(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, selfing_rate=0.1, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=100, selfing_rate=0.1, end_time=0)])
         d = dg.asdict()
         self.assertTrue(d["demes"][0]["epochs"][0]["selfing_rate"] == 0.1)
 
     def test_deme_cloning_rate(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, cloning_rate=0.1, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=100, cloning_rate=0.1, end_time=0)])
         d = dg.asdict()
         self.assertTrue(d["demes"][0]["epochs"][0]["cloning_rate"] == 0.1)
         d = dg.asdict_simplified()
         self.assertTrue(d["demes"][0]["epochs"][0]["cloning_rate"] == 0.1)
-        dg.deme("b", epochs=[Epoch(initial_size=200, end_time=0)])
+        dg.deme("b", epochs=[Epoch(start_size=200, end_time=0)])
         d = dg.asdict_simplified()
         self.assertTrue("cloning_rate" not in d["demes"][1])
         dg.deme(
             "c",
             epochs=[
-                Epoch(initial_size=1, end_time=100, cloning_rate=0.3),
-                Epoch(initial_size=2, end_time=0),
+                Epoch(start_size=1, end_time=100, cloning_rate=0.3),
+                Epoch(start_size=2, end_time=0),
             ],
         )
         d = dg.asdict_simplified()
@@ -1836,8 +1831,8 @@ def test_fill_nonstandard_size_function(self):
         dg.deme(
             "a",
             epochs=[
-                Epoch(initial_size=1, end_time=10),
-                Epoch(final_size=10, size_function="linear", end_time=0),
+                Epoch(start_size=1, end_time=10),
+                Epoch(end_size=10, size_function="linear", end_time=0),
             ],
         )
         d = dg.asdict()
@@ -1849,8 +1844,8 @@ def test_fill_epoch_selfing_rates(self):
             "a",
             defaults={"selfing_rate": 0.3},
             epochs=[
-                Epoch(initial_size=10, end_time=10, selfing_rate=0.2),
-                Epoch(final_size=20, end_time=0, selfing_rate=0.1),
+                Epoch(start_size=10, end_time=10, selfing_rate=0.2),
+                Epoch(end_size=20, end_time=0, selfing_rate=0.1),
             ],
         )
         d = dg.asdict()
@@ -1861,8 +1856,8 @@ def test_fill_epoch_selfing_rates(self):
         dg.deme(
             "a",
             epochs=[
-                Epoch(initial_size=10, end_time=10),
-                Epoch(final_size=20, end_time=0, selfing_rate=0.1),
+                Epoch(start_size=10, end_time=10),
+                Epoch(end_size=20, end_time=0, selfing_rate=0.1),
             ],
         )
         d = dg.asdict()
@@ -1875,8 +1870,8 @@ def test_fill_epoch_cloning_rates(self):
             "a",
             defaults={"cloning_rate": 0.2},
             epochs=[
-                Epoch(initial_size=10, end_time=10),
-                Epoch(final_size=20, end_time=0, cloning_rate=0.1),
+                Epoch(start_size=10, end_time=10),
+                Epoch(end_size=20, end_time=0, cloning_rate=0.1),
             ],
         )
         d = dg.asdict()
@@ -1887,8 +1882,8 @@ def test_fill_epoch_cloning_rates(self):
         dg.deme(
             "a",
             epochs=[
-                Epoch(initial_size=10, end_time=10),
-                Epoch(final_size=20, end_time=0, cloning_rate=0.1),
+                Epoch(start_size=10, end_time=10),
+                Epoch(end_size=20, end_time=0, cloning_rate=0.1),
             ],
         )
         d = dg.asdict()
@@ -1897,15 +1892,15 @@ def test_fill_epoch_cloning_rates(self):
     def test_fill_description(self):
         dg = demes.Graph(description="a", time_units="generations")
         dg.deme(
-            "a", description="described", epochs=[Epoch(initial_size=100, end_time=0)]
+            "a", description="described", epochs=[Epoch(start_size=100, end_time=0)]
         )
         d = dg.asdict()
         self.assertTrue(d["demes"][0]["description"] == dg["a"].description)
 
     def test_fill_migration_bounds(self):
         dg = demes.Graph(description="a", time_units="generations")
-        dg.deme("a", epochs=[Epoch(initial_size=100, end_time=0)])
-        dg.deme("b", epochs=[Epoch(initial_size=100, end_time=0)])
+        dg.deme("a", epochs=[Epoch(start_size=100, end_time=0)])
+        dg.deme("b", epochs=[Epoch(start_size=100, end_time=0)])
         dg.migration(source="a", dest="b", rate=0.01, start_time=20, end_time=10)
         d = dg.asdict()
         self.assertTrue(d["migrations"]["asymmetric"][0]["start_time"] == 20)
@@ -1929,15 +1924,15 @@ def test_bad_custom_attributes(self):
 
     def test_multiple_symmetric_migrations(self):
         g = demes.Graph(description="descr", time_units="generations")
-        g.deme("a", epochs=[Epoch(initial_size=100, end_time=0)])
-        g.deme("b", epochs=[Epoch(initial_size=200, end_time=0)])
-        g.deme("c", epochs=[Epoch(initial_size=300, end_time=0)])
+        g.deme("a", epochs=[Epoch(start_size=100, end_time=0)])
+        g.deme("b", epochs=[Epoch(start_size=200, end_time=0)])
+        g.deme("c", epochs=[Epoch(start_size=300, end_time=0)])
         g.symmetric_migration(demes=["a", "b", "c"], rate=0.01)
         d = g.asdict_simplified()
         self.assertTrue(len(d["migrations"]["symmetric"]) == 1)
         self.assertTrue("asymmetric" not in d["migrations"])
 
-        g.deme("d", epochs=[Epoch(initial_size=400, end_time=0)])
+        g.deme("d", epochs=[Epoch(start_size=400, end_time=0)])
         g.symmetric_migration(demes=["a", "d"], rate=0.01)
         d = g.asdict_simplified()
         self.assertTrue(len(d["migrations"]["symmetric"]) == 2)
@@ -1948,10 +1943,10 @@ def test_multiple_symmetric_migrations(self):
 
     def test_mix_sym_asym_migrations(self):
         g = demes.Graph(description="a", time_units="generations")
-        g.deme("a", epochs=[Epoch(initial_size=1, start_time=100, end_time=0)])
-        g.deme("b", epochs=[Epoch(initial_size=1, end_time=0)])
-        g.deme("c", epochs=[Epoch(initial_size=1, end_time=0)])
-        g.deme("d", epochs=[Epoch(initial_size=1, end_time=0)])
+        g.deme("a", epochs=[Epoch(start_size=1, start_time=100, end_time=0)])
+        g.deme("b", epochs=[Epoch(start_size=1, end_time=0)])
+        g.deme("c", epochs=[Epoch(start_size=1, end_time=0)])
+        g.deme("d", epochs=[Epoch(start_size=1, end_time=0)])
         g.symmetric_migration(demes=["a", "b"], rate=0.01)
         g.symmetric_migration(demes=["b", "c"], rate=0.01)
         g.symmetric_migration(demes=["a", "c", "d"], rate=0.01)
diff --git a/tests/test_load_dump.py b/tests/test_load_dump.py
index e6805e2a..97a0be9b 100644
--- a/tests/test_load_dump.py
+++ b/tests/test_load_dump.py
@@ -35,78 +35,76 @@ def jacobs_papuans():
         ],
         time_units="generations",
     )
-    g.deme("ancestral_hominin", epochs=[Epoch(end_time=20225, initial_size=32671)])
+    g.deme("ancestral_hominin", epochs=[Epoch(end_time=20225, start_size=32671)])
     g.deme(
         "archaic",
         ancestors=["ancestral_hominin"],
-        epochs=[Epoch(end_time=15090, initial_size=N_archaic)],
+        epochs=[Epoch(end_time=15090, start_size=N_archaic)],
     )
 
     g.deme(
         "Den1",
         ancestors=["archaic"],
-        epochs=[Epoch(end_time=12500, initial_size=N_DeniAnc)],
+        epochs=[Epoch(end_time=12500, start_size=N_DeniAnc)],
     )
     g.deme(
         "Den2",
         ancestors=["Den1"],
-        epochs=[Epoch(end_time=9750, initial_size=N_DeniAnc)],
+        epochs=[Epoch(end_time=9750, start_size=N_DeniAnc)],
     )
     # Altai Denisovan (sampling lineage)
-    g.deme(
-        "DenAltai", ancestors=["Den2"], epochs=[Epoch(initial_size=5083, end_time=0)]
-    )
+    g.deme("DenAltai", ancestors=["Den2"], epochs=[Epoch(start_size=5083, end_time=0)])
     # Introgressing Denisovan lineages 1 and 2
     g.deme(
-        "DenI1", ancestors=["Den2"], epochs=[Epoch(initial_size=N_archaic, end_time=0)]
+        "DenI1", ancestors=["Den2"], epochs=[Epoch(start_size=N_archaic, end_time=0)]
     )
     g.deme(
-        "DenI2", ancestors=["Den1"], epochs=[Epoch(initial_size=N_archaic, end_time=0)]
+        "DenI2", ancestors=["Den1"], epochs=[Epoch(start_size=N_archaic, end_time=0)]
     )
 
     g.deme(
         "Nea",
         ancestors=["archaic"],
-        epochs=[Epoch(end_time=3375, initial_size=N_archaic)],
+        epochs=[Epoch(end_time=3375, start_size=N_archaic)],
     )
     # Altai Neanderthal (sampling lineage)
-    g.deme("NeaAltai", ancestors=["Nea"], epochs=[Epoch(initial_size=826, end_time=0)])
+    g.deme("NeaAltai", ancestors=["Nea"], epochs=[Epoch(start_size=826, end_time=0)])
     # Introgressing Neanderthal lineage
     g.deme(
-        "NeaI", ancestors=["Nea"], epochs=[Epoch(end_time=883, initial_size=N_archaic)]
+        "NeaI", ancestors=["Nea"], epochs=[Epoch(end_time=883, start_size=N_archaic)]
     )
 
     g.deme(
         "AMH",
         ancestors=["ancestral_hominin"],
-        epochs=[Epoch(end_time=2218, initial_size=41563)],
+        epochs=[Epoch(end_time=2218, start_size=41563)],
     )
-    g.deme("Africa", ancestors=["AMH"], epochs=[Epoch(initial_size=48433, end_time=0)])
+    g.deme("Africa", ancestors=["AMH"], epochs=[Epoch(start_size=48433, end_time=0)])
     g.deme(
         "Ghost1",
         ancestors=["AMH"],
-        initial_size=N_ghost,
+        start_size=N_ghost,
         epochs=[
             # bottleneck
-            demes.Epoch(end_time=2119, initial_size=1394),
-            demes.Epoch(end_time=1784, initial_size=N_ghost),
+            demes.Epoch(end_time=2119, start_size=1394),
+            demes.Epoch(end_time=1784, start_size=N_ghost),
         ],
     )
     g.deme(
         "Ghost2",
         ancestors=["Ghost1"],
-        epochs=[Epoch(end_time=1758, initial_size=N_ghost)],
+        epochs=[Epoch(end_time=1758, start_size=N_ghost)],
     )
     g.deme(
-        "Ghost3", ancestors=["Ghost2"], epochs=[Epoch(initial_size=N_ghost, end_time=0)]
+        "Ghost3", ancestors=["Ghost2"], epochs=[Epoch(start_size=N_ghost, end_time=0)]
     )
     g.deme(
         "Papua",
         ancestors=["Ghost1"],
         # bottleneck
         epochs=[
-            demes.Epoch(end_time=1685, initial_size=243),
-            demes.Epoch(end_time=0, initial_size=8834),
+            demes.Epoch(end_time=1685, start_size=243),
+            demes.Epoch(end_time=0, start_size=8834),
         ],
     )
     g.deme(
@@ -114,17 +112,17 @@ def jacobs_papuans():
         ancestors=["Ghost2"],
         # bottleneck
         epochs=[
-            demes.Epoch(end_time=T_Eu_bottleneck, initial_size=2231),
-            demes.Epoch(end_time=1293, initial_size=12971),
+            demes.Epoch(end_time=T_Eu_bottleneck, start_size=2231),
+            demes.Epoch(end_time=1293, start_size=12971),
         ],
     )
     g.deme(
         "WestEurasia",
         ancestors=["Eurasia"],
-        epochs=[Epoch(initial_size=6962, end_time=0)],
+        epochs=[Epoch(start_size=6962, end_time=0)],
     )
     g.deme(
-        "EastAsia", ancestors=["Eurasia"], epochs=[Epoch(initial_size=9025, end_time=0)]
+        "EastAsia", ancestors=["Eurasia"], epochs=[Epoch(start_size=9025, end_time=0)]
     )
 
     g.symmetric_migration(
@@ -188,7 +186,7 @@ def test_bad_format_param(self):
 
     def test_bad_filename_param(self):
         g = demes.Graph(description="test", time_units="generations")
-        g.deme("A", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g.deme("A", epochs=[Epoch(start_size=1000, end_time=0)])
 
         class F:
             pass
@@ -215,7 +213,7 @@ def check_dumps_simple(self, *, format, simplified):
             generation_time=42,
         )
         for id, N in zip("ABCD", [100, 200, 300, 400]):
-            g.deme(id, epochs=[Epoch(initial_size=N, end_time=0)])
+            g.deme(id, epochs=[Epoch(start_size=N, end_time=0)])
         string = demes.dumps(g, format=format, simplified=simplified)
         assert "description" in string
         assert g.description in string
@@ -228,7 +226,7 @@ def check_dumps_simple(self, *, format, simplified):
         assert "B" in string
         assert "C" in string
         assert "D" in string
-        assert "initial_size" in string
+        assert "start_size" in string
         assert str(100) in string
         assert str(200) in string
         assert str(300) in string
@@ -244,7 +242,7 @@ def check_dumps_simple(self, *, format, simplified):
             assert "cloning_rate" not in string
 
         g1 = copy.deepcopy(g)
-        g1.deme("E", epochs=[Epoch(initial_size=100, selfing_rate=0.1, end_time=0)])
+        g1.deme("E", epochs=[Epoch(start_size=100, selfing_rate=0.1, end_time=0)])
         string = demes.dumps(g1, format=format, simplified=simplified)
         assert "selfing_rate" in string
         assert "0.1" in string
@@ -252,7 +250,7 @@ def check_dumps_simple(self, *, format, simplified):
             assert "cloning_rate" not in string
 
         g1 = copy.deepcopy(g)
-        g1.deme("E", epochs=[Epoch(initial_size=100, cloning_rate=0.1, end_time=0)])
+        g1.deme("E", epochs=[Epoch(start_size=100, cloning_rate=0.1, end_time=0)])
         string = demes.dumps(g1, format=format, simplified=simplified)
         if simplified:
             assert "selfing_rate" not in string
@@ -327,7 +325,7 @@ def test_loads_json_simple(self):
                         "id": "A",
                         "epochs": [
                         {
-                            "initial_size": 100,
+                            "start_size": 100,
                             "end_time": 0
                         }
                         ]
@@ -336,7 +334,7 @@ def test_loads_json_simple(self):
                         "id": "B",
                         "epochs": [
                         {
-                            "initial_size": 100,
+                            "start_size": 100,
                             "end_time": 0
                         }
                         ]
@@ -348,7 +346,7 @@ def test_loads_json_simple(self):
                         "epochs": [
                         {
                             "start_time": 500,
-                            "initial_size": 100,
+                            "start_size": 100,
                             "end_time": 0
                         }
                         ]
@@ -375,15 +373,15 @@ def test_loads_yaml_simple(self):
             demes:
                 -   id: A
                     epochs:
-                        -   initial_size: 100
+                        -   start_size: 100
                             end_time: 0
                 -   id: B
                     epochs:
-                        -   initial_size: 100
+                        -   start_size: 100
                             end_time: 0
                 -   id: C
                     epochs:
-                        -   initial_size: 100
+                        -   start_size: 100
                             start_time: 500
                             end_time: 0
                     ancestors: [A, B]
@@ -421,7 +419,7 @@ def check_dump_and_load_simple(self, *, format, simplified):
             generation_time=42,
         )
         for id, N in zip("ABCD", [100, 200, 300, 400]):
-            g1.deme(id, epochs=[Epoch(initial_size=N, end_time=0)])
+            g1.deme(id, epochs=[Epoch(start_size=N, end_time=0)])
         with tempfile.TemporaryDirectory() as tmpdir:
             tmpfile = pathlib.Path(tmpdir) / "temp.txt"
             demes.dump(g1, tmpfile, format=format, simplified=simplified)
@@ -526,11 +524,11 @@ class Ne(enum.IntEnum):
         g = demes.Graph(description="test", time_units="generations")
         g.deme(
             "A",
-            initial_size=Ne.INITIAL,
+            start_size=Ne.INITIAL,
             epochs=[
-                demes.Epoch(start_time=500, end_time=400, initial_size=Ne.BOTTLENECK),
-                demes.Epoch(start_time=400, end_time=300, initial_size=Ne.NOMINAL),
-                demes.Epoch(start_time=300, end_time=200, initial_size=Ne.HUGE),
+                demes.Epoch(start_time=500, end_time=400, start_size=Ne.BOTTLENECK),
+                demes.Epoch(start_time=400, end_time=300, start_size=Ne.NOMINAL),
+                demes.Epoch(start_time=300, end_time=200, start_size=Ne.HUGE),
             ],
         )
         self.check_dump_load_roundtrip(g)
@@ -539,11 +537,11 @@ class Ne(enum.IntEnum):
         T = np.array([500, 400, 300, 200], dtype=np.int64)
         g.deme(
             "B",
-            initial_size=N[0],
+            start_size=N[0],
             epochs=[
-                demes.Epoch(start_time=T[0], end_time=T[1], initial_size=N[1]),
-                demes.Epoch(start_time=T[1], end_time=T[2], initial_size=N[2]),
-                demes.Epoch(start_time=T[2], end_time=T[3], initial_size=N[3]),
+                demes.Epoch(start_time=T[0], end_time=T[1], start_size=N[1]),
+                demes.Epoch(start_time=T[1], end_time=T[2], start_size=N[2]),
+                demes.Epoch(start_time=T[2], end_time=T[3], start_size=N[3]),
             ],
         )
         self.check_dump_load_roundtrip(g)
@@ -558,21 +556,21 @@ def test_float_subclass(self):
         )
         g.deme(
             "A",
-            initial_size=N[0],
+            start_size=N[0],
             epochs=[
-                demes.Epoch(start_time=T[0], end_time=T[1], initial_size=N[1]),
-                demes.Epoch(start_time=T[1], end_time=T[2], initial_size=N[2]),
-                demes.Epoch(start_time=T[2], end_time=T[3], initial_size=N[3]),
+                demes.Epoch(start_time=T[0], end_time=T[1], start_size=N[1]),
+                demes.Epoch(start_time=T[1], end_time=T[2], start_size=N[2]),
+                demes.Epoch(start_time=T[2], end_time=T[3], start_size=N[3]),
             ],
         )
         self.check_dump_load_roundtrip(g)
 
-        g.deme("B", epochs=[Epoch(initial_size=N[0], end_time=0)])
+        g.deme("B", epochs=[Epoch(start_size=N[0], end_time=0)])
         g.deme(
             "C",
             ancestors=["A", "B"],
             proportions=[fractions.Fraction(1, 3), fractions.Fraction(2, 3)],
-            epochs=[Epoch(initial_size=N[0], start_time=T[1], end_time=0)],
+            epochs=[Epoch(start_size=N[0], start_time=T[1], end_time=0)],
         )
         self.check_dump_load_roundtrip(g)
 
diff --git a/tests/test_moments.py b/tests/test_moments.py
index 66a50dce..ff6bea0e 100644
--- a/tests/test_moments.py
+++ b/tests/test_moments.py
@@ -63,21 +63,21 @@ def test_convert_to_generations(self):
     def test_num_lineages(self):
         # simple merge model
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=100, end_time=100)])
+        g.deme(id="anc", epochs=[Epoch(start_size=100, end_time=100)])
         g.deme(
-            id="pop1", ancestors=["anc"], epochs=[Epoch(initial_size=100, end_time=10)]
+            id="pop1", ancestors=["anc"], epochs=[Epoch(start_size=100, end_time=10)]
         )
         g.deme(
-            id="pop2", ancestors=["anc"], epochs=[Epoch(initial_size=100, end_time=10)]
+            id="pop2", ancestors=["anc"], epochs=[Epoch(start_size=100, end_time=10)]
         )
         g.deme(
-            id="pop3", ancestors=["anc"], epochs=[Epoch(initial_size=100, end_time=10)]
+            id="pop3", ancestors=["anc"], epochs=[Epoch(start_size=100, end_time=10)]
         )
         g.deme(
             id="pop",
             ancestors=["pop1", "pop2", "pop3"],
             proportions=[0.1, 0.2, 0.7],
-            epochs=[Epoch(initial_size=100, start_time=10, end_time=0)],
+            epochs=[Epoch(start_size=100, start_time=10, end_time=0)],
         )
         sampled_demes = ["pop"]
         demes_demo_events = g.list_demographic_events()
@@ -94,22 +94,16 @@ def test_num_lineages(self):
 
         # simple admix model
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=100, end_time=100)])
-        g.deme(
-            id="pop1", epochs=[Epoch(initial_size=100, end_time=0)], ancestors=["anc"]
-        )
-        g.deme(
-            id="pop2", epochs=[Epoch(initial_size=100, end_time=0)], ancestors=["anc"]
-        )
-        g.deme(
-            id="pop3", epochs=[Epoch(initial_size=100, end_time=0)], ancestors=["anc"]
-        )
+        g.deme(id="anc", epochs=[Epoch(start_size=100, end_time=100)])
+        g.deme(id="pop1", epochs=[Epoch(start_size=100, end_time=0)], ancestors=["anc"])
+        g.deme(id="pop2", epochs=[Epoch(start_size=100, end_time=0)], ancestors=["anc"])
+        g.deme(id="pop3", epochs=[Epoch(start_size=100, end_time=0)], ancestors=["anc"])
         g.deme(
             id="pop",
-            initial_size=100,
+            start_size=100,
             ancestors=["pop1", "pop2", "pop3"],
             proportions=[0.1, 0.2, 0.7],
-            epochs=[Epoch(initial_size=100, start_time=10, end_time=0)],
+            epochs=[Epoch(start_size=100, start_time=10, end_time=0)],
         )
         sampled_demes = ["pop"]
         demes_demo_events = g.list_demographic_events()
@@ -127,7 +121,7 @@ def test_num_lineages(self):
     # test basic results against moments implementation
     def test_one_pop(self):
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="Pop", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g.deme(id="Pop", epochs=[Epoch(start_size=1000, end_time=0)])
         fs = moments_.SFS(g, ["Pop"], [20])
         fs_m = moments.Demographics1D.snm([20])
         self.assertTrue(np.allclose(fs.data, fs_m.data))
@@ -136,8 +130,8 @@ def test_one_pop(self):
         g.deme(
             id="Pop",
             epochs=[
-                demes.Epoch(initial_size=1000, end_time=2000),
-                demes.Epoch(end_time=0, initial_size=10000),
+                demes.Epoch(start_size=1000, end_time=2000),
+                demes.Epoch(end_time=0, start_size=10000),
             ],
         )
         fs = moments_.SFS(g, ["Pop"], [20])
@@ -147,23 +141,23 @@ def test_one_pop(self):
 
     def test_more_than_5_demes(self):
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=1000, end_time=1000)])
+        g.deme(id="anc", epochs=[Epoch(start_size=1000, end_time=1000)])
         for i in range(6):
             g.deme(
                 id=f"pop{i}",
-                epochs=[Epoch(initial_size=1000, end_time=0)],
+                epochs=[Epoch(start_size=1000, end_time=0)],
                 ancestors=["anc"],
             )
         with self.assertRaises(ValueError):
             moments_.SFS(g, ["pop{i}" for i in range(6)], [10 for i in range(6)])
 
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=1000, end_time=1000)])
+        g.deme(id="anc", epochs=[Epoch(start_size=1000, end_time=1000)])
         for i in range(3):
             g.deme(
                 id=f"pop{i}",
                 ancestors=["anc"],
-                epochs=[Epoch(initial_size=1000, end_time=0)],
+                epochs=[Epoch(start_size=1000, end_time=0)],
             )
         with self.assertRaises(ValueError):
             moments_.SFS(
@@ -175,7 +169,7 @@ def test_more_than_5_demes(self):
 
     def test_one_pop_ancient_samples(self):
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="Pop", epochs=[Epoch(initial_size=1000, end_time=0)])
+        g.deme(id="Pop", epochs=[Epoch(start_size=1000, end_time=0)])
         fs = moments_.SFS(g, ["Pop", "Pop"], [20, 4], sample_times=[0, 100])
         fs_m = moments.Demographics1D.snm([24])
         fs_m = moments.Manips.split_1D_to_2D(fs_m, 20, 4)
@@ -195,22 +189,22 @@ def test_OOA(self):
 
     def test_simple_merge(self):
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="Anc", epochs=[Epoch(initial_size=1000, end_time=100)])
+        g.deme(id="Anc", epochs=[Epoch(start_size=1000, end_time=100)])
         g.deme(
             id="Source1",
             ancestors=["Anc"],
-            epochs=[Epoch(initial_size=2000, end_time=10)],
+            epochs=[Epoch(start_size=2000, end_time=10)],
         )
         g.deme(
             id="Source2",
             ancestors=["Anc"],
-            epochs=[Epoch(initial_size=3000, end_time=10)],
+            epochs=[Epoch(start_size=3000, end_time=10)],
         )
         g.deme(
             id="Pop",
             ancestors=["Source1", "Source2"],
             proportions=[0.8, 0.2],
-            epochs=[Epoch(initial_size=4000, start_time=10, end_time=0)],
+            epochs=[Epoch(start_size=4000, start_time=10, end_time=0)],
         )
         fs = moments_.SFS(g, ["Pop"], [20])
 
@@ -223,22 +217,22 @@ def test_simple_merge(self):
 
     def test_simple_admixture(self):
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="Anc", epochs=[Epoch(initial_size=1000, end_time=100)])
+        g.deme(id="Anc", epochs=[Epoch(start_size=1000, end_time=100)])
         g.deme(
             id="Source1",
-            epochs=[Epoch(initial_size=2000, end_time=0)],
+            epochs=[Epoch(start_size=2000, end_time=0)],
             ancestors=["Anc"],
         )
         g.deme(
             id="Source2",
-            epochs=[Epoch(initial_size=3000, end_time=0)],
+            epochs=[Epoch(start_size=3000, end_time=0)],
             ancestors=["Anc"],
         )
         g.deme(
             id="Pop",
             ancestors=["Source1", "Source2"],
             proportions=[0.8, 0.2],
-            epochs=[Epoch(initial_size=4000, start_time=10, end_time=0)],
+            epochs=[Epoch(start_size=4000, start_time=10, end_time=0)],
         )
         fs = moments_.SFS(g, ["Source1", "Source2", "Pop"], [10, 10, 10])
 
@@ -254,8 +248,8 @@ def test_simple_growth_models(self):
         g.deme(
             id="Pop",
             epochs=[
-                demes.Epoch(end_time=1000, initial_size=1000),
-                demes.Epoch(initial_size=500, final_size=5000, end_time=0),
+                demes.Epoch(end_time=1000, start_size=1000),
+                demes.Epoch(start_size=500, end_size=5000, end_time=0),
             ],
         )
         fs = moments_.SFS(g, ["Pop"], [100])
@@ -272,10 +266,10 @@ def nu_func(t):
         g.deme(
             id="Pop",
             epochs=[
-                demes.Epoch(end_time=1000, initial_size=1000),
+                demes.Epoch(end_time=1000, start_size=1000),
                 demes.Epoch(
-                    initial_size=500,
-                    final_size=5000,
+                    start_size=500,
+                    end_size=5000,
                     end_time=0,
                     size_function="linear",
                 ),
@@ -293,14 +287,14 @@ def nu_func(t):
 
     def test_simple_pulse_model(self):
         g = demes.Graph(description="test", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=1000, end_time=100)])
+        g.deme(id="anc", epochs=[Epoch(start_size=1000, end_time=100)])
         g.deme(
             id="source",
-            epochs=[Epoch(initial_size=1000, end_time=0)],
+            epochs=[Epoch(start_size=1000, end_time=0)],
             ancestors=["anc"],
         )
         g.deme(
-            id="dest", epochs=[Epoch(initial_size=1000, end_time=0)], ancestors=["anc"]
+            id="dest", epochs=[Epoch(start_size=1000, end_time=0)], ancestors=["anc"]
         )
         g.pulse(source="source", dest="dest", time=10, proportion=0.1)
         fs = moments_.SFS(g, ["source", "dest"], [20, 20])
@@ -314,15 +308,15 @@ def test_simple_pulse_model(self):
 
     def test_n_way_split(self):
         g = demes.Graph(description="three-way", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=1000, end_time=10)])
+        g.deme(id="anc", epochs=[Epoch(start_size=1000, end_time=10)])
         g.deme(
-            id="deme1", epochs=[Epoch(initial_size=1000, end_time=0)], ancestors=["anc"]
+            id="deme1", epochs=[Epoch(start_size=1000, end_time=0)], ancestors=["anc"]
         )
         g.deme(
-            id="deme2", epochs=[Epoch(initial_size=1000, end_time=0)], ancestors=["anc"]
+            id="deme2", epochs=[Epoch(start_size=1000, end_time=0)], ancestors=["anc"]
         )
         g.deme(
-            id="deme3", epochs=[Epoch(initial_size=1000, end_time=0)], ancestors=["anc"]
+            id="deme3", epochs=[Epoch(start_size=1000, end_time=0)], ancestors=["anc"]
         )
         ns = [10, 15, 20]
         fs = moments_.SFS(g, ["deme1", "deme2", "deme3"], ns)
@@ -344,27 +338,27 @@ def test_n_way_split(self):
 
     def test_n_way_admixture(self):
         g = demes.Graph(description="three-way merge", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=1000, end_time=100)])
+        g.deme(id="anc", epochs=[Epoch(start_size=1000, end_time=100)])
         g.deme(
             id="source1",
-            epochs=[Epoch(initial_size=1000, end_time=10)],
+            epochs=[Epoch(start_size=1000, end_time=10)],
             ancestors=["anc"],
         )
         g.deme(
             id="source2",
-            epochs=[Epoch(initial_size=1000, end_time=10)],
+            epochs=[Epoch(start_size=1000, end_time=10)],
             ancestors=["anc"],
         )
         g.deme(
             id="source3",
-            epochs=[Epoch(initial_size=1000, end_time=10)],
+            epochs=[Epoch(start_size=1000, end_time=10)],
             ancestors=["anc"],
         )
         g.deme(
             id="merged",
             ancestors=["source1", "source2", "source3"],
             proportions=[0.5, 0.2, 0.3],
-            epochs=[Epoch(initial_size=1000, start_time=10, end_time=0)],
+            epochs=[Epoch(start_size=1000, start_time=10, end_time=0)],
         )
         ns = [10]
         fs = moments_.SFS(g, ["merged"], ns)
@@ -380,27 +374,27 @@ def test_n_way_admixture(self):
         self.assertTrue(np.allclose(fs_m.data, fs.data))
 
         g = demes.Graph(description="three-way admix", time_units="generations")
-        g.deme(id="anc", epochs=[Epoch(initial_size=1000, end_time=100)])
+        g.deme(id="anc", epochs=[Epoch(start_size=1000, end_time=100)])
         g.deme(
             id="source1",
-            epochs=[Epoch(initial_size=1000, end_time=0)],
+            epochs=[Epoch(start_size=1000, end_time=0)],
             ancestors=["anc"],
         )
         g.deme(
             id="source2",
-            epochs=[Epoch(initial_size=1000, end_time=0)],
+            epochs=[Epoch(start_size=1000, end_time=0)],
             ancestors=["anc"],
         )
         g.deme(
             id="source3",
-            epochs=[Epoch(initial_size=1000, end_time=0)],
+            epochs=[Epoch(start_size=1000, end_time=0)],
             ancestors=["anc"],
         )
         g.deme(
             id="admixed",
             ancestors=["source1", "source2", "source3"],
             proportions=[0.5, 0.2, 0.3],
-            epochs=[Epoch(initial_size=1000, start_time=10, end_time=0)],
+            epochs=[Epoch(start_size=1000, start_time=10, end_time=0)],
         )
         ns = [10]
         fs = moments_.SFS(g, ["admixed"], ns)