Theano 实例:Softmax 回归

MNIST 数据集的下载和导入

MNIST 数据集 是一个手写数字组成的数据集,现在被当作一个机器学习算法评测的基准数据集。

这是一个下载并解压数据的脚本:

In [1]:

  1. %%file download_mnist.py
  2. import os
  3. import os.path
  4. import urllib
  5. import gzip
  6. import shutil
  7.  
  8. if not os.path.exists('mnist'):
  9. os.mkdir('mnist')
  10.  
  11. def download_and_gzip(name):
  12. if not os.path.exists(name + '.gz'):
  13. urllib.urlretrieve('http://yann.lecun.com/exdb/' + name + '.gz', name + '.gz')
  14. if not os.path.exists(name):
  15. with gzip.open(name + '.gz', 'rb') as f_in, open(name, 'wb') as f_out:
  16. shutil.copyfileobj(f_in, f_out)
  17.  
  18. download_and_gzip('mnist/train-images-idx3-ubyte')
  19. download_and_gzip('mnist/train-labels-idx1-ubyte')
  20. download_and_gzip('mnist/t10k-images-idx3-ubyte')
  21. download_and_gzip('mnist/t10k-labels-idx1-ubyte')
  1. Overwriting download_mnist.py

可以运行这个脚本来下载和解压数据:

In [2]:

  1. %run download_mnist.py

使用如下的脚本来导入 MNIST 数据,源码地址:

https://github.com/Newmu/Theano-Tutorials/blob/master/load.py

In [3]:

  1. %%file load.py
  2. import numpy as np
  3. import os
  4.  
  5. datasets_dir = './'
  6.  
  7. def one_hot(x,n):
  8. if type(x) == list:
  9. x = np.array(x)
  10. x = x.flatten()
  11. o_h = np.zeros((len(x),n))
  12. o_h[np.arange(len(x)),x] = 1
  13. return o_h
  14.  
  15. def mnist(ntrain=60000,ntest=10000,onehot=True):
  16. data_dir = os.path.join(datasets_dir,'mnist/')
  17. fd = open(os.path.join(data_dir,'train-images-idx3-ubyte'))
  18. loaded = np.fromfile(file=fd,dtype=np.uint8)
  19. trX = loaded[16:].reshape((60000,28*28)).astype(float)
  20.  
  21. fd = open(os.path.join(data_dir,'train-labels-idx1-ubyte'))
  22. loaded = np.fromfile(file=fd,dtype=np.uint8)
  23. trY = loaded[8:].reshape((60000))
  24.  
  25. fd = open(os.path.join(data_dir,'t10k-images-idx3-ubyte'))
  26. loaded = np.fromfile(file=fd,dtype=np.uint8)
  27. teX = loaded[16:].reshape((10000,28*28)).astype(float)
  28.  
  29. fd = open(os.path.join(data_dir,'t10k-labels-idx1-ubyte'))
  30. loaded = np.fromfile(file=fd,dtype=np.uint8)
  31. teY = loaded[8:].reshape((10000))
  32.  
  33. trX = trX/255.
  34. teX = teX/255.
  35.  
  36. trX = trX[:ntrain]
  37. trY = trY[:ntrain]
  38.  
  39. teX = teX[:ntest]
  40. teY = teY[:ntest]
  41.  
  42. if onehot:
  43. trY = one_hot(trY, 10)
  44. teY = one_hot(teY, 10)
  45. else:
  46. trY = np.asarray(trY)
  47. teY = np.asarray(teY)
  48.  
  49. return trX,teX,trY,teY
  1. Overwriting load.py

softmax 回归

Softmax 回归相当于 Logistic 回归的一个一般化,Logistic 回归处理的是两类问题,Softmax 回归处理的是 N 类问题。

Logistic 回归输出的是标签为 1 的概率(标签为 0 的概率也就知道了),对应地,对 N 类问题 Softmax 输出的是每个类对应的概率。

具体的内容,可以参考 UFLDL 教程:

http://ufldl.stanford.edu/wiki/index.php/Softmax%E5%9B%9E%E5%BD%92

In [4]:

  1. import theano
  2. from theano import tensor as T
  3. import numpy as np
  4. from load import mnist
  1. Using gpu device 1: Tesla C2075 (CNMeM is disabled)

我们来看它具体的实现。

这两个函数一个是将数据转化为 GPU 计算的类型,另一个是初始化权重:

In [5]:

  1. def floatX(X):
  2. return np.asarray(X, dtype=theano.config.floatX)
  3.  
  4. def init_weights(shape):
  5. return theano.shared(floatX(np.random.randn(*shape) * 0.01))

Softmax 的模型在 theano 中已经实现好了:

