{
  "source_file": "0930",
  "source_platform": "研究机构",
  "author": "PyTorch Tutorials",
  "title_listed": "NLP from Scratch: Classifying Names with RNN",
  "keywords": "RNN,NLP,字符级",
  "domain": "文本处理",
  "content_type": "教程",
  "is_paid_flag": "否",
  "url": "https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html",
  "publish_date": "持续更新",
  "corpus_stage": "文本处理",
  "notes": "字符级 RNN 分类",
  "id": "b5dd6f8bf6d3",
  "collected_at": "2026-10-02T16:42:21",
  "title": "NLP From Scratch: Classifying Names with a Character-Level RNN — PyTorch Tutorials 2.14.0+cu130 documentation",
  "body_markdown": "Note\nGo to the end\nto download the full example code.\nNLP From Scratch: Classifying Names with a Character-Level RNN\n#\nCreated On: Mar 24, 2017 | Last Updated: Nov 11, 2025 | Last Verified: Nov 05, 2024\nAuthor\n:\nSean Robertson\nThis tutorials is part of a three-part series:\nNLP From Scratch: Classifying Names with a Character-Level RNN\nNLP From Scratch: Generating Names with a Character-Level RNN\nNLP From Scratch: Translation with a Sequence to Sequence Network and Attention\nWe will be building and training a basic character-level Recurrent Neural\nNetwork (RNN) to classify words. This tutorial, along with two other\nNatural Language Processing (NLP) “from scratch” tutorials\nNLP From Scratch: Generating Names with a Character-Level RNN\nand\nNLP From Scratch: Translation with a Sequence to Sequence Network and Attention\n, show how to\npreprocess data to model NLP. In particular, these tutorials show how\npreprocessing to model NLP works at a low level.\nA character-level RNN reads words as a series of characters -\noutputting a prediction and “hidden state” at each step, feeding its\nprevious hidden state into each next step. We take the final prediction\nto be the output, i.e. which class the word belongs to.\nSpecifically, we’ll train on a few thousand surnames from 18 languages\nof origin, and predict which language a name is from based on the\nspelling.\nRecommended Preparation\n#\nBefore starting this tutorial it is recommended that you have installed PyTorch,\nand have a basic understanding of Python programming language and Tensors:\nhttps://pytorch.org/\nFor installation instructions\nDeep Learning with PyTorch: A 60 Minute Blitz\nto get started with PyTorch in general\nand learn the basics of Tensors\nLearning PyTorch with Examples\nfor a wide and deep overview\nPyTorch for Former Torch Users\nif you are former Lua Torch user\nIt would also be useful to know about RNNs and how they work:\nThe Unreasonable Effectiveness of Recurrent Neural\nNetworks\nshows a bunch of real life examples\nUnderstanding LSTM\nNetworks\nis about LSTMs specifically but also informative about RNNs in\ngeneral\nPreparing Torch\n#\nSet up torch to default to the right device use GPU acceleration depending on your hardware (CPU or CUDA).\nimport\ntorch\n# Check if CUDA is available\ndevice\n=\ntorch\n.\ndevice\n(\n'cpu'\n)\nif\ntorch\n.\ncuda\n.\nis_available\n():\ndevice\n=\ntorch\n.\ndevice\n(\n'cuda'\n)\ntorch\n.\nset_default_device\n(\ndevice\n)\nprint\n(\nf\n\"Using device =\n{\ntorch\n.\nget_default_device\n()\n}\n\"\n)\nUsing device = cuda:0\nPreparing the Data\n#\nDownload the data from\nhere\nand extract it to the current directory.\nIncluded in the\ndata/names\ndirectory are 18 text files named as\n[Language].txt\n. Each file contains a bunch of names, one name per\nline, mostly romanized (but we still need to convert from Unicode to\nASCII).\nThe first step is to define and clean our data. Initially, we need to convert Unicode to plain ASCII to\nlimit the RNN input layers. This is accomplished by converting Unicode strings to ASCII and allowing only a small set of allowed characters.\nimport\nstring\nimport\nunicodedata\n# We can use \"_\" to represent an out-of-vocabulary character, that is, any character we are not handling in our model\nallowed_characters\n=\nstring\n.\nascii_letters\n+\n\" .,;'\"\n+\n\"_\"\nn_letters\n=\nlen\n(\nallowed_characters\n)\n# Turn a Unicode string to plain ASCII, thanks to https://stackoverflow.com/a/518232/2809427\ndef\nunicodeToAscii\n(\ns\n):\nreturn\n''\n.\njoin\n(\nc\nfor\nc\nin\nunicodedata\n.\nnormalize\n(\n'NFD'\n,\ns\n)\nif\nunicodedata\n.\ncategory\n(\nc\n)\n!=\n'Mn'\nand\nc\nin\nallowed_characters\n)\nHere’s an example of converting a unicode alphabet name to plain ASCII. This simplifies the input layer\nprint\n(\nf\n\"converting 'Ślusàrski' to\n{\nunicodeToAscii\n(\n'Ślusàrski'\n)\n}\n\"\n)\nconverting 'Ślusàrski' to Slusarski\nTurning Names into Tensors\n#\nNow that we have all the names organized, we need to turn them into\nTensors to make any use of them.\nTo represent a single letter, we use a “one-hot vector” of size\n<1\nx\nn_letters>\n. A one-hot vector is filled with 0s except for a 1\nat index of the current letter, e.g.\n\"b\"\n=\n<0\n1\n0\n0\n0\n...>\n.\nTo make a word we join a bunch of those into a 2D matrix\n<line_length\nx\n1\nx\nn_letters>\n.\nThat extra 1 dimension is because PyTorch assumes everything is in\nbatches - we’re just using a batch size of 1 here.\n# Find letter index from all_letters, e.g. \"a\" = 0\ndef\nletterToIndex\n(\nletter\n):\n# return our out-of-vocabulary character if we encounter a letter unknown to our model\nif\nletter\nnot\nin\nallowed_characters\n:\nreturn\nallowed_characters\n.\nfind\n(\n\"_\"\n)\nelse\n:\nreturn\nallowed_characters\n.\nfind\n(\nletter\n)\n# Turn a line into a <line_length x 1 x n_letters>,\n# or an array of one-hot letter vectors\ndef\nlineToTensor\n(\nline\n):\ntensor\n=\ntorch\n.\nzeros\n(\nlen\n(\nline\n),\n1\n,\nn_letters\n)\nfor\nli\n,\nletter\nin\nenumerate\n(\nline\n):\ntensor\n[\nli\n][\n0\n][\nletterToIndex\n(\nletter\n)]\n=\n1\nreturn\ntensor\nHere are some examples of how to use\nlineToTensor()\nfor a single and multiple character string.\nprint\n(\nf\n\"The letter 'a' becomes\n{\nlineToTensor\n(\n'a'\n)\n}\n\"\n)\n#notice that the first position in the tensor = 1\nprint\n(\nf\n\"The name 'Ahn' becomes\n{\nlineToTensor\n(\n'Ahn'\n)\n}\n\"\n)\n#notice 'A' sets the 27th index to 1\nThe letter 'a' becomes tensor([[[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]]], device='cuda:0')\nThe name 'Ahn' becomes tensor([[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]],\n\n        [[0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]],\n\n        [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]]], device='cuda:0')\nCongratulations, you have built the foundational tensor objects for this learning task! You can use a similar approach\nfor other RNN tasks with text.\nNext, we need to combine all our examples into a dataset so we can train, test and validate our models. For this,\nwe will use the\nDataset and DataLoader\nclasses\nto hold our dataset. Each Dataset needs to implement three functions:\n__init__\n,\n__len__\n, and\n__getitem__\n.\nfrom\nio\nimport\nopen\nimport\nglob\nimport\nos\nimport\ntime\nimport\ntorch\nfrom\ntorch.utils.data\nimport\nDataset\nclass\nNamesDataset\n(\nDataset\n):\ndef\n__init__\n(\nself\n,\ndata_dir\n):\nself\n.\ndata_dir\n=\ndata_dir\n#for provenance of the dataset\nself\n.\nload_time\n=\ntime\n.\nlocaltime\n#for provenance of the dataset\nlabels_set\n=\nset\n()\n#set of all classes\nself\n.\ndata\n=\n[]\nself\n.\ndata_tensors\n=\n[]\nself\n.\nlabels\n=\n[]\nself\n.\nlabels_tensors\n=\n[]\n#read all the ``.txt`` files in the specified directory\ntext_files\n=\nglob\n.\nglob\n(\nos\n.\npath\n.\njoin\n(\ndata_dir\n,\n'*.txt'\n))\nfor\nfilename\nin\ntext_files\n:\nlabel\n=\nos\n.\npath\n.\nsplitext\n(\nos\n.\npath\n.\nbasename\n(\nfilename\n))[\n0\n]\nlabels_set\n.\nadd\n(\nlabel\n)\nlines\n=\nopen\n(\nfilename\n,\nencoding\n=\n'utf-8'\n)\n.\nread\n()\n.\nstrip\n()\n.\nsplit\n(\n'\n\\n\n'\n)\nfor\nname\nin\nlines\n:\nself\n.\ndata\n.\nappend\n(\nname\n)\nself\n.\ndata_tensors\n.\nappend\n(\nlineToTensor\n(\nname\n))\nself\n.\nlabels\n.\nappend\n(\nlabel\n)\n#Cache the tensor representation of the labels\nself\n.\nlabels_uniq\n=\nlist\n(\nlabels_set\n)\nfor\nidx\nin\nrange\n(\nlen\n(\nself\n.\nlabels\n)):\ntemp_tensor\n=\ntorch\n.\ntensor\n([\nself\n.\nlabels_uniq\n.\nindex\n(\nself\n.\nlabels\n[\nidx\n])],\ndtype\n=\ntorch\n.\nlong\n)\nself\n.\nlabels_tensors\n.\nappend\n(\ntemp_tensor\n)\ndef\n__len__\n(\nself\n):\nreturn\nlen\n(\nself\n.\ndata\n)\ndef\n__getitem__\n(\nself\n,\nidx\n):\ndata_item\n=\nself\n.\ndata\n[\nidx\n]\ndata_label\n=\nself\n.\nlabels\n[\nidx\n]\ndata_tensor\n=\nself\n.\ndata_tensors\n[\nidx\n]\nlabel_tensor\n=\nself\n.\nlabels_tensors\n[\nidx\n]\nreturn\nlabel_tensor\n,\ndata_tensor\n,\ndata_label\n,\ndata_item\nHere we can load our example data into the\nNamesDataset\nalldata\n=\nNamesDataset\n(\n\"data/names\"\n)\nprint\n(\nf\n\"loaded\n{\nlen\n(\nalldata\n)\n}\nitems of data\"\n)\nprint\n(\nf\n\"example =\n{\nalldata\n[\n0\n]\n}\n\"\n)\nloaded 20074 items of data\nexample = (tensor([6], device='cuda:0'), tensor([[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]],\n\n        [[0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]],\n\n        [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]],\n\n        [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]],\n\n        [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]],\n\n        [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n          0., 0., 0., 0., 0., 0., 0.]]], device='cuda:0'), 'Arabic', 'Khoury')\nUsing the dataset object allows us to easily split the data into train and test sets. Here we create a 85/15\nsplit but the\ntorch.utils.data\nhas more useful utilities. Here we specify a generator since we need to use the\nsame device as PyTorch defaults to above.\ntrain_set\n,\ntest_set\n=\ntorch\n.\nutils\n.\ndata\n.\nrandom_split\n(\nalldata\n,\n[\n.85\n,\n.15\n],\ngenerator\n=\ntorch\n.\nGenerator\n(\ndevice\n=\ndevice\n)\n.\nmanual_seed\n(\n2024\n))\nprint\n(\nf\n\"train examples =\n{\nlen\n(\ntrain_set\n)\n}\n, validation examples =\n{\nlen\n(\ntest_set\n)\n}\n\"\n)\ntrain examples = 17063, validation examples = 3011\nNow we have a basic dataset containing\n20074\nexamples where each example is a pairing of label and name. We have also\nsplit the dataset into training and testing so we can validate the model that we build.\nCreating the Network\n#\nBefore autograd, creating a recurrent neural network in Torch involved\ncloning the parameters of a layer over several timesteps. The layers\nheld hidden state and gradients which are now entirely handled by the\ngraph itself. This means you can implement a RNN in a very “pure” way,\nas regular feed-forward layers.\nThis CharRNN class implements an RNN with three components.\nFirst, we use the\nnn.RNN implementation\n.\nNext, we define a layer that maps the RNN hidden layers to our output. And finally, we apply a\nsoftmax\nfunction. Using\nnn.RNN\nleads to a significant improvement in performance, such as cuDNN-accelerated kernels, versus implementing\neach layer as a\nnn.Linear\n. It also simplifies the implementation in\nforward()\n.\nimport\ntorch.nn\nas\nnn\nimport\ntorch.nn.functional\nas\nF\nclass\nCharRNN\n(\nnn\n.\nModule\n):\ndef\n__init__\n(\nself\n,\ninput_size\n,\nhidden_size\n,\noutput_size\n):\nsuper\n(\nCharRNN\n,\nself\n)\n.\n__init__\n()\nself\n.\nrnn\n=\nnn\n.\nRNN\n(\ninput_size\n,\nhidden_size\n)\nself\n.\nh2o\n=\nnn\n.\nLinear\n(\nhidden_size\n,\noutput_size\n)\nself\n.\nsoftmax\n=\nnn\n.\nLogSoftmax\n(\ndim\n=\n1\n)\ndef\nforward\n(\nself\n,\nline_tensor\n):\nrnn_out\n,\nhidden\n=\nself\n.\nrnn\n(\nline_tensor\n)\noutput\n=\nself\n.\nh2o\n(\nhidden\n[\n0\n])\noutput\n=\nself\n.\nsoftmax\n(\noutput\n)\nreturn\noutput\nWe can then create an RNN with 58 input nodes, 128 hidden nodes, and 18 outputs:\nn_hidden\n=\n128\nrnn\n=\nCharRNN\n(\nn_letters\n,\nn_hidden\n,\nlen\n(\nalldata\n.\nlabels_uniq\n))\nprint\n(\nrnn\n)\nCharRNN(\n  (rnn): RNN(58, 128)\n  (h2o): Linear(in_features=128, out_features=18, bias=True)\n  (softmax): LogSoftmax(dim=1)\n)\nAfter that we can pass our Tensor to the RNN to obtain a predicted output. Subsequently,\nwe use a helper function,\nlabel_from_output\n, to derive a text label for the class.\ndef\nlabel_from_output\n(\noutput\n,\noutput_labels\n):\ntop_n\n,\ntop_i\n=\noutput\n.\ntopk\n(\n1\n)\nlabel_i\n=\ntop_i\n[\n0\n]\n.\nitem\n()\nreturn\noutput_labels\n[\nlabel_i\n],\nlabel_i\ninput\n=\nlineToTensor\n(\n'Albert'\n)\noutput\n=\nrnn\n(\ninput\n)\n#this is equivalent to ``output = rnn.forward(input)``\nprint\n(\noutput\n)\nprint\n(\nlabel_from_output\n(\noutput\n,\nalldata\n.\nlabels_uniq\n))\ntensor([[-2.9296, -2.8874, -3.0263, -3.0041, -2.7860, -3.0096, -2.7459, -3.0404,\n         -2.8524, -2.8495, -2.7922, -2.8589, -2.8415, -2.9286, -2.8064, -2.9198,\n         -2.8885, -2.9232]], device='cuda:0', grad_fn=<LogSoftmaxBackward0>)\n('Arabic', 6)\nTraining\n#\nTraining the Network\n#\nNow all it takes to train this network is show it a bunch of examples,\nhave it make guesses, and tell it if it’s wrong.\nWe do this by defining a\ntrain()\nfunction which trains the model on a given dataset using minibatches. RNNs\nRNNs are trained similarly to other networks; therefore, for completeness, we include a batched training method here.\nThe loop (\nfor\ni\nin\nbatch\n) computes the losses for each of the items in the batch before adjusting the\nweights. This operation is repeated until the number of epochs is reached.\nimport\nrandom\nimport\nnumpy\nas\nnp\ndef\ntrain\n(\nrnn\n,\ntraining_data\n,\nn_epoch\n=\n10\n,\nn_batch_size\n=\n64\n,\nreport_every\n=\n50\n,\nlearning_rate\n=\n0.2\n,\ncriterion\n=\nnn\n.\nNLLLoss\n()):\n\"\"\"\nLearn on a batch of training_data for a specified number of iterations and reporting thresholds\n\"\"\"\n# Keep track of losses for plotting\ncurrent_loss\n=\n0\nall_losses\n=\n[]\nrnn\n.\ntrain\n()\noptimizer\n=\ntorch\n.\noptim\n.\nSGD\n(\nrnn\n.\nparameters\n(),\nlr\n=\nlearning_rate\n)\nstart\n=\ntime\n.\ntime\n()\nprint\n(\nf\n\"training on data set with n =\n{\nlen\n(\ntraining_data\n)\n}\n\"\n)\nfor\niter\nin\nrange\n(\n1\n,\nn_epoch\n+\n1\n):\nrnn\n.\nzero_grad\n()\n# clear the gradients\n# create some minibatches\n# we cannot use dataloaders because each of our names is a different length\nbatches\n=\nlist\n(\nrange\n(\nlen\n(\ntraining_data\n)))\nrandom\n.\nshuffle\n(\nbatches\n)\nbatches\n=\nnp\n.\narray_split\n(\nbatches\n,\nlen\n(\nbatches\n)\n//\nn_batch_size\n)\nfor\nidx\n,\nbatch\nin\nenumerate\n(\nbatches\n):\nbatch_loss\n=\n0\nfor\ni\nin\nbatch\n:\n#for each example in this batch\n(\nlabel_tensor\n,\ntext_tensor\n,\nlabel\n,\ntext\n)\n=\ntraining_data\n[\ni\n]\noutput\n=\nrnn\n.\nforward\n(\ntext_tensor\n)\nloss\n=\ncriterion\n(\noutput\n,\nlabel_tensor\n)\nbatch_loss\n+=\nloss\n# optimize parameters\nbatch_loss\n.\nbackward\n()\nnn\n.\nutils\n.\nclip_grad_norm_\n(\nrnn\n.\nparameters\n(),\n3\n)\noptimizer\n.\nstep\n()\noptimizer\n.\nzero_grad\n()\ncurrent_loss\n+=\nbatch_loss\n.\nitem\n()\n/\nlen\n(\nbatch\n)\nall_losses\n.\nappend\n(\ncurrent_loss\n/\nlen\n(\nbatches\n)\n)\nif\niter\n%\nreport_every\n==\n0\n:\nprint\n(\nf\n\"\n{\niter\n}\n(\n{\niter\n/\nn_epoch\n:\n.0%\n}\n):\n\\t\naverage batch loss =\n{\nall_losses\n[\n-\n1\n]\n}\n\"\n)\ncurrent_loss\n=\n0\nreturn\nall_losses\nWe can now train a dataset with minibatches for a specified number of epochs. The number of epochs for this\nexample is reduced to speed up the build. You can get better results with different parameters.\nstart\n=\ntime\n.\ntime\n()\nall_losses\n=\ntrain\n(\nrnn\n,\ntrain_set\n,\nn_epoch\n=\n27\n,\nlearning_rate\n=\n0.15\n,\nreport_every\n=\n5\n)\nend\n=\ntime\n.\ntime\n()\nprint\n(\nf\n\"training took\n{\nend\n-\nstart\n}\ns\"\n)\ntraining on data set with n = 17063\n5 (19%):         average batch loss = 0.8703744434807051\n10 (37%):        average batch loss = 0.6874526524729919\n15 (56%):        average batch loss = 0.5815612148090619\n20 (74%):        average batch loss = 0.4975119298777531\n25 (93%):        average batch loss = 0.4389242791471073\ntraining took 345.88809752464294s\nPlotting the Results\n#\nPlotting the historical loss from\nall_losses\nshows the network\nlearning:\nimport\nmatplotlib.pyplot\nas\nplt\nimport\nmatplotlib.ticker\nas\nticker\nplt\n.\nfigure\n()\nplt\n.\nplot\n(\nall_losses\n)\nplt\n.\nshow\n()\nEvaluating the Results\n#\nTo see how well the network performs on different categories, we will\ncreate a confusion matrix, indicating for every actual language (rows)\nwhich language the network guesses (columns). To calculate the confusion\nmatrix a bunch of samples are run through the network with\nevaluate()\n, which is the same as\ntrain()\nminus the backprop.\ndef\nevaluate\n(\nrnn\n,\ntesting_data\n,\nclasses\n):\nconfusion\n=\ntorch\n.\nzeros\n(\nlen\n(\nclasses\n),\nlen\n(\nclasses\n))\nrnn\n.\neval\n()\n#set to eval mode\nwith\ntorch\n.\nno_grad\n():\n# do not record the gradients during eval phase\nfor\ni\nin\nrange\n(\nlen\n(\ntesting_data\n)):\n(\nlabel_tensor\n,\ntext_tensor\n,\nlabel\n,\ntext\n)\n=\ntesting_data\n[\ni\n]\noutput\n=\nrnn\n(\ntext_tensor\n)\nguess\n,\nguess_i\n=\nlabel_from_output\n(\noutput\n,\nclasses\n)\nlabel_i\n=\nclasses\n.\nindex\n(\nlabel\n)\nconfusion\n[\nlabel_i\n][\nguess_i\n]\n+=\n1\n# Normalize by dividing every row by its sum\nfor\ni\nin\nrange\n(\nlen\n(\nclasses\n)):\ndenom\n=\nconfusion\n[\ni\n]\n.\nsum\n()\nif\ndenom\n>\n0\n:\nconfusion\n[\ni\n]\n=\nconfusion\n[\ni\n]\n/\ndenom\n# Set up plot\nfig\n=\nplt\n.\nfigure\n()\nax\n=\nfig\n.\nadd_subplot\n(\n111\n)\ncax\n=\nax\n.\nmatshow\n(\nconfusion\n.\ncpu\n()\n.\nnumpy\n())\n#numpy uses cpu here so we need to use a cpu version\nfig\n.\ncolorbar\n(\ncax\n)\n# Set up axes\nax\n.\nset_xticks\n(\nnp\n.\narange\n(\nlen\n(\nclasses\n)),\nlabels\n=\nclasses\n,\nrotation\n=\n90\n)\nax\n.\nset_yticks\n(\nnp\n.\narange\n(\nlen\n(\nclasses\n)),\nlabels\n=\nclasses\n)\n# Force label at every tick\nax\n.\nxaxis\n.\nset_major_locator\n(\nticker\n.\nMultipleLocator\n(\n1\n))\nax\n.\nyaxis\n.\nset_major_locator\n(\nticker\n.\nMultipleLocator\n(\n1\n))\n# sphinx_gallery_thumbnail_number = 2\nplt\n.\nshow\n()\nevaluate\n(\nrnn\n,\ntest_set\n,\nclasses\n=\nalldata\n.\nlabels_uniq\n)\nYou can pick out bright spots off the main axis that show which\nlanguages it guesses incorrectly, e.g. Chinese for Korean, and Spanish\nfor Italian. It seems to do very well with Greek, and very poorly with\nEnglish (perhaps because of overlap with other languages).\nExercises\n#\nGet better results with a bigger and/or better shaped network\nAdjust the hyperparameters to enhance performance, such as changing the number of epochs, batch size, and learning rate\nTry the\nnn.LSTM\nand\nnn.GRU\nlayers\nModify the size of the layers, such as increasing or decreasing the number of hidden nodes or adding additional linear layers\nCombine multiple of these RNNs as a higher level network\nTry with a different dataset of line -> label, for example:\nAny word -> language\nFirst name -> gender\nCharacter name -> writer\nPage title -> blog or subreddit\nTotal running time of the script:\n(5 minutes 52.204 seconds)\nDownload\nJupyter\nnotebook:\nchar_rnn_classification_tutorial.ipynb\nDownload\nPython\nsource\ncode:\nchar_rnn_classification_tutorial.py\nDownload\nzipped:\nchar_rnn_classification_tutorial.zip",
  "metadata": {
    "title": "NLP From Scratch: Classifying Names with a Character-Level RNN — PyTorch Tutorials 2.14.0+cu130 documentation",
    "description": null,
    "keywords": null,
    "author": null,
    "og:image": "https://docs.pytorch.org/docs/stable/_static/img/pytorch_seo.png",
    "article:modified_time": "2022-07-20T23:02:43+00:00"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 200,
    "error": ""
  },
  "code_blocks": [
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-000.txt",
      "chars": 224,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-001.txt",
      "chars": 22,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-002.txt",
      "chars": 519,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-003.txt",
      "chars": 67,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-004.txt",
      "chars": 36,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-005.txt",
      "chars": 584,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-006.txt",
      "chars": 197,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-007.txt",
      "chars": 1180,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-008.txt",
      "chars": 1600,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-009.txt",
      "chars": 116,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-010.txt",
      "chars": 1756,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-011.txt",
      "chars": 217,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-012.txt",
      "chars": 51,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-013.txt",
      "chars": 517,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-014.txt",
      "chars": 87,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-015.txt",
      "chars": 125,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-016.txt",
      "chars": 328,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-017.txt",
      "chars": 253,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-018.txt",
      "chars": 1730,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-019.txt",
      "chars": 158,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-020.txt",
      "chars": 355,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-021.txt",
      "chars": 113,
      "language": "text"
    },
    {
      "file": "attachments/b5dd6f8bf6d3/code/body-022.txt",
      "chars": 1305,
      "language": "text"
    }
  ],
  "images": [
    {
      "status": "ok",
      "url": "https://docs.pytorch.org/tutorials/_images/sphx_glr_char_rnn_classification_tutorial_001.png",
      "bytes": 16286,
      "reused": false,
      "local_path": "attachments/b5dd6f8bf6d3/images/body-d0a98a95b01229498a10.png",
      "src": "https://docs.pytorch.org/tutorials/_images/sphx_glr_char_rnn_classification_tutorial_001.png",
      "alt": "char rnn classification tutorial",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://docs.pytorch.org/tutorials/_images/sphx_glr_char_rnn_classification_tutorial_002.png",
      "bytes": 43028,
      "reused": false,
      "local_path": "attachments/b5dd6f8bf6d3/images/body-c9f352bab800490e1512.png",
      "src": "https://docs.pytorch.org/tutorials/_images/sphx_glr_char_rnn_classification_tutorial_002.png",
      "alt": "char rnn classification tutorial",
      "downloaded": true
    }
  ],
  "audio": [],
  "videos": [],
  "links": [
    {
      "href": "https://github.com/spro",
      "label": "Sean Robertson",
      "type": "a"
    },
    {
      "href": "https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html",
      "label": "NLP From Scratch: Classifying Names with a Character-Level RNN",
      "type": "a"
    },
    {
      "href": "https://pytorch.org/tutorials/intermediate/char_rnn_generation_tutorial.html",
      "label": "NLP From Scratch: Generating Names with a Character-Level RNN",
      "type": "a"
    },
    {
      "href": "https://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html",
      "label": "NLP From Scratch: Translation with a Sequence to Sequence Network and Attention",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/intermediate/char_rnn_generation_tutorial.html",
      "label": "NLP From Scratch: Generating Names with a Character-Level RNN",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html",
      "label": "NLP From Scratch: Translation with a Sequence to Sequence Network and Attention",
      "type": "a"
    },
    {
      "href": "https://pytorch.org/",
      "label": "https://pytorch.org/",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html",
      "label": "Deep Learning with PyTorch: A 60 Minute Blitz",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/beginner/pytorch_with_examples.html",
      "label": "Learning PyTorch with Examples",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/beginner/former_torchies_tutorial.html",
      "label": "PyTorch for Former Torch Users",
      "type": "a"
    },
    {
      "href": "https://karpathy.github.io/2015/05/21/rnn-effectiveness/",
      "label": "The Unreasonable Effectiveness of Recurrent Neural\nNetworks",
      "type": "a"
    },
    {
      "href": "https://colah.github.io/posts/2015-08-Understanding-LSTMs/",
      "label": "Understanding LSTM\nNetworks",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/tensor_attributes.html",
      "label": "device",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.cuda.is_available.html",
      "label": "torch . cuda . is_available",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.set_default_device.html",
      "label": "torch . set_default_device",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.get_default_device.html",
      "label": "torch . get_default_device",
      "type": "a"
    },
    {
      "href": "https://download.pytorch.org/tutorial/data.zip",
      "label": "here",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.zeros.html",
      "label": "torch . zeros",
      "type": "a"
    },
    {
      "href": "https://pytorch.org/tutorials/beginner/basics/data_tutorial.html",
      "label": "Dataset and DataLoader",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/data.html",
      "label": "Dataset",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.tensor.html",
      "label": "torch . tensor",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.Generator.html",
      "label": "torch . Generator",
      "type": "a"
    },
    {
      "href": "https://pytorch.org/docs/stable/generated/torch.nn.RNN.html",
      "label": "nn.RNN implementation",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.nn.Module.html",
      "label": "nn . Module",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.nn.RNN.html",
      "label": "nn . RNN",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.nn.Linear.html",
      "label": "nn . Linear",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.nn.LogSoftmax.html",
      "label": "nn . LogSoftmax",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/tensors.html",
      "label": "output",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html",
      "label": "nn . NLLLoss",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.optim.SGD.html",
      "label": "torch . optim . SGD",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.nn.utils.clip_grad_norm_.html",
      "label": "nn . utils . clip_grad_norm_",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/docs/stable/generated/torch.no_grad.html",
      "label": "torch . no_grad",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/_downloads/13b143c2380f4768d9432d808ad50799/char_rnn_classification_tutorial.ipynb",
      "label": "Download Jupyter notebook: char_rnn_classification_tutorial.ipynb",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/_downloads/37c8905519d3fd3f437b783a48d06eac/char_rnn_classification_tutorial.py",
      "label": "Download Python source code: char_rnn_classification_tutorial.py",
      "type": "a"
    },
    {
      "href": "https://docs.pytorch.org/tutorials/_downloads/9e1d6a0463b9cd1a32b6e306664a0744/char_rnn_classification_tutorial.zip",
      "label": "Download zipped: char_rnn_classification_tutorial.zip",
      "type": "a"
    }
  ],
  "repair_version": 2,
  "repaired_at": "2026-10-14T10:53:58Z",
  "source_url": "https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html",
  "papers": [],
  "actual_video_files": [],
  "body_chars": 19132,
  "expected_body_images": 2,
  "discovery_status": "ok",
  "delivery_status": "ok",
  "missing_reason": "",
  "raw_html": "attachments/b5dd6f8bf6d3/pages/source.html",
  "local_html": "attachments/b5dd6f8bf6d3/pages/article.html",
  "body_base_path": "attachments/b5dd6f8bf6d3/pages/",
  "body_markdown_path": "attachments/b5dd6f8bf6d3/pages/article.md"
}