"""AI01 lab, step 8: teach a tiny network XOR with gradient descent.Run it when step 8 passes: python train.py # trains and prints the loss every 25 steps python train.py --viz # also writes out/xor.html (loss curve + decision map)"""importargparseimportrandomfromnnimportMLP# XOR: the output is +1 when exactly one input is 1, and -1 otherwise.# No single straight line separates the +1 points from the -1 points, which# is why the network needs a hidden layer.XS=[[0.0,0.0],[0.0,1.0],[1.0,0.0],[1.0,1.0]]YS=[-1.0,1.0,1.0,-1.0]defmse_loss(preds,targets):"""Mean squared error: the average of (pred - target)**2 over the examples. preds a list of Values (the model's outputs). targets a list of floats, the same length. Return one Value, so you can call backward() on it. """raiseNotImplementedError("Step 8: mse_loss")deftrain_step(model,xs,ys,lr):"""One step of gradient descent on the whole dataset. Return the loss as a float. 1. Zero every parameter's grad. Never assume they are already clean. 2. Forward: predict every example in xs and compute mse_loss against ys. 3. Backward: loss.backward(). 4. Update: move every parameter a step of size lr against its gradient. Return the loss from step 2 (computed before the update), as a float. """raiseNotImplementedError("Step 8: train_step")deftrain(model,xs,ys,steps,lr):"""Run train_step `steps` times. Return the list of losses, one per step."""raiseNotImplementedError("Step 8: train")defmain():parser=argparse.ArgumentParser(description=__doc__.splitlines()[0])parser.add_argument("--steps",type=int,default=400)parser.add_argument("--lr",type=float,default=0.1)parser.add_argument("--seed",type=int,default=1)parser.add_argument("--viz",action="store_true",help="write out/xor.html")args=parser.parse_args()random.seed(args.seed)model=MLP(2,[4,4,1])losses=train(model,XS,YS,args.steps,args.lr)forstepinrange(0,args.steps,25):print(f"step {step:4d} loss {losses[step]:.5f}")print(f"final loss {losses[-1]:.5f}")forx,yinzip(XS,YS):print(f"input {x} target {y:+.0f} prediction {model(x).data:+.3f}")ifargs.viz:importsysfrompathlibimportPathsys.path.insert(0,str(Path(__file__).resolve().parents[1]/"tools"))importvizpath=viz.plot_training(losses,model,XS,YS,"out/xor.html")print("wrote",path)if__name__=="__main__":main()