digits_adjust.py sample added
authorAlexander Mordvintsev <no@email>
Wed, 27 Jun 2012 05:51:24 +0000 (05:51 +0000)
committerAlexander Mordvintsev <no@email>
Wed, 27 Jun 2012 05:51:24 +0000 (05:51 +0000)
samples/python2/digits_adjust.py [new file with mode: 0644]

diff --git a/samples/python2/digits_adjust.py b/samples/python2/digits_adjust.py
new file mode 100644 (file)
index 0000000..3e1b6b7
--- /dev/null
@@ -0,0 +1,136 @@
+'''\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