The code looks generally alright.
Could you check the gradients of all parameters? Maybe you are dealing with vanishing gradients?
This dummy code snippet prints valid gradients for all parameters:
input_shape = 1
model = Framework()

x = torch.randn(1, 1)
out = model(x)
out[0].mean().backward()

for name, param in model.named_parameters():
    print(name, param.grad.abs().sum())
> fc1.weight tensor(1.2002)
fc1.bias tensor(5.8217)
fc21.weight tensor(8.7014)
fc21.bias tensor(2.8945)
fc22.weight tensor(8.8635)
fc22.bias tensor(2.9484)
fc3.weight tensor(177.9702)
fc3.bias tensor(7.6872)
fc4.weight tensor(15.0663)
fc4.bias tensor(0.4998)