If you have parameters with requires_grad = False backward() does not compute a gradient on those.
So you could try something like:
def train():
    for batch_idx, (data, target) in enumerate(train_loader):
        optimizer.zero_grad()
        output = model(data)

        loss = criterion(output, target)
        loss.backward()
        optimizer.step()

for epoch in range(1, 6):
     if epoch == 2:
         for name, param in NN.name_parameters():
             param.require_grad = False

         # 1. add new layers to the model
         # 2. call add_param() to the optimizer
     elif epoch == 4:
         for name, param in NN.name_parameters():
             param.require_grad = True

     train()

So this would train 1 epoch on the original model. At epoch 2 new layers will be added and only the new layers will be trained until epoch 4, when the entire model un-freezes and get trained for two more epochs