In [6]:

  1. A = T.matrix()
  2.  
  3. B = T.nnet.softmax(A)
  4.  
  5. test_softmax = theano.function([A], B)
  6.  
  7. a = floatX(np.random.rand(3, 4))
  8.  
  9. b = test_softmax(a)
  10.  
  11. print b.shape
  12.  
  13. # 行和
  14. print b.sum(1)
  1. (3, 4)
  2. [ 1.00000012 1. 1. ]

softmax 函数会按照行对矩阵进行 Softmax 归一化。

所以我们的模型为:

In [7]:

  1. def model(X, w):
  2. return T.nnet.softmax(T.dot(X, w))

导入数据:

In [8]:

  1. trX, teX, trY, teY = mnist(onehot=True)

定义变量,并初始化权重:

In [9]:

  1. X = T.fmatrix()
  2. Y = T.fmatrix()
  3.  
  4. w = init_weights((784, 10))

定义模型输出和预测:

In [10]:

  1. py_x = model(X, w)
  2. y_pred = T.argmax(py_x, axis=1)

损失函数为多类的交叉熵,这个在 theano 中也被定义好了:

In [11]:

  1. cost = T.mean(T.nnet.categorical_crossentropy(py_x, Y))
  2. gradient = T.grad(cost=cost, wrt=w)
  3. update = [[w, w - gradient * 0.05]]

编译 trainpredict 函数:

In [12]:

  1. train = theano.function(inputs=[X, Y], outputs=cost, updates=update, allow_input_downcast=True)
  2. predict = theano.function(inputs=[X], outputs=y_pred, allow_input_downcast=True)

迭代 100 次,测试集正确率为 0.925:

In [13]:

  1. for i in range(100):
  2. for start, end in zip(range(0, len(trX), 128), range(128, len(trX), 128)):
  3. cost = train(trX[start:end], trY[start:end])
  4. print "{0:03d}".format(i), np.mean(np.argmax(teY, axis=1) == predict(teX))
  1. 000 0.8862
  2. 001 0.8985
  3. 002 0.9042
  4. 003 0.9084
  5. 004 0.9104
  6. 005 0.9121
  7. 006 0.9121
  8. 007 0.9142
  9. 008 0.9158
  10. 009 0.9163
  11. 010 0.9162
  12. 011 0.9166
  13. 012 0.9171
  14. 013 0.9176
  15. 014 0.9182
  16. 015 0.9182
  17. 016 0.9184
  18. 017 0.9188
  19. 018 0.919
  20. 019 0.919
  21. 020 0.9194
  22. 021 0.9201
  23. 022 0.9204
  24. 023 0.9203
  25. 024 0.9205
  26. 025 0.9207
  27. 026 0.9207
  28. 027 0.9209
  29. 028 0.9214
  30. 029 0.9213
  31. 030 0.9212
  32. 031 0.9211
  33. 032 0.9217
  34. 033 0.9217
  35. 034 0.9217
  36. 035 0.922
  37. 036 0.9222
  38. 037 0.922
  39. 038 0.922
  40. 039 0.9218
  41. 040 0.9219
  42. 041 0.9223
  43. 042 0.9225
  44. 043 0.9226
  45. 044 0.9227
  46. 045 0.9225
  47. 046 0.9227
  48. 047 0.9231
  49. 048 0.9231
  50. 049 0.9231
  51. 050 0.9232
  52. 051 0.9232
  53. 052 0.9231
  54. 053 0.9231
  55. 054 0.9233
  56. 055 0.9233
  57. 056 0.9237
  58. 057 0.9239
  59. 058 0.9239
  60. 059 0.9239
  61. 060 0.924
  62. 061 0.9242
  63. 062 0.9242
  64. 063 0.9243
  65. 064 0.9243
  66. 065 0.9244
  67. 066 0.9244
  68. 067 0.9244
  69. 068 0.9245
  70. 069 0.9244
  71. 070 0.9244
  72. 071 0.9245
  73. 072 0.9244
  74. 073 0.9243
  75. 074 0.9243
  76. 075 0.9244
  77. 076 0.9243
  78. 077 0.9242
  79. 078 0.9244
  80. 079 0.9244
  81. 080 0.9243
  82. 081 0.9242
  83. 082 0.9239
  84. 083 0.9241
  85. 084 0.9242
  86. 085 0.9243
  87. 086 0.9244
  88. 087 0.9243
  89. 088 0.9243
  90. 089 0.9244
  91. 090 0.9246
  92. 091 0.9246
  93. 092 0.9246
  94. 093 0.9247
  95. 094 0.9246
  96. 095 0.9246
  97. 096 0.9246
  98. 097 0.9246
  99. 098 0.9246
  100. 099 0.9248

原文: https://nbviewer.jupyter.org/github/lijin-THU/notes-python/blob/master/09-theano/09.10-softmax-on-mnist.ipynb