--- /dev/null
+'''\r
+Digit recognition adjustment. \r
+Grid search is used to find the best parameters for SVN and KNearest classifiers.\r
+SVM adjustment follows the guidelines given in \r
+http://www.csie.ntu.edu.tw/~cjlin/papers/guide/guide.pdf\r
+\r
+Threading or cloud computing (with http://www.picloud.com/)) may be used \r
+to speedup the computation.\r
+\r
+Usage:\r
+ digits_adjust.py [--model {svm|knearest}] [--cloud] [--env <PiCloud environment>]\r
+ \r
+ --model {svm|knearest} - select the classifier (SVM is the default)\r
+ --cloud - use PiCloud computing platform (for SVM only)\r
+ --env - cloud environment name\r
+\r
+'''\r
+# TODO dataset preprocessing in cloud\r
+# TODO cloud env setup tutorial\r
+\r
+import numpy as np\r
+import cv2\r
+from multiprocessing.pool import ThreadPool\r
+\r
+from digits import *\r
+\r
+def cross_validate(model_class, params, samples, labels, kfold = 3, pool = None):\r
+ n = len(samples)\r
+ folds = np.array_split(np.arange(n), kfold)\r
+ def f(i):\r
+ model = model_class(**params)\r
+ test_idx = folds[i]\r
+ train_idx = list(folds)\r
+ train_idx.pop(i)\r
+ train_idx = np.hstack(train_idx)\r
+ train_samples, train_labels = samples[train_idx], labels[train_idx]\r
+ test_samples, test_labels = samples[test_idx], labels[test_idx]\r
+ model.train(train_samples, train_labels)\r
+ resp = model.predict(test_samples)\r
+ score = (resp != test_labels).mean()\r
+ print ".",\r
+ return score\r
+ if pool is None:\r
+ scores = map(f, xrange(kfold))\r
+ else:\r
+ scores = pool.map(f, xrange(kfold))\r
+ return np.mean(scores)\r
+\r
+def adjust_KNearest(samples, labels):\r
+ print 'adjusting KNearest ...'\r
+ best_err, best_k = np.inf, -1\r
+ for k in xrange(1, 9):\r
+ err = cross_validate(KNearest, dict(k=k), samples, labels)\r
+ if err < best_err:\r
+ best_err, best_k = err, k\r
+ print 'k = %d, error: %.2f %%' % (k, err*100)\r
+ best_params = dict(k=best_k)\r
+ print 'best params:', best_params\r
+ return best_params\r
+\r
+def adjust_SVM(samples, labels, usecloud=False, cloud_env=''):\r
+ Cs = np.logspace(0, 5, 10, base=2)\r
+ gammas = np.logspace(-7, -2, 10, base=2)\r
+ scores = np.zeros((len(Cs), len(gammas)))\r
+ scores[:] = np.nan\r
+\r
+ if usecloud:\r
+ try: \r
+ import cloud\r
+ except ImportError: \r
+ print 'cloud module is not installed'\r
+ usecloud = False\r
+ if usecloud:\r
+ print 'uploading dataset to cloud...'\r
+ np.savez('train.npz', samples=samples, labels=labels)\r
+ cloud.files.put('train.npz')\r
+\r
+ print 'adjusting SVM (may take a long time) ...'\r
+ def f(job):\r
+ i, j = job\r
+ params = dict(C = Cs[i], gamma=gammas[j])\r
+ score = cross_validate(SVM, params, samples, labels)\r
+ return i, j, score\r
+ def fcloud(job):\r
+ i, j = job\r
+ cloud.files.get('train.npz')\r
+ npz = np.load('train.npz')\r
+ params = dict(C = Cs[i], gamma=gammas[j])\r
+ score = cross_validate(SVM, params, npz['samples'], npz['labels'])\r
+ return i, j, score\r
+ \r
+ if usecloud:\r
+ jids = cloud.map(fcloud, np.ndindex(*scores.shape), _env=cloud_env, _profile=True)\r
+ ires = cloud.iresult(jids)\r
+ else:\r
+ pool = ThreadPool(processes=cv2.getNumberOfCPUs())\r
+ ires = pool.imap_unordered(f, np.ndindex(*scores.shape))\r
+\r
+ for count, (i, j, score) in enumerate(ires):\r
+ scores[i, j] = score\r
+ print '%d / %d (best error: %.2f %%, last: %.2f %%)' % (count+1, scores.size, np.nanmin(scores)*100, score*100)\r
+ print scores\r
+\r
+ i, j = np.unravel_index(scores.argmin(), scores.shape)\r
+ best_params = dict(C = Cs[i], gamma=gammas[j])\r
+ print 'best params:', best_params\r
+ print 'best error: %.2f %%' % (scores.min()*100)\r
+ return best_params\r
+\r
+if __name__ == '__main__':\r
+ import getopt\r
+ import sys\r
+ \r
+ print __doc__\r
+\r
+ args, _ = getopt.getopt(sys.argv[1:], '', ['model=', 'cloud', 'env='])\r
+ args = dict(args)\r
+ args.setdefault('--model', 'svm')\r
+ args.setdefault('--env', '')\r
+ if args['--model'] not in ['svm', 'knearest']:\r
+ print 'unknown model "%s"' % args['--model']\r
+ sys.exit(1)\r
+\r
+ digits, labels = load_digits('digits.png')\r
+ shuffle = np.random.permutation(len(digits))\r
+ digits, labels = digits[shuffle], labels[shuffle]\r
+ digits2 = map(deskew, digits)\r
+ samples = np.float32(digits2).reshape(-1, SZ*SZ) / 255.0\r
+ \r
+ t = clock()\r
+ if args['--model'] == 'knearest':\r
+ adjust_KNearest(samples, labels)\r
+ else:\r
+ adjust_SVM(samples, labels, usecloud='--cloud' in args, cloud_env = args['--env'])\r
+ print 'work time: %f s' % (clock() - t)\r
+
\ No newline at end of file