{"record":{"id":"e07d08b25eeadc3c","repo":"d2l-ai/d2l-zh","slug":"train-acc-1-and-train-acc-0-7","errorCode":null,"errorMessage":"train_acc <= 1 and train_acc > 0.7","messagePattern":"train_acc <= 1 and train_acc > 0\\.7","errorType":"validation","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"d2l/mxnet.py","lineNumber":315,"sourceCode":"        for x, y, fmt in zip(self.X, self.Y, self.fmts):\n            self.axes[0].plot(x, y, fmt)\n        self.config_axes()\n        display.display(self.fig)\n        display.clear_output(wait=True)\n\ndef train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):\n    \"\"\"训练模型（定义见第3章）\n\n    Defined in :numref:`sec_softmax_scratch`\"\"\"\n    animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],\n                        legend=['train loss', 'train acc', 'test acc'])\n    for epoch in range(num_epochs):\n        train_metrics = train_epoch_ch3(net, train_iter, loss, updater)\n        test_acc = evaluate_accuracy(net, test_iter)\n        animator.add(epoch + 1, train_metrics + (test_acc,))\n    train_loss, train_acc = train_metrics\n    assert train_loss < 0.5, train_loss\n    assert train_acc <= 1 and train_acc > 0.7, train_acc\n    assert test_acc <= 1 and test_acc > 0.7, test_acc\n\ndef predict_ch3(net, test_iter, n=6):\n    \"\"\"预测标签（定义见第3章）\n\n    Defined in :numref:`sec_softmax_scratch`\"\"\"\n    for X, y in test_iter:\n        break\n    trues = d2l.get_fashion_mnist_labels(y)\n    preds = d2l.get_fashion_mnist_labels(d2l.argmax(net(X), axis=1))\n    titles = [true +'\\n' + pred for true, pred in zip(trues, preds)]\n    d2l.show_images(\n        d2l.reshape(X[0:n], (n, 28, 28)), 1, n, titles=titles[0:n])\n\ndef evaluate_loss(net, data_iter, loss):\n    \"\"\"评估给定数据集上模型的损失\n\n    Defined in :numref:`sec_model_selection`\"\"\"","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/d2l-ai/d2l-zh/blob/e6b18ccea71451a55fcd861d7b96fddf2587b09a/d2l/mxnet.py#L297-L333","documentation":"Python AssertionError from d2l.mxnet.train_ch3's post-training sanity check: after the final epoch, training accuracy must lie in (0.7, 1]. It guards the book's promise that softmax regression on Fashion-MNIST reaches ~0.8+ train accuracy; a value outside that band means the model underfit, diverged, or the metric computation is off.","triggerScenarios":"Final train_acc <= 0.7 because of a diverging lr, too few epochs, an updater that never updates (empty params list passed to d2l.sgd), or labels/loss mismatch (e.g. using squared loss on integer labels instead of cross_entropy). train_acc > 1 is essentially impossible unless a custom accuracy accumulator double-counts.","commonSituations":"Users shorten num_epochs in slow CPU/GPU environments; users pass net.collect_params() before initialize() so weights stay random; users swap in a custom net with a wrong output shape; mixing torch dataloaders with the mxnet training loop so y is a torch tensor and argmax comparisons silently misbehave.","solutions":["Confirm cross-entropy (d2l.cross_entropy or gluon.loss.SoftmaxCrossEntropyLoss) is the loss, not L2 loss, and labels are int32/float as the framework expects","Restore num_epochs=10 and lr=0.1 from the book before trusting the assert","Ensure net.initialize() ran and the params list handed to d2l.sgd is non-empty","Print per-epoch metrics from the Animator to see whether accuracy rises at all; flat ~0.1 accuracy means the updater is a no-op or outputs are shuffled"],"exampleFix":"// before\nloss = gluon.loss.L2Loss()\ntrain_ch3(net, train_iter, test_iter, loss, 10, updater)  # train_acc ~0.1 -> AssertionError\n// after\nloss = gluon.loss.SoftmaxCrossEntropyLoss()\ntrain_ch3(net, train_iter, test_iter, loss, 10, updater)  # train_acc ~0.85","handlingStrategy":"validation","validationCode":"# verify the metric pipeline before training\nX, y = next(iter(train_iter))\ny_hat = net(X)\nassert y_hat.shape[1] == 10, f'expected 10 logits, got {y_hat.shape}'\nassert float(loss(y_hat, y)) > 0, 'loss must be positive'\nassert updater is not None and callable(updater)","typeGuard":"def valid_train_setup(net, loss, updater, n_classes=10) -> bool:\n    return (callable(updater)\n            and 'SoftmaxCrossEntropy' in type(loss).__name__\n            and getattr(net, 'output_dim', n_classes) == n_classes)","tryCatchPattern":"try:\n    train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)\nexcept AssertionError as e:\n    value = e.args[0]\n    if value <= 0.7:\n        print('underfit: check lr, epochs, and that updater updates params')\n    raise","preventionTips":["Confirm cross-entropy loss and int/float label dtype match mxnet expectations","Pass net.collect_params().values() (non-empty) to d2l.sgd","Check the Animator each epoch: flat 0.1 accuracy means the updater is a no-op","Re-initialize the net between experiment runs"],"tags":["d2l","mxnet","assertion","training","accuracy","convergence"],"backgroundTag":null,"analyzedSha":"e6b18ccea71451a55fcd861d7b96fddf2587b09a","analyzedAt":"2026-08-14T20:05:26.414Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}