One approach is to have two processes in two different terminals.

First process runs training, at end of each epoch, writes the model to disk (torch.save(model.state_dict()) or something)
Second process polls for a valid checkpoint on disk, and once it detects the file, it loads it and runs the checkpoint on the validation set.

Personally, I just run train -> validation -> train -> validation, all on GPU, because GPU is kinda much faster.