├── Blog ├── 2015-10-20-DNA-Sequncer.md ├── 2016-01-23-thread-pool.md └── images │ ├── DNAsequncer │ ├── DNAsequencer.png │ ├── Model.png │ ├── PCRbridge.png │ ├── capture.png │ ├── design.png │ ├── imageprocess.png │ ├── light.png │ ├── seq1.PNG │ ├── seq2.PNG │ └── seq3.PNG │ ├── backbonechrome │ ├── notes-draft.jpg │ ├── notes-logo.jpg │ └── notes-settings.jpg │ ├── external_link.gif │ ├── external_link_on.gif │ ├── githubpages │ ├── bootcamp_1_ssh.jpg │ ├── bootcamp_1_token.jpg │ ├── bootcamp_1_win_gitbash.jpg │ ├── disqus-site.jpg │ ├── github-account-setting.png │ ├── other-pages.png │ ├── ssh-key-set.png │ └── user-pages.png │ ├── icons.gif │ ├── markdown │ └── Aaron_Swartz.jpg │ ├── other │ ├── Tabby-440.png │ ├── Tabby-pro1.png │ ├── Tabby-pro2.png │ ├── auto-edit-bar.jpg │ └── side-slide.jpg │ ├── overapi │ ├── icon-small.png │ └── overapi.jpg │ ├── rainingchrome │ ├── RainingChrome.crx │ ├── RainingChrome.pem │ ├── rain.jpg │ └── update.xml │ └── threadpool │ ├── consumer.png │ ├── producer.png │ └── threadpool.png ├── Code ├── C++ 实现高性能内存池.md ├── DesignPattern.md ├── JVM.md ├── ObjectPool.md ├── Polymorphism.md ├── Python Numpy教程.md ├── threadpool.md └── threadpool │ ├── consumer.png │ ├── producer.png │ └── threadpool.png ├── ComputerVision ├── Automatic-license-plate-recognition.md ├── FaceRecognition.md ├── Feature.md ├── ImageRetrieval.md ├── PatternRecognition.md ├── ResourcesInVisualTracking.md ├── SIF Matching with RANSAC.md ├── Saliency.md ├── Segmentation.md ├── pic │ ├── Automatic001.jpg │ ├── Automatic002.jpg │ ├── Automatic003.jpg │ ├── Automatic004.jpg │ ├── Automatic005.jpg │ ├── Automatic006.jpg │ ├── Automatic007.jpg │ ├── Automatic008.jpg │ ├── SIFT001.jpg │ ├── SIFT002.jpg │ ├── SIFT003.jpg │ └── SIFT004.jpg ├── 为什么深度学习几乎成了计算机视觉研究的标配.md ├── 二维码条形码简介.md ├── 人脸识别.md ├── 图像分类笔记.md ├── 基于深度学习的物体检测.md └── 验证码识别.md ├── LICENSE ├── ML ├── Deep Reinforcement Learning 基础知识(DQN方面).md ├── MachineLearning.md ├── OCR.md ├── RGB图像在CNN中如何进行convolution.md ├── 基于深度学习的物体检测.md └── 深度学习框架自动求导.md ├── README.md ├── RGB图像在CNN中如何进行convolution.md └── 作品 ├── 一种高通量基因测序碱基荧光图像捕获系统装置及方法专利授权证书.jpg ├── 三位重构项目.pdf ├── 中兴人工智能比赛-人脸认证.pdf ├── 书——机器视觉组态软件Xavis.pdf ├── 双目视觉动态目标测距技术研究与系统实现_终极打印版.doc └── 工业4.0.png /Blog/2015-10-20-DNA-Sequncer.md: -------------------------------------------------------------------------------- 1 | layout: post 2 | title: DNA sequncer 3 | category: project 4 | description: 高通量基因测序 5 | 6 | ##一种高通量基因测序碱基荧光图像捕获系统装置 7 | 国内目前没有一家科研机构或者企业具有生产制造商用基因测序仪的能力,基因测序仪市场是一个被国外巨头垄断的市场。 8 | 国外对基因测序技术的研究主要集中在对二代测序技术的进一步完善和对新一代单分子测序技术的研究上。 9 | 国内对基因测序技术的研究主要集中在二代测序仪器的研发、测序技术的应用推广和测序序列的分析,主要的科研机构和企业有中科院北京基因组研究所和深圳华大基因等。 10 | 11 | ###高通量基因测序技术-测序原理 12 | ![seq1](/Blog/images/DNAsequncer/seq1.PNG) 13 | 14 | ![seq2](/Blog/images/DNAsequncer/seq2.PNG) 15 | 16 | ![seq3](/Blog/images/DNAsequncer/seq3.PNG) 17 | 18 | ###基因测序硬件技术-硬件总体设计 19 | 20 | ![Model](/Blog/images/DNAsequncer/Model.png) 21 | 22 | ###桥式PCR扩增模块 23 | 24 | ![PCRbridge](/Blog/images/DNAsequncer/PCRbridge.png) 25 | 26 | ###荧光图像处理算法 27 | 28 | ![light](/Blog/images/DNAsequncer/light.png) 29 | ![imageprocess](/Blog/images/DNAsequncer/imageprocess.png) 30 | 31 | ###总体设计图 32 | 33 | ![design](/Blog/images/DNAsequncer/design.png) 34 | 35 | 36 | [ForrestPi]: http://forrestpi.github.io/ "ForrestPi" 37 | [1]: {{ page.url}} ({{ page.title }}) -------------------------------------------------------------------------------- /Blog/2016-01-23-thread-pool.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: thread pool 4 | category: project 5 | description: 线程池 6 | --- 7 | ##半同步半异步线程池## 8 | 半同步半异步模式线程池:多线程处理更灵活性 9 | 10 | 11 | ###线程池有两个活动过程:### 12 | > + 外面不停的往线程池添加任务 13 | > + 线程池内部不停的取任务执行 14 | 15 | 引入设计模式思想,实现解耦,提高代码可复用性 16 | 生产者-消费者模式 17 | > + 同步层是生产者,不断将新任务丢到排队层 18 | > + 消费者是异步层,线程执行排队层的任务 19 | > ![threadpool](/Blog/images/threadpool/threadpool.png) 20 | 21 | ###半同步半异步线程池-消费者### 22 | 23 | ![consumer](/Blog/images/threadpool/consumer.png) 24 | 25 | ###半同步半异步线程池-生产者### 26 | 27 | ![producer](/Blog/images/threadpool/producer.png) 28 | 29 | ###半同步半异步线程池特性### 30 | 半同步半异步线程池特性介绍: 31 | > + 锁机制、条件变量实现线程安全 32 | > + 右值引用、move移动语义、forward完美转发减少内存占用率 33 | > + 实现对不同系统平台以及不同编译环境的兼容性 34 | > + 半同步半异步线程池为轻量级线程池库,具有极佳的可伸缩性 35 | > + 开源、通用性强 36 | 37 | ###源码链接### 38 | > [线程池库](https://github.com/ForrestPi/Cplusplus11_project/tree/master/threadPool"ThreadPool")。 39 | 40 | 41 | 42 | 43 | [ForrestPi]: http://forrestpi.github.io/ "ForrestPi" 44 | [1]: {{ page.url}} ({{ page.title }}) -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/DNAsequencer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/DNAsequencer.png -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/Model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/Model.png -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/PCRbridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/PCRbridge.png -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/capture.png -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/design.png -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/imageprocess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/imageprocess.png -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/light.png -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/seq1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/seq1.PNG -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/seq2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/seq2.PNG -------------------------------------------------------------------------------- /Blog/images/DNAsequncer/seq3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/DNAsequncer/seq3.PNG -------------------------------------------------------------------------------- /Blog/images/backbonechrome/notes-draft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/backbonechrome/notes-draft.jpg -------------------------------------------------------------------------------- /Blog/images/backbonechrome/notes-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/backbonechrome/notes-logo.jpg -------------------------------------------------------------------------------- /Blog/images/backbonechrome/notes-settings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/backbonechrome/notes-settings.jpg -------------------------------------------------------------------------------- /Blog/images/external_link.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/external_link.gif -------------------------------------------------------------------------------- /Blog/images/external_link_on.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/external_link_on.gif -------------------------------------------------------------------------------- /Blog/images/githubpages/bootcamp_1_ssh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/bootcamp_1_ssh.jpg -------------------------------------------------------------------------------- /Blog/images/githubpages/bootcamp_1_token.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/bootcamp_1_token.jpg -------------------------------------------------------------------------------- /Blog/images/githubpages/bootcamp_1_win_gitbash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/bootcamp_1_win_gitbash.jpg -------------------------------------------------------------------------------- /Blog/images/githubpages/disqus-site.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/disqus-site.jpg -------------------------------------------------------------------------------- /Blog/images/githubpages/github-account-setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/github-account-setting.png -------------------------------------------------------------------------------- /Blog/images/githubpages/other-pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/other-pages.png -------------------------------------------------------------------------------- /Blog/images/githubpages/ssh-key-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/ssh-key-set.png -------------------------------------------------------------------------------- /Blog/images/githubpages/user-pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/githubpages/user-pages.png -------------------------------------------------------------------------------- /Blog/images/icons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/icons.gif -------------------------------------------------------------------------------- /Blog/images/markdown/Aaron_Swartz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/markdown/Aaron_Swartz.jpg -------------------------------------------------------------------------------- /Blog/images/other/Tabby-440.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/other/Tabby-440.png -------------------------------------------------------------------------------- /Blog/images/other/Tabby-pro1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/other/Tabby-pro1.png -------------------------------------------------------------------------------- /Blog/images/other/Tabby-pro2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/other/Tabby-pro2.png -------------------------------------------------------------------------------- /Blog/images/other/auto-edit-bar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/other/auto-edit-bar.jpg -------------------------------------------------------------------------------- /Blog/images/other/side-slide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/other/side-slide.jpg -------------------------------------------------------------------------------- /Blog/images/overapi/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/overapi/icon-small.png -------------------------------------------------------------------------------- /Blog/images/overapi/overapi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/overapi/overapi.jpg -------------------------------------------------------------------------------- /Blog/images/rainingchrome/RainingChrome.crx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/rainingchrome/RainingChrome.crx -------------------------------------------------------------------------------- /Blog/images/rainingchrome/RainingChrome.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOF8opuHTCeKu9XoG 3 | iqxj1MVr+nB3QJENsl7GwzoLR77240HunaLDwZDhpElXqunVNe7yWrJSlWZagmwsN 4 | U+tsQIJO43sNj7Q7g4GN97JZbng59YYXZydiktzMjAGOfww0D4O9BvrM+DdWMhFr1 5 | uwmRoUK3/duJFIww7zyMYJd1vAgMBAAECgYEAkY/G3QYLeF9MALuT4Mm9D1KpvApl 6 | JOhqQcjR3pQnRKArzDAYBByi91UyEpMAOWmNELNuRBxrezTNSjIhBZg1nMKjwdzyB 7 | Anw6qKoDqkA9FpUnla44cvHSe3Iru4cE4dg1JFk2iVm4uD1B8QD4+ZzEsbQHsJHVn 8 | PcbnxkhNx87xkCQQD2fRl7f/QrDdhOfl4Y7k/5MA2abhWVp0moXexv2SQjwOPn1t0 9 | 8gPY2PovyFHfYgWrJGgShqCNznEzF/EX9wDEjAkEA6jASjEejv0F7qXiD1X1uKG2r 10 | V3zWAxkuaGP7jM66aCrBHCxQupGFsJKD18LvuiR6wdaIJNxpAgagt1T1dVhVRQJAI 11 | ZUfwKzJNoh3XRJofZsSeE/suoqfFDmrlm3dhcue2eQw6OhkUhb79J4G8R+KyIuxYd 12 | 7SnLfMxLaZ2yuo2Y6y4wJAI3ggdwqqrF74odRU81LKCmmB2ABaUaHQu5LZGJx+8yP 13 | 2l5PGrls4CmRGf7lQobrAtPcPK7YOWXYzhVDi1GEKmQJBAOUn7dfVqDgJScNeQjwY 14 | F//SHDT1oaG0xBwGtYd5a0FxTbBy2r+gQyV462haQVjeDKuBkBFet+krLVFBGhJJ7 15 | fo= 16 | -----END PRIVATE KEY----- 17 | -------------------------------------------------------------------------------- /Blog/images/rainingchrome/rain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/rainingchrome/rain.jpg -------------------------------------------------------------------------------- /Blog/images/rainingchrome/update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Blog/images/threadpool/consumer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/threadpool/consumer.png -------------------------------------------------------------------------------- /Blog/images/threadpool/producer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/threadpool/producer.png -------------------------------------------------------------------------------- /Blog/images/threadpool/threadpool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Blog/images/threadpool/threadpool.png -------------------------------------------------------------------------------- /Code/C++ 实现高性能内存池.md: -------------------------------------------------------------------------------- 1 | # C++ 实现高性能内存池 2 | 3 | 4 | 5 | 在 C/C++ 中,内存管理是一个非常棘手的问题,我们在编写一个程序的时候几乎不可避免的要遇到内存的分配逻辑,这时候随之而来的有这样一些问题:是否有足够的内存可供分配? 分配失败了怎么办? 如何管理自身的内存使用情况? 等等一系列问题。在一个高可用的软件中,如果我们仅仅单纯的向操作系统去申请内存,当出现内存不足时就退出软件,是明显不合理的。正确的思路应该是在内存不足的时,考虑如何管理并优化自身已经使用的内存,这样才能使得软件变得更加可用。本次项目我们将实现一个内存池,并使用一个栈结构来测试我们的内存池提供的分配性能。最终,我们要实现的内存池在栈结构中的性能,要远高于使用 `std::allocator` 和 `std::vector` 6 | 7 | - C++ 中的内存分配器 `std::allocator` 8 | - 内存池技术 9 | - 手动实现模板链式栈 10 | - 链式栈和列表栈的性能比较 11 | 12 | ### 内存池简介 13 | 14 | 内存池是池化技术中的一种形式。通常我们在编写程序的时候回使用 `new` `delete` 这些关键字来向操作系统申请内存,而这样造成的后果就是每次申请内存和释放内存的时候,都需要和操作系统的系统调用打交道,从堆中分配所需的内存。如果这样的操作太过频繁,就会找成大量的内存碎片进而降低内存的分配性能,甚至出现内存分配失败的情况。 15 | 16 | 而内存池就是为了解决这个问题而产生的一种技术。从内存分配的概念上看,内存申请无非就是向内存分配方索要一个指针,当向操作系统申请内存时,操作系统需要进行复杂的内存管理调度之后,才能正确的分配出一个相应的指针。而这个分配的过程中,我们还面临着分配失败的风险。 17 | 18 | 所以,每一次进行内存分配,就会消耗一次分配内存的时间,设这个时间为 T,那么进行 n 次分配总共消耗的时间就是 nT;如果我们一开始就确定好我们可能需要多少内存,那么在最初的时候就分配好这样的一块内存区域,当我们需要内存的时候,直接从这块已经分配好的内存中使用即可,那么总共需要的分配时间仅仅只有 T。当 n 越大时,节约的时间就越多。 19 | 20 | ## 二、主函数设计 21 | 22 | 我们要设计实现一个高性能的内存池,那么自然避免不了需要对比已有的内存,而比较内存池对内存的分配性能,就需要实现一个需要对内存进行动态分配的结构(比如:链表栈),为此,可以写出如下的代码: 23 | 24 | ```c++ 25 | #include // std::cout, std::endl 26 | #include // assert() 27 | #include // clock() 28 | #include // std::vector 29 | 30 | #include "MemoryPool.hpp" // MemoryPool 31 | #include "StackAlloc.hpp" // StackAlloc 32 | 33 | // 插入元素个数 34 | #define ELEMS 10000000 35 | // 重复次数 36 | #define REPS 100 37 | 38 | int main() 39 | { 40 | clock_t start; 41 | 42 | // 使用 STL 默认分配器 43 | StackAlloc > stackDefault; 44 | start = clock(); 45 | for (int j = 0; j < REPS; j++) { 46 | assert(stackDefault.empty()); 47 | for (int i = 0; i < ELEMS; i++) 48 | stackDefault.push(i); 49 | for (int i = 0; i < ELEMS; i++) 50 | stackDefault.pop(); 51 | } 52 | std::cout << "Default Allocator Time: "; 53 | std::cout << (((double)clock() - start) / CLOCKS_PER_SEC) << "\n\n"; 54 | 55 | // 使用内存池 56 | StackAlloc > stackPool; 57 | start = clock(); 58 | for (int j = 0; j < REPS; j++) { 59 | assert(stackPool.empty()); 60 | for (int i = 0; i < ELEMS; i++) 61 | stackPool.push(i); 62 | for (int i = 0; i < ELEMS; i++) 63 | stackPool.pop(); 64 | } 65 | std::cout << "MemoryPool Allocator Time: "; 66 | std::cout << (((double)clock() - start) / CLOCKS_PER_SEC) << "\n\n"; 67 | 68 | return 0; 69 | } 70 | ``` 71 | 72 | 在上面的两段代码中,`StackAlloc` 是一个链表栈,接受两个模板参数,第一个参数是栈中的元素类型,第二个参数就是栈使用的内存分配器。 73 | 74 | 因此,这个内存分配器的模板参数就是整个比较过程中唯一的变量,使用默认分配器的模板参数为 `std::allocator`,而使用内存池的模板参数为 `MemoryPool`。 75 | 76 | > std::allocator 是 C++标准库中提供的默认分配器,他的特点就在于我们在 使用 new 来申请内存构造新对象的时候,势必要调用类对象的默认构造函数,而使用 std::allocator 则可以将内存分配和对象的构造这两部分逻辑给分离开来,使得分配的内存是原始、未构造的。 77 | 78 | 下面我们来实现这个链表栈。 79 | 80 | ## 三、模板链表栈 81 | 82 | 栈的结构非常的简单,没有什么复杂的逻辑操作,其成员函数只需要考虑两个基本的操作:入栈、出栈。为了操作上的方便,我们可能还需要这样一些方法:判断栈是否空、清空栈、获得栈顶元素。 83 | 84 | ```c++ 85 | #include 86 | 87 | template 88 | struct StackNode_ 89 | { 90 | T data; 91 | StackNode_* prev; 92 | }; 93 | 94 | // T 为存储的对象类型, Alloc 为使用的分配器, 并默认使用 std::allocator 作为对象的分配器 95 | template > 96 | class StackAlloc 97 | { 98 | public: 99 | // 使用 typedef 简化类型名 100 | typedef StackNode_ Node; 101 | typedef typename Alloc::template rebind::other allocator; 102 | 103 | // 默认构造 104 | StackAlloc() { head_ = 0; } 105 | // 默认析构 106 | ~StackAlloc() { clear(); } 107 | 108 | // 当栈中元素为空时返回 true 109 | bool empty() {return (head_ == 0);} 110 | 111 | // 释放栈中元素的所有内存 112 | void clear(); 113 | 114 | // 压栈 115 | void push(T element); 116 | 117 | // 出栈 118 | T pop(); 119 | 120 | // 返回栈顶元素 121 | T top() { return (head_->data); } 122 | 123 | private: 124 | // 125 | allocator allocator_; 126 | // 栈顶 127 | Node* head_; 128 | }; 129 | ``` 130 | 131 | 简单的逻辑诸如构造、析构、判断栈是否空、返回栈顶元素的逻辑都非常简单,直接在上面的定义中实现了,下面我们来实现 `clear()`, `push()` 和 `pop()` 这三个重要的逻辑: 132 | 133 | ```c++ 134 | // 释放栈中元素的所有内存 135 | void clear() { 136 | Node* curr = head_; 137 | // 依次出栈 138 | while (curr != 0) 139 | { 140 | Node* tmp = curr->prev; 141 | // 先析构, 再回收内存 142 | allocator_.destroy(curr); 143 | allocator_.deallocate(curr, 1); 144 | curr = tmp; 145 | } 146 | head_ = 0; 147 | } 148 | // 入栈 149 | void push(T element) { 150 | // 为一个节点分配内存 151 | Node* newNode = allocator_.allocate(1); 152 | // 调用节点的构造函数 153 | allocator_.construct(newNode, Node()); 154 | 155 | // 入栈操作 156 | newNode->data = element; 157 | newNode->prev = head_; 158 | head_ = newNode; 159 | } 160 | 161 | // 出栈 162 | T pop() { 163 | // 出栈操作 返回出栈元素 164 | T result = head_->data; 165 | Node* tmp = head_->prev; 166 | allocator_.destroy(head_); 167 | allocator_.deallocate(head_, 1); 168 | head_ = tmp; 169 | return result; 170 | } 171 | ``` 172 | 173 | ## 总结 174 | 175 | 本节我们实现了一个用于测试性能比较的模板链表栈,目前的代码如下。在下一节中,我们开始详细实现我们的高性能内存池。 176 | 177 | ```c++ 178 | // StackAlloc.hpp 179 | 180 | #ifndef STACK_ALLOC_H 181 | #define STACK_ALLOC_H 182 | 183 | #include 184 | 185 | template 186 | struct StackNode_ 187 | { 188 | T data; 189 | StackNode_* prev; 190 | }; 191 | 192 | // T 为存储的对象类型, Alloc 为使用的分配器, 193 | // 并默认使用 std::allocator 作为对象的分配器 194 | template > 195 | class StackAlloc 196 | { 197 | public: 198 | // 使用 typedef 简化类型名 199 | typedef StackNode_ Node; 200 | typedef typename Alloc::template rebind::other allocator; 201 | 202 | // 默认构造 203 | StackAlloc() { head_ = 0; } 204 | // 默认析构 205 | ~StackAlloc() { clear(); } 206 | 207 | // 当栈中元素为空时返回 true 208 | bool empty() {return (head_ == 0);} 209 | 210 | // 释放栈中元素的所有内存 211 | void clear() { 212 | Node* curr = head_; 213 | while (curr != 0) 214 | { 215 | Node* tmp = curr->prev; 216 | allocator_.destroy(curr); 217 | allocator_.deallocate(curr, 1); 218 | curr = tmp; 219 | } 220 | head_ = 0; 221 | } 222 | 223 | // 入栈 224 | void push(T element) { 225 | // 为一个节点分配内存 226 | Node* newNode = allocator_.allocate(1); 227 | // 调用节点的构造函数 228 | allocator_.construct(newNode, Node()); 229 | 230 | // 入栈操作 231 | newNode->data = element; 232 | newNode->prev = head_; 233 | head_ = newNode; 234 | } 235 | 236 | // 出栈 237 | T pop() { 238 | // 出栈操作 返回出栈结果 239 | T result = head_->data; 240 | Node* tmp = head_->prev; 241 | allocator_.destroy(head_); 242 | allocator_.deallocate(head_, 1); 243 | head_ = tmp; 244 | return result; 245 | } 246 | 247 | // 返回栈顶元素 248 | T top() { return (head_->data); } 249 | 250 | private: 251 | allocator allocator_; 252 | Node* head_; 253 | }; 254 | 255 | #endif // STACK_ALLOC_H 256 | 257 | // main.cpp 258 | 259 | #include 260 | #include 261 | #include 262 | #include 263 | 264 | // #include "MemoryPool.hpp" 265 | #include "StackAlloc.hpp" 266 | 267 | // 根据电脑性能调整这些值 268 | // 插入元素个数 269 | #define ELEMS 25000000 270 | // 重复次数 271 | #define REPS 50 272 | 273 | int main() 274 | { 275 | clock_t start; 276 | 277 | // 使用默认分配器 278 | StackAlloc > stackDefault; 279 | start = clock(); 280 | for (int j = 0; j < REPS; j++) { 281 | assert(stackDefault.empty()); 282 | for (int i = 0; i < ELEMS; i++) 283 | stackDefault.push(i); 284 | for (int i = 0; i < ELEMS; i++) 285 | stackDefault.pop(); 286 | } 287 | std::cout << "Default Allocator Time: "; 288 | std::cout << (((double)clock() - start) / CLOCKS_PER_SEC) << "\n\n"; 289 | 290 | // 使用内存池 291 | // StackAlloc > stackPool; 292 | // start = clock(); 293 | // for (int j = 0; j < REPS; j++) { 294 | // assert(stackPool.empty()); 295 | // for (int i = 0; i < ELEMS; i++) 296 | // stackPool.push(i); 297 | // for (int i = 0; i < ELEMS; i++) 298 | // stackPool.pop(); 299 | // } 300 | // std::cout << "MemoryPool Allocator Time: "; 301 | // std::cout << (((double)clock() - start) / CLOCKS_PER_SEC) << "\n\n"; 302 | 303 | return 0; 304 | } 305 | ``` 306 | 307 | ## 二、设计内存池 308 | 309 | 在节中,我们在模板链表栈中使用了默认构造器来管理栈操作中的元素内存,一共涉及到了 `rebind::other`, `allocate()`, `dealocate()`, `construct()`, `destroy()`这些关键性的接口。所以为了让代码直接可用,我们同样应该在内存池中设计同样的接口: 310 | 311 | ```c++ 312 | #ifndef MEMORY_POOL_HPP 313 | #define MEMORY_POOL_HPP 314 | 315 | #include 316 | #include 317 | 318 | template 319 | class MemoryPool 320 | { 321 | public: 322 | // 使用 typedef 简化类型书写 323 | typedef T* pointer; 324 | 325 | // 定义 rebind::other 接口 326 | template struct rebind { 327 | typedef MemoryPool other; 328 | }; 329 | 330 | // 默认构造, 初始化所有的槽指针 331 | // C++11 使用了 noexcept 来显式的声明此函数不会抛出异常 332 | MemoryPool() noexcept { 333 | currentBlock_ = nullptr; 334 | currentSlot_ = nullptr; 335 | lastSlot_ = nullptr; 336 | freeSlots_ = nullptr; 337 | } 338 | 339 | // 销毁一个现有的内存池 340 | ~MemoryPool() noexcept; 341 | 342 | // 同一时间只能分配一个对象, n 和 hint 会被忽略 343 | pointer allocate(size_t n = 1, const T* hint = 0); 344 | 345 | // 销毁指针 p 指向的内存区块 346 | void deallocate(pointer p, size_t n = 1); 347 | 348 | // 调用构造函数 349 | template 350 | void construct(U* p, Args&&... args); 351 | 352 | // 销毁内存池中的对象, 即调用对象的析构函数 353 | template 354 | void destroy(U* p) { 355 | p->~U(); 356 | } 357 | 358 | private: 359 | // 用于存储内存池中的对象槽, 360 | // 要么被实例化为一个存放对象的槽, 361 | // 要么被实例化为一个指向存放对象槽的槽指针 362 | union Slot_ { 363 | T element; 364 | Slot_* next; 365 | }; 366 | 367 | // 数据指针 368 | typedef char* data_pointer_; 369 | // 对象槽 370 | typedef Slot_ slot_type_; 371 | // 对象槽指针 372 | typedef Slot_* slot_pointer_; 373 | 374 | // 指向当前内存区块 375 | slot_pointer_ currentBlock_; 376 | // 指向当前内存区块的一个对象槽 377 | slot_pointer_ currentSlot_; 378 | // 指向当前内存区块的最后一个对象槽 379 | slot_pointer_ lastSlot_; 380 | // 指向当前内存区块中的空闲对象槽 381 | slot_pointer_ freeSlots_; 382 | 383 | // 检查定义的内存池大小是否过小 384 | static_assert(BlockSize >= 2 * sizeof(slot_type_), "BlockSize too small."); 385 | }; 386 | 387 | #endif // MEMORY_POOL_HPP 388 | ``` 389 | 390 | 在上面的类设计中可以看到,在这个内存池中,其实是使用链表来管理整个内存池的内存区块的。内存池首先会定义固定大小的基本内存区块(Block),然后在其中定义了一个可以实例化为存放对象内存槽的对象槽(Slot_)和对象槽指针的一个联合。然后在区块中,定义了四个关键性质的指针,它们的作用分别是: 391 | 392 | 1. `currentBlock_`: 指向当前内存区块的指针 393 | 2. `currentSlot_`: 指向当前内存区块中的对象槽 394 | 3. `lastSlot_`: 指向当前内存区块中的最后一个对象槽 395 | 4. `freeSlots_`: 指向当前内存区块中所有空闲的对象槽 396 | 397 | 梳理好整个内存池的设计结构之后,我们就可以开始实现关键性的逻辑了。 398 | 399 | ## 三、实现 400 | 401 | ### MemoryPool::construct() 实现 402 | 403 | `MemoryPool::construct()` 的逻辑是最简单的,我们需要实现的,仅仅只是调用信件对象的构造函数即可,因此: 404 | 405 | ```c++ 406 | // 调用构造函数, 使用 std::forward 转发变参模板 407 | template 408 | void construct(U* p, Args&&... args) { 409 | new (p) U (std::forward(args)...); 410 | } 411 | ``` 412 | 413 | ### MemoryPool::deallocate() 实现 414 | 415 | `MemoryPool::deallocate()` 是在对象槽中的对象被析构后才会被调用的,主要目的是销毁内存槽。其逻辑也不复杂: 416 | 417 | ```c++ 418 | // 销毁指针 p 指向的内存区块 419 | void deallocate(pointer p, size_t n = 1) { 420 | if (p != nullptr) { 421 | // reinterpret_cast 是强制类型转换符 422 | // 要访问 next 必须强制将 p 转成 slot_pointer_ 423 | reinterpret_cast(p)->next = freeSlots_; 424 | freeSlots_ = reinterpret_cast(p); 425 | } 426 | } 427 | ``` 428 | 429 | ### MemoryPool::~MemoryPool() 实现 430 | 431 | 析构函数负责销毁整个内存池,因此我们需要逐个删除掉最初向操作系统申请的内存块: 432 | 433 | ```c++ 434 | // 销毁一个现有的内存池 435 | ~MemoryPool() noexcept { 436 | // 循环销毁内存池中分配的内存区块 437 | slot_pointer_ curr = currentBlock_; 438 | while (curr != nullptr) { 439 | slot_pointer_ prev = curr->next; 440 | operator delete(reinterpret_cast(curr)); 441 | curr = prev; 442 | } 443 | } 444 | ``` 445 | 446 | ### MemoryPool::allocate() 实现 447 | 448 | `MemoryPool::allocate()` 毫无疑问是整个内存池的关键所在,但实际上理清了整个内存池的设计之后,其实现并不复杂。具体实现如下: 449 | 450 | ```c++ 451 | // 同一时间只能分配一个对象, n 和 hint 会被忽略 452 | pointer allocate(size_t n = 1, const T* hint = 0) { 453 | // 如果有空闲的对象槽,那么直接将空闲区域交付出去 454 | if (freeSlots_ != nullptr) { 455 | pointer result = reinterpret_cast(freeSlots_); 456 | freeSlots_ = freeSlots_->next; 457 | return result; 458 | } else { 459 | // 如果对象槽不够用了,则分配一个新的内存区块 460 | if (currentSlot_ >= lastSlot_) { 461 | // 分配一个新的内存区块,并指向前一个内存区块 462 | data_pointer_ newBlock = reinterpret_cast(operator new(BlockSize)); 463 | reinterpret_cast(newBlock)->next = currentBlock_; 464 | currentBlock_ = reinterpret_cast(newBlock); 465 | // 填补整个区块来满足元素内存区域的对齐要求 466 | data_pointer_ body = newBlock + sizeof(slot_pointer_); 467 | uintptr_t result = reinterpret_cast(body); 468 | size_t bodyPadding = (alignof(slot_type_) - result) % alignof(slot_type_); 469 | currentSlot_ = reinterpret_cast(body + bodyPadding); 470 | lastSlot_ = reinterpret_cast(newBlock + BlockSize - sizeof(slot_type_) + 1); 471 | } 472 | return reinterpret_cast(currentSlot_++); 473 | } 474 | } 475 | ``` 476 | 477 | ## 四、与 std::vector 的性能对比 478 | 479 | 我们知道,对于栈来说,链栈其实并不是最好的实现方式,因为这种结构的栈不可避免的会涉及到指针相关的操作,同时,还会消耗一定量的空间来存放节点之间的指针。事实上,我们可以使用 `std::vector` 中的 `push_back()` 和 `pop_back()` 这两个操作来模拟一个栈,我们不妨来对比一下这个 `std::vector` 与我们所实现的内存池在性能上谁高谁低,我们在 主函数中加入如下代码: 480 | 481 | ```c++ 482 | // 比较内存池和 std::vector 之间的性能 483 | std::vector stackVector; 484 | start = clock(); 485 | for (int j = 0; j < REPS; j++) { 486 | assert(stackVector.empty()); 487 | for (int i = 0; i < ELEMS; i++) 488 | stackVector.push_back(i); 489 | for (int i = 0; i < ELEMS; i++) 490 | stackVector.pop_back(); 491 | } 492 | std::cout << "Vector Time: "; 493 | std::cout << (((double)clock() - start) / CLOCKS_PER_SEC) << "\n\n"; 494 | ``` -------------------------------------------------------------------------------- /Code/DesignPattern.md: -------------------------------------------------------------------------------- 1 | ### [初学设计模式的一点感悟](http://blog.hesey.net/2011/01/thinking-in-beginning-of-design-patterns.html) 2 | 3 | 最近几个星期的时间对设计模式做了入门学习,之前读过GoF的那本《[**设计模式**](http://book.douban.com/subject/1052241/)》,感觉非常晦涩。在面向对象开发技术这门课中有设计模式的内容,这才重新拾起这个东西,发现比之前那次学明显容易多了。自己反思了一下,应该是和后来打好了比较好的面向对象思想的基础有关,所以也建议想要学习设计模式的朋友,**先把面向对象的基本思想搞明白**,起码得知道多态是干嘛用的,为什么要多态,多态有什么好处,这些问题可以看我之前写的那篇《[**浅谈多态机制的意义及实现**](http://blog.hesey.net/2010/12/significance-and-implementation-of-polymorphism.html)》。然后再来学习设计模式,才算有迹可循。 4 | 5 | 本文是对设计模式的入门学习做一些感悟和分享,希望能和大家一起多多交流关于模式的心得。 6 | 7 | # 一、基本概念 8 | 9 | > ### 1、被封装的应该是什么 10 | > 11 | > > 通常意义上,我们习惯于认为,面向对象最大的特点就像UML图一样,是由错综复杂的继承和依赖关系组成的。但是[**Alan Shalloway**](http://www.netobjectives.com/bio-alan-shalloway)认为,**对象真正的威力并不在于继承,而是来自封装行为。** 12 | > > 13 | > > 封装是面向对象三大特性之一,一般我们会认为,封装就是对类里面的实例变量进行保护,使其对外部类不可见。我们似乎很少会去关注对方法和行为的封装。就像我们经常做的:把实例变量设为private,把方法设为public,对于实例变量,我们会编写一系列set/get方法来间接修改/获得。 14 | > > 15 | > > 但是问题并不仅仅到此为止。尽管我们把数据隐藏了,但是通过set/get来操作数据,总让人感觉有一种换汤不换药的味道。一种更为深刻的思想是:**封装不仅仅是“数据隐藏”,封装应该被视为“任何形式的隐藏”。除了数据我们还可以隐藏以下各种东西:实现细节、派生类、设计细节、实例化规则。** 16 | > > 17 | > > 最简单的就是我们可以在重构代码时把某些类内部使用的方法标记为private,因为这些方法仅仅是这个类内部使用,并不想给外部类调用。另外一方面,当我们使用抽象类或是接口时,事实上就已经默许了派生和实现的封装:你不会知道这个类将会有哪些子类去继承它。而精髓恰恰在此:**通过多态实现的类型封装比单纯的数据封装有更深刻的意义。** 18 | > 19 | > ### 2、视角框架 20 | > 21 | > > [**Martin Fowler**](http://en.wikipedia.org/wiki/Martin_Fowler)提出了面向对象范型应该考虑的视角。他建议面向对象程序员应该从三个视角去考虑问题: 22 | > > 23 | > > > **1)概念视角:软件是用来做什么的;** 24 | > > > 25 | > > > **2)规约视角:提供了哪些接口(如何调用方法去完成这个任务);** 26 | > > > 27 | > > > **3)实现视角:这些接口/方法该怎么实现。** 28 | > > 29 | > > **在设计时,我们通常是从概念和规约的视角去看待问题**:首先明确软件的目的(概念视角),然后通过设计一系列接口以及接口提供的方法来对程序整体作架构设计(规约视角)。这个阶段我们并不应该过多考虑实现的细节,因为实现相比设计总是容易的。但是**初学者通常会在设计时不由自主地陷入实现的泥潭中:这个设计在代码层面该如何实现?用什么API?究其根本我认为正是因为实现相比设计更具体,这样的问题更容易解决的缘故。** 30 | > > 31 | > > **而在具体实现时,就应该从规约和实现视角去解决问题**:根据接口设计的方法(规约视角),通过实现类的代码做具体实现(实现视角),此时才应该考虑之前的问题。 32 | > 33 | > ### 3、对象究竟是什么 34 | > 35 | > > 传统上对象被视为具有方法的数据,很显然,对象是类的实例,在类这个蓝图中,包含了对象可以拥有的数据变量和方法(仔细想一想你之前对对象的认识是不是和这种观点有类似之处)。 36 | > > 37 | > > 当我们明确了封装更深刻的意义在于对行为的封装时,自然而然地,我们可以对对象作出更大的期待:**对象不仅仅是一个包裹,它应该像一个人一样,去完成一些事情。**所以,对对象更有意义的定义应该是:**对象是具有责任的一个实体。**这样我们就明确了对象的用处,同时也能让人**更加关注对象的责任,关注对象究竟该干什么而不是拥有什么。**不明确这一点,对象职责的解耦就无从谈起。 38 | > > 39 | > > 另一方面,如果我们采用[**Martin Fowler**](http://en.wikipedia.org/wiki/Martin_Fowler)的视角框架来观察对象,我们就可以从三个视角来对对象作更全面的认识: 40 | > > 41 | > > > **1)在概念层次上,对象是一组责任。** 42 | > > > 43 | > > > **2)在规约层次上,对象是一组可以被其他对象或对象自己调用的方法(也称行为)。** 44 | > > > 45 | > > > **3)在实现层次上,对象是代码和数据,以及它们之间的计算交互。** 46 | > > 47 | > > 看,之前提到的那种传统的看法**仅仅只是停留在实现层次上。** 48 | 49 | # 二、设计方法 50 | 51 | > ### 1、设计步骤 52 | > 53 | > > [**Alan Shalloway**](http://www.netobjectives.com/bio-alan-shalloway)认为,传统的**从需求分析中找出名词作为类,找出动词作为方法的设计思想是一种非常有局限性的方式,缺点之一就是会产生大量原本可能并不需要的类。** 54 | > > 55 | > > 在这里我们引入[**Jim Coplien**](http://en.wikipedia.org/wiki/Jim_Coplien)的共性分析和可变性分析的概念。 56 | > > 57 | > > **共性分析就是寻找一些共同的要素,这些要素可以帮助我们理解成员之间的共性在哪里。** 58 | > > 59 | > > **可变性分析建立在共性分析的基础之上,它要求找出元素之间的差异所在。** 60 | > > 61 | > > 具体来说,共性分析帮助我们提取出抽象类或接口作为规范的定义存在,而可变性分析则帮助我们针对这些接口进行差异化的实现。 62 | > > 63 | > > 明确这一个问题的关键目的在于,**我们需要为类组织起结构,而不仅仅是类与类之间单纯的消息传递。** 64 | > > 65 | > > 从架构的视角来看,共性分析为架构提供长效的要素(正如我们所知道的,接口通常不会变化),而可变性分析则促进它适应实际使用所需(不同的实现方式)。共通的概念用抽象类或者接口表示,可变性分析所发现的变化通过具体类实现。 66 | > 67 | > ### 2、组合优先于继承的更多优点 68 | > 69 | > > 设计模式中提倡组合优先原则,当然这是针对继承的许多缺点所做的对策。我们不妨思考一下,继承最大的优点在哪?毫无疑问,是代码复用,面向对象出现之初的一个口号就是复用代码。但是如果继承给我们带来的好处大于其坏处,那在继承时或许我们应该更保守一些。事实上,**重用并不是使用面向对象方法的根本原因。降低维护成本和使代码更加灵活、更容易扩展才是更重要的考虑因素。**为什么我们要设计?目的就在于此。使用正确的面向对象技术当然可能实现重用,但并不是通过直接使用该对象,然后派生新的变体对其重用即可达到的。这样只会产生难以维护的代码。(想想Bridge模式的初衷吧!) 70 | > 71 | > ### 3、整体和部分的关系 72 | > 73 | > > 在谈到整体与部分的关系时,我们必须介绍一本著作,[**Christopher Alexander**](http://en.wikipedia.org/wiki/Christopher_Alexander)的《[**建筑的永恒之道(The Timeless Way of Building)**](http://book.douban.com/subject/1177968/)》。这本书本来是讲建筑的,但其最受追捧的领域却是在软件界。它对模式的探讨带给软件开发人员许多思考,**软件开发是否也像建筑一样,存在某些公式化的模式,只要我们直接去套用,就能像建高楼一样。又快又好地开发出理想的软件?** 74 | > > 75 | > > 首先对这个问题的解答让人失望,直到目前为止,并不存在这样一种套路可以保证软件的质量。1986年,[**Fred Brooks**](http://en.wikipedia.org/wiki/Fred_Brooks)发表了一篇著名的论文《[**No Silver Bullet — Essence and Accidents of Software Engineering**](http://en.wikipedia.org/wiki/No_Silver_Bullet)》,“没有银弹”是许多人的遗憾,也成为软件工程师们的一个梦想。有兴许的朋友可以去读[**Scott Rosenberg**](http://www.wordyard.com/about/)的《[**梦断代码(Dreaming in Code)**](http://book.douban.com/subject/3142280/)》,这本书讲述了两打优秀的程序员在软件开发的过程中的辛酸故事,让人感慨。 76 | > > 77 | > > 《建筑的永恒之道》一书中有这么一段话:**每个部分都因其存在于更大整体的背景中而被赋予了特定的形式。**这是一个分化的过程。它把设计看成是一系列**复杂化**的活动;**结构是通过对整体操作、使其起皱而注入其中的,而不是通过一小部分一小部分添加而成。**在分化的过程中,**整体孕育了部分**:整体的形式及其各个部分是同时产生的。分化过程就好像是胚胎的成长过程。 78 | > > 79 | > > 通常我们在设计软件时都习惯于自底向上设计:先把最底层的工具类实现好,再使用这些工具类实现一些略微高层的类,再通过这些高层的类去组合成更上层的类。这似乎是理所当然的:没有下面的东西,上面的抽象怎么可能正常工作?Alexander却认为,**无论是设计什么,都应该从整体入手,在对整体的不断细化中再考虑具体的部分。** 80 | > > 81 | > > 令人感到微微诧异的是,我们在生活中正是这么做的。假设现在你想要一辆新的自行车,那么也许你会这么去描述它:首先这是一辆自行车而不是摩托车,然后它的整体颜色应该是红色,把手应该是向下弯曲的,有一个车铃在右侧把手上,后轮的中间有变速器,变速器可以调整4道变速…… 82 | > > 83 | > > 这不正是从整体到部分的层层细化吗?这正是Alexander所认为的正确的设计之道。 84 | > > 85 | > > 从这里我们不难得出一个结论:**如果我们实现从部分的角度开始考虑设计,最终将预先形成的部分(模块)组合起来,我们便无法得到一个优秀的软件设计。** 86 | > 87 | > ### 4、设计模式的用法 88 | > 89 | > > 首先,**设计模式不是万能的,更不是公式化的**,并不存在某一个问题必须套用某种模式的说法。**模式应该相互配合,共同解决问题,这才是设计模式的正确用法。** 90 | > > 91 | > > 千万不能生搬硬套模式,我个人比较倾向于去深刻体会并理解模式的思想,而不是把模式的名字都记下来,再分别细述。 92 | > > 93 | > > 模式的理想使用我认为应该是这样,举例来说,当我要使用一个旧的类而不能直接使用时,我的脑海里应该自然而然地冒出来在中间加个转换器的想法。当然,这里我很清楚,这个转换器就是适配器。而当我要对一个系统作调用的简化处理时,应该非常自然地冒出来封装入口的思想。注意,在这里我自始至终没有刻意提起Adapter或是Facade模式,名字神马的都是浮云,**理解它们的原理和作用才是重点。**设计模式是被人发现和总结出来的,而不是人为发明的,没有设计模式的时候也有人这么做,我们的思想应该向他们靠拢。 94 | > > 95 | > > 而在进行设计决策时,我们通常会面临好几种不同的解决方案,它们各有利弊,该如何选择?许多开发人员会这样问:“这些实现方式中哪个更好?”这种问法并不明智。问题在于,**往往没有哪个实现方式天生就优于另一个(否则另一个还有存在的意义吗?)。**应该这样问,对于每种实现方式,“**什么情况下它优于其它方式?**”然后再问:“**哪种情况与我的问题领域最相似?**”在这种思考中,我们会逐渐**对不同的解决方案和模式有更深刻的体会和认识。** 96 | 97 | # 三、常用模式的心得体会 98 | 99 | 这里对集中常用的设计模式作一些感悟总结,我喜欢对比模式之间的区别,以此对模式的适用领域和根本思想做深入的分析并理解,但还是要强调,不能把模式孤立看待,必须让模式互相配合,共同解决问题。 100 | 101 | > ### 1、Facade/Adapter/Decorator的联系和区别 102 | > 103 | > > 曾经看到有人把Facade和Adapter两种模式进行了对比,因为它们都存在对类的包装(wrap),事实上我认为Adapter和Decorator更像。**Adapter完全可以理解为是对不符合新接口的旧对象进行装饰**,区别在于在Decorator里,被装饰的对象也继承于装饰者的父类,而Adapter里被适配的对象不行(正是因为不行才需要适配)。同时,Decorator中的父类的作用更侧重于是便于对类的组织。 104 | > > 105 | > > 明确三种模式的目的有助于我们更精确的理解其思想。 106 | > > 107 | > > > **Facade:简化接口,避免复杂逻辑和调用;** 108 | > > > 109 | > > > **Adapter:转换接口,相当于两相插座和三相插头之间的拖线板;** 110 | > > > 111 | > > > **Decorator:增加额外特性。** 112 | > 113 | > ### 2、Facade/Proxy的区别 114 | > 115 | > > Facade通常使用多种对象组合实现功能,但Proxy通常只使用一类对象。此外Proxy的接口方法通常与被调用的对象方法名相同,以此保证调用代理和调用实际对象的方式一致。 116 | > > 117 | > > Facade通常用于简化系统的使用(典型例子就是API)。此外它还有如下两个作用: 118 | > > 119 | > > > **1)通过限定使用入口来对系统进行监测。** 120 | > > > 121 | > > > **2)对系统的修改可以对调用者透明,便于系统切换和更新。** 122 | > > 123 | > > Proxy的典型用途是: 124 | > > 125 | > > > **1)简化对象调用(比如权限控制之类的事情可以在Proxy内部实现,不需要调用者操心)。** 126 | > > > 127 | > > > **2)使对象调用轻量化,原本需要对N个对象进行调用的操作,现在只需通过一个Proxy,内存开销大大减小。** 128 | > 129 | > ### 3、有switch,考虑Strategy模式 130 | > 131 | > > switch语句常常说明: 132 | > > 133 | > > > **1)需要多态行为。** 134 | > > > 135 | > > > **2)存在指责错放(类的职责过多)。** 136 | > > 137 | > > 这里可以采用Strategy模式配合多态简化判断逻辑,**把职责下放给子类,消除集中的父类职责。** 138 | > 139 | > ### 4、Bridge模式 140 | > 141 | > > Bridge模式是典型的“组合优先于继承”的范例,牢记一点:**对象和方法是多对多关系的时候,就可以考虑使用Bridge模式,而不是滥用继承。**此外Bridge模式对系统的可扩展性有极大的帮助。 142 | > 143 | > ### 5、Template Method模式 144 | > 145 | > > 我觉得Template Method模式和重构中的[**Extract Method**](http://www.refactoring.com/catalog/extractMethod.html)非常相似,都是提取公共代码从而消除冗余并避免重复代码潜在的隐患。而Template Method模式最常用的的意图是:**定义一个操作中算法的骨架,而将一些步骤延迟到子类中。在不改变算法的结构的前提下重定义它的步骤。**这种思想和之前讲的反过来,先有父类,定义算法骨架,其中某些步骤是确定的,某些是不确定的或是需要变化的。根据可变性分析,后者就应该延迟到子类实现,子类实现时只需要实现那些会变化的方法即可。 -------------------------------------------------------------------------------- /Code/JVM.md: -------------------------------------------------------------------------------- 1 | ### [浅析Java虚拟机结构与机制](http://blog.hesey.net/2011/04/introduction-to-java-virtual-machine.html) 2 | 3 | 本文旨在给所有希望了解[**JVM**](http://en.wikipedia.org/wiki/Java_Virtual_Machine)(Java Virtual Machine)的同学一个概念性的入门,主要介绍了JVM的组成部分以及它们内部工作的机制和原理。当然本文只是一个简单的入门,不会涉及过多繁杂的参数和配置,感兴趣的同学可以做更深入的研究,在研究JVM的过程中会发现,其实JVM本身就是一个计算机体系结构,很多原理和我们平时的硬件、微机原理、操作系统都有十分相似的地方,所以学习JVM本身也是加深自我对计算机结构认识的一个很好的途径。 4 | 5 | 另外需要注意的是,虽然平时我们用的大多是Sun(现已被Oracle收购)JDK提供的JVM,但是JVM本身是一个[**规范**](http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html),所以可以有多种实现,除了[**Hotspot**](http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136373.html)外,还有诸如Oracle的[**JRockit**](http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html)、IBM的[**J9**](http://en.wikipedia.org/wiki/IBM_J9)也都是非常有名的JVM。 6 | 7 | # 一、JVM结构 8 | 9 | > 下图展示了JVM的主要结构: 10 | > 11 | > [![1353310](http://blog.hesey.net/wp-content/uploads/2011/04/1353310.png)](http://blog.hesey.net/wp-content/uploads/2011/04/1353310.png) 12 | > 13 | > 可以看出,JVM主要由**类加载器子系统、运行时数据区(内存空间)、执行引擎以及与本地方法接口**等组成。其中运行时数据区又由**方法区、堆、Java栈、PC寄存器、本地方法栈**组成。 14 | > 15 | > 从上图中还可以看出,在内存空间中**方法区和堆是所有Java线程共享的**,而**Java栈、本地方法栈、PC寄存器则由每个线程私有**,这会引出一些问题,后文会进行具体讨论。 16 | > 17 | > 众所周知,Java语言具有跨平台的特性,这也是由JVM来实现的。更准确地说,是Sun利用JVM在不同平台上的实现帮我们把平台相关性的问题给解决了,这就好比是HTML语言可以在不同厂商的浏览器上呈现元素(虽然某些浏览器在对W3C标准的支持上还有一些问题)。同时,Java语言支持通过JNI(Java Native Interface)来实现本地方法的调用,但是需要注意到,如果你在Java程序用调用了本地方法,那么你的程序就很可能不再具有跨平台性,即本地方法会破坏平台无关性。 18 | 19 | # 二、类加载器子系统(Class Loader) 20 | 21 | > 类加载器子系统负责加载编译好的.class字节码文件,并装入内存,使JVM可以实例化或以其它方式使用加载后的类。JVM的类加载子系统支持在运行时的动态加载,动态加载的优点有很多,例如可以节省内存空间、灵活地从网络上加载类,动态加载的另一好处是可以通过命名空间的分隔来实现类的隔离,增强了整个系统的安全性。 22 | > 23 | > ### 1、ClassLoader的分类: 24 | > 25 | > **a.启动类加载器(BootStrap Class Loader)**:负责加载rt.jar文件中所有的Java类,即Java的核心类都是由该ClassLoader加载。在Sun JDK中,这个类加载器是由C++实现的,并且在Java语言中无法获得它的引用。 26 | > 27 | > **b.扩展类加载器(Extension Class Loader)**:负责加载一些扩展功能的jar包。 28 | > 29 | > **c.系统类加载器(System Class Loader)**:负责加载启动参数中指定的Classpath中的jar包及目录,通常我们自己写的Java类也是由该ClassLoader加载。在Sun JDK中,系统类加载器的名字叫AppClassLoader。 30 | > 31 | > **d.用户自定义类加载器(User Defined Class Loader)**:由用户自定义类的加载规则,可以手动控制加载过程中的步骤。 32 | > 33 | > ### 2、ClassLoader的工作原理 34 | > 35 | > 类加载分为装载、链接、初始化三步。 36 | > 37 | > **a.装载** 38 | > 39 | > > 通过类的全限定名和ClassLoader加载类,主要是将指定的.class文件加载至JVM。当类被加载以后,在JVM内部就以“类的全限定名+ClassLoader实例ID”来标明类。 40 | > > 41 | > > 在内存中,ClassLoader实例和类的实例都位于堆中,它们的类信息都位于方法区。 42 | > > 43 | > > 装载过程采用了一种被称为“[**双亲委派模型(Parent Delegation Model)**](http://publib.boulder.ibm.com/infocenter/javasdk/v6r0/index.jsp?topic=/com.ibm.java.doc.diagnostics.60/diag/understanding/cl_delegation.html)”的方式,当一个ClassLoader要加载类时,它会先请求它的双亲ClassLoader(其实这里只有两个ClassLoader,所以称为父ClassLoader可能更容易理解)加载类,而它的双亲ClassLoader会继续把加载请求提交再上一级的ClassLoader,直到启动类加载器。只有其双亲ClassLoader无法加载指定的类时,它才会自己加载类。 44 | > > 45 | > > 双亲委派模型是JVM的第一道安全防线,它保证了类的安全加载,这里同时依赖了类加载器隔离的原理:不同类加载器加载的类之间是无法直接交互的,即使是同一个类,被不同的ClassLoader加载,它们也无法感知到彼此的存在。这样即使有恶意的类冒充自己在核心包(例如java.lang)下,由于它无法被启动类加载器加载,也造成不了危害。 46 | > > 47 | > > 由此也可见,如果用户自定义了类加载器,那就必须自己保障类加载过程中的安全。 48 | > 49 | > **b.链接** 50 | > 51 | > > 链接的任务是把二进制的类型信息合并到JVM运行时状态中去。 52 | > > 53 | > > 链接分为以下三步: 54 | > > 55 | > > > a.验证:校验.class文件的正确性,确保该文件是符合规范定义的,并且适合当前JVM使用。 56 | > > > 57 | > > > b.准备:为类分配内存,同时初始化类中的静态变量赋值为默认值。 58 | > > > 59 | > > > c.解析(可选):主要是把类的常量池中的符号引用解析为直接引用,这一步可以在用到相应的引用时再解析。 60 | > 61 | > **c.初始化** 62 | > 63 | > > 初始化类中的静态变量,并执行类中的static代码、构造函数。 64 | > > 65 | > > JVM规范严格定义了何时需要对类进行初始化: 66 | > > 67 | > > > a、通过new关键字、反射、clone、反序列化机制实例化对象时。 68 | > > > 69 | > > > b、调用类的静态方法时。 70 | > > > 71 | > > > c、使用类的静态字段或对其赋值时。 72 | > > > 73 | > > > d、通过反射调用类的方法时。 74 | > > > 75 | > > > e、初始化该类的子类时(初始化子类前其父类必须已经被初始化)。 76 | > > > 77 | > > > f、JVM启动时被标记为启动类的类(简单理解为具有main方法的类)。 78 | 79 | # 三、Java栈(Java Stack) 80 | 81 | > Java栈由栈帧组成,一个帧对应一个方法调用。调用方法时压入栈帧,方法返回时弹出栈帧并抛弃。Java栈的主要任务是存储方法参数、局部变量、中间运算结果,并且提供部分其它模块工作需要的数据。前面已经提到Java栈是线程私有的,这就保证了线程安全性,使得程序员无需考虑栈同步访问的问题,只有线程本身可以访问它自己的局部变量区。 82 | > 83 | > 它分为三部分:局部变量区、操作数栈、帧数据区。 84 | > 85 | > **1、局部变量区** 86 | > 87 | > > 局部变量区是以字长为单位的数组,在这里,byte、short、char类型会被转换成int类型存储,除了long和double类型占两个字长以外,其余类型都只占用一个字长。特别地,boolean类型在编译时会被转换成int或byte类型,boolean数组会被当做byte类型数组来处理。局部变量区也会包含对象的引用,包括类引用、接口引用以及数组引用。 88 | > > 89 | > > 局部变量区包含了方法参数和局部变量,此外,实例方法隐含第一个局部变量this,它指向调用该方法的对象引用。对于对象,局部变量区中永远只有指向堆的引用。 90 | > 91 | > **2、操作数栈** 92 | > 93 | > > 操作数栈也是以字长为单位的数组,但是正如其名,它只能进行入栈出栈的基本操作。在进行计算时,操作数被弹出栈,计算完毕后再入栈。 94 | > 95 | > **3、帧数据区** 96 | > 97 | > > 帧数据区的任务主要有: 98 | > > 99 | > > a.记录指向类的常量池的指针,以便于解析。 100 | > > 101 | > > b.帮助方法的正常返回,包括恢复调用该方法的栈帧,设置PC寄存器指向调用方法对应的下一条指令,把返回值压入调用栈帧的操作数栈中。 102 | > > 103 | > > c.记录异常表,发生异常时将控制权交由对应异常的catch子句,如果没有找到对应的catch子句,会恢复调用方法的栈帧并重新抛出异常。 104 | > 105 | > 局部变量区和操作数栈的大小依照具体方法在编译时就已经确定。调用方法时会从方法区中找到对应类的类型信息,从中得到具体方法的局部变量区和操作数栈的大小,依此分配栈帧内存,压入Java栈。 106 | 107 | # 四、本地方法栈(Native Method Stack) 108 | 109 | > 本地方法栈类似于Java栈,主要存储了本地方法调用的状态。在Sun JDK中,本地方法栈和Java栈是同一个。 110 | 111 | # 五、方法区(Method Area) 112 | 113 | > 类型信息和类的静态变量都存储在方法区中。方法区中对于每个类存储了以下数据: 114 | > 115 | > > a.类及其父类的全限定名(java.lang.Object没有父类) 116 | > > 117 | > > b.类的类型(Class or Interface) 118 | > > 119 | > > c.访问修饰符(public, abstract, final) 120 | > > 121 | > > d.实现的接口的全限定名的列表 122 | > > 123 | > > e.常量池 124 | > > 125 | > > f.字段信息 126 | > > 127 | > > g.方法信息 128 | > > 129 | > > h.静态变量 130 | > > 131 | > > i.ClassLoader引用 132 | > > 133 | > > j.Class引用 134 | > 135 | > 可见类的所有信息都存储在方法区中。由于方法区是所有线程共享的,所以必须保证线程安全,举例来说,如果两个类同时要加载一个尚未被加载的类,那么一个类会请求它的ClassLoader去加载需要的类,另一个类只能等待而不会重复加载。 136 | > 137 | > 此外为了加快调用方法的速度,通常还会为每个非抽象类创建私有的方法表,方法表是一个数组,存放了实例可能被调用的实例方法的直接引用。方法表对于多态有非常重要的意义,具体可以参照《[**浅谈多态机制的意义及实现**](http://blog.hesey.net/2010/12/significance-and-implementation-of-polymorphism.html)》一文中“多态的实现”一节。 138 | > 139 | > 在Sun JDK中,方法区对应了持久代(Permanent Generation),默认最小值为16MB,最大值为64MB。 140 | 141 | # 六、堆(Heap) 142 | 143 | > 堆用于存储对象实例以及数组值。堆中有指向类数据的指针,该指针指向了方法区中对应的类型信息。堆中还可能存放了指向方法表的指针。堆是所有线程共享的,所以在进行实例化对象等操作时,需要解决同步问题。此外,堆中的实例数据中还包含了对象锁,并且针对不同的垃圾收集策略,可能存放了引用计数或清扫标记等数据。 144 | > 145 | > 在堆的管理上,Sun JDK从1.2版本开始引入了分代管理的方式。主要分为新生代、旧生代。分代方式大大改善了垃圾收集的效率。 146 | > 147 | > **1、新生代(New Generation)** 148 | > 149 | > > 大多数情况下新对象都被分配在新生代中,新生代由Eden Space和两块相同大小的Survivor Space组成,后两者主要用于Minor GC时的对象复制(Minor GC的过程在此不详细讨论)。 150 | > > 151 | > > JVM在Eden Space中会开辟一小块独立的[**TLAB**](http://blogs.sun.com/jonthecollector/entry/the_real_thing)(Thread Local Allocation Buffer)区域用于更高效的内存分配,我们知道在堆上分配内存需要锁定整个堆,而在TLAB上则不需要,JVM在分配对象时会尽量在TLAB上分配,以提高效率。 152 | > 153 | > **2、旧生代(Old Generation/Tenuring Generation)** 154 | > 155 | > > 在新生代中存活时间较久的对象将会被转入旧生代,旧生代进行垃圾收集的频率没有新生代高。 156 | 157 | # 七、执行引擎 158 | 159 | > 执行引擎是JVM执行Java字节码的核心,执行方式主要分为**解释执行、编译执行、自适应优化执行、硬件芯片执行**方式。 160 | > 161 | > JVM的指令集是基于栈而非寄存器的,这样做的好处在于可以使指令尽可能紧凑,便于快速地在网络上传输(别忘了Java最初就是为网络设计的),同时也很容易适应通用寄存器较少的平台,并且有利于代码优化,由于Java栈和PC寄存器是线程私有的,线程之间无法互相干涉彼此的栈。每个线程拥有独立的JVM执行引擎实例。 162 | > 163 | > JVM指令由单字节操作码和若干操作数组成。对于需要操作数的指令,通常是先把操作数压入操作数栈,即使是对局部变量赋值,也会先入栈再赋值。注意这里是“通常”情况,之后会讲到由于优化导致的例外。 164 | > 165 | > **1、解释执行** 166 | > 167 | > > 和一些动态语言类似,JVM可以解释执行字节码。Sun JDK采用了[**token-threading**](http://www.complang.tuwien.ac.at/forth/threaded-code.html)的方式,感兴趣的同学可以深入了解一下。 168 | > > 169 | > > 解释执行中有几种优化方式: 170 | > > 171 | > > > **a.栈顶缓存** 172 | > > > 173 | > > > 将位于操作数栈顶的值直接缓存在寄存器上,对于大部分只需要一个操作数的指令而言,就无需再入栈,可以直接在寄存器上进行计算,结果压入操作数站。这样便减少了寄存器和内存的交换开销。 174 | > > > 175 | > > > **b.部分栈帧共享** 176 | > > > 177 | > > > 被调用方法可将调用方法栈帧中的操作数栈作为自己的局部变量区,这样在获取方法参数时减少了复制参数的开销。 178 | > > > 179 | > > > **c.执行机器指令** 180 | > > > 181 | > > > 在一些特殊情况下,JVM会执行机器指令以提高速度。 182 | > 183 | > **2、编译执行** 184 | > 185 | > > 为了提升执行速度,Sun JDK提供了将字节码编译为机器指令的支持,主要利用了[**JIT**](http://en.wikipedia.org/wiki/Just-in-time_compilation)(Just-In-Time)编译器在运行时进行编译,它会在第一次执行时编译字节码为机器码并缓存,之后就可以重复利用。Oracle JRockit采用的是完全的编译执行。 186 | > 187 | > **3、自适应优化执行** 188 | > 189 | > > 自适应优化执行的思想是程序中10%~20%的代码占据了80%~90%的执行时间,所以通过将那少部分代码编译为优化过的机器码就可以大大提升执行效率。自适应优化的典型代表是Sun的Hotspot VM,正如其名,JVM会监测代码的执行情况,当判断特定方法是瓶颈或热点时,将会启动一个后台线程,把该方法的字节码编译为极度优化的、静态链接的C++代码。当方法不再是热区时,则会取消编译过的代码,重新进行解释执行。 190 | > > 191 | > > 自适应优化不仅通过利用小部分的编译时间获得大部分的效率提升,而且由于在执行过程中时刻监测,对内联代码等优化也起到了很大的作用。由于面向对象的多态性,一个方法可能对应了很多种不同实现,自适应优化就可以通过监测只内联那些用到的代码,大大减少了内联函数的大小。 192 | > 193 | > Sun JDK在编译上采用了两种模式:Client和Server模式。前者较为轻量级,占用内存较少。后者的优化程序更高,占用内存更多。 194 | > 195 | > 在Server模式中会进行对象的逃逸分析,即方法中的对象是否会在方法外使用,如果被其它方法使用了,则该对象是逃逸的。对于非逃逸对象,JVM会在栈上直接分配对象(所以对象不一定是在堆上分配的),线程获取对象会更加快速,同时当方法返回时,由于栈帧被抛弃,也有利于对象的垃圾收集。Server模式还会通过分析去除一些不必要的同步,感兴趣的同学可以研究一下Sun JDK 6引入的[**Biased Locking**](http://blogs.sun.com/dave/entry/biased_locking_in_hotspot)机制。 196 | > 197 | > 此外,执行引擎也必须保证线程安全性,因而[**JMM**](http://www.cs.umd.edu/%7Epugh/java/memoryModel/)(Java Memory Model)也是由执行引擎确保的。 -------------------------------------------------------------------------------- /Code/ObjectPool.md: -------------------------------------------------------------------------------- 1 | # ObjectPool 2 | 3 | ## 一个超级对象池的实现 4 | 5 | 6 | 7 | 对象池对于创建开销比较大的对象来说很有意义,为了避免重复创建开销比较大的对象,我们可以通过对象池来优化。对象池的思路比较简单,事先创建好一批对 8 | 象,放到一个集合中,以后每当程序需要新的对象时候,都从对象池里获取,每当程序用完该对象后,都把该对象归还给对象池。这样会避免重复的对象创建,提高 9 | 程序性能。先来看看对象池的简单实现: 10 | 11 | ```c++ 12 | #include 13 | 14 | template 15 | class ObjectPool 16 | { 17 | public: 18 | 19 | ObjectPool(size_t unSize) : 20 | m_unSize(unSize) 21 | { 22 | for (size_t unIdx = 0; unIdx < m_unSize; ++ unIdx) 23 | { 24 | m_oPool.push_back(new Object()); 25 | } 26 | } 27 | 28 | ~ObjectPool() 29 | { 30 | typename std::list::iterator oIt = m_oPool.begin(); 31 | while (oIt != m_oPool.end()) 32 | { 33 | delete (*oIt); 34 | ++ oIt; 35 | } 36 | m_unSize = 0; 37 | } 38 | 39 | Object * GetObject() 40 | { 41 | Object * pObj = NULL; 42 | if (0 == m_unSize) 43 | { 44 | pObj = new Object(); 45 | } 46 | else 47 | { 48 | pObj = m_oPool.front(); 49 | m_oPool.pop_front(); 50 | -- m_unSize; 51 | } 52 | 53 | return pObj; 54 | } 55 | 56 | void ReturnObject(Object * pObj) 57 | { 58 | m_oPool.push_back(pObj); 59 | ++ m_unSize; 60 | } 61 | 62 | private: 63 | size_t m_unSize; 64 | std::list m_oPool; 65 | }; 66 | ``` 67 | 68 | 这个object pool的实现很典型,初始创建一定数量的对象,取的时候就直接从池子中取,用完之后再回收到池子。一般的对象池的实现思路和这个类似,这种实现方式虽然能达到目的,但是存在以下不足: 69 | 70 | 1. 对象池ObjectPool只能容纳特定类型的对象,不能容纳所有类型的对象,可以支持重载的和参数不同的构造函数; 71 | 2. 对象用完之后需要手动回收,用起来不够方便,更大的问题是存在忘记回收的风险; 72 | 73 |   我希望能有一个更强大的对象池,这个对象池能容纳所有的对象,还能自动回收用完了对象,不需要手动回收,用起来更方便。要实现这样的对象池需要解决前面提到的两个问题,通过c++11就可以解决这两个问题。 74 | 75 |   对于问题1:容纳所有的对象。本质上需要将对象池中的对象类型擦除,这里用Any类型就可以解决。 76 | 77 |   对于问题2:自动回收用完的对象。这里用智能指针就可以解决,在创建智能指针时可以指定删除器,在删除器中不删除对象,而是回收到对象池中,而这个过程对外界来说是看不见的,由智能指针自己完成。 78 | 79 | ```c++ 80 | #include 81 | #include 82 | #include 83 | #include 84 | 85 | #include "Any.hpp" 86 | 87 | const int MaxObjectNum = 10; 88 | 89 | class ObjectPool 90 | { 91 | template 92 | using Constructor = std::function(Args...)>; 93 | public: 94 | 95 | ObjectPool() : needClear(false) 96 | { 97 | } 98 | 99 | ~ObjectPool() 100 | { 101 | needClear = true; 102 | } 103 | 104 | //默认创建多少个对象 105 | template 106 | void Create(int num) 107 | { 108 | if (num <= 0 || num > MaxObjectNum) 109 | throw std::logic_error("object num errer"); 110 | 111 | auto constructName = typeid(Constructor).name(); 112 | 113 | Constructor f = [constructName, this](Args... args) 114 | { 115 | return createPtr(string(constructName), args...); 116 | }; 117 | 118 | m_map.emplace(typeid(T).name(), f); 119 | 120 | m_counter.emplace(constructName, num); 121 | } 122 | 123 | template 124 | std::shared_ptr createPtr(std::string& constructName, Args... args) 125 | { 126 | return std::shared_ptr(new T(args...), [constructName, this](T* t) 127 | { 128 | if (needClear) 129 | delete[] t; 130 | else 131 | m_object_map.emplace(constructName, std::shared_ptr(t)); 132 | }); 133 | } 134 | 135 | template 136 | std::shared_ptr Get(Args... args) 137 | { 138 | using ConstructType = Constructor; 139 | 140 | std::string constructName = typeid(ConstructType).name(); 141 | auto range = m_map.equal_range(typeid(T).name()); 142 | 143 | for (auto it = range.first; it != range.second; ++it) 144 | { 145 | if (it->second.Is()) 146 | { 147 | auto ptr = GetInstance(constructName, args...); 148 | 149 | if (ptr != nullptr) 150 | return ptr; 151 | 152 | return CreateInstance(it->second, constructName, args...); 153 | } 154 | } 155 | 156 | return nullptr; 157 | } 158 | 159 | private: 160 | template 161 | std::shared_ptr CreateInstance(Any& any, 162 | std::string& constructName, Args... args) 163 | { 164 | using ConstructType = Constructor; 165 | ConstructType f = any.AnyCast(); 166 | 167 | return createPtr(constructName, args...); 168 | } 169 | 170 | template 171 | void InitPool(T& f, std::string& constructName, Args... args) 172 | { 173 | int num = m_counter[constructName]; 174 | 175 | if (num != 0) 176 | { 177 | for (int i = 0; i < num - 1; i++) 178 | { 179 | m_object_map.emplace(constructName, f(args...)); 180 | } 181 | m_counter[constructName] = 0; 182 | } 183 | } 184 | 185 | template 186 | std::shared_ptr GetInstance(std::string& constructName, Args... args) 187 | { 188 | auto it = m_object_map.find(constructName); 189 | if (it == m_object_map.end()) 190 | return nullptr; 191 | 192 | auto ptr = it->second.AnyCast>(); 193 | if (sizeof...(Args)>0) 194 | *ptr.get() = std::move(T(args...)); 195 | 196 | m_object_map.erase(it); 197 | return ptr; 198 | } 199 | 200 | private: 201 | std::multimap m_map; 202 | std::multimap m_object_map; 203 | std::map m_counter; 204 | bool needClear; 205 | }; 206 | ``` -------------------------------------------------------------------------------- /Code/Polymorphism.md: -------------------------------------------------------------------------------- 1 | # [浅谈多态机制的意义及实现](http://blog.hesey.net/2010/12/significance-and-implementation-of-polymorphism.html) 2 | 3 | 在面向对象编程([**Object-Oriented Programming**](http://en.wikipedia.org/wiki/Object-Oriented_Programming), OOP)中,多态机制无疑是其最具特色的功能,甚至可以说,不运用多态的编程不能称之为OOP。这也是为什么有人说,**使用面向对象语言的编程和面向对象的编程是两码事。** 4 | 5 | 多态并没有一个严格的定义,维基百科上给它下的定义比较宽松: 6 | 7 | > **Subtype polymorphism, almost universally called just polymorphism in the context of object-oriented programming, is the ability of one type, A, to appear as and be used like another type, B.** 8 | 9 | ## 一、子类型和子类 10 | 11 | > 这里我想先提一下子类型([**Subtype**](http://en.wikipedia.org/wiki/Subtype))这个词和子类([**Subclass**](http://en.wikipedia.org/wiki/Subclass_%28computer_science%29))的区别,简单地说,只要是A类运用了extends关键字实现了对B类的继承,那么我们就可以说Class A是Class B的子类,**子类是一个语法层面上的词,只要满足继承的语法,就存在子类关系。** 12 | > 13 | > 子类型比子类有更严格的要求,它不仅要求有继承的语法,同时要求如果存在子类对父类方法的改写(override),那么**改写的内容必须符合父类原本的语义,其被调用后的作用应该和父类实现的效果方向一致。** 14 | > 15 | > 对二者的对比是想强调一点:**只有保证子类都是子类型,多态才有意义。** 16 | 17 | ## 二、多态的机制 18 | 19 | > 本质上多态分两种: 20 | > 21 | > > **1、编译时多态(又称静态多态)** 22 | > > 23 | > > **2、运行时多态(又称动态多态)** 24 | > 25 | > 重载(overload)就是编译时多态的一个例子,编译时多态在编译时就已经确定,运行时运行的时候调用的是确定的方法。 26 | > 27 | > **我们通常所说的多态指的都是运行时多态,也就是编译时不确定究竟调用哪个具体方法,一直延迟到运行时才能确定。**这也是为什么有时候多态方法又被称为延迟方法的原因。 28 | > 29 | > 在维基百科中多态的行为被描述为: 30 | > 31 | > > **The primary usage of polymorphism in industry (object-oriented programming theory) is the ability of objects belonging to different types to respond to method, field, or property calls of the same name, each one according to an appropriate type-specific behavior.** 32 | > 33 | > 下面简要介绍一下运行时多态(以下简称多态)的机制。 34 | > 35 | > 多态通常有两种实现方法: 36 | > 37 | > > **1、子类继承父类(extends)** 38 | > > 39 | > > **2、类实现接口(implements)** 40 | > 41 | > 无论是哪种方法,其核心之处就在于对父类方法的改写或对接口方法的实现,以取得在运行时不同的执行效果。 42 | > 43 | > 要使用多态,在声明对象时就应该遵循一条法则:**声明的总是父类类型或接口类型,创建的是实际类型。**举例来说,假设我们要创建一个ArrayList对象,声明就应该采用这样的语句: 44 | > 45 | > ``` 46 | > List list = new ArrayList(); 47 | > ``` 48 | > 49 | > 而不是 50 | > 51 | > ``` 52 | > ArrayList list = new ArrayList(); 53 | > ``` 54 | > 55 | > **在定义方法参数时也通常总是应该优先使用父类类型或接口类型**,例如某方法应该写成: 56 | > 57 | > ``` 58 | > public void doSomething(List list); 59 | > ``` 60 | > 61 | > 而不是 62 | > 63 | > ``` 64 | > public void doSomething(ArrayList list); 65 | > ``` 66 | > 67 | > 这样声明最大的好处在于结构的灵活性:假如某一天我认为ArrayList的特性无法满足我的要求,我希望能够用LinkedList来代替它,那么只需要在对象创建的地方把new ArrayList()改为new LinkedList即可,其它代码一概不用改动。 68 | > 69 | > > **The programmer (and the program) does not have to know the exact type of the object in advance, and so the exact behavior is determined at run-time (this is called late binding or dynamic binding).** 70 | > 71 | > 虚拟机会在执行程序时动态调用实际类的方法,它会通过一种名为动态绑定(又称延迟绑定)的机制自动实现,这个过程对程序员来说是透明的。 72 | 73 | # 三、多态的用途 74 | 75 | > 多态最大的用途我认为在于**对设计和架构的复用**,更进一步来说,《[**设计模式**](http://book.douban.com/subject/1052241/)》中提倡的针对接口编程而不是针对实现编程就是充分利用多态的典型例子。**定义功能和组件时定义接口,实现可以留到之后的流程中。**同时一个接口可以有多个实现,甚至于完全可以在一个设计中同时使用一个接口的多种实现(例如针对ArrayList和LinkedList不同的特性决定究竟采用哪种实现)。 76 | 77 | # 四、多态的实现 78 | 79 | > 下面从虚拟机运行时的角度来简要介绍多态的实现原理,这里以Java虚拟机([**Java Virtual Machine**](http://en.wikipedia.org/wiki/Java_Virtual_Machine), JVM)规范的实现为例。 80 | > 81 | > 在JVM执行Java字节码时,**类型信息被存放在方法区中**,通常为了优化对象调用方法的速度,方法区的类型信息中增加一个指针,该指针指向一张记录该类方法入口的表(称为方法表),**表中的每一项都是指向相应方法的指针。** 82 | > 83 | > 方法表的构造如下: 84 | > 85 | > 由于Java的单继承机制,一个类只能继承一个父类,而所有的类又都继承自Object类。方法表中**最先存放的是Object类的方法,接下来是该类的父类的方法,最后是该类本身的方法。**这里关键的地方在于,**如果子类改写了父类的方法,那么子类和父类的那些同名方法共享一个方法表项,都被认作是父类的方法。** 86 | > 87 | > 注意这里只有非私有的实例方法才会出现,并且静态方法也不会出现在这里,原因很容易理解:静态方法跟对象无关,可以将方法地址直接引用,而不像实例方法需要间接引用。 88 | > 89 | > 更深入地讲,静态方法是由虚拟机指令invokestatic调用的,私有方法和构造函数则是由invokespecial指令调用,只有被invokevirtual和invokeinterface指令调用的方法才会在方法表中出现。 90 | > 91 | > 由于以上方法的排列特性(Object——父类——子类),使得**方法表的偏移量总是固定的**。例如,对于任何类来说,其方法表中equals方法的偏移量总是一个定值,所有继承某父类的子类的方法表中,其父类所定义的方法的偏移量也总是一个定值。 92 | > 93 | > 前面说过,方法表中的表项都是指向该类对应方法的指针,这里就开始了多态的实现: 94 | > 95 | > 假设Class A是Class B的子类,并且A改写了B的方法method(),那么在B的方法表中,method方法的指针指向的就是B的method方法入口。 96 | > 97 | > 而对于A来说,它的方法表中的method方法则会指向其自身的method方法而非其父类的(这在类加载器载入该类时已经保证,同时JVM会保证总是能从对象引用指向正确的类型信息)。 98 | > 99 | > 结合**方法指针偏移量是固定的**以及**指针总是指向实际类的方法域**,我们不难发现多态的机制就在这里: 100 | > 101 | > 在调用方法时,实际上必须首先完成实例方法的符号引用解析,结果是该符号引用被解析为方法表的偏移量。虚拟机通过对象引用得到方法区中类型信息的入口,查询类的方法表,当将子类对象声明为父类类型时,形式上调用的是父类方法,此时虚拟机会从实际类的方法表(虽然声明的是父类,但是实际上这里的类型信息中存放的是子类的信息)中查找该方法名对应的指针(这里用“查找”实际上是不合适的,前面提到过,方法的偏移量是固定的,所以只需根据偏移量就能获得指针),进而就能指向实际类的方法了。 102 | > 103 | > 我们的故事还没有结束,事实上上面的过程仅仅是利用继承实现多态的内部机制,多态的另外一种实现方式:实现接口相比而言就更加复杂,原因在于,**Java的单继承保证了类的线性关系,而接口可以同时实现多个,这样光凭偏移量就很难准确获得方法的指针。**所以在JVM中,多态的实例方法调用实际上有两种指令: 104 | > 105 | > > **invokevirtual指令用于调用声明为类的方法;** 106 | > > 107 | > > **invokeinterface指令用于调用声明为接口的方法。** 108 | > 109 | > 当使用invokeinterface指令调用方法时,就不能采用固定偏移量的办法,只能老老实实挨个找了(当然实际实现并不一定如此,JVM规范并没有规定究竟如何实现这种查找,不同的JVM实现可以有不同的优化算法来提高搜索效率)。我们不难看出,**在性能上,调用接口引用的方法通常总是比调用类的引用的方法要慢。**这也告诉我们,在类和接口之间优先选择接口作为设计并不总是正确的,当然设计问题不在本文探讨的范围之内,但显然具体问题具体分析仍然不失为更好的选择。 -------------------------------------------------------------------------------- /Code/Python Numpy教程.md: -------------------------------------------------------------------------------- 1 | # Python Numpy教程 2 | 3 | 我们将使用Python编程语言来完成本课程的所有作业。Python是一门伟大的通用编程语言,在一些常用库(numpy, scipy, matplotlib)的帮助下,它又会变成一个强大的科学计算环境。 4 | 5 | 你们还可以查看[本教程的IPython notebook版](https://link.zhihu.com/?target=https%3A//github.com/kuleshov/cs228-material/blob/master/tutorials/python/cs228-python-tutorial.ipynb)。该教程是由[Volodymyr Kuleshov](https://link.zhihu.com/?target=http%3A//web.stanford.edu/%257Ekuleshov/)和[Isaac Caswell](https://link.zhihu.com/?target=https%3A//symsys.stanford.edu/viewing/symsysaffiliate/21335)为课程[CS 228](https://link.zhihu.com/?target=http%3A//cs.stanford.edu/%257Eermon/cs228/index.html)创建的。 6 | 7 | 内容列表: 8 | 9 | - Python 10 | 11 | - - 基本数据类型 12 | 13 | - 容器 14 | 15 | - - 列表 16 | - 字典 17 | - 集合 18 | - 元组 19 | 20 | - 函数 21 | 22 | - 类 23 | 24 | - Numpy 25 | 26 | - - 数组 27 | - 访问数组 28 | - 数据类型 29 | - 数组计算 30 | - 广播 31 | 32 | - SciPy 33 | 34 | - - 图像操作 35 | - MATLAB文件 36 | - 点之间的距离 37 | 38 | - Matplotlib 39 | 40 | - - 绘制图形 41 | - 绘制多个图形 42 | - 图像 43 | 44 | ## Python 45 | 46 | Python是一种高级的,动态类型的多范型编程语言。很多时候,大家会说Python看起来简直和伪代码一样,这是因为你能够通过很少行数的代码表达出很有力的思想。举个例子,下面是用Python实现的经典的quicksort算法例子: 47 | 48 | ```python 49 | def quicksort(arr): 50 | if len(arr) <= 1: 51 | return arr 52 | pivot = arr[len(arr) / 2] 53 | left = [x for x in arr if x < pivot] 54 | middle = [x for x in arr if x == pivot] 55 | right = [x for x in arr if x > pivot] 56 | return quicksort(left) + middle + quicksort(right) 57 | 58 | print quicksort([3,6,8,10,1,2,1]) 59 | # Prints "[1, 1, 2, 3, 6, 8, 10]" 60 | ``` 61 | 62 | ## Python版本 63 | 64 | Python有两个支持的版本,分别是2.7和3.4。这有点让人迷惑,3.0向语言中引入了很多不向后兼容的变化,2.7下的代码有时候在3.4下是行不通的。在这个课程中,我们使用的是2.7版本。 65 | 66 | 如何查看版本呢?使用**python --version**命令。 67 | 68 | ## 基本数据类型 69 | 70 | 和大多数编程语言一样,Python拥有一系列的基本数据类型,比如整型、浮点型、布尔型和字符串等。这些类型的使用方式和在其他语言中的使用方式是类似的。 71 | 72 | **数字**:整型和浮点型的使用与其他语言类似。 73 | 74 | ```python 75 | x = 3 76 | print type(x) # Prints "" 77 | print x # Prints "3" 78 | print x + 1 # Addition; prints "4" 79 | print x - 1 # Subtraction; prints "2" 80 | print x * 2 # Multiplication; prints "6" 81 | print x ** 2 # Exponentiation; prints "9" 82 | x += 1 83 | print x # Prints "4" 84 | x *= 2 85 | print x # Prints "8" 86 | y = 2.5 87 | print type(y) # Prints "" 88 | print y, y + 1, y * 2, y ** 2 # Prints "2.5 3.5 5.0 6.25" 89 | ``` 90 | 91 | 需要注意的是,Python中没有 x++ 和 x-- 的操作符。 92 | 93 | Python也有内置的长整型和复杂数字类型,具体细节可以查看[文档](https://link.zhihu.com/?target=https%3A//docs.python.org/2/library/stdtypes.html%23numeric-types-int-float-long-complex)。 94 | 95 | **布尔型**:Python实现了所有的布尔逻辑,但用的是英语,而不是我们习惯的操作符(比如&&和||等)。 96 | 97 | ```python 98 | t = True 99 | f = False 100 | print type(t) # Prints "" 101 | print t and f # Logical AND; prints "False" 102 | print t or f # Logical OR; prints "True" 103 | print not t # Logical NOT; prints "False" 104 | print t != f # Logical XOR; prints "True" 105 | ``` 106 | 107 | **字符串**:Python对字符串的支持非常棒。 108 | 109 | ```python 110 | hello = 'hello' # String literals can use single quotes 111 | world = "world" # or double quotes; it does not matter. 112 | print hello # Prints "hello" 113 | print len(hello) # String length; prints "5" 114 | hw = hello + ' ' + world # String concatenation 115 | print hw # prints "hello world" 116 | hw12 = '%s %s %d' % (hello, world, 12) # sprintf style string formatting 117 | print hw12 # prints "hello world 12" 118 | ``` 119 | 120 | 字符串对象有一系列有用的方法,比如: 121 | 122 | ```python 123 | s = "hello" 124 | print s.capitalize() # Capitalize a string; prints "Hello" 125 | print s.upper() # Convert a string to uppercase; prints "HELLO" 126 | print s.rjust(7) # Right-justify a string, padding with spaces; prints " hello" 127 | print s.center(7) # Center a string, padding with spaces; prints " hello " 128 | print s.replace('l', '(ell)') # Replace all instances of one substring with another; 129 | # prints "he(ell)(ell)o" 130 | print ' world '.strip() # Strip leading and trailing whitespace; prints "world" 131 | ``` 132 | 133 | 如果想详细查看字符串方法,请看[文档](https://link.zhihu.com/?target=https%3A//docs.python.org/2/library/stdtypes.html%23string-methods)。 134 | 135 | ## 容器Containers 136 | 137 | **译者注**:有知友建议container翻译为复合数据类型,供读者参考。 138 | 139 | Python有以下几种容器类型:列表(lists)、字典(dictionaries)、集合(sets)和元组(tuples)。 140 | 141 | ## 列表Lists 142 | 143 | 列表就是Python中的数组,但是列表长度可变,且能包含不同类型元素。 144 | 145 | ```python 146 | xs = [3, 1, 2] # Create a list 147 | print xs, xs[2] # Prints "[3, 1, 2] 2" 148 | print xs[-1] # Negative indices count from the end of the list; prints "2" 149 | xs[2] = 'foo' # Lists can contain elements of different types 150 | print xs # Prints "[3, 1, 'foo']" 151 | xs.append('bar') # Add a new element to the end of the list 152 | print xs # Prints 153 | x = xs.pop() # Remove and return the last element of the list 154 | print x, xs # Prints "bar [3, 1, 'foo']" 155 | ``` 156 | 157 | 列表的细节,同样可以查阅[文档**](https://link.zhihu.com/?target=https%3A//docs.python.org/2/tutorial/datastructures.html%23more-on-lists)。 158 | 159 | **切片Slicing**:为了一次性地获取列表中的元素,Python提供了一种简洁的语法,这就是切片。 160 | 161 | ```python 162 | nums = range(5) # range is a built-in function that creates a list of integers 163 | print nums # Prints "[0, 1, 2, 3, 4]" 164 | print nums[2:4] # Get a slice from index 2 to 4 (exclusive); prints "[2, 3]" 165 | print nums[2:] # Get a slice from index 2 to the end; prints "[2, 3, 4]" 166 | print nums[:2] # Get a slice from the start to index 2 (exclusive); prints "[0, 1]" 167 | print nums[:] # Get a slice of the whole list; prints ["0, 1, 2, 3, 4]" 168 | print nums[:-1] # Slice indices can be negative; prints ["0, 1, 2, 3]" 169 | nums[2:4] = [8, 9] # Assign a new sublist to a slice 170 | print nums # Prints "[0, 1, 8, 8, 4]" 171 | ``` 172 | 173 | 在Numpy数组的内容中,我们会再次看到切片语法。 174 | 175 | **循环Loops**:我们可以这样遍历列表中的每一个元素: 176 | 177 | ```python 178 | animals = ['cat', 'dog', 'monkey'] 179 | for animal in animals: 180 | print animal 181 | # Prints "cat", "dog", "monkey", each on its own line. 182 | ``` 183 | 184 | 如果想要在循环体内访问每个元素的指针,可以使用内置的**enumerate**函数 185 | 186 | ```python 187 | animals = ['cat', 'dog', 'monkey'] 188 | for idx, animal in enumerate(animals): 189 | print '#%d: %s' % (idx + 1, animal) 190 | # Prints "#1: cat", "#2: dog", "#3: monkey", each on its own line 191 | ``` 192 | 193 | **列表推导List comprehensions**:在编程的时候,我们常常想要将一种数据类型转换为另一种。下面是一个简单例子,将列表中的每个元素变成它的平方。 194 | 195 | ```python 196 | nums = [0, 1, 2, 3, 4] 197 | squares = [] 198 | for x in nums: 199 | squares.append(x ** 2) 200 | print squares # Prints [0, 1, 4, 9, 16] 201 | ``` 202 | 203 | 使用列表推导,你就可以让代码简化很多: 204 | 205 | ```python 206 | nums = [0, 1, 2, 3, 4] 207 | squares = [x ** 2 for x in nums] 208 | print squares # Prints [0, 1, 4, 9, 16] 209 | ``` 210 | 211 | 列表推导还可以包含条件: 212 | 213 | ```python 214 | nums = [0, 1, 2, 3, 4] 215 | even_squares = [x ** 2 for x in nums if x % 2 == 0] 216 | print even_squares # Prints "[0, 4, 16]" 217 | ``` 218 | 219 | ### 字典Dictionaries 220 | 221 | 字典用来储存(键, 值)对,这和Java中的Map差不多。你可以这样使用它: 222 | 223 | ```python 224 | d = {'cat': 'cute', 'dog': 'furry'} # Create a new dictionary with some data 225 | print d['cat'] # Get an entry from a dictionary; prints "cute" 226 | print 'cat' in d # Check if a dictionary has a given key; prints "True" 227 | d['fish'] = 'wet' # Set an entry in a dictionary 228 | print d['fish'] # Prints "wet" 229 | # print d['monkey'] # KeyError: 'monkey' not a key of d 230 | print d.get('monkey', 'N/A') # Get an element with a default; prints "N/A" 231 | print d.get('fish', 'N/A') # Get an element with a default; prints "wet" 232 | del d['fish'] # Remove an element from a dictionary 233 | print d.get('fish', 'N/A') # "fish" is no longer a key; prints "N/A" 234 | ``` 235 | 236 | 想要知道字典的其他特性,请查阅[文档**](https://link.zhihu.com/?target=https%3A//docs.python.org/2/library/stdtypes.html%23dict)。 237 | 238 | **循环Loops**:在字典中,用键来迭代更加容易。 239 | 240 | ```python 241 | d = {'person': 2, 'cat': 4, 'spider': 8} 242 | for animal in d: 243 | legs = d[animal] 244 | print 'A %s has %d legs' % (animal, legs) 245 | # Prints "A person has 2 legs", "A spider has 8 legs", "A cat has 4 legs" 246 | ``` 247 | 248 | 如果你想要访问键和对应的值,那就使用**iteritems**方法: 249 | 250 | ```python 251 | d = {'person': 2, 'cat': 4, 'spider': 8} 252 | for animal, legs in d.iteritems(): 253 | print 'A %s has %d legs' % (animal, legs) 254 | # Prints "A person has 2 legs", "A spider has 8 legs", "A cat has 4 legs" 255 | ``` 256 | 257 | **字典推导Dictionary comprehensions**:和列表推导类似,但是允许你方便地构建字典。 258 | 259 | ```python 260 | nums = [0, 1, 2, 3, 4] 261 | even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0} 262 | print even_num_to_square # Prints "{0: 0, 2: 4, 4: 16}" 263 | ``` 264 | 265 | ### 集合Sets 266 | 267 | 集合是独立不同个体的无序集合。示例如下: 268 | 269 | ```python 270 | animals = {'cat', 'dog'} 271 | print 'cat' in animals # Check if an element is in a set; prints "True" 272 | print 'fish' in animals # prints "False" 273 | animals.add('fish') # Add an element to a set 274 | print 'fish' in animals # Prints "True" 275 | print len(animals) # Number of elements in a set; prints "3" 276 | animals.add('cat') # Adding an element that is already in the set does nothing 277 | print len(animals) # Prints "3" 278 | animals.remove('cat') # Remove an element from a set 279 | print len(animals) # Prints "2" 280 | ``` 281 | 282 | 和前面一样,要知道更详细的,查看[文档**](https://link.zhihu.com/?target=https%3A//docs.python.org/2/library/sets.html%23set-objects)。 283 | 284 | **循环Loops**:在集合中循环的语法和在列表中一样,但是集合是无序的,所以你在访问集合的元素的时候,不能做关于顺序的假设。 285 | 286 | ```python 287 | animals = {'cat', 'dog', 'fish'} 288 | for idx, animal in enumerate(animals): 289 | print '#%d: %s' % (idx + 1, animal) 290 | # Prints "#1: fish", "#2: dog", "#3: cat" 291 | ``` 292 | 293 | **集合推导****Set comprehensions**:和字典推导一样,可以很方便地构建集合: 294 | 295 | ``` 296 | from math import sqrt 297 | nums = {int(sqrt(x)) for x in range(30)} 298 | print nums # Prints "set([0, 1, 2, 3, 4, 5])" 299 | 300 | ``` 301 | 302 | ### 元组Tuples 303 | 304 | 元组是一个值的有序列表(不可改变)。从很多方面来说,元组和列表都很相似。和列表最重要的不同在于,元组可以在字典中用作键,还可以作为集合的元素,而列表不行。例子如下: 305 | 306 | ```python 307 | d = {(x, x + 1): x for x in range(10)} # Create a dictionary with tuple keys 308 | print d 309 | t = (5, 6) # Create a tuple 310 | print type(t) # Prints "" 311 | print d[t] # Prints "5" 312 | print d[(1, 2)] # Prints "1" 313 | ``` 314 | 315 | [文档**](https://link.zhihu.com/?target=https%3A//docs.python.org/2/tutorial/datastructures.html%23tuples-and-sequences)有更多元组的信息。 316 | 317 | ## 函数Functions 318 | 319 | Python函数使用def来定义函数: 320 | 321 | ```python 322 | def sign(x): 323 | if x > 0: 324 | return 'positive' 325 | elif x < 0: 326 | return 'negative' 327 | else: 328 | return 'zero' 329 | 330 | for x in [-1, 0, 1]: 331 | print sign(x) 332 | # Prints "negative", "zero", "positive" 333 | ``` 334 | 335 | 我们常常使用可选参数来定义函数: 336 | 337 | ``` 338 | def hello(name, loud=False): 339 | if loud: 340 | print 'HELLO, %s' % name.upper() 341 | else: 342 | print 'Hello, %s!' % name 343 | 344 | hello('Bob') # Prints "Hello, Bob" 345 | hello('Fred', loud=True) # Prints "HELLO, FRED!" 346 | 347 | ``` 348 | 349 | 函数还有很多内容,可以查看[文档**](https://link.zhihu.com/?target=https%3A//docs.python.org/2/tutorial/controlflow.html%23defining-functions)。 350 | 351 | ## 类Classes 352 | 353 | Python对于类的定义是简单直接的: 354 | 355 | ```python 356 | class Greeter(object): 357 | 358 | # Constructor 359 | def __init__(self, name): 360 | self.name = name # Create an instance variable 361 | 362 | # Instance method 363 | def greet(self, loud=False): 364 | if loud: 365 | print 'HELLO, %s!' % self.name.upper() 366 | else: 367 | print 'Hello, %s' % self.name 368 | 369 | g = Greeter('Fred') # Construct an instance of the Greeter class 370 | g.greet() # Call an instance method; prints "Hello, Fred" 371 | g.greet(loud=True) # Call an instance method; prints "HELLO, FRED!" 372 | ``` 373 | 374 | 更多类的信息请查阅[文档](https://link.zhihu.com/?target=https%3A//docs.python.org/2/tutorial/classes.html)。 375 | 376 | # Numpy 377 | 378 | Numpy是Python中用于科学计算的核心库。它提供了高性能的多维数组对象,以及相关工具。 379 | 380 | ## 数组Arrays 381 | 382 | 一个numpy数组是一个由不同数值组成的网格。网格中的数据都是同一种数据类型,可以通过非负整型数的元组来访问。维度的数量被称为数组的阶,数组的大小是一个由整型数构成的元组,可以描述数组不同维度上的大小。 383 | 384 | 我们可以从列表创建数组,然后利用方括号访问其中的元素: 385 | 386 | ``` 387 | import numpy as np 388 | 389 | a = np.array([1, 2, 3]) # Create a rank 1 array 390 | print type(a) # Prints "" 391 | print a.shape # Prints "(3,)" 392 | print a[0], a[1], a[2] # Prints "1 2 3" 393 | a[0] = 5 # Change an element of the array 394 | print a # Prints "[5, 2, 3]" 395 | 396 | b = np.array([[1,2,3],[4,5,6]]) # Create a rank 2 array 397 | print b # 显示一下矩阵b 398 | print b.shape # Prints "(2, 3)" 399 | print b[0, 0], b[0, 1], b[1, 0] # Prints "1 2 4" 400 | 401 | ``` 402 | 403 | Numpy还提供了很多其他创建数组的方法: 404 | 405 | ```python 406 | import numpy as np 407 | 408 | a = np.zeros((2,2)) # Create an array of all zeros 409 | print a # Prints "[[ 0. 0.] 410 | # [ 0. 0.]]" 411 | 412 | b = np.ones((1,2)) # Create an array of all ones 413 | print b # Prints "[[ 1. 1.]]" 414 | 415 | c = np.full((2,2), 7) # Create a constant array 416 | print c # Prints "[[ 7. 7.] 417 | # [ 7. 7.]]" 418 | 419 | d = np.eye(2) # Create a 2x2 identity matrix 420 | print d # Prints "[[ 1. 0.] 421 | # [ 0. 1.]]" 422 | 423 | e = np.random.random((2,2)) # Create an array filled with random values 424 | print e # Might print "[[ 0.91940167 0.08143941] 425 | # [ 0.68744134 0.87236687]]" 426 | ``` 427 | 428 | 其他数组相关方法,请查看[文档](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/user/basics.creation.html%23arrays-creation)。 429 | 430 | ## 访问数组 431 | 432 | Numpy提供了多种访问数组的方法。 433 | 434 | **切片**:和Python列表类似,numpy数组可以使用切片语法。因为数组可以是多维的,所以你**必须**为每个维度指定好切片。 435 | 436 | ```python 437 | import numpy as np 438 | 439 | # Create the following rank 2 array with shape (3, 4) 440 | # [[ 1 2 3 4] 441 | # [ 5 6 7 8] 442 | # [ 9 10 11 12]] 443 | a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) 444 | 445 | # Use slicing to pull out the subarray consisting of the first 2 rows 446 | # and columns 1 and 2; b is the following array of shape (2, 2): 447 | # [[2 3] 448 | # [6 7]] 449 | b = a[:2, 1:3] 450 | 451 | # A slice of an array is a view into the same data, so modifying it 452 | # will modify the original array. 453 | print a[0, 1] # Prints "2" 454 | b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1] 455 | print a[0, 1] # Prints "77" 456 | ``` 457 | 458 | 你可以同时使用整型和切片语法来访问数组。但是,这样做会产生一个比原数组低阶的新数组。需要注意的是,这里和MATLAB中的情况是不同的: 459 | 460 | ```python 461 | import numpy as np 462 | 463 | # Create the following rank 2 array with shape (3, 4) 464 | # [[ 1 2 3 4] 465 | # [ 5 6 7 8] 466 | # [ 9 10 11 12]] 467 | a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) 468 | 469 | # Two ways of accessing the data in the middle row of the array. 470 | # Mixing integer indexing with slices yields an array of lower rank, 471 | # while using only slices yields an array of the same rank as the 472 | # original array: 473 | row_r1 = a[1, :] # Rank 1 view of the second row of a 474 | row_r2 = a[1:2, :] # Rank 2 view of the second row of a 475 | print row_r1, row_r1.shape # Prints "[5 6 7 8] (4,)" 476 | print row_r2, row_r2.shape # Prints "[[5 6 7 8]] (1, 4)" 477 | 478 | # We can make the same distinction when accessing columns of an array: 479 | col_r1 = a[:, 1] 480 | col_r2 = a[:, 1:2] 481 | print col_r1, col_r1.shape # Prints "[ 2 6 10] (3,)" 482 | print col_r2, col_r2.shape # Prints "[[ 2] 483 | # [ 6] 484 | # [10]] (3, 1)" 485 | ``` 486 | 487 | **整型数组访问**:当我们使用切片语法访问数组时,得到的总是原数组的一个子集。整型数组访问允许我们利用其它数组的数据构建一个新的数组: 488 | 489 | ```python 490 | import numpy as np 491 | 492 | a = np.array([[1,2], [3, 4], [5, 6]]) 493 | 494 | # An example of integer array indexing. 495 | # The returned array will have shape (3,) and 496 | print a[[0, 1, 2], [0, 1, 0]] # Prints "[1 4 5]" 497 | 498 | # The above example of integer array indexing is equivalent to this: 499 | print np.array([a[0, 0], a[1, 1], a[2, 0]]) # Prints "[1 4 5]" 500 | 501 | # When using integer array indexing, you can reuse the same 502 | # element from the source array: 503 | print a[[0, 0], [1, 1]] # Prints "[2 2]" 504 | 505 | # Equivalent to the previous integer array indexing example 506 | print np.array([a[0, 1], a[0, 1]]) # Prints "[2 2]" 507 | ``` 508 | 509 | 整型数组访问语法还有个有用的技巧,可以用来选择或者更改矩阵中每行中的一个元素: 510 | 511 | ```python 512 | import numpy as np 513 | 514 | # Create a new array from which we will select elements 515 | a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]]) 516 | 517 | print a # prints "array([[ 1, 2, 3], 518 | # [ 4, 5, 6], 519 | # [ 7, 8, 9], 520 | # [10, 11, 12]])" 521 | 522 | # Create an array of indices 523 | b = np.array([0, 2, 0, 1]) 524 | 525 | # Select one element from each row of a using the indices in b 526 | print a[np.arange(4), b] # Prints "[ 1 6 7 11]" 527 | 528 | # Mutate one element from each row of a using the indices in b 529 | a[np.arange(4), b] += 10 530 | 531 | print a # prints "array([[11, 2, 3], 532 | # [ 4, 5, 16], 533 | # [17, 8, 9], 534 | # [10, 21, 12]]) 535 | ``` 536 | 537 | **布尔型数组访问**:布尔型数组访问可以让你选择数组中任意元素。通常,这种访问方式用于选取数组中满足某些条件的元素,举例如下: 538 | 539 | ```python 540 | import numpy as np 541 | 542 | a = np.array([[1,2], [3, 4], [5, 6]]) 543 | 544 | bool_idx = (a > 2) # Find the elements of a that are bigger than 2; 545 | # this returns a numpy array of Booleans of the same 546 | # shape as a, where each slot of bool_idx tells 547 | # whether that element of a is > 2. 548 | 549 | print bool_idx # Prints "[[False False] 550 | # [ True True] 551 | # [ True True]]" 552 | 553 | # We use boolean array indexing to construct a rank 1 array 554 | # consisting of the elements of a corresponding to the True values 555 | # of bool_idx 556 | print a[bool_idx] # Prints "[3 4 5 6]" 557 | 558 | # We can do all of the above in a single concise statement: 559 | print a[a > 2] # Prints "[3 4 5 6]" 560 | ``` 561 | 562 | 为了教程的简介,有很多数组访问的细节我们没有详细说明,可以查看[文档](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/reference/arrays.indexing.html)。 563 | 564 | ## 数据类型 565 | 566 | 每个Numpy数组都是数据类型相同的元素组成的网格。Numpy提供了很多的数据类型用于创建数组。当你创建数组的时候,Numpy会尝试猜测数组的数据类型,你也可以通过参数直接指定数据类型,例子如下: 567 | 568 | ```python 569 | import numpy as np 570 | 571 | x = np.array([1, 2]) # Let numpy choose the datatype 572 | print x.dtype # Prints "int64" 573 | 574 | x = np.array([1.0, 2.0]) # Let numpy choose the datatype 575 | print x.dtype # Prints "float64" 576 | 577 | x = np.array([1, 2], dtype=np.int64) # Force a particular datatype 578 | print x.dtype # Prints "int64" 579 | ``` 580 | 581 | 更多细节查看[文档**](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/reference/arrays.dtypes.html)。 582 | 583 | ## 数组计算 584 | 585 | 基本数学计算函数会对数组中元素逐个进行计算,既可以利用操作符重载,也可以使用函数方式: 586 | 587 | ```python 588 | import numpy as np 589 | 590 | x = np.array([[1,2],[3,4]], dtype=np.float64) 591 | y = np.array([[5,6],[7,8]], dtype=np.float64) 592 | 593 | # Elementwise sum; both produce the array 594 | # [[ 6.0 8.0] 595 | # [10.0 12.0]] 596 | print x + y 597 | print np.add(x, y) 598 | 599 | # Elementwise difference; both produce the array 600 | # [[-4.0 -4.0] 601 | # [-4.0 -4.0]] 602 | print x - y 603 | print np.subtract(x, y) 604 | 605 | # Elementwise product; both produce the array 606 | # [[ 5.0 12.0] 607 | # [21.0 32.0]] 608 | print x * y 609 | print np.multiply(x, y) 610 | 611 | # Elementwise division; both produce the array 612 | # [[ 0.2 0.33333333] 613 | # [ 0.42857143 0.5 ]] 614 | print x / y 615 | print np.divide(x, y) 616 | 617 | # Elementwise square root; produces the array 618 | # [[ 1. 1.41421356] 619 | # [ 1.73205081 2. ]] 620 | print np.sqrt(x) 621 | ``` 622 | 623 | 和MATLAB不同,*是元素逐个相乘,而不是矩阵乘法。在Numpy中使用dot来进行矩阵乘法: 624 | 625 | ```python 626 | import numpy as np 627 | 628 | x = np.array([[1,2],[3,4]]) 629 | y = np.array([[5,6],[7,8]]) 630 | 631 | v = np.array([9,10]) 632 | w = np.array([11, 12]) 633 | 634 | # Inner product of vectors; both produce 219 635 | print v.dot(w) 636 | print np.dot(v, w) 637 | 638 | # Matrix / vector product; both produce the rank 1 array [29 67] 639 | print x.dot(v) 640 | print np.dot(x, v) 641 | 642 | # Matrix / matrix product; both produce the rank 2 array 643 | # [[19 22] 644 | # [43 50]] 645 | print x.dot(y) 646 | print np.dot(x, y) 647 | ``` 648 | 649 | Numpy提供了很多计算数组的函数,其中最常用的一个是**sum**: 650 | 651 | ```python 652 | import numpy as np 653 | 654 | x = np.array([[1,2],[3,4]]) 655 | 656 | print np.sum(x) # Compute sum of all elements; prints "10" 657 | print np.sum(x, axis=0) # Compute sum of each column; prints "[4 6]" 658 | print np.sum(x, axis=1) # Compute sum of each row; prints "[3 7]" 659 | ``` 660 | 661 | 想要了解更多函数,可以查看[文档](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/reference/routines.math.html)。 662 | 663 | 除了计算,我们还常常改变数组或者操作其中的元素。其中将矩阵转置是常用的一个,在Numpy中,使用**T**来转置矩阵: 664 | 665 | ```python 666 | import numpy as np 667 | 668 | x = np.array([[1,2], [3,4]]) 669 | print x # Prints "[[1 2] 670 | # [3 4]]" 671 | print x.T # Prints "[[1 3] 672 | # [2 4]]" 673 | 674 | # Note that taking the transpose of a rank 1 array does nothing: 675 | v = np.array([1,2,3]) 676 | print v # Prints "[1 2 3]" 677 | print v.T # Prints "[1 2 3]" 678 | ``` 679 | 680 | Numpy还提供了更多操作数组的方法,请查看[文档](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/reference/routines.array-manipulation.html)。 681 | 682 | ## 广播Broadcasting 683 | 684 | 广播是一种强有力的机制,它让Numpy可以让不同大小的矩阵在一起进行数学计算。我们常常会有一个小的矩阵和一个大的矩阵,然后我们会需要用小的矩阵对大的矩阵做一些计算。 685 | 686 | 举个例子,如果我们想要把一个向量加到矩阵的每一行,我们可以这样做: 687 | 688 | ``` 689 | import numpy as np 690 | 691 | # We will add the vector v to each row of the matrix x, 692 | # storing the result in the matrix y 693 | x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]]) 694 | v = np.array([1, 0, 1]) 695 | y = np.empty_like(x) # Create an empty matrix with the same shape as x 696 | 697 | # Add the vector v to each row of the matrix x with an explicit loop 698 | for i in range(4): 699 | y[i, :] = x[i, :] + v 700 | 701 | # Now y is the following 702 | # [[ 2 2 4] 703 | # [ 5 5 7] 704 | # [ 8 8 10] 705 | # [11 11 13]] 706 | print y 707 | 708 | ``` 709 | 710 | 这样是行得通的,但是当x矩阵非常大,利用循环来计算就会变得很慢很慢。我们可以换一种思路: 711 | 712 | ```python 713 | import numpy as np 714 | 715 | # We will add the vector v to each row of the matrix x, 716 | # storing the result in the matrix y 717 | x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]]) 718 | v = np.array([1, 0, 1]) 719 | vv = np.tile(v, (4, 1)) # Stack 4 copies of v on top of each other 720 | print vv # Prints "[[1 0 1] 721 | # [1 0 1] 722 | # [1 0 1] 723 | # [1 0 1]]" 724 | y = x + vv # Add x and vv elementwise 725 | print y # Prints "[[ 2 2 4 726 | # [ 5 5 7] 727 | # [ 8 8 10] 728 | # [11 11 13]]" 729 | ``` 730 | 731 | Numpy广播机制可以让我们不用创建vv,就能直接运算,看看下面例子: 732 | 733 | ```python 734 | import numpy as np 735 | 736 | # We will add the vector v to each row of the matrix x, 737 | # storing the result in the matrix y 738 | x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]]) 739 | v = np.array([1, 0, 1]) 740 | y = x + v # Add v to each row of x using broadcasting 741 | print y # Prints "[[ 2 2 4] 742 | # [ 5 5 7] 743 | # [ 8 8 10] 744 | # [11 11 13]]" 745 | ``` 746 | 747 | 对两个数组使用广播机制要遵守下列规则: 748 | 749 | 1. 如果数组的秩不同,使用1来将秩较小的数组进行扩展,直到两个数组的尺寸的长度都一样。 750 | 2. 如果两个数组在某个维度上的长度是一样的,或者其中一个数组在该维度上长度为1,那么我们就说这两个数组在该维度上是**相容**的。 751 | 3. 如果两个数组在所有维度上都是相容的,他们就能使用广播。 752 | 4. 如果两个输入数组的尺寸不同,那么注意其中较大的那个尺寸。因为广播之后,两个数组的尺寸将和那个较大的尺寸一样。 753 | 5. 在任何一个维度上,如果一个数组的长度为1,另一个数组长度大于1,那么在该维度上,就好像是对第一个数组进行了复制。 754 | 755 | 如果上述解释看不明白,可以读一读[文档](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/user/basics.broadcasting.html)和这个[解释](https://link.zhihu.com/?target=http%3A//scipy.github.io/old-wiki/pages/EricsBroadcastingDoc)。**译者注**:强烈推荐阅读文档中的例子。 756 | 757 | 支持广播机制的函数是全局函数。哪些是全局函数可以在[文档](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/reference/ufuncs.html%23available-ufuncs)中查找。 758 | 759 | 下面是一些广播机制的使用: 760 | 761 | ```python 762 | import numpy as np 763 | 764 | # Compute outer product of vectors 765 | v = np.array([1,2,3]) # v has shape (3,) 766 | w = np.array([4,5]) # w has shape (2,) 767 | # To compute an outer product, we first reshape v to be a column 768 | # vector of shape (3, 1); we can then broadcast it against w to yield 769 | # an output of shape (3, 2), which is the outer product of v and w: 770 | # [[ 4 5] 771 | # [ 8 10] 772 | # [12 15]] 773 | print np.reshape(v, (3, 1)) * w 774 | 775 | # Add a vector to each row of a matrix 776 | x = np.array([[1,2,3], [4,5,6]]) 777 | # x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3), 778 | # giving the following matrix: 779 | # [[2 4 6] 780 | # [5 7 9]] 781 | print x + v 782 | 783 | # Add a vector to each column of a matrix 784 | # x has shape (2, 3) and w has shape (2,). 785 | # If we transpose x then it has shape (3, 2) and can be broadcast 786 | # against w to yield a result of shape (3, 2); transposing this result 787 | # yields the final result of shape (2, 3) which is the matrix x with 788 | # the vector w added to each column. Gives the following matrix: 789 | # [[ 5 6 7] 790 | # [ 9 10 11]] 791 | print (x.T + w).T 792 | 793 | # Another solution is to reshape w to be a row vector of shape (2, 1); 794 | # we can then broadcast it directly against x to produce the same 795 | # output. 796 | print x + np.reshape(w, (2, 1)) 797 | 798 | # Multiply a matrix by a constant: 799 | # x has shape (2, 3). Numpy treats scalars as arrays of shape (); 800 | # these can be broadcast together to shape (2, 3), producing the 801 | # following array: 802 | # [[ 2 4 6] 803 | # [ 8 10 12]] 804 | print x * 2 805 | ``` 806 | 807 | 广播机制能够让你的代码更简洁更迅速,能够用的时候请尽量使用! 808 | 809 | ## Numpy文档 810 | 811 | 这篇教程涉及了你需要了解的numpy中的一些重要内容,但是numpy远不止如此。可以查阅[numpy文献](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/numpy/reference/)来学习更多。 812 | 813 | # SciPy 814 | 815 | Numpy提供了高性能的多维数组,以及计算和操作数组的基本工具。[SciPy](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/scipy/reference/)基于Numpy,提供了大量的计算和操作数组的函数,这些函数对于不同类型的科学和工程计算非常有用。 816 | 817 | 熟悉SciPy的最好方法就是阅读[文档](https://link.zhihu.com/?target=http%3A//docs.scipy.org/doc/scipy/reference/index.html)。我们会强调对于本课程有用的部分。 818 | 819 | ## 图像操作 820 | 821 | SciPy提供了一些操作图像的基本函数。比如,它提供了将图像从硬盘读入到数组的函数,也提供了将数组中数据写入的硬盘成为图像的函数。下面是一个简单的例子: 822 | 823 | ```python 824 | from scipy.misc import imread, imsave, imresize 825 | 826 | # Read an JPEG image into a numpy array 827 | img = imread('assets/cat.jpg') 828 | print img.dtype, img.shape # Prints "uint8 (400, 248, 3)" 829 | 830 | # We can tint the image by scaling each of the color channels 831 | # by a different scalar constant. The image has shape (400, 248, 3); 832 | # we multiply it by the array [1, 0.95, 0.9] of shape (3,); 833 | # numpy broadcasting means that this leaves the red channel unchanged, 834 | # and multiplies the green and blue channels by 0.95 and 0.9 835 | # respectively. 836 | img_tinted = img * [1, 0.95, 0.9] 837 | 838 | # Resize the tinted image to be 300 by 300 pixels. 839 | img_tinted = imresize(img_tinted, (300, 300)) 840 | 841 | # Write the tinted image back to disk 842 | imsave('assets/cat_tinted.jpg', img_tinted) 843 | ``` 844 | 845 | **译者注**:如果运行这段代码出现类似**ImportError: cannot import name imread**的报错,那么请利用pip进行Pillow的下载,可以解决问题。命令:pip install Pillow。 -------------------------------------------------------------------------------- /Code/threadpool.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: thread pool 4 | category: project 5 | description: 线程池 6 | --- 7 | ##半同步半异步线程池## 8 | 半同步半异步模式线程池:多线程处理更灵活性 9 | 10 | 11 | ###线程池有两个活动过程:### 12 | > + 外面不停的往线程池添加任务 13 | > + 线程池内部不停的取任务执行 14 | 15 | 引入设计模式思想,实现解耦,提高代码可复用性 16 | 生产者-消费者模式 17 | > + 同步层是生产者,不断将新任务丢到排队层 18 | > + 消费者是异步层,线程执行排队层的任务 19 | > ![threadpool](/Code/threadpool/threadpool.png) 20 | 21 | ###半同步半异步线程池-消费者### 22 | 23 | ![consumer](/Code/threadpool/consumer.png) 24 | 25 | ###半同步半异步线程池-生产者### 26 | 27 | ![producer](/Code/threadpool/producer.png) 28 | 29 | ###半同步半异步线程池特性### 30 | 半同步半异步线程池特性介绍: 31 | > + 锁机制、条件变量实现线程安全 32 | > + 右值引用、move移动语义、forward完美转发减少内存占用率 33 | > + 实现对不同系统平台以及不同编译环境的兼容性 34 | > + 半同步半异步线程池为轻量级线程池库,具有极佳的可伸缩性 35 | > + 开源、通用性强 36 | 37 | ###源码链接### 38 | > [线程池库](https://github.com/ForrestPi/Cplusplus11_project/tree/master/threadPool"ThreadPool")。 39 | 40 | 41 | 42 | 43 | [ForrestPi]: http://forrestpi.github.io/ "ForrestPi" 44 | [1]: {{ page.url}} ({{ page.title }}) -------------------------------------------------------------------------------- /Code/threadpool/consumer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Code/threadpool/consumer.png -------------------------------------------------------------------------------- /Code/threadpool/producer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Code/threadpool/producer.png -------------------------------------------------------------------------------- /Code/threadpool/threadpool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/Code/threadpool/threadpool.png -------------------------------------------------------------------------------- /ComputerVision/Automatic-license-plate-recognition.md: -------------------------------------------------------------------------------- 1 | # Automatic license plate recognition 2 | 3 | # ——车牌识别算法介绍 4 | 5 | 汽车牌照自动识别整个处理过程分为预处理、边缘提取、车牌定位、字符分割、字符识别五大模块,其中字符识别过程主要由以下3个部分组成: 6 | 7 | ①正确地分割文字图像区域; 8 | 9 | ②正确的分离单个文字; 10 | 11 | ③正确识别单个字符。 12 | 13 | 14 | 15 | 系统设计概述 16 | 17 | 由于车辆牌照是机动车唯一的管理标识符号,在交通管理中具有不可替代的作用,因此车辆牌照识别系统应具有很高的识别正确率,对环境光照条件、拍摄位置和车辆行驶速度等因素的影响应有较大的容阈,并且要求满足实时性要求。 18 | 19 |                              ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic001.jpg) 20 | 21 | 该系统是计算机图像处理与字符识别技术在智能化交通管理系统中的应用,它主要由牌照图像的采集和预处理、牌照区域的定位和提取、牌照字符的分割和识别等几个部分组成。 22 | 23 | 其基本工作过程如下: 24 | 25 |     (1)当行驶的车辆经过时,触发埋设在固定位置的传感器,系统被唤醒处于工作状态; 26 | 27 |          一旦连接摄像头光快门的光电传感器被触发,设置在车辆前方、后方和侧面的相机同时拍摄下车辆图像; 28 | 29 |     (2)由摄像机或CCD摄像头拍摄的含有车辆牌照的图像通视频卡输入计算机进行预处理, 30 | 31 |          图像预处理包括图像转换、图像增强、滤波和水平较正等; 32 | 33 |     (3)由检索模块进行牌照搜索与检测,定位并分割出包含牌照字符号码的矩形区域; 34 | 35 |     (4)对牌照字符进行二值化并分割出单个字符,经归一化后输入字符识别系统进行识别。 36 | 37 | 总体设计方案: 38 | 39 | 车辆牌照识别整个系统主要是由车牌定位和字符识别两部分组成,其中车牌定位又可以分为图像预处理及边缘提取模块和牌照的定位及分割模块;字符识别可以分为字符分割与特征提取和单个字符识别两个模块。 40 | 41 | 为了用于牌照的分割和牌照字符的识别,原始图象应具有适当的亮度,较大的对比度和清晰可辩的牌照图象。但由于该系统的摄像部分工作于开放的户外环境,加之车辆牌照的整洁度、自然光照条件、拍摄时摄像机与牌照的矩离和角度以及车辆行驶速度等因素的影响,牌照图象可能出现模糊、歪斜和缺损等严重缺陷,因此需要对原始图象进行识别前的预处理。 42 | 43 | 牌照的定位和分割是牌照识别系统的关键技术之一,其主要目的是在经图象预处理后的原始灰度图象中确定牌照的具体位置,并将包含牌照字符的一块子图象从整个图象中分割出来,供字符识别子系统识别之用,分割的准确与否直接关系到整个牌照字符识别系统的识别率。 44 | 45 | 由于拍摄时的光照条件、牌照的整洁程度的影响,和摄像机的焦距调整、镜头的光学畸变所产生的噪声都会不同程度地造成牌照字符的边界模糊、细节不清、笔划断开或粗细不均,加上牌照上的污斑等缺陷,致使字符提取困难,进而影响字符识别的准确性。因此,需要对字符在识别之前再进行一次针对性的处理。 46 | 47 | 车牌识别的最终目的就是对车牌上的文字进行识别。 48 | 49 |   50 | 51 | 各部分实现流程: 52 | 53 | 一、图像采集和转换 54 | 55 | 考虑到现有牌照的字符与背景的颜色搭配一般有蓝底白字、黄底黑字、白底红字、绿底白字和黑底白字等几种,利用不同的色彩通道就可以将区域与背景明显地区分出来,例如,对蓝底白字这种最常见的牌照,采用蓝色B 通道时牌照区域为一亮的矩形,而牌照字符在区域中并不呈现。因为蓝色(255,0,0)与白色(255,255,255)在B通道中并无区分,而在G、R 通道或是灰度图象中并无此便利。同理对白底黑字的牌照可用R 通道,绿底白字的牌照可以用G 通道就可以明显呈现出牌照区域的位置,便于后续处理。 56 | 57 | 二、边缘提取 58 | 59 | 边缘是指图像局部亮度变化显著的部分,是图像风、纹理特征提取和形状特征提取等图像分析的重要基础。所以在此我们要对图像进行边缘检测。图象增强处理对图象牌照的可辩认度的改善和简化后续的牌照字符定位和分割的难度都是很有必要的。增强图象对比度度的方法有:灰度线性变换、图象平滑处理等。 60 | 61 | 2.1 灰度矫正 62 | 63 | 由于牌照图象在拍摄时受到种种条件的限制和干扰,图象的灰度值往往与实际景物不完全匹配,这将直接影响到图象的后续处理。如果造成这种影响的原因主要是由于被摄物体的远近不同,使得图象中央区域和边缘区域的灰度失衡,或是由于摄像头在扫描时各点的灵敏度有较大的差异而产生图象灰度失真,或是由于曝光不足而使得图像的灰度变化范围很窄。这时就可以采用灰度校正的方法来处理,增强灰度的变化范围、丰富灰度层次,以达到增强图象的对比度和分辨率。我们发现车辆牌照图象的灰度取值范围大多局限在r=(50,200)之间,而且总体上灰度偏低,图象较暗。根据图象处理系统的条件,最好将灰度范围展开到s=(0,255)之间。 64 | 65 | 2.2图像平滑处理 66 | 67 | 对于受噪声干扰严重的图象,由于噪声点多在频域中映射为高频分量,因此可以在通过低也可以直接在空域中用求邻域平均值的方法来通滤波器来滤除噪声,但实际中为了简化算法,削弱噪声的影响,这种方法称为图象平滑处理。 68 | 69 |     然而,邻域平均值的平滑处理会使得图象灰度急剧变化的地方,尤其是物体边缘区域和字符轮廓等部分产生模糊作用。为了克服这种平均化引起的图象模糊现象,我们给中心点象素值与其邻域平均值的差值设置一固定的阈值,只有大于该阈值的点才能替换为邻域平均值,而差值不大于阈值时,仍保留原来的值,从而减少由于平均化引起的图象模糊。 70 | 71 |                                            ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic002.jpg) 72 | 73 |     图像中车辆牌照是具有比较显著特征的一块图象区域,这此特征表现在:近似水平的矩形区域;其中字符串都是按水平方向排列的;在整体图象中的位置较为固定。正是由于牌照图象的这些特点,再经过适当的图象变换,它在整幅中可以明显地呈现出其边缘。边缘提取是较经典的算法,此处边缘的提取采用的是Roberts算子。 74 | 75 |                  ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic003.jpg) 76 | 77 | 分析这种情况产生的原因,归纳起来主要有以下方面: 78 | 79 |  1、原始图像清晰度比较高,从而简化了预处理 80 | 81 |  2、图像的平滑处理会使图像的边缘信息受到损失,图像变得模糊 82 | 83 |  3、图像的锐化可以增强图像中物体的边缘轮廓,但同时也使一些噪声得到了增强 84 | 85 |   86 | 87 | 三、牌照的定位和分割 88 | 89 | 牌照的定位和分割是牌照识别系统的关键技术之一,其主要目的是在经图象预处理后的原始灰度图象中确定牌照的具体位置,并将包含牌照字符的一块子图象从整个图象中分割出来,供字符识别子系统识别之用,分割的准确与否直接关系到整个牌照字符识别系统的识别率。由于牌照图象在原始图象中是很有特征的一个子区域,确切说是水平度较高的横向近似的长方形,它在原始图象中的相对位置比较集中,而且其灰度值与周边区域有明显的不同,因而在其边缘形成了灰度突变的边界,这样就便于通过边缘检测来对图象进行分割。 90 | 91 |     3.1牌照区域定位 92 | 93 |     ​牌照图象经过了以上的处理后,牌照区域已经十分明显,而且其边缘得到了勾勒和加强。此时可进一步确定牌照在整幅图象中的准确位置。这里选用的是数学形态学的方法,其基本思想是用具有一定形态的机构元素去量度和提取图像中的对应形状以达到对图像分析和识别的目的。数学形态学的应用可以简化图像数据,保持它们基本的形态特征,并除去不相干的结构。 94 | 95 |   3.2牌照区域分割    ​ 96 | 97 | 对车牌的分割可以有很多种方法,本程序是利用车牌的彩色信息的彩色分割方法。根据车牌底色等有关的先验知识,采用彩色像素点统计的方法分割出合理的车牌区域,确定车牌底色蓝色RGB对应的各自灰度范围,然后行方向统计在此颜色范围内的像素点数量,设定合理的阈值,确定车牌在行方向的合理区域。然后,在分割出的行区域内,统计列方向蓝色像素点的数量,最终确定完整的车牌区域。 98 | 99 |                             ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic004.jpg) 100 | 101 | 3.3统一处理    ​ 102 | 103 | 经过上述方法分割出来的车牌图像中存在目标物体、背景还有噪声,要想从图像中直接提取出目标物体,最常用的方法就是设定一个阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群,即对图像二值化。均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素。再用模板中的全体像素的平均值来代替原来像素值。 104 | 105 |                                   ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic005.jpg) 106 | 107 | 四、字符分割和比对 108 | 109 | 4.1字符分割 110 | 111 | 在汽车牌照自动识别过程中,字符分割有承前启后的作用。它在前期牌照定位的基础上进行字符的分割,然后再利用分割的结果进行字符识别。字符识别的算法很多,因为车牌字符间间隔较大,不会出现字符粘连情况,所以此处采用的方法为寻找连续有文字的块,若长度大于某阈值,则认为该块有两个字符组成,需要分割。 112 | 113 |                                  ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic006.jpg) 114 | 115 | 4.2字符归一化 116 | 117 | 一般分割出来的字符要进行进一步的处理,以满足下一步字符识别的需要。但是对于车牌的识别,并不需要太多的处理就已经可以达到正确识别的目的。在此只进行了归一化处理,然后进行后期处理。 118 | 119 |                                      ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic007.jpg) 120 | 121 | 4.3字符识别 122 | 123 | 字符的识别目前用于车牌字符识别(OCR)中的算法主要有基于模板匹配的OCR算法以及基于人工神经网络的OCR算法。基于模板匹配的OCR的基本过程是:首先对待识别字符进行二值化并将其尺寸大小缩放为字符数据库中模板的大小,然后与所有的模板进行匹配,最后选最佳匹配作为结果。用人工神经网络进行字符识别主要有两种方法:一种方法是先对待识别字符进行特征提取,然后用所获得的特征来训练神经网络分类器。识别效果与字符特征的提取有关,而字符特征提取往往比较耗时。因此,字符特征的提取就成为研究的关键。另一种方法则充分利用神经网络的特点,直接把待处理图像输入网络,由网络自动实现特征提取直至识别。 124 | 125 | 模板匹配的主要特点是实现简单,当字符较规整时对字符图像的缺损、污迹干扰适应力强且识别率相当高。综合模板匹配的这些优点我们将其用为车牌字符识别的主要方法。 126 | 127 | 模板匹配是图象识别方法中最具代表性的基本方法之一,它是将从待识别的图象或图象区域f(i,j)中提取的若干特征量与模板T(i,j)相应的特征量逐个进行比较,计算它们之间规格化的互相关量,其中互相关量最大的一个就表示期间相似程度最高,可将图象归于相应的类。也可以计算图象与模板特征量之间的距离,用最小距离法判定所属类。然而,通常情况下用于匹配的图象各自的成像条件存在差异,产生较大的噪声干扰,或图象经预处理和规格化处理后,使得图象的灰度或像素点的位置发生改变。在实际设计模板的时候,是根据各区域形状固有的特点,突出各类似区域之间的差别,并将容易由处理过程引起的噪声和位移等因素都考虑进去,按照一些基于图象不变特性所设计的特征量来构建模板,就可以避免上述问题。 128 | 129 | 此处采用相减的方法来求得字符与模板中哪一个字符最相似,然后找到相似度最大的输出。汽车牌照的字符一般有七个,大部分车牌第一位是汉字,通常代表车辆所属省份,或是军种、警别等有特定含义的字符简称;紧接其后的为字母与数字。车牌字符识别与一般文字识别在于它的字符数有限,汉字共约50多个,大写英文字母26个,数字10个。所以建立字符模板库也极为方便。为了实验方便,结合本次设计所选汽车牌照的特点,只建立了4个数字26个字母与10个数字的模板。其他模板设计的方法与此相同。 130 | 131 | 首先取字符模板,接着依次取待识别字符与模板进行匹配,将其与模板字符相减,得到的0越多那么就越匹配。把每一幅相减后的图的0值个数保存,然后找数值最大的,即为识别出来的结果。 132 | 133 |                                               ![img](https://github.com/ForrestPi/Blog/blob/master/ComputerVision/pic/Automatic008.jpg) -------------------------------------------------------------------------------- /ComputerVision/FaceRecognition.md: -------------------------------------------------------------------------------- 1 | # 人脸识别:Deep Face Recognition论文阅读 2 | 3 | ## 基本概念 4 | 5 | 在具体到人脸识别方法之前,先对人脸识别中的Face detection, Face alignment, Face verification和Face identification(recognization)进行必要的讲解说明,以方便后续知识的展开。 6 | 7 | ### 人脸检测 8 | 9 | Face detection, 对图像中的人脸进行检测,并将结果用矩形框框出来。 10 | 11 | ### 人脸校正 12 | 13 | Face alignment,对检测到的人脸进行姿态的校正,使其人脸尽可能的”正”,通过校正可以提高人脸识别的精度。校正的方法有2D校正、3D校正的方法,3D校正的方法可以使侧脸得到较好的识别。目前校正在处理过程中完全可以达到实时性的要求,具体可以阅读Face Alignment at 3000 FPS via Regressing Local Binary Features这篇文章([论文笔记](http://blog.csdn.net/boosting1/article/details/26085223))。在进行人脸校正的时候,会有检测特征点的位置这一步,这些特征点位置主要是诸如鼻子左侧,鼻孔下侧,瞳孔位置,上嘴唇下侧等等位置,知道了这些特征点的位置后,做一下位置驱动的变形,脸即可被校”正”了。下面两幅图像分别显示了原来的人脸和经过校正后了的人脸。 14 | 15 | ![drawing](http://i300.photobucket.com/albums/nn17/willard-yuan/blog/f3_zpswxvtrty0.jpg)![drawing](http://i300.photobucket.com/albums/nn17/willard-yuan/blog/Face_zpsxvrwiwan.jpg) 16 | 17 | ### 人脸校验 18 | 19 | Face verification,人脸校验是基于pair matching的方式,所以它得到的答案是“是”或者“不是”。在具体操作的时候,给定一张测试图片,然后挨个进行pair matching,matching上了则说明测试图像与该张匹配上的人脸为同一个人的人脸。一般在**小型**办公室人脸刷脸打卡系统中采用的(应该)是这种方法,具体操作方法大致是这样一个流程:离线逐个录入员工的人脸照片(一个员工录入的人脸一般不止一张),员工在刷脸打卡的时候相机捕获到图像后,通过前面所讲的先进行人脸检测,然后进行人脸校正,再进行人脸校验,一旦match结果为“是”,说明该名刷脸的人员是属于本办公室的,人脸校验到这一步就完成了。在离线录入员工人脸的时候,我们可以将人脸与人名对应,这样一旦在人脸校验成功后,就可以知道这个人是谁了。上面所说的这样一种系统优点是开发费用低廉,适合小型办公场所,缺点是在捕获时不能有遮挡,而且还要求人脸姿态比较正(这种系统我们所有,不过没体验过)。下图给出了示意说明,不过那个“Am I SW?”应该改一下,改成“Am I the same to the seleted face image?”。 20 | 21 | ![drawing](http://mind.kaist.ac.kr/images/amisw.png) 22 | 23 | ### 人脸识别 24 | 25 | Face identification或Face recognition,人脸识别正如下图所示的,它要回答的是“我是谁?”,相比于人脸校验采用的pair matching,它在识别阶段更多的是采用分类的手段。它实际上是对进行了前面两步即人脸检测、人脸校正后做的图像(人脸)分类。![drawing](http://mind.kaist.ac.kr/images/whoami.png)根据上面所介绍的这4个概念,人脸识别包括下面三个模块:![img](http://vis-www.cs.umass.edu/faceAlignment/DAR_sm.jpg)上面进行细拆分包括下图所示的几个步骤:![drawing](http://mind.kaist.ac.kr/images/facerecogflow.png) 26 | 27 | 对上面的概念清楚了后,我们再接着讲一下在人脸识别里面的人脸图像数据库。 28 | 29 | ## 人脸图像数据库 30 | 31 | 人脸图像这个东西因为受到安全隐私等限制,所以一般大规模的人脸数据库比较难拿到,目前我知道到的公开的人脸图像库有LFW(Labelled Faces in the Wild)和YFW(Youtube Faces in the Wild)。下面再列举一些大规模的人脸图像数据库:![img](http://i300.photobucket.com/albums/nn17/willard-yuan/blog/facedatasets_zps8mujnhcl.png) 32 | 33 | ## Deep Face Recognition 34 | 35 | 人脸识别按特征分类可以分成两种:一种是基于浅层特征的人脸识别,一种是基于深度学习的人脸识别方法。Deep Face Recognition这篇文章做了两件事:一是介绍了一种抓取网络上的图片并在有限的人力标注下得到一个大规模人脸图像的方法,二是测试了不同CNN网络结构下人脸校正以及度量学习对人脸识别的精度的影响。 36 | 37 | ### 浅层人脸识别方法 38 | 39 | 首先提取人脸图像的局部特征,比如SIFT、LBP、HOG等特征,然后通过某种pooling机制将它们aggregate成全局人脸描述子,如Fisher Vector(可以参阅A compact and discriminative face track descriptor和Fisher Vector Faces in the Wild这两篇文章)。 40 | 41 | ### 基于深度学习的人脸识别方法 42 | 43 | 通常使用CNN结构,比较典型的代码是DeepFace(Deep-Face:Closing the gap to human-level performance in the face verification),该方法使用一个深层的CNN网络结构,训练所使用的数据集数目为4百万,共包含4000个人的人脸。DeepFace在预处理的阶段使用了3D模型将人脸图像校准到典型姿态下。在当时DeepFace在LFW和在YFW人脸数据库上都取得了最好的结果。后来,文章的作者有对其工作进行了拓展(具体可以阅读Web-scale traing for face identification这篇文章),其训练图库比原来的图库大了两个量级,包括100万个人的脸(英文作identities),每个identity有50张图像,他们通过一种自举策略来选择identities进行网络的训练,并说明了可以通过控制全连接层的维数还提高网络的泛化能力。 44 | 45 | DeepFace的工作后来被进一步拓展成了DeepId系列,具体可以阅读Y. Sun的4篇关于人脸识别的文章: 46 | 47 | - Deep learning face representation by joint identificationverification,在分类和验证(virification)的时候使用多任务学习。 48 | - Deep learning face representation from predicting 10,000 classes,将多个CNNs结构联合起来 49 | - Deeply learned face representations are sparse, selective, and robust,在全连接层前面使用不同的CNN结构。 50 | - Deepid3: Face recognition with very deep neural networks,使用更深的网络结构,大约用到了200个CNN结构,模型非常的复杂。 51 | 52 | 相比于DeepFace,DeepID没有使用3D的校准,而是使用了一种更简单的2D仿射校准,所用的训练图库是由CelebFaces和WDRef两个人脸图像库混合而成的。 53 | 54 | 在2015年谷歌的Facenet中,谷歌的研究人员使用了前面介绍的人脸图像库中的Google人脸数据库上去训练CNN网络,他们使用的是”triplet-based”损失,通过最小化类内差异和最大化类间差异,并在训练阶段将该损失应用在多层(不仅仅是最后一层),在LFW和YTF上获得了最好的识别成绩。 55 | 56 | ## 人脸数据库搜集 57 | 58 | 1. **获取候选人名**。IMDB电影名人列表大约有500K个不同的人名,先从上面通过popularity排序获取到5k个人名,其中男女各一半。这些人名通过不断的筛选排除,最后得到了2622个人人名。 59 | 2. **为每一个人名搜集图片**。借助Google和Bing图片搜索引擎,分别按**人名**和**人名 actor**的两种方式进行查询,比如“Leonardo DiCaprio”和“Leonardo DiCaprio actor”,每次查询选前面500张,这样可以为每个人名(后面将其称为identity)获取到2000张图像。 60 | 3. **用自动filter提高纯度**。对于每一个基于Google查询的结果,将前50个样本作为正样本,其他identity查询的前50个结果作为负样本,用Fisher Vector描述子训练一个one-vs-rest线性分类器。用这个线性分类器对每一个identity的2000个下载结果进行排序,保留前1000个的结果。 61 | 4. **删除近似样本**:对每一幅图像计算其VLAD描述子,并对每一个identity的1000张图像进行聚类,经过这一步后,每个identity的图片数目为623个。文章在这一步说明操作的时候比较简略,比如聚类完后直接说”retaining a single element per cluster”,个人觉得没讲清楚,按照我的理解是应该是这么操作的:对每个identity的1000张图片聚类,聚类数目设置为623,聚完类后共623类,对每一类只保留跟那个类中心最近的那一幅图片,剔除掉该类的其他图片(这么做细想起来还是非常有道理的),这样每一个identity便得到了623张图片。 62 | 5. **最终的人工过滤**。这一步借助训练CNN网络来加速标注过程,具体操作按如下进行:选用AlexNet网络在这2622个identities上进行训练,然后用网络最后输出的softmax分数对每一个identity(此时的每一个identity包含有623张图片)进行降序排序,排序的依据是成为内点(按照我的理解这里的内点就是属于这个identity)的可能性,标注者按照排序的结果进行验证(文章里讲每一个identity的排序结果以200个块进行展示,如果近似纯度大于95%则说明这个块是好的,没怎么搞明白这个地方讲的),最后获取得了982803张较好的图片。 63 | 64 | 下表使每个过程标注所花费的时间:![img](http://i300.photobucket.com/albums/nn17/willard-yuan/blog/datatime_zpsteframsl.png) 65 | 66 | ## 网络结构与训练 67 | 68 | 在文章中,作者将其视为一个N=2622的分类问题,即每一个identity都是一类,选用的网络结构是vggNet,网络的最后一层是分类器(W,b) 69 | 70 | ,分类的误差用softmax log-loss来计算。一旦学习过程完成后,就可以把分类器 71 | 72 | (W,b) 73 | 74 | 去除,分数向量 75 | 76 | ϕ(lt) 77 | 78 | 便可以作为特征通过计算欧式距离进行人脸校验。上面得到的分数向量能够进一步得到改善,通过在欧式空间里面使用”triplet loss”的方式进行训练。其实这里所说使用”triplet loss”的方式进行训练,是对特征的进一步精炼,使用的”triplet loss”学习方非常的常见,是度量学习里面的一种,下面具体讲一下这个特征再学习过程。 79 | 80 | ## 使用triplet loss进行特征再学习 81 | 82 | 对于上面网络的输出分数向量ϕ(lt)∈RD 83 | 84 | ,对其进行 85 | 86 | l2 87 | 88 | 归一化,然后使用affine投影将其投影为 89 | 90 | xt=W′ϕ(lt)/||ϕ(lt)||2 91 | 92 | ,其中 93 | 94 | W′∈RL×D 95 | 96 | , 97 | 98 | W′ 99 | 100 | 为要求解的投影矩阵, 101 | 102 | W′ 103 | 104 | 通过triplet loss损失进行求解(也称作嵌入学习,Embedding learing): 105 | 106 | 上式中p是相对于a而言的正样本,n是相对于a而言的负样本,通过对该式进行优化,即可得到投影矩阵 107 | 108 | W 109 | 110 | ,这样在求得这个投影矩阵后,对上面网络输出的分数向量进行L2归一化,再跟该投影矩阵 111 | 112 | W 113 | 114 | 相乘即可得到特征的最终表示。下表显示了在YFW人脸数据库上不进行特征再学习和进行特征在学习后的识别结果(特征再学习在下表中为Embedding learning):![img](http://i300.photobucket.com/albums/nn17/willard-yuan/blog/lfwVGG_zpsedragzcr.png)从上表可以看到,Embedding learning将原来的91.6%的识别率提高到了97.3%。说明对网络输出的特征进行在学习(跟特征的fine-tune差不多的意思),可以提高精度。另外在[VGG Face Descriptor](http://www.robots.ox.ac.uk/%7Evgg/software/vgg_face/)项目主页上作者贴出了LFW和YFW两个人脸图像库上的识别率。![img](http://www.robots.ox.ac.uk/%7Evgg/software/vgg_face/table.png) 115 | 116 | ## 实验结果 117 | 118 | 在文章中,作者在LFW人脸数据库上分别对Fisher Vector Faces、DeepFace、Fusion、DeepID-2,3、FaceNet、FaceNet+Alignment以及作者的方法进行对比,具体的识别精度我们看下表。![img](http://i300.photobucket.com/albums/nn17/willard-yuan/blog/YFWVGG_zpsr0vz0jzf.png)从上表可以看到,Deep Face Recognition这篇文章所提出的方法训练所用图库大小最小,但取得了跟其他方法具有可比性的结果。 119 | 120 | ## 自己验证效果 121 | 122 | Deep Face Recognition这篇文章其实去年刚发出来的时候就看了,当时还对其效果进行了验证,采用的是人脸减速的方式进行验证的,今天既然对它写成了笔记,就把这个小验证实验也跟着说说。先把结论说一下:**效果确实比较好**!。具体的实验代码可以到我的github上下载:[CNN-for-Face-Image-Retrieval](https://github.com/willard-yuan/CNN-for-Face-Image-Retrieval) 123 | 124 | 当时我做的是人脸检索实验,即用Deep Face Recognition提供的训练好了的网络模型抽取特征,维度为4096维,然后对抽取的特征进行L2归一化,再用余弦距离进行相似性度量,使用的人脸图像库不大,是别人提供给我的,比较规则,大概3000多张(虽然我测的只是这样一个小图库,我相信在大规模的人脸库上,它的效果也会很好),下面是检索的结果: 125 | 126 | ![drawing](https://camo.githubusercontent.com/92504dfe5d43354d0d20dec19cbb5f62e8083445/687474703a2f2f693330302e70686f746f6275636b65742e636f6d2f616c62756d732f6e6e31372f77696c6c6172642d7975616e2f64335f7a7073366c637a65706e7a2e706e67) 127 | 128 | 查询实例1 129 | 130 | 另外VGG还提供的了已经训练好了的Caffe版本模型,具体可以阅读项目主页[VGG Face Descriptor](http://www.robots.ox.ac.uk/%7Evgg/software/vgg_face/) 131 | 132 | -------------------------------------------------------------------------------- /ComputerVision/Feature.md: -------------------------------------------------------------------------------- 1 | # Feature 2 | 3 | ## 特征 4 | 5 | 特征的代表作是SIFT特征,我对此印象特别深刻,当年我在法国做的就是其改进版SURF的加速。后来出现了[BRIEF](http://cvlab.epfl.ch/software/brief/) 、[ORB](http://docs.opencv.org/modules/features2d/doc/feature_detection_and_description.html)、[BRISK](http://www.asl.ethz.ch/people/lestefan/personal/BRISK)和[FREAK](http://www.ivpe.com/freak.htm) 等二值特征,不过现在随着深度学习的快速发展,利用机器学习获取有效的特征取得了巨大的进展,对此的需求也就不再那么强烈,且最近几年并无有影响力的工作。 6 | 7 | [图像特征小结 - Rana专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/sunboyiris/article/details/18229035) 8 | 9 | [FeatureSource](http://rogerioferis.com/VisualRecognitionAndSearch2014/Resources.html) 10 | 11 | [SIFT算法详解 - zddhub的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/zddblog/article/details/7521424) 12 | 13 | [SIFT on GPU (siftgpu)](http://www.cs.unc.edu/%7Eccwu/siftgpu/) 14 | 15 | [HOG:用于人体检测的梯度方向直方图 Histograms of Oriented Gradients for Human Detection - Why So Serious? - 博客频道 - CSDN.NET](http://blog.csdn.net/masibuaa/article/details/14056807) 16 | 17 | [图像物体检测识别中的LBP特征 - 雨石 - 博客频道 - CSDN.NET](http://blog.csdn.net/stdcoutzyx/article/details/37317863) 18 | 19 | [Jiashi Feng](https://sites.google.com/site/jshfeng/home) 20 | 21 | [[CVPR14\] Reconstructing Storyline Graphs from Web Community Photos](http://www.cs.cmu.edu/%7Egunhee/r_storygraph.html) 22 | 23 | [Fast-Match](http://www.eng.tau.ac.il/%7Esimonk/FastMatch/) 24 | 25 | [shape context (形状上下文) - 知行文 - 博客频道 - CSDN.NET](http://blog.csdn.net/aivin24/article/details/8846293) 26 | 27 | [LIOP特征 - 计算机视觉小菜鸟的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/carson2005/article/details/8733339) 28 | 29 | [基于SIFT特征的全景图像拼接 - Why So Serious? - 博客频道 - CSDN.NET](http://blog.csdn.net/masibuaa/article/details/9246493) 30 | 31 | [SIFT算法与SURF算法特征检测效率对比 - Why So Serious? - 博客频道 - CSDN.NET](http://blog.csdn.net/masibuaa/article/details/9357747) 32 | 33 | [尺度空间理论 - ☆Ronny丶 - 博客园](http://www.cnblogs.com/ronny/p/3886013.html) 34 | 35 | [关于推荐系统中的特征工程 - 博客 - 伯乐在线](http://blog.jobbole.com/74951/) 36 | 37 | [LBP原理加源码解析 - 梦想腾飞 - 博客频道 - CSDN.NET](http://blog.csdn.net/xidianzhimeng/article/details/19634573) 38 | 39 | [【计算机视觉】LBP纹理特征 | Jason's Techblog](http://jasonding1354.github.io/2014/11/04/Machine%20Learning/%E3%80%90%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E3%80%91LBP%E7%BA%B9%E7%90%86%E7%89%B9%E5%BE%81/) 40 | 41 | [Harris原理及OpenCV实 - Note of Transposition - 博客频道 - CSDN.NET](http://blog.csdn.net/ttransposition/article/details/11538709) 42 | 43 | [HOG特征(毕业论文节选) - Note of Transposition - 博客频道 - CSDN.NET](http://blog.csdn.net/ttransposition/article/details/41805767) 44 | 45 | [图像局部特征点检测算法综述 - ☆Ronny丶 - 博客园](http://www.cnblogs.com/ronny/p/4260167.html) -------------------------------------------------------------------------------- /ComputerVision/ImageRetrieval.md: -------------------------------------------------------------------------------- 1 | # Image Retrieval 2 | 3 | ## 图像检索 4 | 5 | 6 | 7 | 课题组有个服装检索的国基,组里有好几个搞相关的研究,每次报告都会有他们读过的论文,我耳濡目染,也算是半个检索人了。之前是李菲菲她们的BOW词包模型,后来又到了deep learning大放异彩。不过就我的感觉来看,目前并没有什么特别有效的方法,实验的数据量也不大,且基本都是闭源的,无从验证算法的优劣,这点和tracking是有很大区别的。排序是google的PR算法,我看到好多算法都有借鉴它。 8 | 9 | **综述数据集** 10 | 11 | [各大搜索引擎的比较 - Tuesday - 博客频道 - CSDN.NET](http://blog.csdn.net/naturebe/article/details/7910423) 12 | 13 | [基于内容图像检索的若干技术研究 - William Valentine - 博客频道 - CSDN.NET](http://blog.csdn.net/williamvalentine/article/details/6534198) 14 | 15 | [Image Retrieval: Ideas, influences, and trends of the new age 图像检索综述 文献翻译(一) - William Valentine - 博客频道 - CSDN.NET](http://blog.csdn.net/williamvalentine/article/details/5886804) 16 | 17 | [Image Retrieval: Ideas, Influences, and Trends of the New Age - zjgtan - 博客园](http://www.cnblogs.com/zjgtan/archive/2013/04/07/3006357.html) 18 | 19 | [互联网环境下大规模图像的内容分析笔记 - zjgtan - 博客园](http://www.cnblogs.com/zjgtan/archive/2013/04/11/3014682.html) 20 | 21 | **爬虫** 22 | 23 | [一个简单的多线程爬虫 - CodeMeals - 博客园](http://www.cnblogs.com/fengfenggirl/p/3737738.html) 24 | 25 | **PageRank** 26 | 27 | [搜索引擎基本原理 - Keosu - 博客园](http://www.cnblogs.com/answeryi/archive/2012/09/30/2709291.html) 28 | 29 | [Google 的秘密- PageRank 彻底解说 中文版](http://www.kreny.com/pagerank_cn.htm) 30 | 31 | [PageRank算法 - guisu,程序人生。 逆水行舟,不进则退。 - 博客频道 - CSDN.NET](http://blog.csdn.net/hguisu/article/details/7996185) 32 | 33 | [深入探讨PageRank(一):PageRank算法原理入门 - 愤怒的小狐狸----博客专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/monkey_d_meng/article/details/6554518) 34 | 35 | [谷歌背后的数学](http://www.changhai.org/articles/technology/misc/google_math.php) 36 | 37 | [数据挖掘10大算法(1)——PageRank - 风中之炎 - 博客园](http://www.cnblogs.com/FengYan/archive/2011/11/12/2246461.html) 38 | 39 | [搜索引擎技术之概要预览 - 结构之法 算法之道 - 博客频道 - CSDN.NET](http://blog.csdn.net/v_july_v/article/details/6827391) 40 | 41 | [PageRank实践-博客园用户PageRank排名 - CodeMeals - 博客园](http://www.cnblogs.com/fengfenggirl/p/pagerank-cnblogs.html) 42 | 43 | [利用python、Gephi绘制人人的社交网络图 - Code my world - 博客频道 - CSDN.NET](http://blog.csdn.net/zdw12242/article/details/8687644) 44 | 45 | [二十大数据可视化工具点评 - IT经理网](http://www.ctocio.com/hotnews/8874.html) 46 | 47 | [PageRank算法简介及Map-Reduce实现 - CodeMeals - 博客园](http://www.cnblogs.com/fengfenggirl/p/pagerank-introduction.html) 48 | 49 | **LSH** 50 | 51 | [局部敏感哈希(Locality-Sensitive Hashing, LSH)方法介绍 - CVPR|OpenCV|图像检索|视频检索 - 博客频道 - CSDN.NET](http://blog.csdn.net/icvpr/article/details/12342159) 52 | 53 | [Locality Sensitive Hashing (LSH) Home Page](http://www.mit.edu/%7Eandoni/LSH/) 54 | 55 | [实习日记:图像检索算法 LSH 的总结与分析 - 进阶之路 - 博客园](http://www.cnblogs.com/liyangguang1988/p/3875998.html) 56 | 57 | [Hamming Embedding 汉明嵌入简介 - defineWL的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/definewl/article/details/41217441) 58 | 59 | [CVPR14与图像视频检索相关的论文 - 姜文晖的博客 - 博客频道 - CSDN.NET](http://blog.csdn.net/jwh_bupt/article/details/23039357) 60 | 61 | [百度图像搜索探秘_dengyafeng_新浪博客](http://blog.sina.com.cn/s/blog_6ae183910101gily.html) 62 | 63 | [Computer Vision Group - Shape Analysis](http://vision.in.tum.de/research/shape_analysis) 64 | 65 | [SCHEMA - Network of Excellence in Content-Based Semantic Scene Analysis and Information Retrieval](http://www.iti.gr/SCHEMA/index.html) 66 | 67 | [Gunhee Kim @ CSD.CMU.EDU](http://www.cs.cmu.edu/%7Egunhee/index.html#pub_vis) 68 | 69 | [www.liangzheng.com.cn/Project/project_baseline.html](http://www.liangzheng.com.cn/Project/project_baseline.html) 70 | 71 | [Holidays dataset](http://lear.inrialpes.fr/people/jegou/data.php#holidays) 72 | 73 | [Bag of Word闲谈_zjjconan_新浪博客](http://blog.sina.com.cn/s/blog_4cb0b54301014hxu.html) 74 | 75 | [用python做网页抓取与解析入门笔记 - chentingpc - Ting Chen](http://chentingpc.me/article/article.php?id=961) 76 | 77 | [图像检索:一维直方图+EMD距离 - wxcdzhangping的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/zhangping1987/article/details/37560397) 78 | 79 | [竞赛描述 ](http://www.pkbigdata.com/c/00000000057) 80 | 81 | [2012年06月03日_清醒网_新浪博客](http://blog.sina.com.cn/s/blog_6728688a01016yz2.html) 82 | 83 | [从搜老婆到看AV,拍照搜索未来八大匪夷所思用法_互联网的一些事](http://www.yixieshi.com/it/18682.html) 84 | 85 | [拍照搜索巅峰对决:手机百度完胜谷歌Goggles_DoNews-IT数码](http://www.donews.com/it/201408/2834827.shtm) 86 | 87 | [用Python和OpenCV创建一个图片搜索引擎的完整指南 - Python - 伯乐在线](http://python.jobbole.com/80860/) 88 | 89 | [Private Content Based Image Retrieval](http://cvit.iiit.ac.in/projects/cbir/PCBIR/index.html) 90 | 91 | [Submodular Reranking with Multiple Feature Modalities for Image Retrieval](http://www.umiacs.umd.edu/%7Efyang/papers/submodular.html) 92 | 93 | **LTR** 94 | 95 | [史上最全的搜索下拉提示用户交互研究——读《An Eye-tracking Study of User Interactions with Query Auto Completion》 - Stay hungry, Stay foolish - 博客频道 - CSDN.NET](http://blog.csdn.net/huagong_adu/article/details/40951409) 96 | 97 | [学习排序 Learning to Rank 小结 - nanjunxiao的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/nanjunxiao/article/details/8976195) 98 | 99 | [浅谈网络广告 - Stay hungry, Stay foolish - 博客频道 - CSDN.NET](http://blog.csdn.net/huagong_adu/article/details/7270578) -------------------------------------------------------------------------------- /ComputerVision/PatternRecognition.md: -------------------------------------------------------------------------------- 1 | # Pattern Recognition 2 | 3 | ## 模式识别 4 | 5 | **模式识别是可以直接带来效益的领域,它依赖于机器学习的算法,因此在尚未接触机器学习之前不建议强攻。神经网络、SVM和深度学习是必须掌握的技能。最近看到开源的[EasyPR](http://www.cnblogs.com/subconscious/),眼前一亮,这才是做研究的榜样,感谢你们。代码很全,跨越各个主流平台,而且相关的文章分析的很透彻。我也深受感染,这也是我分享这么多好收藏的源动力,愿我们共同成长。** 6 | 7 | **OCR** 8 | 9 | [Neural Network for Recognition of Handwritten Digits - CodeProject](http://www.codeproject.com/Articles/16650/Neural-Network-for-Recognition-of-Handwritten-Digi) 10 | 11 | [MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges](http://yann.lecun.com/exdb/mnist/index.html) 12 | 13 | [字符识别OCR研究三 字符识别,字符区域定位 经验总结: - JDI工作室 - 博客频道 - CSDN.NET](http://blog.csdn.net/zhubenfulovepoem/article/details/7285038) 14 | 15 | [python生成汉字图片字库 - CodeMeals - 博客园](http://www.cnblogs.com/fengfenggirl/p/python_worddb.html) 16 | 17 | [使用OPENCV训练手写数字识别分类器 - firefight的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/firefight/article/details/6452188) 18 | 19 | [自然场景文字检测与识别 | VALSE在线讨论](http://valse.mmcheng.net/scenetext/) 20 | 21 | 22 | 23 | **验证码识别** 24 | 25 | [什么是验证码CAPTCHA 验证码的现在与未来[好网角文章收藏\]](http://www.wang1314.com/doc/topic-175609-1.html) 26 | 27 | [各种稀奇古怪的验证码_互联网的一些事](http://www.yixieshi.com/it/11436.html) 28 | 29 | [如何识别高级验证码 - 其他综合 - 红黑联盟](http://www.2cto.com/kf/201203/123440.html) 30 | 31 | [PWNtcha – Caca Labs](http://caca.zoy.org/wiki/PWNtcha) 32 | 33 | [我的图像之路之CAPTCHA 和 break CAPTCHA - 水木 - 博客园](http://www.cnblogs.com/hsapphire/archive/2011/01/07/1929638.html) 34 | 35 | [libcaptcha - CAPTCHA library - tiny CAPTCHA anti-bot image generator library source code](http://brokestream.com/captcha.html) 36 | 37 | [CV投票网--验证码识别,认证码识别,验证码源代码](http://www.cnvote.net/web3/qf.htm) 38 | 39 | [VC利用 zint 库生成二维码 - liuyu60305002的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/liuyu60305002/article/details/8858795) 40 | 41 | [使用摄像头解析二维码,且可以生成含具体信息的二维码 - liuyu60305002的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/liuyu60305002/article/details/18050521) 42 | 43 | [X86系统下 VC环境整二维码识别 - liuyu60305002的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/liuyu60305002/article/details/8713399) 44 | 45 | [Zbar二维码解析库编译 - liuyu60305002的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/liuyu60305002/article/details/9091567) 46 | 47 | 48 | 49 | **交通标志识别** 50 | 51 | [交通标志识别库](http://blog.sina.com.cn/s/blog_e1b9226a0101k39k.html) 52 | 53 | [MASTIF: datasets](http://www.zemris.fer.hr/%7Essegvic/mastif/datasets.shtml) 54 | 55 | [Radu Timofte, ETH Zurich](http://www.vision.ee.ethz.ch/%7Etimofter/) 56 | 57 | [交通标志抠图规则(需要做中国库建立的同学进来看一下)_火星人努力学习_新浪博客](http://blog.sina.com.cn/s/blog_e1b9226a0101h7yl.html) 58 | 59 | [交通标志检测RESORT汇总_火星人努力学习_新浪博客](http://blog.sina.com.cn/s/blog_e1b9226a0101h879.html) 60 | 61 | [Traffic sign detection using computer vision](http://moegelmose.com/p10/) 62 | 63 | [国产汽车标志图片大全_国产汽车标志大全_国产汽车标志_国产车标大全_国产车标志_911查询](http://chebiao.911cha.com/guochan.html) 64 | 65 | 66 | 67 | **车牌识别** 68 | 69 | [简单、直观的实现优于复杂、难懂的实现,最近开发扑克识别过程的总结 - xiaotie - 博客园](http://www.cnblogs.com/xiaotie/archive/2010/05/23/1741946.html) 70 | 71 | [车牌识别 - 知识天地 - 博客园](http://www.cnblogs.com/mfryf/archive/2013/05/29/3105262.html) 72 | 73 | [车牌识别及验证码识别的一般思路 - xiaotie - 博客园](http://www.cnblogs.com/xiaotie/archive/2009/01/15/1376677.html) 74 | 75 | [EasyPR](http://www.cnblogs.com/subconscious/) 76 | 77 | [openalpr · GitHub](https://github.com/openalpr) 78 | 79 | [liuruoze/EasyPR · GitHub](https://github.com/liuruoze/EasyPR) 80 | 81 | [模式识别课程教学心得之二:戏说STPR - houq2008的日志 - 网易博客](http://houq2008.blog.163.com/blog/static/3062833520104410355791/) 82 | 83 | [Face Recognition Homepage - Interesting Papers](http://www.face-rec.org/interesting-papers/#CITATIONS) 84 | 85 | [通过人脸判断性别 - 通往人工智能的崎岖之路 - 博客频道 - CSDN.NET](http://blog.csdn.net/kklots/article/details/8247738) 86 | 87 | [人脸识别方法个人见解 - bluenight专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/chl033/article/details/6112555) 88 | 89 | [文章分享:“ why is facial occlusion a challenging problem?”以及对Sparse coding人脸识别的探讨 - 通往人工智能的崎岖之路 - 博客频道 - CSDN.NET](http://blog.csdn.net/kklots/article/details/9087375) 90 | 91 | [Human action recognition](http://ivipc.uestc.edu.cn/project/har_qyh/) 92 | 93 | [Demo for Point Matching](http://www.umiacs.umd.edu/%7Ezhengyf/PointMatching.htm) -------------------------------------------------------------------------------- /ComputerVision/ResourcesInVisualTracking.md: -------------------------------------------------------------------------------- 1 | # Resources in Visual Tracking V2.0 2 | 3 | ## 视觉追踪资源 4 | 5 | 6 | 7 | **这是我发表在valseonline上的技术报告,系统总结了单目标 model-tracking当前的现状。** 8 | 9 | **Tracking是计算机视觉非常活跃的研究领域,每年在CVPR、ICCV、ECCV和PAMI等国际会议和期刊上都有大量相关的文章发表。它的分类有很多,根据追踪目标数量的不同,可分为单目标追踪和多目标追踪,根据是否在线更新模板可分为离线追踪和在线追踪。早期的研究多关注于离线追踪,代表性方法有Kalman滤波和粒子滤波,甚至meanshift在大行其道时也曾登上PAMI的大堂。不过由于近年来tracking发展很快,这些方法都已经濒临淘汰,对他们的总结见下面列出的Tutorials-Advances inVisual Tracking,由于精力有限,本文只关注在线单目标追踪方法。多目标追踪见ReferenceGuide: Multiple Object Tracking、Multi-Object Tracking和Multi_Object TrackingFramework,他们总结的很好,我就不班门弄斧了。 10 | 11 | 上次在[CSDN发布的](http://blog.csdn.net/minstyrain/article/details/38640541)只是单纯的连接,并不能节省大家宝贵的时间,这次相比来说就要全面的多。提醒大家一句CDSN上基本都是初学者的总结,断章取义、望文生义等屡见不鲜,还是自己真读过才会领会作者的真实意图。先来几篇我认为比较写好的吧: 12 | 13 | **视频讲座** 14 | 15 | VALSE曾做过几期有关tracking的讲座,包括专题[tracking](http://valse.mmcheng.net/tracking/),张开华老师的[FCT](http://valse.mmcheng.net/%E5%A5%BD%E6%96%87%E4%BD%9C%E8%80%85%E9%9D%A2%E6%8E%88%E6%8B%9B-20150128/),[贾奎ROML](http://valse.mmcheng.net/%E5%A5%BD%E6%96%87%E4%BD%9C%E8%80%85%E9%9D%A2%E6%8E%88%E6%8B%9B-20150506/),视频下载链接[http://vision.ouc.edu.cn/valse/](http://vision.ouc.edu.cn/valse/)。Techtalks上录制的CVPR tracking相关的视频:CVPR2014:[AdaptiveColor Attributes for Real-Time Visual Tracking](http://techtalks.tv/talks/adaptive-color-attributes-for-real-time-visual-tracking-2/60282/)CVPR2012:[RobustVisual Tracking via Multi-Task Sparse Learning](http://techtalks.tv/talks/robust-visual-tracking-via-multi-task-sparse-learning/56242/)其他的我相信搞计算机的应该有相应的搜索能力了。 16 | 17 | **值得看的中文博客** 18 | 19 | 首推[Correlation Filter in Visual Tracking](http://www.cnblogs.com/hanhuili/),它给出了算法的直觉,逻辑推理的过程值得深究。       [目标跟踪学习系列](http://blog.csdn.net/ikerpeng/article/details/20703421)共13篇,基本总结了online-tracker所有要看的东西。 20 | 21 | **各大牛人的主页** 22 | 23 | 一定要经常看,不时就会有新的东西:[Ming-Hsuan Yang's HomePage](http://faculty.ucmerced.edu/mhyang/)[KyoungMuLee](http://cv.snu.ac.kr/jhkwon/tracking/)[Arnold Smeulders](http://staff.science.uva.nl/%7Esmeulder/)[Haibin Ling](http://www.dabi.temple.edu/%7Ehbling/publication-selected.htm)[Lei Zhang](http://www4.comp.polyu.edu.hk/%7Ecslzhang/papers.htm)[Horst Possegger](http://lrs.icg.tugraz.at/members/possegger#occgeo)[Sinisa Todorovic](http://web.engr.oregonstate.edu/%7Esinisa/)[Dr. Zdenek Kalal](http://personal.ee.surrey.ac.uk/Personal/Z.Kalal/)[Charles Bibby | ResearchInterest: Active Vision and SLAM](http://www.robots.ox.ac.uk/%7Ecbibby/research_pwp.shtml)[Kevin Cannons, Mitacs Elevate PostdoctoralFellow](http://www.cse.yorku.ca/%7Ekcannons/)[卢湖川](http://ice.dlut.edu.cn/lu/publications.html)[João F. Henriques](http://home.isr.uc.pt/%7Ehenriques/index.html)[Shai Avidan](http://www.eng.tau.ac.il/%7Eavidan/)[www.eng.tau.ac.il/~oron/](http://www.eng.tau.ac.il/%7Eoron/)[Helmut Grabner](http://www.vision.ee.ethz.ch/%7Ehegrabne/)[Anton Milan](http://www.milanton.de/)[Tomáš Vojíř](http://cmp.felk.cvut.cz/%7Evojirtom/)[Naiyan Wang - Home](http://winsty.net/index.html)[西北大学吴郢](http://users.eecs.northwestern.edu/%7Eyingwu/)[信息与控制学院--吴 毅](http://web2.nuist.edu.cn:8080/xky/2013-11/2013112141929.html)[张开华](http://web2.nuist.edu.cn/jszy/Professor.aspx?id=1991)[Sam Hare](http://www.samhare.net/)[Bohyung Han's homepage](http://cvlab.postech.ac.kr/%7Ebhhan/)[vision.cse.psu.edu/home/home.shtml](http://vision.cse.psu.edu/home/home.shtml)[张天柱](https://sites.google.com/site/zhangtianzhu2012/)[Welcome to Jianming Zhang's Home Page](http://cs-people.bu.edu/jmzhang/)[Charles Bibby | ResearchInterest: Active Vision and SLAM](http://www.robots.ox.ac.uk/%7Ecbibby/index.shtml)[Deva Ramanan - UC Irvine - Computer Vision](http://www.ics.uci.edu/%7Edramanan/)[Georg Nebehay](http://www.gnebehay.com/publications/)[文珑银](http://www.cbsr.ia.ac.cn/users/lywen/)帖子长度有限制,不过这难不倒技术宅,我把文档的pdf版本放在了[github](https://github.com/imistyrain/OpenTracking)上,也欢迎大家补充相关资料。 24 | 25 | 一、Survey and benchmark: 26 | 27 | 1. [VOT challenge](http://www.votchallenge.net/),这个不用说了吧,大名鼎鼎,如雷贯耳,如果连这个都不知道,基本上不用在tracking圈混了。 28 | 2. PAMI2014:[Visual Tracking_ An Experimental Survey](http://74.125.12.3/search?newwindow=1&q=Visual+Tracking_+An+Experimental+Survey&oq=Visual+Tracking_+An+Experimental+Survey&gs_l=serp.12..0i13l2.68555.68555.0.69234.1.1.0.0.0.0.475.475.4-1.1.0....0...1c.1.51.serp..0.1.473.jnnqc1LhZOk),阿姆斯特丹大学建立的包括300多个视频序列的库,代码:[http://alov300pp.joomlafree.it/trackers-resource.html](http://alov300pp.joomlafree.it/trackers-resource.html) 29 | 3. CVPR2013:[Online Object Tracking: A Benchmark](http://visual-tracking.net/)(需翻墙) ,吴毅老师的库,刚开始是50个序列,后扩展到100个,为评估初始化对tracker的影响,加入了OPE、TRE、SRE和TRER、SRER等评估指标。 30 | 4. ICCV2013:Finding the Best from the Second Bests – Inhibiting Subjective Bias inEvaluation of Visual Tracking Algorithms 31 | 5. Signal Processing 2011:[Video Tracking Theory and Practice](http://download.csdn.net/detail/mgqmha/4450053) 32 | 6. ACCV2006:[Tutorials-Advances in Visual Tracking](http://www.accv2010.org/tut_tracking.html):中文:[视觉跟踪的进展](http://www.tuicool.com/articles/e2q6nm) 33 | 7. Evaluation of an online learning approach for robust object tracking 34 | 35 |   36 | 37 | 二、研究团体: 38 | 39 | 1. University of California at Merced:[Ming-Hsuan Yang](http://faculty.ucmerced.edu/mhyang/)视觉跟踪当之无愧第一人,后面的人基本上都和气其有合作关系,他引近9000 40 | 41 | [Publications](http://faculty.ucmerced.edu/mhyang/pubs.html)PAMI:6,CVPR:26,ECCV:17,BMCV:6,NIPS:6,IJCV:3,ACCV:3 42 | 43 | 代表作:Robust Visual Tracking via Consistent Low-Rank Sparse Learning 44 | 45 | **FCT**,IJCV2014:Fast Compressive Tracking 46 | 47 | **RST**,PAMI2014:Robust Superpixel Tracking; SPT,ICCV2011, Superpixel tracking 48 | 49 | **SVD**,TIP2014:Learning Structured Visual Dictionary for Object Tracking 50 | 51 | ECCV2014: Spatiotemporal Background Subtraction Using Minimum Spanning Tree and Optical Flow 52 | 53 | PAMI2011:Robust Object Tracking with Online Multiple Instance Learning 54 | 55 | **MIT**,CVPR2009: Visual tracking with online multiple instance learning 56 | 57 | IJCV2008: Incremental Learning for Robust Visual Tracking 58 | 59 |   60 | 61 | 1. Seoul National University Professor:[KyoungMuLee](http://cv.snu.ac.kr/jhkwon/tracking/)2013年在PAMI上发表5篇,至今无人能及 62 | 63 | [文献列表](http://cv.snu.ac.kr/international)PAMI:13,CVPR:30,ECCV:12,ICCV:8,PR:4 64 | 65 | PAMI2014:A Geometric Particle Filter for Template-Based Visual Tracking 66 | 67 | ECCV2014: Robust Visual Tracking with Double Bounding Box Model 68 | 69 | PAMI2013:Highly Nonrigid Object Tracking via Patch-based Dynamic Appearance Modeling 70 | 71 | CVPR2014: Interval Tracker: Tracking by Interval Analysis 72 | 73 | CVPR2013: Minimum Uncertainty Gap for Robust Visual Tracking 74 | 75 | CVPR2012:Robust Visual Tracking using Autoregressive Hidden Markov Model 76 | 77 | **VTS** ,ICCV2011:Tracking by Sampling Trackers. 78 | 79 | **VTD**,CVPR2010: Visual Tracking Decomposition 80 | 81 | **TST**,ICCV2011: Tracking by sampling trackers 82 | 83 | 1. Temple University,[凌海滨](http://www.dabi.temple.edu/%7Ehbling/) 84 | 85 | [Publication List](http://www.dabi.temple.edu/%7Ehbling/publication-selected.htm) PMAI:4,CVPR:19,ICCV:17,ECCV:5,TIP:9 86 | 87 | CVPR2014:Multi-target Tracking with Motion Context in Tenor Power Iteration 88 | 89 | ECCV2014:Transfer Learning Based Visual Tracking with Gaussian Process Regression 90 | 91 | ICCV2013:Finding the Best from the Second Bests - Inhibiting Subjective Bias in Evaluation of Visual Tracking Algorithms 92 | 93 | CVPR2013: Multi-target Tracking by Rank-1 Tensor Approximation 94 | 95 | CVPR2012:Real Time Robust L1 Tracker Using Accelerated Proximal Gradient Approach 96 | 97 | TIP2012: Real-time Probabilistic Covariance Tracking with Efficient Model Update 98 | 99 | ICCV2011: Blurred Target Tracking by Blur-driven Tracker 100 | 101 | PAMI2011ICCV2009: Robust Visual Tracking and Vehicle Classification via Sparse Representation 102 | 103 | ICCV2011:Robust Visual Tracking using L1 Minimization 104 | 105 | **L1O**,CVPR2011: Minimum error bounded efficient l1 tracker with occlusion detection 106 | 107 | **L1T**, ICCV2009:Robust visual tracking using l1 minimization 108 | 109 | 1. Hong Kong Polytechnic University Associate Professor: [Lei Zhang](http://www4.comp.polyu.edu.hk/%7Ecslzhang/) 110 | 111 | [Papers](http://www4.comp.polyu.edu.hk/%7Ecslzhang/papers.htm)PAMI:2,CVPR:18,ICCV:14,ECCV:12,ICPR:6,PR:28,TIP:4 112 | 113 | **STC**,ECCV2014: Fast Tracking via Dense Spatio-Temporal Context Learning 114 | 115 | **FCT**,PAMI2014,ECCV2012:[Fast Compressive Tracking](http://www4.comp.polyu.edu.hk/%7Ecslzhang/CT/CT.htm), Minghsuan Yang 116 | 117 | IET Computer Vision2012:Scale and Orientation Adaptive Mean Shift Tracking 118 | 119 | IJPRAI2009:Robust Object Tracking using Joint Color-Texture Histogram 120 | 121 | 1. 大连理工大学教授 [卢湖川](http://ice.dlut.edu.cn/lu/publications.html)国内追踪领域第一人 122 | 123 | CVPR2014:Visual Tracking via Probability Continuous Outlier Model 124 | 125 | TIP2014:Visual Tracking via Discriminative Sparse Similarity Map 126 | 127 | TIP2014: Robust Superpixel Tracking 128 | 129 | TIP2014: Robust Object Tracking via Sparse Collaborative Appearance Model 130 | 131 | CVPR2013: Least Soft-threshold Squares Tracking, Minghsuan Yang 132 | 133 | TIP2013:[Online Object Tracking with Sparse Prototypes](http://ice.dlut.edu.cn/lu/Project/TIP12-SP/TIP12-SP.htm), Minghsuan Yang 134 | 135 | Signal Processing Letters2013: Graph-Regularized Saliency Detection With Convex-Hull-Based Center Prior 136 | 137 | Signal Processing2013: On-line Learning Parts-based Representation via Incremental Orthogonal Projective Non-negative Matrix Factorization 138 | 139 | CVPR2012:[Robust Object Tracking viaSparsity-based Collaborative Model](http://ice.dlut.edu.cn/lu/Project/cvpr12_scm/cvpr12_scm.htm), Minghsuan Yang 140 | 141 | CVPR2012:[Visual Tracking via Adaptive Structural Local Sparse Appearance Model](http://ice.dlut.edu.cn/lu/Project/cvpr12_jia_project/cvpr12_jia_project.htm), Minghsuan Yang 142 | 143 | Signal Processing Letters 2012:Object tracking via 2DPCA and L1-regularization 144 | 145 | IET Image Processing 2012:Visual Tracking via Bag of Features 146 | 147 | ICPR2012: Superpixel Level Object Recognition Under Local Learning Framework 148 | 149 | ICPR2012: Fragment-Based Tracking Using Online Multiple Kernel Learning 150 | 151 | ICPR2012: Object Tracking Based On Local Learning 152 | 153 | ICPR2012: Object Tracking with L2_RLS 154 | 155 | ICPR2011:Complementary Visual Tracking 156 | 157 | FG2011:Online Multiple Support Instance Tracking 158 | 159 | Signal Processing2010: A novel method for gaze tracking by local pattern model and support vector regressor 160 | 161 | ACCV2010: On Feature Combination and Multiple Kernel Learning for Object Tracking 162 | 163 | ACCV: Robust Tracking Based on Pixel-wise Spatial Pyramid and Biased Fusion 164 | 165 | ACCV2010: Human Tracking by Multiple Kernel Boosting with Locality Affinity Constraints 166 | 167 | ICCV2011:Superpixel Tracking, Minghsuan Yang 168 | 169 | ICPR2010: Robust Tracking Based on Boosted Color Soft Segmentation and ICA-R 170 | 171 | ICPR2010: Incremental MPCA for Color Object Tracking 172 | 173 | ICPR2010: Bag of Features Tracking 174 | 175 | ICPR2008: Gaze Tracking By Binocular Vision and LBP Features 176 | 177 | 1. 南京信息工程大学教授,[KaiHua Zhang](http://smart.nuist.edu.cn/People/khzhang/khzhang.html) 178 | 179 | **FCT**,PAMI2014:Fast Compressive Tracking, L. Zhang, and M-H. Yang 180 | 181 | Trans. Circuits and Systems for Video Technology2013:Robust Object Tracking via Active Feature Selection, L. Zhang, M-H. Yang 182 | 183 | TIP2013:Real-Time Object Tracking via Online Discriminative Feature Selection, L. Zhang, and M-H. Yang 184 | 185 | 1. Oregonstate Professor,[Sinisa Todorovic](http://web.engr.oregonstate.edu/%7Esinisa/)由视频分割转向Tracking 186 | 187 | **CSL**,CVPR2014: Multi-Object Tracking via Constrained Sequential Labeling 188 | 189 | CVPR2011:Multiobject Tracking as Maximum Weight Independent Set 190 | 191 | 1. Graz University of Technology, Austria,[Horst Possegger](http://lrs.icg.tugraz.at/members/possegger#occgeo)博士 192 | 193 | CVPR2014:Occlusion Geodesics for Online Multi-Object Tracking 194 | 195 | CVPR2013: Robust Real-Time Tracking of Multiple Objects by Volumetric Mass Densities 196 | 197 | 1. 马里兰大学[Zdenek Kalal](http://personal.ee.surrey.ac.uk/Personal/Z.Kalal/)博士 198 | 199 | **TLD**,PAMI2011: Tracking-Learning-Detection 200 | 201 | TIP2010: Face-TLD: Tracking-Learning-Detection Applied to Faces 202 | 203 | ICPR2010:Forward-Backward Error: Automatic Detection of Tracking Failures 204 | 205 | CVPR2010: P-N Learning: Bootstrapping Binary Classifiers by Structural Constraints 206 | 207 | BMVC2008: Weighted Sampling for Large-Scale Boosting 208 | 209 | 中文讲解: 210 | 211 | [TLD视觉跟踪算法](http://blog.sina.com.cn/s/blog_6163bdeb0102eh7b.html) 212 | 213 | [TLD源码深度分析](http://quandb2007.blog.163.com/blog/static/41878875201351241741534/) 214 | 215 | [庖丁解牛TLD](http://blog.sina.com.cn/s/blog_73ee929c01010yok.html) 216 | 217 | [TLD(Tracking-Learning-Detection)学习与源码理解](http://blog.csdn.net/zouxy09/article/details/7893011) 218 | 219 |   220 | 221 | 三、其他早期工作: 222 | 223 | [Tracking of a Non-Rigid Objectvia Patch-based Dynamic Appearance Modeling and Adaptive Basin Hopping Monte Carlo Sampling](http://cv.snu.ac.kr/research/%7Ebhmctracker/) 224 | 225 | [tracking-by-detection](http://www.vision.ee.ethz.ch/showroom/tracking/) 226 | 227 | [粒子滤波 演示与opencv代码](http://blog.csdn.net/onezeros/article/details/6319180) 228 | 229 | [opencv学习笔记-入门(6)-camshift](http://blog.csdn.net/wobuaishangdiao/article/details/7660668) 230 | 231 | [Camshift算法原理及其Opencv实现](http://blog.csdn.net/leixiaohua1020/article/details/12236091) 232 | 233 | [Camshift算法](http://blog.csdn.net/seawaywjd/article/details/7458196)  234 | 235 | [CamShift算法,OpenCV实现1--Back Projection](http://blog.csdn.net/houdy/article/details/175739) 236 | 237 | [**目标跟踪学习笔记****_2(particle filter****初探****1)**](http://www.cnblogs.com/tornadomeet/archive/2012/03/18/2404817.html) 238 | 239 | [**目标跟踪学习笔记****_3(particle filter****初探****2)**](http://www.cnblogs.com/tornadomeet/archive/2012/05/08/2490943.html) 240 | 241 | [**目标跟踪学习笔记****_4(particle filter****初探****3)**](http://www.cnblogs.com/tornadomeet/archive/2012/06/23/2559193.html) 242 | 243 | [目标跟踪学习系列一:on-line boosting and vision 阅读](http://blog.csdn.net/ikerpeng/article/details/18985573) -------------------------------------------------------------------------------- /ComputerVision/SIF Matching with RANSAC.md: -------------------------------------------------------------------------------- 1 | # SIFT Matching with RANSAC 2 | 3 | 一般在词袋模型中,为了提高检索的精度,你可以通过很多的trick来提高其精度(mAP),其中一个广泛使用的技巧就是对返回的图像进行重排,重排有很 4 | 多种方法,比如对多特征在分数层(决策层)进行融合也是一种重排方式,不过这里要做的是通过剔除查询图像与候选图像错配点对的方式进行重排,剔除错配点一 5 | 般采用的是RANSAC算法,关于RANSAC原理可以阅读[RANSAC算法做直线拟合](http://yongyuan.name/blog/fitting-line-with-ransac.html)这篇文章,或者采用类RANSAC算法。作为初级阶段的实践,这里从两幅图像的匹配逐步深入。 6 | 7 | ## 1NN匹配 8 | 9 | “1NN匹配”(勿wiki,自创的一个词汇),讲起来比较顺口,而且从字面也应该可以猜测出点意思来,所以就这么写在这里了。所谓的“1NN”匹配,即是对于图像im1中的某个SIFT特征点point1,通过在im2图像上所有SIFT关键点查找到与point1最近的SIFT关键点,重复这个过程,即可得到图像im1中所有的特征点在im2中的匹配点(最近邻,1NN)。这种匹配方法,会出现很多的错配点,下面是采用1NN匹配的结果: 10 |
11 | 图片1 12 |
13 | 从上图可以看到,1NN匹配的方法出现了很多的错配点,而这些错配点对无论是对图像检索中的重排,还是图像拼接等,都是不希望看到的,所以得进一步对其中的错配点对进行剔除,下面采用“1NN/2NN<0.8”的方法进行错配点对剔除。 14 | 15 | ## 1NN/2NN<0.8 16 | 17 | “1NN/2NN<0.8”,不要诧异你未见过这样一种说法,没错,自己瞎创的一种表述。对上面1NN方法理解了,这个水到渠成。所谓“1NN/2NN<0.8”,即对于图像im1中的某个SIFT特征点point1,通过在im2图像上所有SIFT关键点查找到与point1最近的SIFT关键点point21(记该关键点point21到point1的距离为dis1)和次近的关键点point22(记该关键点point22到point1的距离为dis2),如果dis1/dis2<0.8,则我们将其视为正确匹配的点对,否则则为错配的点对予以剔除。这种寻找匹配的方法,由Lowe在其Distinctive image features from scale-invariant keypoints中有说明,当然,0.8这个阈值是可以调整的,不过一般都采用0.8。下面是采用该方法进行匹配后的结果: 18 |
19 | 图片2 20 |
21 | 可以看到,经过该方法匹配后,相比与“1NN”匹配方法,相比于“1NN”,这种方法进行匹配时有了很大的改善,不过正配点相比与1NN有部分损失。下面再探讨用RANSAC方法对这两种情况进行错配点剔除。 22 | 23 | ## 1NN+RANSAC 24 | 25 | 回到前面的“1NN”匹配的点对,我们再采用RANSAC方法对其进行错配点剔除,RANSAC方法的原理前面已有相关文章[RANSAC算法做直线拟合](http://yongyuan.name/blog/fitting-line-with-ransac.html),这里不再重复,相关的代码请看`utils.cpp`中`findInliers`函数,调用的是OpenCV中的`cv::findFundamentalMat`函数计算其变换矩阵,下面是“1NN”经过RANSAC剔除错配点对的结果: 26 |
27 | 图片3 28 |
29 | 可以看到,经过RANSAC后,“1NN”中的很多错配点对差不多剔除得比较好了,不过还有错配的点对没有剔除掉,图中用红色矩形框标出了未剔除的错配点对。我们在来看看对“1NN/2NN<0.8”进行RANSAC后会是怎样的结果呢? 30 | 31 | ## 1NN/2NN<0.8+RANSAC 32 | 33 | 在看匹配结果前,我们可以先做一个大概的预测,因为“1NN/2NN<0.8”得到的很多点就是正确匹配的点对,所以将其放入RANSAC中后,能够得到很好的拟合模型,所以其剔除错配点对效果也应该更好。为了验证这一预测,我们看一下“1NN/2NN<0.8+RANSAC”具体的效果,如下图所示: 34 |
35 | 图片4 36 |
37 | 可以看到,已经完全没有错配点了,从这一点来说,其效果是非常好的。不过,从正配点对数目来看,“1NN+RANSAC”的结果更密集,也就是说“1NN+RANSAC”包含了更多的正配点对,“1NN/2NN<0.8+RANSAC”正配点对要稍微少些。在大多数情况下,我们会选择完全剔除了错配点对的模型。 38 | 39 | 40 | ## 总结 41 | 42 | 上面分别介绍了两种匹配方法,分别是“1NN”和“1NN/2NN<0.8”匹配方法,以及对它们采用RANSAC剔除错配点对的方法。有时候,如果要求经过RANSAC匹配后保留更多的正配点对,这时候,我们可以采用Affine-SIFT,简称ASIFT,具体可以阅读[ASIFT: An Algorithm for Fully Affine Invariant Comparison](http://www.ipol.im/pub/art/2011/my-asift/)这篇文章,作者提供了ASIFT的C++代码和匹配算法,可以在[ASIFT](http://yongyuan.name/blog/%28http://www.ipol.im/pub/art/2011/my-asift/%29)下载得到,我大概跑了一下里面的demo,相比与SIFT,ASIFT可以提取到很多的关键点,对旋转等变换具有更好的不变性,不过缺点也很明显,速度实在太慢,很难做到实时,所以要使用的话,一般应用在对实时性不做要求的场合。我那个代码里有OpenCV的实现,你也可以试一下其效果,该OpenCV代码实现来源于[OPENCV ASIFT C++ IMPLEMENTATION](http://www.mattsheckells.com/opencv-asift-c-implementation/),OpenCV自带其Python实现,使用比较方便,就是速度太慢,所以自己在图像检索在写的项目中,也不打算用它了。 43 | 44 | -------------------------------------------------------------------------------- /ComputerVision/Saliency.md: -------------------------------------------------------------------------------- 1 | # Saliency 2 | 3 | ## 图像显著性 4 | 5 | 6 | 7 | 显著性是一个一夜爆红的领域,知名人物有: 8 | 9 | [程明明](http://mmcheng.net/zh/) 10 | 11 | [卢湖川](http://ice.dlut.edu.cn/lu/index.html) 12 | 13 | [Ayellet Tal](http://webee.technion.ac.il/%7Eayellet/papers.html) 14 | 15 | [Yang Wu](http://mm.media.kyoto-u.ac.jp/members/yangwu/publications.html) 16 | 17 | [李寅](http://yinli.cvpr.net/) 18 | 19 | [侯晓迪](http://www.houxiaodi.com/) 20 | 21 | [ilab.usc.edu/borji/](http://ilab.usc.edu/borji/) 22 | 23 | 好的博客是 24 | 25 | - [图像显著性_小虫不会飞__新浪博客](http://blog.sina.com.cn/s/blog_6f611c3001018k0w.html) 26 | - [现有的Saliency计算模型的几个常见问题及回答 - hSheng - 博客园](http://www.cnblogs.com/hSheng/archive/2012/12/06/2804385.html) 27 | - [显著性论文学习阶段总结(一) - 微雪 - 博客园](http://www.cnblogs.com/yingying0907/archive/2013/03/22/2975172.html) 28 | - [图像显著度(saliency detection)研究现状调研 - huangbo10的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/huangbo10/article/details/19788547) 29 | - [图像/视觉显著性检测技术发展情况梳理(Saliency Detection、Visual Attention)--计算机视觉专题2 - Donkey Vision - 博客频道 - CSDN.NET](http://blog.csdn.net/anshan1984/article/details/8657176) 30 | - [四种简单的图像显著性区域特征提取方法-----> AC/HC/LC/FT。 - laviewpbt的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/laviewpbt/article/details/38357017) 31 | - [显著算法回顾(一)Itti算法_永不放弃_新浪博客](http://blog.sina.com.cn/s/blog_c303278b0101air2.html) 32 | - [图像显著性论文(一)—A Model of saliency Based Visual Attention for Rapid Scene Analysis - chenjiazhou12的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/chenjiazhou12/article/details/39456589) 33 | - [CVPR2014结果出来了,小伙伴们赶紧来啊~~~~ - 脚踏实地 - 博客频道 - CSDN.NET](http://blog.csdn.net/xiaojidan2011/article/details/20667491) 34 | - [Saliency Filters: Contrast Based Filtering for Salient Region Detection | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=1052) 35 | - [Context-Aware Saliency Detection | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=396) 36 | - [Saliency detection via absorbing Markov chain](http://ice.dlut.edu.cn/lu/Project/DSR_saliency_iccv13/web_DSR_saliency.html) 37 | 38 | 39 | 40 | [Saliency Benchmark](http://people.csail.mit.edu/tjudd/SaliencyBenchmark/index.html) 41 | 42 | [Frequency-tuned salient Region Detection | IVRG](http://ivrg.epfl.ch/supplementary_material/RK_CVPR09/) 43 | 44 | [Saliency Detection via Graph-based Manifold Ranking](http://ice.dlut.edu.cn/lu/Project/CVPR13%5Byangchuan%5D/cvprsaliency.htm) 45 | 46 | [Huaizu Jiang Homepage](http://www.jianghz.com/) 47 | 48 | [MSRA Salient Object Database](http://research.microsoft.com/en-us/um/people/jiansun/SalientObject/salient_object.htm) 49 | 50 | [Saliency Detection: A Boolean Map Approach](http://cs-people.bu.edu/jmzhang/BMS/BMS.html) 51 | 52 | [MIT Saliency Benchmark](http://saliency.mit.edu/) 53 | 54 | [visual saliency与benchmark tricks - 机器视觉x模式识别 - 知乎专栏](http://zhuanlan.zhihu.com/cvprnet/19821399) 55 | [The Secrets of Salient Object Segmentation](http://cbi.gatech.edu/salobj/) 56 | [BBB: Beyond Busy Benchmarking - 机器视觉x模式识别 - 知乎专栏](http://zhuanlan.zhihu.com/cvprnet/19826536) 57 | [Deep Learning for Saliency](http://www.ece.nus.edu.sg/stfpage/eleqiz/deep_saliency.html) 58 | [Hypergraph Saliency | Yao Li 李尧](http://cs.adelaide.edu.au/%7Eyaoli/?page_id=149) 59 | [Parthipan Siva( Research - Saliency )](http://www.psiva.ca/Papers/CVPR2013/CVPR2013.html) 60 | 61 | [Salient Object Dataset](http://elderlab.yorku.ca/SOD/#download) 62 | 63 | -------------------------------------------------------------------------------- /ComputerVision/Segmentation.md: -------------------------------------------------------------------------------- 1 | # Segmentation 2 | 3 | ## 分割 4 | 5 | 6 | 7 | 分割是视觉领域一个难题,图像分割和视频分割以及共分割。不过自从grabcut后对数学的要求陡然升高,尤其是最大流最小割、子模性和 8 | 9 | 下面是我整理的资料链接 10 | 11 | 图割 12 | 13 |  [Tutorial](http://www.csd.uwo.ca/faculty/yuri/Abstracts/eccv06-tutorial.html) 14 | 15 | - [二分图匹配算法总结(phoenixinter) - hqd_acm的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/hqd_acm/article/details/5829687) 16 | - [我对KM算法的理解 - 茅屋 - ITeye技术网站](http://philoscience.iteye.com/blog/1754498) 17 | - [KM算法入门 - skyming - 博客园](http://www.cnblogs.com/skyming/archive/2012/02/18/2356919.html) 18 | - [【学习笔记】 网络流问题 - 脑残的孩子只有慢慢学。。 - 博客频道 - CSDN.NET](http://blog.csdn.net/lin375691011/article/details/18923267) 19 | - [[zz\][基础算法] Graph Cut and Its Application in Computer Vision - ありかどう的日志 - 网易博客](http://blog.163.com/gz_ricky/blog/static/18204911820127148143483/) 20 | - [清华大学研究生图论_百度文库](http://wenku.baidu.com/link?url=PzvXCEaMGj9sb-BLC0HfaTO6BRApHZCptByXvtxg1MhQQwxx_DMX_CnW1dAOyZ9OVdIUjNfevMu2RAloo0zAhM0S19ChuQvul3WIV0xKHWi) 21 | - [图像分割—基于图的图像分割(Graph-Based Image Segmentation) - Note of Transposition - 博客频道 - CSDN.NET](http://blog.csdn.net/ttransposition/article/details/38024557) 22 | - [图像分割—基于图的图像分割(OpenCV源码注解) - Note of Transposition - 博客频道 - CSDN.NET](http://blog.csdn.net/ttransposition/article/details/38024605) 23 | - [有上下界的网络流问题 - Mr. Ant - 博客园](http://www.cnblogs.com/kane0526/archive/2013/04/05/3001108.html) 24 | - [poj 2396(有源汇的上下界可行流。。。。。dinic) - 水杯 - 博客频道 - CSDN.NET](http://blog.csdn.net/water_glass/article/details/6823741) 25 | - [有上下界的网络流问题 - iwtwiioi - 推酷](http://www.tuicool.com/articles/jUJZnmU) 26 | - [Hungarian Algorithm](http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=hungarianAlgorithm) 27 | - [子模的性质(submodular) - 我是一只小小鸟 - 博客频道 - CSDN.NET](http://blog.csdn.net/s1102379635/article/details/8524397) 28 | - [submodularity.org: Tutorials, References, Activities and Tools for Submodular Optimization](http://submodularity.org/) 29 | - [Graphcut Related](http://www.jdl.ac.cn/user/jfliu/graphcutrelated.htm) 30 | - [从图割到图像分割(一)——最大流算法 | Moondark](http://liaoxl.github.io/blog/20131013/tu-ge/) 31 | - [从图割到图像分割(二)——图的构造 | Moondark](http://liaoxl.github.io/blog/20131020/tu-de-gou-zao/) 32 | - [从图割到图像分割(三)——多层图图割 | Moondark](http://liaoxl.github.io/blog/20131021/duo-ceng-tu/#) 33 | - [最大流算法统计 | Moondark](http://liaoxl.github.io/blog/20141029/cut/) 34 | - [最大流问题:增广路径算法的比较 - SuperFC之替天行道 - 博客频道 - CSDN.NET](http://blog.csdn.net/fengchaokobe/article/details/7584781) 35 | - [Graph Cuts on the GPU_小腹黑zju_新浪博客](http://blog.sina.com.cn/s/blog_60a0e97e0101bc75.html) 36 | - [最大流算法统计 - Moondark - 博客园](http://www.cnblogs.com/moondark/p/4059578.html) 37 | - Superpixel[Superpixel, Empirical Studies and Applications](http://homes.cs.washington.edu/%7Exren/research/superpixel/)[Superpixel segmentation | IVRG](http://ivrg.epfl.ch/research/superpixels#SLICO)[SEEDS](http://www.mvdblive.org/seeds/)[superpixelsgraphcut](http://www2.cs.sfu.ca/%7Emori/research/superpixels/)[mean shift 图像分割 (一) - Note of Transposition - 博客频道 - CSDN.NET](http://blog.csdn.net/ttransposition/article/details/38514127)[OpenCV Watersheds 算法学习 - StevenMeng - 博客园](http://www.cnblogs.com/steven-blog/archive/2012/12/10/2919259.html)[TU Chemnitz: ETIT: Automation Technology: Computer Vision](https://www.tu-chemnitz.de/etit/proaut/forschung/cv/segmentation.html.en)ObjectnessBasedSegmentation 38 | 39 | 40 | - [Category Independent Object Proposals, University of Illinois at Urbana-Champaign](http://vision.cs.uiuc.edu/proposals/) 41 | - [CPMC](http://www.maths.lth.se/matematiklth/personal/sminchis/code/cpmc/index.html) 42 | - [keysegments](http://vision.cs.utexas.edu/projects/keysegments/keysegments.html) 43 | - [Dong Zhang](http://www.dromston.com/index.php) 44 | - [CALVIN Fast Video Segmentation](http://groups.inf.ed.ac.uk/calvin/software.html) 45 | - [Fast Video Segmentation](http://groups.inf.ed.ac.uk/calvin/FastVideoSegmentation/) 46 | - [Tianyang's Homepage](http://astro.temple.edu/%7Etuc09847/) 47 | 48 | 49 | 50 | 综合 51 | 52 | [UC Berkeley Computer Vision Group - Contour Detection and Image Segmentation - Resources](http://www.eecs.berkeley.edu/Research/Projects/CS/vision/grouping/resources.html) 53 | 54 | [Pedro Felzenszwalb's Home Page](http://cs.brown.edu/%7Epff/) 55 | 56 | [Philip Torr's Home Page](http://www.robots.ox.ac.uk/%7Ephst/) 57 | 58 | [Vladimir Kolmogorov's homepage](http://pub.ist.ac.at/%7Evnk/) 59 | 60 | [Carsten Rother](http://www.inf.tu-dresden.de/index.php?node_id=3519&ln=de) 61 | 62 | [Segmentation of Images](http://cms.brookes.ac.uk/staff/PhilipTorr/Code/seg_page_1.htm) 63 | 64 | [Scissors](http://www.cs.technion.ac.il/%7Ecs234326/projects/scissors/Scissors.html) 65 | 66 | [Random Walker Image Segmentation Demo Page](http://www.cns.bu.edu/%7Elgrady/Random_Walker_Image_Segmentation.html) 67 | 68 | [Camille Couprie](http://www.esiee.fr/%7Ecoupriec/index.html) 69 | 70 | [Joseph Tighe](http://www.cs.unc.edu/%7Ejtighe/) 71 | 72 | [CMU Image Data Base: motion](http://vasc.ri.cmu.edu/idb/html/motion/index.html) 73 | 74 | [alpha Matting Evaluation Website](http://www.alphamatting.com/index.html) 75 | 76 | [LabelMe. The Open annotation tool](http://labelme2.csail.mit.edu/Release3.0/browserTools/php/matlab_toolbox.php) 77 | 78 | [图像分割___图像分割方法综述 - Vast_Sea的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/vast_sea/article/details/8196507) 79 | 80 | [图像抠图算法学习 - Shared Sampling for Real-Time Alpha Matting - laviewpbt的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/laviewpbt/article/details/19218529) 81 | 82 | [Yuri Boykov - Home Page](http://www.csd.uwo.ca/%7Eyuri/) 83 | 84 | [Prof. Dr. Jianbing Shen](http://www.vision.ee.ethz.ch/%7Eshenj/) 85 | 86 | [Intelligent Scissors](http://www.cs.utexas.edu/%7Elrl542/) 87 | 88 | [random walker](http://cns.bu.edu/%7Elgrady/index.html) 89 | 90 | [Image Processing and Analysis with Graphs: Theory and Practice | contents](http://greyc.stlo.unicaen.fr/lezoray/IPAG/contents.php) 91 | 92 | 93 | 94 | 中文博客解析 95 | 96 | 97 | - [读论文:ICCV11 Distributed Cosegmentation via Submodular Optimization on Anisotropic Diffusion | bfcat-计算机视觉博客](http://www.bfcat.com/index.php/2012/10/iccv11-cosand/) 98 | - [[CVPR12\] On Multiple Foreground Cosegmentation](http://www.cs.cmu.edu/%7Egunhee/r_mfc.html) 99 | - [Key-Segments for Video Object Segmentation | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=1033) 100 | - [Video Object Segmentation by Hypergraph Cut | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=1008) 101 | - [Efficient Hierarchical Graph-Based Video Segmentation | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=946) 102 | - [Video Segmentation by Non-Local Consensus Voting | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=1267) 103 | - [Video Object Segmentation by Salient Segment Chain Composition | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=1257) 104 | - [Unsupervized Video Segmentation With Low Depth of Field | 浙江工业大学图形可视小组](http://blog.zjutvcg.com/?p=1113) -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic001.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic002.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic003.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic004.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic005.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic006.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic007.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/Automatic008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/Automatic008.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/SIFT001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/SIFT001.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/SIFT002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/SIFT002.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/SIFT003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/SIFT003.jpg -------------------------------------------------------------------------------- /ComputerVision/pic/SIFT004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/ComputerVision/pic/SIFT004.jpg -------------------------------------------------------------------------------- /ComputerVision/为什么深度学习几乎成了计算机视觉研究的标配.md: -------------------------------------------------------------------------------- 1 | #为什么深度学习几乎成了计算机视觉研究的标配 2 | 3 | 本次CVPR 2016上,深度学习几乎成了如今计算机视觉研究的标配,人脸识别、图像识别、视频识别、行人检测、大规模场景识别的相关论文里都用到了深度学习的方法,加上Google,Facebook这样的大企业助力,很多人疑惑,为什么深度学习相比其它的AI实现方法,已然呈现出一副碾压之态? 4 | 5 | 本期硬创公开课嘉宾我们邀请了商汤科技执行研发总监曹旭东,其刚从CVPR 2016现场赶回来,正好在这里为大家解释一下为什么深度学习几乎成了计算机视觉研究的标配这个问题。以及为大家讲解CV和深度学习的现状和未来趋势。 6 | 7 | 曹旭东,商汤科技执行研发总监,深度学习专家。毕业于清华大学。前微软亚洲研究院副研究员,负责研发的人脸算法曾用于微软Xbox、How-old等知名产品,现象级产品How [http://Old.net](https://link.zhihu.com/?target=http%3A//Old.net)有数亿用户。在CVPR/ICCV/ECCV等计算机视觉顶级会议发表论文十余篇,其中三篇CVPR论文和两篇ICCV论文获得口头报告荣誉(接收率小5%)。 8 | 9 | ## 基于深度学习的物体检测 10 | 11 | **Q:目前的深度学习用于目标检测中有什么优点和缺点?** 12 | 13 | 首先简单介绍一下传统物体检测的方法和基于深度学习的物体检测方法。 14 | 15 | 传统方法使用滑动窗口的框架,把一张图分解成几百万个不同位置不同尺度的子窗口,针对每一个窗口使用分类器判断是否包含目标物体。传统方法针对不同的类别的物体,一般会设计不同的特征和分类算法,比如人脸检测的经典算法是Harr特征+Adaboosting分类器;行人检测的经典算法是HOG(histogram of gradients) + Support Vector Machine;一般性物体的检测的话是HOG的特征加上DPM(deformable part model)的算法。 16 | 17 | > 基于深度学习的物体检测的经典算法是RCNN系列: RCNN,fast RCNN (Ross Girshick),faster RCNN (少卿、凯明、孙剑、Ross)。这三个工作的核心思想是分别是:使用更好的CNN模型判断候选区域的类别;复用预计算的sharing feature map加快模型训练和物体检测的速度;进一步使用sharing feature map大幅提高计算候选区域的速度。其实基于深度学习的物体检测也可以看成对海量滑动窗口分类,只是用全卷积的方式。 18 | 19 | RCNN系列算法还是将物体检测分为两个步骤。现在还有一些工作是端到端(end-to-end)的物体检测,比如说YOLO(You Only Look Once: Unified, Real-Time Object Detection)和SSD(SSD: Single Shot MultiBox Detector)这样的算法。这两个算法号称和faster RCNN精度相似但速度更快。物体检测正负样本极端非均衡,two-stage cascade可以更好的应对非均衡。端到端学习是否可以超越faster RCNN还需要更多研究实验。 20 | 21 | ## 深度学习为何成为CV研究的标配 22 | 23 | **Q:针对本届大会深度学习几乎成了如今计算机视觉研究的标配,法国 Inria 研究所的研究员 Nikos Paragios 在 LinkedIn 撰文表示了担忧,似乎过于单一了,对这个有什么看法?** 24 | 25 | 先回答深度学习为什么会成为现在计算机视觉标配的方法。 26 | 27 | 首先,最重要的原因是深度学习可以做到传统方法无法企及的精度,这是关键中的关键,如果说这个优点是1的话,其它的优点都是1后面的0。深度学习革命爆发在2011~2012年,11年的时候在语音识别领域有重大突破,12年的时候在图像识别领域有重大突破。深度学习革命,使得计算机视觉在很多应用领域达到了实用水平,催生了工业界的大量应用。这也是为什么在11年前,机器视觉&人工智能的博士生都是找不到工作的,但是12年之后,尤其是现在,都变成了被众多公司高薪争夺的宝贝。 28 | 29 | 另外深度学习成为标配,还有其它的优点。 30 | 31 | > 第一,深度学习算法的通用性很强,刚才提到的检测,在传统算法里面,针对不同的物体需要定制化不同的算法。相比来看,基于深度学习的算法更加通用,比如faster RCNN在人脸、行人、一般物体检测任务上都可以取得非常好的效果。 32 | > 33 | > 34 | > 35 | > 第二,深度学习获得的特征(feature)有很强的迁移能力。所谓特征迁移能力,指的是在A任务上学习到一些特征,在B任务上使用也可以获得非常好的效果。例如在ImageNet(物体为主)上学习到的特征在场景分类任务上也能取得非常好的效果。 36 | > 37 | > 38 | > 39 | > 第三, 工程开发、优化、维护成本低。深度学习计算主要是卷积和矩阵乘,针对这种计算优化,所有深度学习算法都可以提升性能。另外,通过组合现有的层(layer),我们可以实现大量复杂网络结构和一些算法,开发维护的成本低。想想同时开发、维护Boosting,Random Forest等算法是非常痛苦的一件事情。 40 | 41 | 再回答深度学习过于单一的问题。 42 | 43 | 深度学习过于单一的说法,我觉得是不准确的。就好比说一个包容万象的宇宙过于单一了。 44 | 45 | 简单来说,机器学习就是学习输入到输出的一个映射,传统方法使用浅层的简单映射,现在深度学习是多层的复合映射。深度学习有很多的自由度,学习目标和学习方法有很多种选择,网络结构层与层之间有无数的可能连接方式,每一层映射的具体形式到底是卷积,还是全连接,还是其它的形式,并没有限制,其实除了全连接和卷积之外,还可以用其它的映射形式,比如说去年ICCV上的一个工作:微软研究院用Random Forest做为新的映射形式。 46 | 47 | ## 深度学习技术树 48 | 49 | **Q: 商汤科技CVPR2016送选论文重点介绍了四篇论文《物体分割》《服饰识别搜索技术》《行为识别和定位》《人脸检测中级联卷积神经网络的联合训练》,这4篇有何重要意义?这与你们目前的业务侧重点有何关系?** 50 | 51 | 深度学习的技术框架是一棵树形结构。 52 | 53 | 训练平台是树根,如caffe、tensorflow等。现在深度学习还处于实验科学阶段,实验效率很大程度上决定着研发效率,好的训练平台可以把实验周期从一个月缩短到一天,对于深度学习研发非常重要。 54 | 55 | 模型是树干。自06年提出深度学习概念,学术界花了六年时间才认识到模型结构的研究才是深度学习的重点。典型的成果有AlexNet、VGGNet、GoogleNet、ResNet等。学术界大家主要研究怎么把模型做的精度更好。在工业界我们还要考虑怎么把模型做得更快,更小。 56 | 57 | 在树干上有几个主干的枝丫,对应着计算机视觉里的核心任务,包括了检测、识别、分割、特征点定位、序列学习等五个大的任务,任何计算机视觉的具体的应用都可以由这五个任务组合而成。以人脸识别为例,人脸识别要完成整个流程,要涉及到人脸的检测、特征点定位,特征的提取&验证。这就包含了检测、特征点定位和识别三个部分。 58 | 59 | 我们在刚才提到的那五个重要的主干方向其实都投入了非常大的研究力量,一方面是保证我们在学术界的前沿有所突破,另一方面,针对我们一些重要应用也开发出了一整套与学术界并行的方法,能够做到十倍的加速和百倍模型的压缩,同时保持很好的精度。这个问题中提到的四篇论文主要是我们在这五个计算机视觉的核心任务上取得的一些研究方向的成果。其实我们除了在研究方向成果之外在工业实用方面有更大、更多的成果,比如我们的人脸检测在做到学术界最好结果的同时能做到300FPS的速度。人脸特征点的定位超过学术界最好结果的同时,做到3000FPS的速度。在学术界公开的论文中,我还没有看到这样的性能。 60 | 61 | **Q:在《物体分割》这篇文章中(作者石建萍)主要解决的问题是 instance segmentation(也称为Simultaneous Detection and Segmentation)。Instance segmentation 最近逐渐成为一个新的热点问题。它要解决的问题是检测(Object Detection)和语义分割(Semantic Segmentation)综合的一个问题。比起检测,需要得到物体更精确的边界信息;比起语义分割,需要区分不同的物体个体。** 62 | 63 | **检测好懂,现在都强调从2D检测升级到3D,4D的深度检测;语义分割一直在做的都是区分不同的物体个体,那么现在的语义分割与之前的区别是什么?是不是指语义分割要上升到结合场景的语义理解?** 64 | 65 | 在深度学习领域有一个简单但又非常通用的原理。在学习时,指导信息越丰富、越精细,学习的效果一般来说也会越好。 66 | 举个简单的例子,在数据量充足的情况下,如果我对我图像类别的标注仅仅是动物、植物、场景的话,学习出来的模型和特征可能一般。但是如果把这些类别标记细化,比如最开始有十类数据,我们把它细化到一千类,例如把狗分成斑点狗、斗牛犬等,把猫分成波斯猫、大花猫等,通常来说可以学习到更好的模型和更加好的特征。 67 | 另一个例子是物体检测,如果在bounding box的基础上增加额外的监督信息通长会得到更好的结果。比如标注出人脸的眼睛、鼻子、嘴的位置,人脸的角度,种族性别男女等属性,做成一个多任务学习的算法的话,通常来说能得到更好的效果。 68 | 69 | 两个代表性工作可以参考:Joint cascade face detection and alignment,Facial landmark detection by deep multi-task learning。 70 | 有时候多个标注/任务是并列关系,可以通过Multi-Task Learning的框架来学习。另外一些情况,多个任务是递进关系,前一个任务的结果可以帮助后一个任务,例如将每一个人都独立的检测出来之后再分割每个人身体的Mask。合理利用这种递进关系,可以得到比并列关系更好的结果,这其实就是Instance segmentation的核心思想。因为同传统语义分割不同的是,传统语义分割只需要对物体类别进行分类,不需要区分不同的个体。物体分割(Instance segmentation)是既需要区分类别,又需要区分同一物体的个体,所以深度学习的网络需要学习到比之前语义分割任务更多的信息。这方面微软亚洲研究院的戴继峰做了非常开创性的工作。我们商汤科技石建萍高级研究员的工作也非常有创建性。通过多尺度局部区域融合的方法,端到端的实现了instance segmentation 物体类别与区分统一类别不同个体的信息。 71 | 72 | ## 计算机视觉黑科技 73 | 74 | **Q:最近CV的应用出现了一些黑科技,比如MIT给机器“看电视剧”预测人类行为;MIT的人工智能为视频配音;迪士尼研究院可以让AI直接识别视频里正在发生的事。这些黑科技是噱头多还是真的有意义?** 75 | 76 | 做深度学习的人都是有一个终极的追求。现在的深度学习模式其实比较傻。给定一个数据,以及对应的标签(label)。比如说给一张图片,标签是一只猫,给另一幅图片,标签是一只狗,然后把这些数据送到神经网络里去学习,最终达到一个很好的识别效果。这样的方法叫做监督学习,虽然非常有效,但是和人类学习的方法还是不一样的。深度学习的研究者希望,机器可以更加聪明,可以像人一样学习。 77 | 78 | 在监督学习领域取得了重大成果之后,大家就把更多的精力投入到更接近人类学习方式的半监督学习(semi-supervised)和无监督学习(unsupervised)上。一方面,我们希望更加的深入的理解人类视觉的机理、甚至人的智能的机理。另一方面,监督学习需要大量的数据,如果能用半监督或无监督学习的方式绕过大数据标注难题,达到相同精度,这对工业界非常有吸引力。 79 | 80 | 问题中提到的这些黑科技,都是朝着人类学习方式探索性工作,非常有意义。 81 | 82 | 其实朝着这个方向努力的工作还有很多。这些工作都使用没有监督信息的图像或者视频。这些数据虽然没有标签,但数据内部其实都是蕴含着一些结构。比如视频里物体的运动、行为存在特定规律;在一张图片里,一个物体也是有特定的结构的。利用这些视频或图像中特定的结构,我们可以把一个无监督的问题转化为一个有监督问题,然后利用有监督学习的方法来学习。 83 | 84 | 有两个典型的工作。第一个工作把图像划分成2x2或者3x3的图像区域,给定任意两个区域预测他们之间的相对位置关系。这个工作利用到的物体、场景的固有结构特点,例如天空在道路上方,双腿在身体下方。另一个工作利用视频数据学习物体边缘,主要用到了视频中物体的边缘相对于背景有较大的运动这一个特点。 85 | 86 | 长期来看的话,探索人类学习过程的半监督、非监督、多感知输入的学习方式是深度学习的另一个发展趋势。 87 | 88 | ## 怎么看最佳论文们 89 | 90 | **Q:微软亚洲研究院的论文 Deep Residual Learning for Image Recognition 荣获最佳论文奖,本届 CVPR 2016最佳学生论文是斯坦福大学的 Structural-RNN: Deep Learning on Spatio-Temporal Graphs,您对这两篇论文有什么看法?** 91 | 92 | 凯明、孙剑的两篇best paper都是十分钟就能看懂,一天就能复现出结果。而对于之后的研究产生长远影响的工作。另外,孙剑做研究的风格对我影响很大。问题导向,解决重要问题,做真正work的研究。这些方法论不仅在学术界非常有价值,而且在工业界研究更加重要。 93 | 94 | > 回到论文本身,这篇论文解决的是深度网络一般超过20~30层的时候,训练和测试的loss不再下降,甚至随着层数的增加,loss会逐渐增加,针对这个问题提出了一个非常行之有效的解决方案。这个方法之所以有效,有很多解释,比如说有一种解释是通过跨层(skip-layer)可以把loss反传到中间的很多层,解决了梯度传播的问题。另一种解释认为ResNet通过skip-layer,可以做到深度方面的多模型融合。 95 | > 96 | > 97 | > 98 | > 我的解释稍微有点复杂。我认为,没有降采样的情况下,当深度达到一定的程度的时候,卷积层的学习能力是逐渐减弱的。当网络过深,增加的卷积层只能学习到噪音,并且造成有效信息损失,导致训练和测试loss都增加的情况。Skip layer可以很好的自适应的调整每一层的学习目标,解决这个问题。 99 | 100 | 另外ResNet有很大的冗余,把152层网络中的后面几层去掉也不会改变精度,可能这些层都被skip了。保持精度的情况下,去掉这些冗余,做到更小更经济的网络,非常有研究价值。 101 | 102 | ## 产业落地:从学术界到工业界 103 | 104 | **Q:论文总体上大概有基础理论研究的论文和提出具体解决办法的论文两类,对于论文的产业化,我们正确的态度是怎样的,比如多久论文投入实用的周期是适合?以及怎样发挥最大意义?** 105 | 106 | 现在产业界跟学术界的研究基本是并行进行的,总体来说,产业界没有落后于学术界,学术界也没有落后于产业界,只是产业界和学术界的侧重点不一样。 107 | 108 | 现在深度学习的研究迭代速度是非常非常快的,而且快的惊人。在其他领域的话,学术研究主要是通过发表期刊文章来交流,期刊周期短的话可能一年,长的话可能要两三年的时间。而在计算机领域,大家更多的是发表会议论文,会议论文的时间周期大概是半年的时间。在深度学习领域,大家第一时间把自己做出来的成果放在预印本(Arxiv),半年之后再把论文投稿到会议上去。 109 | 110 | 在商汤科技,很多研究员养成的习惯就是每天先到预印本(Arxiv)上去看最新论文,如果这个论文的思想有价值或者这个论文做出了一些非常突出的成果的话大家都会第一时间尝试复现,做一些探索性的实验。 111 | 112 | 我认为,在深度学习这个特定的领域,新技术落地的周期几乎为零。 113 | 114 | **Q:CVPR 上这么多主题演讲(main conference),觉得认为哪几个版块的内容最有用?** 115 | 116 | 我觉得CVPR的很多版块都非常有意思。要说哪个版块最有用的话,从工业界实用的角度出发,当然是检测识别的板块最有用。 117 | 118 | **Q:参加本届CVPR后有什么心得体会?** 119 | 120 | 最大的体会是华人圈做计算机视觉真的很厉害。去年参加ICCV的时候所有ImageNet的比赛第一名都被华人包揽了。这次CVPR的时候也看到了非常多的华人的优秀论文。凯明、少卿、翔宇、孙剑还拿了最佳论文奖。华人在计算机视觉领域的研究水平越来越高。这是非常振奋人心的事。稍微鸡汤一下,我们中国错过了工业革命,错过了电气革命,信息革命也只是跟随状态。但人工智能的革命,我们跟世界上的领先国家是并肩往前跑的。能身处这个时代浪潮之中,做一番伟大的事业,经常激动的夜不能寐。 121 | 122 | ## 小结: 123 | 124 | 本期硬创公开课上,曹旭东重点为我们介绍了深度学习目前相对其它AI实现方法占优的4个特点:精度好; 算法通用;特征推广性好;工程框架统一。这或许可以解释为深度学习现在在AI界大受欢迎的原因。 125 | 126 | 另外他指出计算机视觉里的核心任务,包括检测、识别、分割、特征点定位、序列学习等五个大的任务,为计算机视觉的具体应用勾画了一个清晰的脉络。 127 | 128 | 不过令人震惊的是,谈到深度学习这个特定领域的研究迭代速度,谈到论文投入实用的合理周期,他认为在深度学习这个特定的领域落地的周期应该是零。虽然现在谷歌,Facebook等大公司正在引导论文从文字到实践的产业化热潮,但这样的周期显然是让业内人士感到惊心动魄的一个速度。 -------------------------------------------------------------------------------- /ComputerVision/二维码条形码简介.md: -------------------------------------------------------------------------------- 1 | # 二维码条形码简介 2 | 3 | # 什么是二维码? 4 | 5 | 二维码 (dimensional barcode) 6 | ,又称二维条码,是在一维条码的基础上扩展出的一种具有可读性的条码。设备扫描二维条码,通过识别条码的长度和宽度中所记载的二进制数据,可获取其中所包 7 | 含的信息。相比一维条码,二维码记载更复杂的数据,比如图片、网络链接等。如下图: 8 | [![二维码](http://img.blog.csdn.net/20140826183645347?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2tpbGxjb2xsZWdl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)](http://img.blog.csdn.net/20140826183645347?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2tpbGxjb2xsZWdl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)二维码 9 | 10 | # 什么是一维码? 11 | 12 | 说完了二维码,接下来就说说一维码吧,一维条形码只是在一个方向(一般是水平方向)表达信息,而在垂直方向则不表达任何信息,其一定的高度通常是为 13 | 了便于阅读器的对准。一维条形码的应用可以提高信息录入的速度,减少差错率,但是一维条形码也存在一些不足之处:数据容量较小:30个字符左右。只能包含 14 | 字母和数字。如下图: 15 | [![一维码](http://img.blog.csdn.net/20140826184506453)](http://img.blog.csdn.net/20140826184506453) 16 | 17 | 18 | 19 | 20 | 21 | 参考项目 22 | 23 | 24 | 25 | 26 | 27 | 开源项目 28 | 29 | - ZBar官网: [http://zbar.sourceforge.net/](http://zbar.sourceforge.net/) 30 | 31 | - ZBar GitHub地址: [https://github.com/ZBar/ZBar](https://github.com/ZBar/ZBar) 32 | 33 | - 其中NDK开发环境搭建可以参考: [http://www.eoeandroid.com/forum.php?mod=viewthread&tid=272919](http://www.eoeandroid.com/forum.php?mod=viewthread&tid=272919) 34 | 35 | - ZBar项目编译可以参考: [[http://magiclen.org/zbar/](http://magiclen.org/zbar/)](http://magiclen.org/zbar/) 36 | 37 | - ZXing的下载地址:[ZXing](https://github.com/zxing/zxing) 38 | 39 | ​ 40 | 41 | ​ -------------------------------------------------------------------------------- /ComputerVision/人脸识别.md: -------------------------------------------------------------------------------- 1 | # 人脸识别:人脑认知与计算机算法 2 | 3 | 现阶段,人脸识别是人工智能领域最炙手可热的话题之一。Google和Facebook,以及国内一些创业公司都投入重金在该领域进行研发,并且有相当多的商业应用。随着Deep Learning算法的引入,计算机在人脸识别方面的准确率和鲁棒性得到了一个突破性的提高 [1, 2], 计算机算法犯第二类错误(把假当作真,即把非A识别为A)的概率也下降了很多,相比于识别失败率,这个参数在工业场景的应用中可能更为重要,因为他会更直接关系到产品的安全性。计算机人脸识别系统在安全方面的应用因此有了更好的接受度。 4 | 5 | 计算机人脸识别的准确率已经超过人类。目前的算法体现出来一些特征,从人脑的人脸认知和识别角度来看,显得非常的有趣。计算机人脸识别算法面对自然场景的人脸识别(Face Recognition in the Wild)问题时仍然有一些困难[3],而这些困难又跟人脑在自然场景做人脸识别时面对的困难又有一些相似和不同。这些问题的根本原因,还是在于计算机与人脑在人脸识别任务上处理的方法,或者说算法原理方面的相似性和不同。 6 | 7 | 大略来看,在人脸方面我们可以问以下一类问题: 8 | 9 | 1. 人在做人脸识别时候的注意点 跟 计算机算法(特别地,深度神经网络)的“认知”重点有什么差异 10 | 2. 人在做人脸识别的学习过程中,需要的样本数量很多,但是跟深度神经网络训练所需的动则上百万个样本这样一个数量级还是有很大的差距 [4],是什么导致了这个问题 11 | 3. 人脑人脸识别任务的一些低识别率场景是怎么导致的;计算机算法也会面对类似的问题,其原因是什么;两种算法(人脑的识别算法/模型 与 计算机的算法)如何相互参考 12 | 4. 计算机人脸识别算法最新趋势中跟人脑认知的差异 13 | 5. ....... 14 | 15 | 16 | 17 | 在做人脸识别训练方面,人脑认知与计算机算法的第一个不同在于,人类接受的**人脸图像训练是多角度的、动态的**,而目前**计算机算法在训练之中使用的基本上是静态的图片**[1]。现有的图像训练数据库,无论是常用的一类公开数据集LFW, CASIA-WebFace, 还是Google和Facebook使用的闭源数据库,即便对同一个人有很多张不同时间和场景的图片,他们都只是截取了有限的角度。 18 | 19 | 20 | 21 | 人类在要认识一个陌生人时,不免需要多观察几眼,特别是对于一个长的美貌/化妆过的人脸,由于更接近平均人脸,外在特征(external features: hair, face, outline)和内在特征(internal features: eyes, nose, mouth) [2] 相对来说不明显,一般需要动态观察更久才能记住。 22 | 23 | 实验室条件下的受限环境刺激和训练证明,人类识别/记住一个陌生人脸,使用动态图像比使用静态图片更有优势 [3, 4]: 24 | 25 | ![img](https://pic3.zhimg.com/6b973a77d85d33f76c130bc0899e62b6_b.png) 26 | 27 | 28 | 29 | 不难想象的,动态人脸能提供来自更多角度的更多可供识别的信息,即使实验场景下,这些动态人脸提供的信息跟真实场景中的还有一定的差距,但是动态人脸刺激相比于静态人类刺激的优势在实验场景下可观测的。 30 | 31 | 在计算机算法方面,近年来随着深度学习的引入,主流人脸识别算法对训练图像的数量提出了越来越高的需求,动则达到数百万以上,Google 的FaceNet更是达到令人嗔目结舌的20亿数量级[5, 6],但是不开放。传统学术界的实验室算法受限于使用公开数据集,为了达到更好的效果不得不另辟蹊径,在有限的图像上获取更多信息,也就是Data Augmentation [7]. 最简单的Face Data Augmentation无疑是变换图像的左右,但是这种做法有可能已经改变了人脸的内在特征。需要权衡带来的好处(图像数量增加)与缺陷(部分特征可能被抵消)。另一类算法通过模拟人脸在其他视角的图像做Face Data Augmentation. 最初来源于人脸摆正(face frontalization)[8]。 32 | 33 | ![img](https://pic4.zhimg.com/917605ee17c2263df65f2903f4ea1de7_b.png) 34 | 35 | [8] 中算法通过Face Landmark Detector处理目标图像和三维模型图像(二维化之后),得到一组对应的Landmark. 而二维化之后的三维模型上的Landmark({Xi, Yi})在三维模型中具有对应的坐标({Xi, Yi, Zi}). 据此可以估测相机参数,进行相机标定 [9]。从而可以模拟模型与目标图像一样的角度,反过来得出目标图像中像素在摆正之后的位置。 36 | 37 | ![img](https://pic2.zhimg.com/4602d32e87c3058cc6656424ac2bef45_b.png) 38 | 39 | ![img](https://pic2.zhimg.com/23c95841aa4c6479112f4699786df755_b.png) 40 | 41 | 不难理解的,该套算法稍加变化,就可以使用一张人脸图片得出多个角度的人脸图片,即既可以用来做人脸摆正,也可以生成侧脸图像 [10, 11]: 42 | 43 | 44 | 45 | 这种做法虽然没有增加投入到训练算法中的信息,但大大增加了算法的识别率并降低了误识率(FAR, False Acceptance Rate): 46 | ![img](https://pic4.zhimg.com/f7d18f7be140ba56ae2646c55686cd2f_b.png) 47 | 48 | 当然,生成不同角度的图像更原本就有同一个场景的连续变化视角的图像(视频)对人脸识别来说还是有一些不同的。更为接近自然场景中人脑的人脸识别任务的,是视频中人脸图像的识别。但是目前由于受限于人脸视频的稀缺性(搜集一个人脸的视频比搜集其图片要繁琐的多,同时视频中的特征标定也是一个严重的问题),深度学习/深度神经网络在视频人脸图像的研究还却如。目前在这个领域使用的一般是基于模型的传统算法[12-14]。视频中人脸的分辨率跟目前人脸图像数据及中的分辨率还有一定差距,同时视频图像的噪声更大,场景的复杂度好更高。因此视频中人脸识别跟静态图像中人类识别几乎是用的是完全不同的方法。在结合这两者,应用大量视频图像做人脸识别算法训练之前还得解决以上一系列的技术问题。 49 | \-------- 50 | 51 | 简单的说,外在特征(external features)指的是头发(颜色、发型)、脸部轮廓、脸颊等,内在特征(internal features)指的是眼睛、鼻子和嘴巴以及它们之间的内在关系 [1]。 52 | 53 | ![img](https://pic2.zhimg.com/50e303054a7a0e3aa9cab6f1b13c6c25_b.png) 54 | 55 | 人类视野的分辨率从视野中央往外侧快速下降,因此需要不断的调整注视方向来获取高精度图像,也就是注意力点的变化。同时,人眼运动控制的相当部分是直接由脑干区域的神经核团支配的,也就是说,不受大脑皮层的控制,因此眼动在大部分情况下不进入意识层面,其运动控制表现出对注意力控制的被支配性。通过观测注视(眼动)的变化,可以获知人的注意力的重点 [2],也就是信息获取的关键,眼动因此成为了人类意识的一个易于观测的外显参数 [3]。在我们人类发育的早期,观察人脸首先是注意外在特征多,然后逐步发展的更注意内在特征[4]。当然,这也可能与一岁以下的婴儿的视觉感知情况与更年长者有别有关,两个月以下的婴儿,他/她们的视觉处在一个快速发展的时期——由不清晰到清晰,同时色彩的感知也发生快速的变化[5-7]。 56 | 57 | 在成人的人脸识别过程总,内在特征与外在特征所扮演的角色各不相同,一般地,我们认为在识别陌生人脸的过程中,外部特征占有比较重要的作用(或者同等重要),当人脸变得熟悉时,外部特征在人脸识别中的重要性逐渐下降,而内部特种的重要性逐渐升高的主导地位 [8]。通过一些量化参数,我们可以大致的描述内在特征和外在特总在人脑的人脸识别任务中的地位[9, 10]: 58 | 59 | 60 | 当然地,一般认为,人脑人脸识别中,内在特征和外在特征是作为一个整体在大脑皮层的相关区域 (Fusiform Face Area, FFA; Occipital Face Area, OFA; Superior Temporal Sulcus, STS)处理,而不是分开的 [11]。 61 | 62 | 在计算机人脸识别领域,特别是在深度学习出现以前的使用模型的时代,算法研究一直将重心放在内在特征上 [12],这跟计算机人脸识别的应用场景,以及投入到训练算法中的图像训练集有一定的关系。训练集里的同一个人经常有不同时期不同发型、妆容的图像,易于理解的,算法关注外在特征会降低算法的识别率并增加误识率,这对算法的性能是不利的 [13]。 63 | 64 | 65 | 66 | 当然,也有一些人在外在特征方面做过一些尝试,[14] 中算法先使用训练集训练,得到外在特征块的集合Building Block Set,再使用特征块去匹配测试人脸图像,匹配度最高的Building Block提供了测试人脸特征,从而可以用来进行分类。 67 | 68 | 69 | 70 | 该算法在当时能做到其他模型接近的精度,证明了外在特征进行人脸识别的可行性。但是如上文所说过的,外在特征天然的不稳定性,并不是做人脸识别的最优信息来源。由于大数据集和深度学习的普遍使用 [15],外在特征在人脸识别算法中被研究人员不自觉的抛弃。新的人脸识别算法对遮挡、发型、妆容、光照这些外在影响的鲁棒性得到了很大的提高,人们对外在特征的关注似乎就到此为止了。 -------------------------------------------------------------------------------- /ComputerVision/图像分类笔记.md: -------------------------------------------------------------------------------- 1 | # 图像分类笔记 2 | 3 | 这是一篇介绍性教程,面向非计算机视觉领域的同学。教程将向同学们介绍图像分类问题和数据驱动方法。下面是**内容列表**: 4 | 5 | - 图像分类、数据驱动方法和流程 6 | 7 | - Nearest Neighbor分类器 8 | 9 | - - k-Nearest Neighbor 10 | 11 | - 验证集、交叉验证集和超参数调参 12 | 13 | - Nearest Neighbor的优劣 14 | 15 | - 小结 16 | 17 | - 小结:应用kNN实践 18 | 19 | - 拓展阅读 20 | 21 | ## 图像分类 22 | 23 | **目标**:这一节我们将介绍图像分类问题。所谓图像分类问题,就是已有固定的分类标签集合,然后对于输入的图像,从分类标签集合中找出一个分类标签,最后把分类标签分配给该输入图像。虽然看起来挺简单的,但这可是计算机视觉领域的核心问题之一,并且有着各种各样的实际应用。在后面的课程中,我们可以看到计算机视觉领域中很多看似不同的问题(比如物体检测和分割),都可以被归结为图像分类问题。 24 | 25 | **例子**:以下图为例,图像分类模型读取该图片,并生成该图片属于集合 {cat, dog, hat, mug}中各个标签的概率。需要注意的是,对于计算机来说,图像是一个由数字组成的巨大的3维数组。在这个例子中,猫的图像大小是宽248像素,高400像素,有3个颜色通道,分别是红、绿和蓝(简称RGB)。如此,该图像就包含了248X400X3=297600个数字,每个数字都是在范围0-255之间的整型,其中0表示全黑,255表示全白。我们的任务就是把这些上百万的数字变成一个简单的标签,比如“猫”。 26 | 27 | ————————————————————————————————————————— 28 | 29 | ![img](https://pic2.zhimg.com/baab9e4b97aceb77ec70abeda6be022d_b.png)图像分类的任务,就是对于一个给定的图像,预测它属于的那个分类标签(或者给出属于一系列不同标签的可能性)。图像是3维数组,数组元素是取值范围从0到255的整数。数组的尺寸是宽度x高度x3,其中这个3代表的是红、绿和蓝3个颜色通道。 30 | 31 | ————————————————————————————————————————— 32 | 33 | **困难和挑战**:对于人来说,识别出一个像“猫”一样视觉概念是简单至极的,然而从计算机视觉算法的角度来看就值得深思了。我们在下面列举了计算机视觉算法在图像识别方面遇到的一些困难,要记住图像是以3维数组来表示的,数组中的元素是亮度值。 34 | 35 | - **视角变化(Viewpoint variation)**:同一个物体,摄像机可以从多个角度来展现。 36 | - **大小变化(Scale variation)**:物体可视的大小通常是会变化的(不仅是在图片中,在真实世界中大小也是变化的)。 37 | - **形变(Deformation)**:很多东西的形状并非一成不变,会有很大变化。 38 | - **遮挡(Occlusion)**:目标物体可能被挡住。有时候只有物体的一小部分(可以小到几个像素)是可见的。 39 | - **光照条件(Illumination conditions)**:在像素层面上,光照的影响非常大。 40 | - **背景干扰(Background clutter)**:物体可能混入背景之中,使之难以被辨认。 41 | - **类内差异(Intra-class variation)**:一类物体的个体之间的外形差异很大,比如椅子。这一类物体有许多不同的对象,每个都有自己的外形。 42 | 43 | 面对以上所有变化及其组合,好的图像分类模型能够在维持分类结论稳定的同时,保持对类间差异足够敏感。 44 | 45 | ————————————————————————————————————————— 46 | 47 | ![img](https://pic2.zhimg.com/1ee9457872f773d671dd5b225647ef45_b.jpg)————————————————————————————————————————— 48 | 49 | **数据驱动方法**:如何写一个图像分类的算法呢?这和写个排序算法可是大不一样。怎么写一个从图像中认出猫的算法?搞不清楚。因此,与其在代码中直接写明各类物体到底看起来是什么样的,倒不如说我们采取的方法和教小孩儿看图识物类似:给计算机很多数据,然后实现学习算法,让计算机学习到每个类的外形。这种方法,就是*数据驱动方法*。既然该方法的第一步就是收集已经做好分类标注的图片来作为训练集,那么下面就看看数据库到底长什么样: 50 | 51 | ————————————————————————————————————————— 52 | 53 | ![img](https://pic1.zhimg.com/bbbfd2e6878d6f5d2a82f8239addbbc0_b.jpg)一个有4个视觉分类的训练集。在实际中,我们可能有上千的分类,每个分类都有成千上万的图像。 54 | 55 | ————————————————————————————————————————— 56 | 57 | **图像分类流程**。在课程视频中已经学习过,**图像分类**就是输入一个元素为像素值的数组,然后给它分配一个分类标签。完整流程如下: 58 | 59 | - **输入**:输入是包含N个图像的集合,每个图像的标签是K种分类标签中的一种。这个集合称为*训练集。* 60 | - **学习**:这一步的任务是使用训练集来学习每个类到底长什么样。一般该步骤叫做*训练分类器*或者*学习一个模型*。 61 | - **评价**:让分类器来预测它未曾见过的图像的分类标签,并以此来评价分类器的质量。我们会把分类器预测的标签和图像真正的分类标签对比。毫无疑问,分类器预测的分类标签和图像真正的分类标签如果一致,那就是好事,这样的情况越多越好。 62 | 63 | ## Nearest Neighbor分类器 64 | 65 | 作为课程介绍的第一个方法,我们来实现一个**Nearest Neighbor分类器**。虽然这个分类器和卷积神经网络没有任何关系,实际中也极少使用,但通过实现它,可以让读者对于解决图像分类问题的方法有个基本的认识。 66 | 67 | **图像分类数据集:CIFAR-10。**一个非常流行的图像分类数据集是[CIFAR-10](https://link.zhihu.com/?target=http%3A//www.cs.toronto.edu/%7Ekriz/cifar.html)。这个数据集包含了60000张32X32的小图像。每张图像都有10种分类标签中的一种。这60000张图像被分为包含50000张图像的训练集和包含10000张图像的测试集。在下图中你可以看见10个类的10张随机图片。 68 | 69 | ————————————————————————————————————————— 70 | 71 | ![img](https://pic1.zhimg.com/fff49fd8cec00f77f657a4c4a679b030_b.jpg)**左边**:从[CIFAR-10](https://link.zhihu.com/?target=http%3A//www.cs.toronto.edu/%7Ekriz/cifar.html)数据库来的样本图像。**右边**:第一列是测试图像,然后第一列的每个测试图像右边是使用Nearest Neighbor算法,根据像素差异,从训练集中选出的10张最类似的图片。 72 | 73 | ————————————————————————————————————————— 74 | 75 | 假设现在我们有CIFAR-10的50000张图片(每种分类5000张)作为训练集,我们希望将余下的10000作为测试集并给他们打上标签。Nearest Neighbor算法将会拿着测试图片和训练集中每一张图片去比较,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片。上面右边的图片就展示了这样的结果。请注意上面10个分类中,只有3个是准确的。比如第8行中,马头被分类为一个红色的跑车,原因在于红色跑车的黑色背景非常强烈,所以这匹马就被错误分类为跑车了。 76 | 77 | 那么具体如何比较两张图片呢?在本例中,就是比较32x32x3的像素块。最简单的方法就是逐个像素比较,最后将差异值全部加起来。换句话说,就是将两张图片先转化为两个向量![I_1](https://zhihu.com/equation?tex=I_1)和![I_2](https://zhihu.com/equation?tex=I_2),然后计算他们的**L1距离:** 78 | 79 | 这里的求和是针对所有的像素。下面是整个比较流程的图例: 80 | 81 | ————————————————————————————————————————— 82 | 83 | ![img](https://pic2.zhimg.com/95cfe7d9efb83806299c218e0710a6c5_b.jpg)以图片中的一个颜色通道为例来进行说明。两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1值将会非常大。 84 | 85 | ————————————————————————————————————————— 86 | 87 | 下面,让我们看看如何用代码来实现这个分类器。首先,我们将CIFAR-10的数据加载到内存中,并分成4个数组:训练数据和标签,测试数据和标签。在下面的代码中,**Xtr**(大小是50000x32x32x3)存有训练集中所有的图像,**Ytr**是对应的长度为50000的1维数组,存有图像对应的分类标签(从0到9): 88 | 89 | ```python 90 | Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide 91 | # flatten out all images to be one-dimensional 92 | Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072 93 | Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072 94 | ``` 95 | 96 | 现在我们得到所有的图像数据,并且把他们拉长成为行向量了。接下来展示如何训练并评价一个分类器: 97 | 98 | ```python 99 | nn = NearestNeighbor() # create a Nearest Neighbor classifier class 100 | nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels 101 | Yte_predict = nn.predict(Xte_rows) # predict labels on the test images 102 | # and now print the classification accuracy, which is the average number 103 | # of examples that are correctly predicted (i.e. label matches) 104 | print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) ) 105 | ``` 106 | 107 | 作为评价标准,我们常常使用**准确率**,它描述了我们预测正确的得分。请注意以后我们实现的所有分类器都需要有这个API:**train(X, y)**函数。该函数使用训练集的数据和标签来进行训练。从其内部来看,类应该实现一些关于标签和标签如何被预测的模型。这里还有个**predict(X)**函数,它的作用是预测输入的新数据的分类标签。现在还没介绍分类器的实现,下面就是使用L1距离的Nearest Neighbor分类器的实现套路: 108 | 109 | ```python 110 | import numpy as np 111 | 112 | class NearestNeighbor(object): 113 | def __init__(self): 114 | pass 115 | 116 | def train(self, X, y): 117 | """ X is N x D where each row is an example. Y is 1-dimension of size N """ 118 | # the nearest neighbor classifier simply remembers all the training data 119 | self.Xtr = X 120 | self.ytr = y 121 | 122 | def predict(self, X): 123 | """ X is N x D where each row is an example we wish to predict label for """ 124 | num_test = X.shape[0] 125 | # lets make sure that the output type matches the input type 126 | Ypred = np.zeros(num_test, dtype = self.ytr.dtype) 127 | 128 | # loop over all test rows 129 | for i in xrange(num_test): 130 | # find the nearest training image to the i'th test image 131 | # using the L1 distance (sum of absolute value differences) 132 | distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1) 133 | min_index = np.argmin(distances) # get the index with smallest distance 134 | Ypred[i] = self.ytr[min_index] # predict the label of the nearest example 135 | 136 | return Ypred 137 | ``` 138 | 139 | 如果你用这段代码跑CIFAR-10,你会发现准确率能达到**38.6%**。这比随机猜测的10%要好,但是比人类识别的水平([据研究推测是94%**](https://link.zhihu.com/?target=http%3A//karpathy.github.io/2011/04/27/manually-classifying-cifar10/))和卷积神经网络能达到的95%还是差多了。点击查看基于CIFAR-10数据的[Kaggle算法竞赛排行榜**](https://link.zhihu.com/?target=http%3A//www.kaggle.com/c/cifar-10/leaderboard)。 140 | 141 | **距离选择**:计算向量间的距离有很多种方法,另一个常用的方法是**L2距离**,从几何学的角度,可以理解为它在计算两个向量间的欧式距离。L2距离的公式如下: 142 | 143 | 换句话说,我们依旧是在计算像素间的差值,只是先求其平方,然后把这些平方全部加起来,最后对这个和开方。在Numpy中,我们只需要替换上面代码中的1行代码就行: 144 | 145 | ```python 146 | distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1)) 147 | ``` 148 | 149 | 注意在这里使用了**np.sqrt**,但是在实际中可能不用。因为求平方根函数是一个*单调函数*,它对不同距离的绝对值求平方根虽然改变了数值大小,但依然保持了不同距离大小的顺序。所以用不用它,都能够对像素差异的大小进行正确比较。如果你在CIFAR-10上面跑这个模型,正确率是**35.4%**,比刚才低了一点。 150 | 151 | **L1和L2比较**。比较这两个度量方式是挺有意思的。在面对两个向量之间的差异时,L2比L1更加不能容忍这些差异。也就是说,相对于1个巨大的差异,L2距离更倾向于接受多个中等程度的差异。L1和L2都是在[p-norm**](https://link.zhihu.com/?target=http%3A//planetmath.org/vectorpnorm)常用的特殊形式。 152 | 153 | ## k-Nearest Neighbor分类器 154 | 155 | 你可能注意到了,为什么只用最相似的1张图片的标签来作为测试图像的标签呢?这不是很奇怪吗!是的,使用**k-Nearest Neighbor分类器**就能做得更好。它的思想很简单:与其只找最相近的那1个图片的标签,我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。所以当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器。从直观感受上就可以看到,更高的k值可以让分类的效果更平滑,使得分类器对于异常值更有抵抗力。 156 | 157 | ————————————————————————————————————————— 158 | 159 | ![img](https://pic3.zhimg.com/51aef845faa10195e33bdd4657592f86_b.jpg)上面示例展示了Nearest Neighbor分类器和5-Nearest Neighbor分类器的区别。例子使用了2维的点来表示,分成3类(红、蓝和绿)。不同颜色区域代表的是使用L2距离的分类器的**决策边界**。白色的区域是分类模糊的例子(即图像与两个以上的分类标签绑定)。需要注意的是,在NN分类器中,异常的数据点(比如:在蓝色区域中的绿点)制造出一个不正确预测的孤岛。5-NN分类器将这些不规则都平滑了,使得它针对测试数据的**泛化(****generalization****)**能力更好(例子中未展示)。注意,5-NN中也存在一些灰色区域,这些区域是因为近邻标签的最高票数相同导致的(比如:2个邻居是红色,2个邻居是蓝色,还有1个是绿色)。 -------------------------------------------------------------------------------- /ComputerVision/基于深度学习的物体检测.md: -------------------------------------------------------------------------------- 1 | ## 基于深度学习的物体检测 2 | 3 | 4 | 5 | **目前的深度学习用于目标检测中有什么优点和缺点?** 6 | 7 | 首先简单介绍一下传统物体检测的方法和基于深度学习的物体检测方法。 8 | 9 | 传统方法使用滑动窗口的框架,把一张图分解成几百万个不同位置不同尺度的子窗口,针对每一个窗口使用分类器判断是否包含目标物体。传统方法针对不同的类别的物体,一般会设计不同的特征和分类算法,比如人脸检测的经典算法是Harr特征+Adaboosting分类器;行人检测的经典算法是HOG(histogram of gradients) + Support Vector Machine;一般性物体的检测的话是HOG的特征加上DPM(deformable part model)的算法。 10 | 11 | > 基于深度学习的物体检测的经典算法是RCNN系列: RCNN,fast RCNN (Ross Girshick),faster RCNN (少卿、凯明、孙剑、Ross)。这三个工作的核心思想是分别是:使用更好的CNN模型判断候选区域的类别;复用预计算的sharing feature map加快模型训练和物体检测的速度;进一步使用sharing feature map大幅提高计算候选区域的速度。其实基于深度学习的物体检测也可以看成对海量滑动窗口分类,只是用全卷积的方式。 12 | 13 | RCNN系列算法还是将物体检测分为两个步骤。现在还有一些工作是端到端(end-to-end)的物体检测,比如说YOLO(You Only Look Once: Unified, Real-Time Object Detection)和SSD(SSD: Single Shot MultiBox Detector)这样的算法。这两个算法号称和faster RCNN精度相似但速度更快。物体检测正负样本极端非均衡,two-stage cascade可以更好的应对非均衡。端到端学习是否可以超越faster RCNN还需要更多研究实验。 14 | 15 | 深度学习可以做到传统方法无法企及的精度,这是关键中的关键,如果说这个优点是1的话,其它的优点都是1后面的0。深度学习革命爆发在2011~2012年,11年的时候在语音识别领域有重大突破,12年的时候在图像识别领域有重大突破。深度学习革命,使得计算机视觉在很多应用领域达到了实用水平,催生了工业界的大量应用。这也是为什么在11年前,机器视觉&人工智能的博士生都是找不到工作的,但是12年之后,尤其是现在,都变成了被众多公司高薪争夺的宝贝。 16 | 17 | 另外深度学习成为标配,还有其它的优点。 18 | 19 | > 第一,深度学习算法的通用性很强,刚才提到的检测,在传统算法里面,针对不同的物体需要定制化不同的算法。相比来看,基于深度学习的算法更加通用,比如faster RCNN在人脸、行人、一般物体检测任务上都可以取得非常好的效果。 20 | > 21 | > 22 | > 23 | > 第二,深度学习获得的特征(feature)有很强的迁移能力。所谓特征迁移能力,指的是在A任务上学习到一些特征,在B任务上使用也可以获得非常好的效果。例如在ImageNet(物体为主)上学习到的特征在场景分类任务上也能取得非常好的效果。 24 | > 25 | > 26 | > 27 | > 第三, 工程开发、优化、维护成本低。深度学习计算主要是卷积和矩阵乘,针对这种计算优化,所有深度学习算法都可以提升性能。另外,通过组合现有的层(layer),我们可以实现大量复杂网络结构和一些算法,开发维护的成本低。想想同时开发、维护Boosting,Random Forest等算法是非常痛苦的一件事情。 28 | 29 | 再回答深度学习过于单一的问题。 30 | 31 | 深度学习过于单一的说法,我觉得是不准确的。就好比说一个包容万象的宇宙过于单一了。 32 | 33 | 简单来说,机器学习就是学习输入到输出的一个映射,传统方法使用浅层的简单映射,现在深度学习是多层的复合映射。深度学习有很多的自由度,学习目标和学习方法有很多种选择,网络结构层与层之间有无数的可能连接方式,每一层映射的具体形式到底是卷积,还是全连接,还是其它的形式,并没有限制,其实除了全连接和卷积之外,还可以用其它的映射形式,比如说去年ICCV上的一个工作:微软研究院用Random Forest做为新的映射形式。 34 | 35 | 深度学习的技术框架是一棵树形结构。 36 | 37 | 训练平台是树根,如caffe、tensorflow等。现在深度学习还处于实验科学阶段,实验效率很大程度上决定着研发效率,好的训练平台可以把实验周期从一个月缩短到一天,对于深度学习研发非常重要。 38 | 39 | 模型是树干。自06年提出深度学习概念,学术界花了六年时间才认识到模型结构的研究才是深度学习的重点。典型的成果有AlexNet、VGGNet、GoogleNet、ResNet等。学术界大家主要研究怎么把模型做的精度更好。在工业界我们还要考虑怎么把模型做得更快,更小。 40 | 41 | 在树干上有几个主干的枝丫,对应着计算机视觉里的核心任务,包括了检测、识别、分割、特征点定位、序列学习等五个大的任务,任何计算机视觉的具体的应用都可以由这五个任务组合而成。以人脸识别为例,人脸识别要完成整个流程,要涉及到人脸的检测、特征点定位,特征的提取&验证。这就包含了检测、特征点定位和识别三个部分。 42 | 43 | 我们在刚才提到的那五个重要的主干方向其实都投入了非常大的研究力量,一方面是保证我们在学术界的前沿有所突破,另一方面,针对我们一些重要应用也开发出了一整套与学术界并行的方法,能够做到十倍的加速和百倍模型的压缩,同时保持很好的精度。这个问题中提到的四篇论文主要是我们在这五个计算机视觉的核心任务上取得的一些研究方向的成果。其实我们除了在研究方向成果之外在工业实用方面有更大、更多的成果,比如我们的人脸检测在做到学术界最好结果的同时能做到300FPS的速度。人脸特征点的定位超过学术界最好结果的同时,做到3000FPS的速度。在学术界公开的论文中,我还没有看到这样的性能。 44 | 45 | 在深度学习领域有一个简单但又非常通用的原理。在学习时,指导信息越丰富、越精细,学习的效果一般来说也会越好。 46 | 举个简单的例子,在数据量充足的情况下,如果我对我图像类别的标注仅仅是动物、植物、场景的话,学习出来的模型和特征可能一般。但是如果把这些类别标记细化,比如最开始有十类数据,我们把它细化到一千类,例如把狗分成斑点狗、斗牛犬等,把猫分成波斯猫、大花猫等,通常来说可以学习到更好的模型和更加好的特征。 47 | 另一个例子是物体检测,如果在bounding box的基础上增加额外的监督信息通长会得到更好的结果。比如标注出人脸的眼睛、鼻子、嘴的位置,人脸的角度,种族性别男女等属性,做成一个多任务学习的算法的话,通常来说能得到更好的效果。 48 | 49 | 两个代表性工作可以参考:Joint cascade face detection and alignment,Facial landmark detection by deep multi-task learning。 50 | 有时候多个标注/任务是并列关系,可以通过Multi-Task Learning的框架来学习。另外一些情况,多个任务是递进关系,前一个任务的结果可以帮助后一个任务,例如将每一个人都独立的检测出来之后再分割每个人身体的Mask。合理利用这种递进关系,可以得到比并列关系更好的结果,这其实就是Instance segmentation的核心思想。因为同传统语义分割不同的是,传统语义分割只需要对物体类别进行分类,不需要区分不同的个体。物体分割(Instance segmentation)是既需要区分类别,又需要区分同一物体的个体,所以深度学习的网络需要学习到比之前语义分割任务更多的信息。这方面微软亚洲研究院的戴继峰做了非常开创性的工作。我们商汤科技石建萍高级研究员的工作也非常有创建性。通过多尺度局部区域融合的方法,端到端的实现了instance segmentation 物体类别与区分统一类别不同个体的信息。 -------------------------------------------------------------------------------- /ComputerVision/验证码识别.md: -------------------------------------------------------------------------------- 1 | # 端到端的OCR:验证码识别 2 | 3 | 4 | 5 | OCR是一个古老的研究领域,简单说就是把图片上的文字转化为文本的过程。在最近几年随着大数据的发展,广大爬虫工程师在对抗验证码时也得用上OCR。所以,这篇文章主要说的OCR其实就是图片验证码的识别。OCR并不是我的研究方向,我研究这个问题是因为OCR是一个可以同时用CNN,RNN两种算法都可以很好解决的问题,所以用这个问题来熟悉一个深度学习框架是非常适合的。我主要通过研究这个问题来了解[mxnet**](https://link.zhihu.com/?target=https%3A//github.com/dmlc/mxnet)。验证码识别的思路非常暴力,大概就是这样:去噪+二值化字符分割每个字符识别 6 | 验证码的难度在这3步上都有反应。比如噪声:加一条贯穿全图的曲线,比如网格线,还有图的一半是白底黑字,另一半是黑底白字。 7 | 分割:字符粘连,7和4粘在一起。识别:字符各种扭曲,各种旋转。但相对而言,难度最大的是第2步,分割。所以就有人想,我能不能不做分割,就把验证码给识别了。深度学习擅长做端到端的学习,因此这个不分割就想识别的事情交给深度学习是最合适的。基于CNN的验证码识别基于CNN去识别验证码,其实就是一个图片的多标签学习问题。比如考虑一个4个数字组成的验证码,那么相当于每张图就有4个标签。那么我们把原始图片作为输入,4个标签作为输出,扔进CNN里,看看能不能收敛就行了。下面这段代码定义了mxnet上的一个DataIter,我们用了python-captcha这个库来自动生成训练样本,所以可以假设训练样本是无穷多的。 8 | 9 | ```python 10 | 11 | class OCRIter(mx.io.DataIter): 12 | def __init__(self, count, batch_size, num_label, height, width): 13 | super(OCRIter, self).__init__() 14 | self.captcha = ImageCaptcha(fonts=['./data/OpenSans-Regular.ttf']) 15 | self.batch_size = batch_size 16 | self.count = count 17 | self.height = height 18 | self.width = width 19 | self.provide_data = [('data', (batch_size, 3, height, width))] 20 | self.provide_label = [('softmax_label', (self.batch_size, num_label))] 21 | 22 | def __iter__(self): 23 | for k in range(self.count / self.batch_size): 24 | data = [] 25 | label = [] 26 | for i in range(self.batch_size): 27 | # 生成一个四位数字的随机字符串 28 | num = gen_rand() 29 | # 生成随机字符串对应的验证码图片 30 | img = self.captcha.generate(num) 31 | img = np.fromstring(img.getvalue(), dtype='uint8') 32 | img = cv2.imdecode(img, cv2.IMREAD_COLOR) 33 | img = cv2.resize(img, (self.width, self.height)) 34 | cv2.imwrite("./tmp" + str(i % 10) + ".png", img) 35 | img = np.multiply(img, 1/255.0) 36 | img = img.transpose(2, 0, 1) 37 | data.append(img) 38 | label.append(get_label(num)) 39 | 40 | data_all = [mx.nd.array(data)] 41 | label_all = [mx.nd.array(label)] 42 | data_names = ['data'] 43 | label_names = ['softmax_label'] 44 | 45 | data_batch = OCRBatch(data_names, data_all, label_names, label_all) 46 | yield data_batch 47 | 48 | def reset(self): 49 | pass 50 | ``` 51 | 52 | 53 | 54 | 下面这段代码是网络结构: 55 | 56 | ```python 57 | def get_ocrnet(): 58 | data = mx.symbol.Variable('data') 59 | label = mx.symbol.Variable('softmax_label') 60 | conv1 = mx.symbol.Convolution(data=data, kernel=(5,5), num_filter=32) 61 | pool1 = mx.symbol.Pooling(data=conv1, pool_type="max", kernel=(2,2), stride=(1, 1)) 62 | relu1 = mx.symbol.Activation(data=pool1, act_type="relu") 63 | 64 | conv2 = mx.symbol.Convolution(data=relu1, kernel=(5,5), num_filter=32) 65 | pool2 = mx.symbol.Pooling(data=conv2, pool_type="avg", kernel=(2,2), stride=(1, 1)) 66 | relu2 = mx.symbol.Activation(data=pool2, act_type="relu") 67 | 68 | conv3 = mx.symbol.Convolution(data=relu2, kernel=(3,3), num_filter=32) 69 | pool3 = mx.symbol.Pooling(data=conv3, pool_type="avg", kernel=(2,2), stride=(1, 1)) 70 | relu3 = mx.symbol.Activation(data=pool3, act_type="relu") 71 | 72 | flatten = mx.symbol.Flatten(data = relu3) 73 | fc1 = mx.symbol.FullyConnected(data = flatten, num_hidden = 512) 74 | fc21 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 75 | fc22 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 76 | fc23 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 77 | fc24 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 78 | fc2 = mx.symbol.Concat(*[fc21, fc22, fc23, fc24], dim = 0) 79 | label = mx.symbol.transpose(data = label) 80 | label = mx.symbol.Reshape(data = label, target_shape = (0, )) 81 | return mx.symbol.SoftmaxOutput(data = fc2, label = label, name = "softmax") 82 | ``` 83 | 84 | 上面这个网络要稍微解释一下。因为这个问题是一个有顺序的多label的图片分类问题。我们在fc1的层上面接了4个Full Connect层(fc21,fc22,fc23,fc24),用来对应不同位置的4个数字label。然后将它们Concat在一起。然后同时学习这4个label。目前用上面的网络训练,4位数字全部预测正确的精度可以达到95%左右(因为是无穷多的训练样本,所以只要能不断训练下去,精度还是可以提高的,只是我训练到95%左右就停止训练了)。 85 | 86 | 用CNN解决验证码识别有个问题,就是必须针对固定长度的验证码去做。如果长度不固定,或者是手写一行字的识别这种长度肯定不固定的问题,CNN就没办法了。这个时候就需要引入序列学习的模型了。 87 | 88 | ## 基于LSTM+CTC的验证码识别 89 | 90 | LSTM+CTC被广泛的用在语音识别领域把音频解码成汉字,从这个角度说,OCR其实就是把图片解码成汉字,并没有太本质的区别。而且在整个过程中,不需要提前知道究竟要解码成几个字。 91 | 92 | 这个算法的思路是这样的。假设要识别的图片是80x30的图片,里面是一个长度为k的数字验证码。那么我们可以沿着x轴对图片进行切分,切成n个图片,作为LSTM的n个输入。在最极端的例子里,n=80。那么就是把图片的每一列都作为输入。LSTM有n个输入就会有n个输出,而这n个输出可以通过CTC计算和k个验证码标签之间的Loss,然后进行反向传播。 93 | 94 | ![img](https://pic2.zhimg.com/66418cba4311abd02bcd2f4019093d81_b.png) 95 | 96 | 我们同样用python-captcha自动生成验证码作为训练样本,用如下的代码来定义网络结构: 97 | 98 | ```python 99 | 作者:项亮 100 | 链接:https://zhuanlan.zhihu.com/p/21344595 101 | 来源:知乎 102 | 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 103 | 104 | def lstm_unroll(num_lstm_layer, seq_len, 105 | num_hidden, num_label): 106 | param_cells = [] 107 | last_states = [] 108 | for i in range(num_lstm_layer): 109 | state = LSTMState(c=mx.sym.Variable("l%d_init_c" % i), 110 | h=mx.sym.Variable("l%d_init_h" % i)) 111 | last_states.append(state) 112 | assert(len(last_states) == num_lstm_layer) 113 | 114 | # embeding layer 115 | data = mx.sym.Variable('data') 116 | label = mx.sym.Variable('label') 117 | wordvec = mx.sym.SliceChannel(data=data, num_outputs=seq_len, squeeze_axis=1) 118 | 119 | hidden_all = [] 120 | for seqidx in range(seq_len): 121 | hidden = wordvec[seqidx] 122 | for i in range(num_lstm_layer): 123 | next_state = lstm(num_hidden, indata=hidden, 124 | prev_state=last_states[i], 125 | param=param_cells[i], 126 | seqidx=seqidx, layeridx=i) 127 | hidden = next_state.h 128 | last_states[i] = next_state 129 | hidden_all.append(hidden) 130 | 131 | hidden_concat = mx.sym.Concat(*hidden_all, dim=0) 132 | pred = mx.sym.FullyConnected(data=hidden_concat, num_hidden=11) 133 | 134 | label = mx.sym.Reshape(data=label, target_shape=(0,)) 135 | label = mx.sym.Cast(data = label, dtype = 'int32') 136 | sm = mx.sym.WarpCTC(data=pred, label=label, label_length = num_label, input_length = seq_len) 137 | return sm 138 | ``` 139 | 140 | 这里有2点需要注意的: 141 | 142 | 1. 在一般的mxnet的lstm实现中,label需要转置,但是在warpctc的实现中不需要。 143 | 2. label需要是int32的格式,需要cast。 144 | 145 | 关于CTC Loss的重要性,我试过不用CTC的两个不同想法: 146 | 147 | 1. 用encode-decode模式。用80个输入做encode,然后decode成4个输出。实测效果很差。 148 | 2. 4个label每个copy20遍,从而变成80个label。实测也很差。 149 | 150 | 用ctc loss的体会就是,如果input的长度远远大于label的长度,比如我这里是80和4的关系。那么一开始的收敛会比较慢。在其中有一段时间cost几乎不变。此刻一定要有耐心,最终一定会收敛的。在ocr识别的这个例子上最终可以收敛到95%的精度。 151 | 152 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Forrest-Zhu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ML/Deep Reinforcement Learning 基础知识(DQN方面).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # [Deep Reinforcement Learning 基础知识(DQN方面)](http://blog.csdn.net/songrotek/article/details/50580904) 4 | 5 | -------------------------------------------------------------------------------- /ML/MachineLearning.md: -------------------------------------------------------------------------------- 1 | # Machine Learning 2 | 3 | ## 机器学习 4 | 5 | 总算到了让我魂牵梦绕的机器学习了,我在寒假看完了龙兴计划,斯坦福的大牛的没有时间看了,毕竟我只是拿来用用而已,太深入的东西没个三年两载的是搞不出来的。深知自己能力有限,吃过的墨水还不是很多,不敢妄自菲薄。 6 | 7 | **Course** 8 | 9 | [UFLDL教程 - Ufldl](http://deeplearning.stanford.edu/wiki/index.php/UFLDL%E6%95%99%E7%A8%8B) 10 | 11 | [机器学习(Machine Learning)大家与资源 - loadstar_kun的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/loadstar_kun/article/details/41354739) 12 | 13 | [龙星计划_机器学习_课程视频_免费高速下载|百度云 网盘-分享无限制](http://pan.baidu.com/share/link?shareid=27613&uk=1513052211#path=%252F%25E9%25BE%2599%25E6%2598%259F%25E8%25AE%25A1%25E5%2588%2592_%25E6%259C%25BA%25E5%2599%25A8%25E5%25AD%25A6%25E4%25B9%25A0_%25E8%25AF%25BE%25E7%25A8%258B%25E8%25A7%2586%25E9%25A2%2591) 14 | 15 | [龙星计划2013_免费高速下载|百度云 网盘-分享无限制](http://pan.baidu.com/share/link?shareid=3220401770&uk=723014463) 16 | 17 | [加州理工学院公开课:机器学习与数据挖掘_全18集_网易公开课](http://v.163.com/special/opencourse/learningfromdata.html) 18 | 19 | [TUTORIAL ON DEEP LEARNING FOR VISION at CVPR 2014 | Big Data Digest](http://bigdata.memect.com/?p=11531) 20 | 21 | [斯坦福大学公开课 :机器学习课程_全20集_网易公开课](http://v.163.com/special/opencourse/machinelearning.html) 22 | 23 | [机器学习理论与实战 - 计算机视觉、机器学习朝拜者 - 博客频道 - CSDN.NET](http://blog.csdn.net/marvin521/article/details/9251205) 24 | 25 | [斯坦福大学Andrew Ng教授主讲的《机器学习》公开课观后感 - loadstar_kun的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/loadstar_kun/article/details/39494223) 26 | 27 | [PRML读书会系列 | 我爱计算机](http://www.52cs.org/?p=374) 28 | 29 | [机器学习基石笔记1——在何时可以使用机器学习(1) - 杜少 - 博客园](http://www.cnblogs.com/ymingjingr/p/4271742.html) 30 | 31 | **牛人** 32 | 33 | [Xin-Yu Ou(欧新宇)](http://ouxinyu.github.io/Blogs/20140723001.html) 34 | 35 | [Pang Wei Koh](http://cs.stanford.edu/%7Epangwei/projects.html) 36 | 37 | [GangWang](http://www3.ntu.edu.sg/home/wanggang/Publications.html) 38 | 39 | **朴素贝叶斯分类器** 40 | 41 | [朴素贝叶斯分类器的应用 - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html) 42 | 43 | [算法杂货铺——分类算法之朴素贝叶斯分类(Naive Bayesian classification) - T2噬菌体 - 博客园](http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html) 44 | 45 | [数学之美番外篇:平凡而又神奇的贝叶斯方法](http://mindhacks.cn/2008/09/21/the-magical-bayesian-method/) 46 | 47 | [集成树类模型及其在百度搜索推荐系统中的应用 | Dustinsea](http://semocean.com/%E9%9B%86%E6%88%90%E6%A0%91%E7%B1%BB%E6%A8%A1%E5%9E%8B%E5%8F%8A%E5%85%B6%E5%9C%A8%E6%90%9C%E7%B4%A2%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/) 48 | 49 | [传统算法](http://blog.sciencenet.cn/home.php?mod=space&uid=941987&do=blog&id=690984) 50 | 51 | **DeepLearning** 52 | 53 | [people.idsia.ch/~ciresan/](http://people.idsia.ch/%7Eciresan/) 54 | 55 | [ConvNetJS: Deep Learning in your browser](http://cs.stanford.edu/people/karpathy/convnetjs/) 56 | 57 | [Deep Learning - tornadomeet - 博客园](http://www.cnblogs.com/tornadomeet/category/497607.html) 58 | 59 | [深度学习( Deep Learning )软件资源列表 - CV数据机器识别研究 视觉计算研究论坛 -](http://www.sigvc.org/bbs/thread-557-1-1.html) 60 | 61 | [科学网—caffe for windows 安装 - 高常鑫的博文](http://blog.sciencenet.cn/blog-43092-812757.html) 62 | 63 | [能量模型(EBM)、限制波尔兹曼机(RBM) - carrierlxksuper的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/carrierlxksuper/article/details/38781029) 64 | 65 | [MatConvNet](http://www.vlfeat.org/matconvnet/) 66 | 67 | [deeplearning库Caffe在windows下的配置_机器学习讲座_新浪博客](http://blog.sina.com.cn/s/blog_eb3aea990102uybn.html) 68 | 69 | [Caffe](http://blog.csdn.net/pirage) 70 | 71 | [Caffe Windows版本的编译_phdxie_新浪博客](http://blog.sina.com.cn/s/blog_52f26d0f0102v6hm.html) 72 | 73 | [cuda-convnet1-梯度计算的并行代码分析](http://www.baidu.com/p/caochunshui?from=wenku) 74 | 75 | [LinJM/convnet-benchmarks · GitHub](https://github.com/LinJM/convnet-benchmarks) 76 | 77 | [Facebook AI Director Yann LeCun on His Quest to Unleash Deep Learning and Make Machines Smarter - IEEE Spectrum](http://spectrum.ieee.org/automaton/robotics/artificial-intelligence/facebook-ai-director-yann-lecun-on-deep-learning) 78 | 79 | [VS2010环境下编译cuda-convnet(Win7_64位) - chrispher](http://www.datakit.cn/blog/2014/11/25/VS2010_cuda-convnet%28Win7_64%29.html) 80 | 81 | [Deep Learning 学习随记](http://www.cnblogs.com/bzjia-blog/) 82 | 83 | [DeepLearning(深度学习)原理与实现(一) - 计算机视觉、机器学习朝拜者 - 博客频道 - CSDN.NET](http://blog.csdn.net/marvin521/article/details/8886971) 84 | 85 | [【面向代码】学习 Deep Learning(一)Neural Network - DarkScope从这里开始 - 博客频道 - CSDN.NET](http://blog.csdn.net/dark_scope/article/details/9421061) 86 | 87 | [关于深度学习(deep learning)_zerocv_新浪博客](http://blog.sina.com.cn/s/blog_70a384770101f58p.html) 88 | 89 | [从Clarifai的估值聊聊深度学习 - 机器视觉x模式识别 - 知乎专栏](http://zhuanlan.zhihu.com/cvprnet/19821292) 90 | 91 | **CNN** 92 | 93 | [“看懂”卷积神经网(Visualizing and Understanding Convolutional Networks) - 通往人工智能的崎岖之路 - 博客频道 - CSDN.NET](http://blog.csdn.net/kklots/article/details/17136059) 94 | 95 | [深度学习(卷积神经网络)一些问题总结 - nan355655600的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/nan355655600/article/details/17690029) 96 | 97 | [数据挖掘系列(10)——卷积神经网络算法的一个实现 - CodeMeals - 博客园](http://www.cnblogs.com/fengfenggirl/p/cnn_implement.html) 98 | 99 | [卷积神经网络(Convolutional Neural Network)学习资料 - lipse_huang的日志 - 网易博客](http://blog.163.com/lipse_huang/blog/static/19165754520133954138888/) 100 | 101 | [Caffe 深度学习框架上手教程 - OPEN 开发经验库](http://www.open-open.com/lib/view/open1421995285109.html) 102 | 103 | **SVM** 104 | 105 | [关于SVM | 在路上](http://zhangliliang.github.io/2014/08/25/about-svm/) 106 | 107 | [LIBSVM -- A Library for Support Vector Machines](http://www.csie.ntu.edu.tw/%7Ecjlin/libsvm/index.html) 108 | 109 | [OpenCV 2.4+ C++ SVM线性不可分处理 - Justany_WhiteSnow - 博客园](http://www.cnblogs.com/justany/archive/2012/11/26/2788509.html) 110 | 111 | [SVM-rank: Support Vector Machine for Ranking](http://www.cs.cornell.edu/people/tj/svm_light/svm_rank.html) 112 | 113 | [LibLinear(SVM包)使用说明之(一)README - zouxy09的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/zouxy09/article/details/10947323) 114 | 115 | [LibSVM 在matlab中的使用 - Rachel Zhang的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/abcjennifer/article/details/7370177) 116 | 117 | [LibSVM分类的实用指南_PHPer_Eric_新浪博客](http://blog.sina.com.cn/s/blog_6d4bfb040100uw45.html) 118 | 119 | [SVM神经网络理论理论分析_视频在线观看 - 56.com](http://www.56.com/u74/v_OTk1NTY2NjM.html) 120 | 121 | [【理论】支持向量机5:Numerical Optimization —— 简要介绍求解求解 SVM 的数值优化算法 - zhazhiqiang2010的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/zhazhiqiang/article/details/19495949) 122 | 123 | [SMO-MKL Code for Efficient Multiple Kernel Learning](http://research.microsoft.com/en-us/um/people/manik/code/smo-mkl/download.html) 124 | 125 | [我对VC维的理解 - kunlong0909的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/kunlong0909/article/details/14456713) 126 | 127 | **稀疏表达** 128 | 129 | [Sparse Representation_lycdx_新浪博客](http://blog.sina.com.cn/s/blog_6d0e97bb01015wol.html) 130 | 131 | [稀疏表示(sparse representation)和字典学习(一) - houge的日志 - 网易博客](http://blog.163.com/hougeamm@126/blog/static/8812804420124269257279/) 132 | 133 | [{Reship}{Sparse Representation}稀疏表示入门 - Lvpengms - 博客园](http://www.cnblogs.com/lvpengms/p/3473961.html) 134 | 135 | [Michael Elad - Personal Page](http://www.cs.technion.ac.il/%7Eelad/) 136 | 137 | **中文教程** 138 | 139 | [成功应用机器学习的七个步骤 - 计算机视觉、机器学习朝拜者 - 博客频道 - CSDN.NET](http://blog.csdn.net/marvin521/article/details/16119509) 140 | 141 | [C++的机器学习开源库_webbery508_新浪博客](http://blog.sina.com.cn/s/blog_569d6df801014x4x.html) 142 | 143 | [Stanford机器学习---第八讲. 支持向量机SVM - Rachel Zhang的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/abcjennifer/article/details/7849812) 144 | 145 | [18个最热深度学习Github项目逐一介绍 - 技术文摘 - LUPA开源社区](http://www.lupaworld.com/portal.php?mod=view&aid=241291&page=all) 146 | 147 | [机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理) - tornadomeet - 博客园](http://www.cnblogs.com/tornadomeet/p/3395593.html) 148 | 149 | [理解机器学习算法的一点心得 - DarkScope从这里开始 - 博客频道 - CSDN.NET](http://blog.csdn.net/dark_scope/article/details/25485893) 150 | 151 | [推荐几个机器学习算法及应用领域相关的中国大牛: - 信息科学 - 小木虫论坛 - 学术科研第一站](http://emuch.net/bbs/viewthread.php?tid=4842092&fpage=1) 152 | 153 | [机器学习之旅---奇异值分解 - 图像处理与模式识别 - 博客频道 - CSDN.NET](http://blog.csdn.net/jinshengtao/article/details/41387379) 154 | 155 | [机器学习 - 随笔分类 - ☆Ronny丶 - 博客园](http://www.cnblogs.com/ronny/category/366232.html) 156 | 157 | [从机器学习谈起 - 计算机的潜意识 - 博客园](http://www.cnblogs.com/subconscious/p/4107357.html) 158 | 159 | [Machine Learning - Stan1989的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/Stan1989/article/category/1336682) 160 | 161 | [机器学习刀光剑影 之 屠龙刀 | 我爱计算机](http://www.52cs.org/?p=383&utm_source=tuicool) 162 | 163 | [跨界的机器学习 | 谷子粒](http://1.guzili.sinaapp.com/?p=91) 164 | 165 | [supervised learning & semi-supervised learning & transfer learning & self-taught learning & deep learning | 谷子粒](http://1.guzili.sinaapp.com/?p=5) 166 | 167 | [也谈 机器学习到底有没有用 ? | 谷子粒](http://1.guzili.sinaapp.com/?p=234) 168 | 169 | [科学网—[转载\]机器学习的那些事](http://www.360doc.com/content/13/1020/18/7673502_322833764.shtml) 170 | 171 | [机器学习常见算法分类汇总 - 博客 - 伯乐在线](http://blog.jobbole.com/77620/) 172 | 173 | [机器学习有没有用? | 我爱计算机](http://www.52cs.org/?p=76) 174 | 175 | [机器学习系列 | Jason's Techblog](http://jasonding1354.github.io/2018/01/01/MLStick/) 176 | 177 | [【独家】IEEE深度对话Facebook人工智能负责人Yann LeCun:让深度学习摆脱束缚](http://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid=203710189&idx=1&sn=f6df1ac1e20788bfb7cabd89811d2e1e&scene=2&from=timeline&isappinstalled=0#rd) 178 | 179 | [漫谈:机器学习中距离和相似性度量方法 - daniel-D - 博客园](http://www.cnblogs.com/daniel-D/p/3244718.html) 180 | 181 | [机器学习中导数最优化方法(基础篇) - daniel-D - 博客园](http://www.cnblogs.com/daniel-D/p/3377840.html) 182 | 183 | **NN** 184 | 185 | [神经网络简史_浙江工业大学王万良_新浪博客](http://blog.sina.com.cn/s/blog_8a4651600102v32p.html) 186 | 187 | [反向传播BP算法 - CeleryChen 致力于语音图像视频算法在各种硬件体系结构下的最优化实现 - 博客频道 - CSDN.NET](http://blog.csdn.net/celerychen2009/article/details/8964753) 188 | 189 | [传统神经网络ANN训练算法总结 - Bluebelfast的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/bluebelfast/article/details/17139095) 190 | 191 | [传统神经网络ANN简介 - Bluebelfast的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/bluebelfast/article/details/17091803) 192 | 193 | [对比传统模式识别方法理解 Deep Learning - Bluebelfast的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/bluebelfast/article/details/17141265) 194 | 195 | [哺乳动物视觉皮层的深层结构研究 - kuaitoukid的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/kuaitoukid/article/details/41749371) 196 | 197 | [柜位预测(二)——神经网络-FANN库 - 风水月的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/fengshuiyue/article/details/41446257) 198 | 199 | **统计** 200 | 201 | [JinZhihui: LDA-math-MCMC 和 Gibbs Sampling | 统计之都 (中国统计学门户网站,免费统计学服务平台)](http://cos.name/2013/01/lda-math-mcmc-and-gibbs-sampling/) 202 | 203 | [机器学习中贝叶斯判决、概率分布、样本等概念间的关系 - viewcode的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/viewcode/article/details/8820272) 204 | 205 | [百度余凯:收集数据需要时间,跑在前面的永远跑在前面-看点-虎嗅网](http://www.huxiu.com/article/106486/1.html) 206 | 207 | [加大伯克利分校著名科学家:大数据的“冬天”即将到来](http://mp.weixin.qq.com/s?__biz=MjM5NzM5ODQ4Mg==&mid=202369542&idx=1&sn=9fef36f14033872fda5f0ed2fe1b6a24&scene=2&from=timeline&isappinstalled=0#rd) 208 | 209 | [对线性回归、逻辑回归、各种回归的概念学习 - viewcode的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/viewcode/article/details/8794401) 210 | 211 | [统计学习笔记(1)——统计学习方法概论 - Liam Q的专栏 - 博客频道 - CSDN.NET](http://blog.csdn.net/qll125596718/article/details/8351337) 212 | 213 | **trick** 214 | 215 | [OpenCV中Adaboost训练的经验总结 - 梦想腾飞 - 博客频道 - CSDN.NET](http://blog.csdn.net/xidianzhimeng/article/details/42147601) 216 | 217 | [论文笔记](http://zhangliliang.com/) 218 | 219 | [Boosting原理及其应用 - busyfruit - 博客园](http://www.cnblogs.com/lyfruit/articles/3011429.html) 220 | 221 | [PCA的应用示例 - New begin, new life - 博客频道 - CSDN.NET](http://blog.csdn.net/watkinsong/article/details/38539289) -------------------------------------------------------------------------------- /ML/OCR.md: -------------------------------------------------------------------------------- 1 | # 端到端的OCR:验证码识别 2 | 3 | 4 | 5 | OCR是一个古老的研究领域,简单说就是把图片上的文字转化为文本的过程。在最近几年随着大数据的发展,广大爬虫工程师在对抗验证码时也得用上OCR。所以,这篇文章主要说的OCR其实就是图片验证码的识别。我研究这个问题是因为OCR是一个可以同时用CNN,RNN两种算法都可以很好解决的问题,所以用这个问题来熟悉一个深度学习框架是非常适合的。我主要通过研究这个问题来了解[mxnet](https://link.zhihu.com/?target=https%3A//github.com/dmlc/mxnet)。验证码识别的思路非常暴力,大概就是这样:去噪+二值化字符分割每个字符识别 6 | 验证码的难度在这3步上都有反应。比如噪声:加一条贯穿全图的曲线,比如网格线,还有图的一半是白底黑字,另一半是黑底白字。 7 | 分割:字符粘连,7和4粘在一起。识别:字符各种扭曲,各种旋转。但相对而言,难度最大的是第2步,分割。所以就有人想,我能不能不做分割,就把验证码给识别了。深度学习擅长做端到端的学习,因此这个不分割就想识别的事情交给深度学习是最合适的。基于CNN的验证码识别基于CNN去识别验证码,其实就是一个图片的多标签学习问题。比如考虑一个4个数字组成的验证码,那么相当于每张图就有4个标签。那么我们把原始图片作为输入,4个标签作为输出,扔进CNN里,看看能不能收敛就行了。下面这段代码定义了mxnet上的一个DataIter,我们用了python-captcha这个库来自动生成训练样本,所以可以假设训练样本是无穷多的。 8 | 9 | ```python 10 | 11 | class OCRIter(mx.io.DataIter): 12 | def __init__(self, count, batch_size, num_label, height, width): 13 | super(OCRIter, self).__init__() 14 | self.captcha = ImageCaptcha(fonts=['./data/OpenSans-Regular.ttf']) 15 | self.batch_size = batch_size 16 | self.count = count 17 | self.height = height 18 | self.width = width 19 | self.provide_data = [('data', (batch_size, 3, height, width))] 20 | self.provide_label = [('softmax_label', (self.batch_size, num_label))] 21 | 22 | def __iter__(self): 23 | for k in range(self.count / self.batch_size): 24 | data = [] 25 | label = [] 26 | for i in range(self.batch_size): 27 | # 生成一个四位数字的随机字符串 28 | num = gen_rand() 29 | # 生成随机字符串对应的验证码图片 30 | img = self.captcha.generate(num) 31 | img = np.fromstring(img.getvalue(), dtype='uint8') 32 | img = cv2.imdecode(img, cv2.IMREAD_COLOR) 33 | img = cv2.resize(img, (self.width, self.height)) 34 | cv2.imwrite("./tmp" + str(i % 10) + ".png", img) 35 | img = np.multiply(img, 1/255.0) 36 | img = img.transpose(2, 0, 1) 37 | data.append(img) 38 | label.append(get_label(num)) 39 | 40 | data_all = [mx.nd.array(data)] 41 | label_all = [mx.nd.array(label)] 42 | data_names = ['data'] 43 | label_names = ['softmax_label'] 44 | 45 | data_batch = OCRBatch(data_names, data_all, label_names, label_all) 46 | yield data_batch 47 | 48 | def reset(self): 49 | pass 50 | ``` 51 | 52 | 53 | 54 | 下面这段代码是网络结构: 55 | 56 | ```python 57 | def get_ocrnet(): 58 | data = mx.symbol.Variable('data') 59 | label = mx.symbol.Variable('softmax_label') 60 | conv1 = mx.symbol.Convolution(data=data, kernel=(5,5), num_filter=32) 61 | pool1 = mx.symbol.Pooling(data=conv1, pool_type="max", kernel=(2,2), stride=(1, 1)) 62 | relu1 = mx.symbol.Activation(data=pool1, act_type="relu") 63 | 64 | conv2 = mx.symbol.Convolution(data=relu1, kernel=(5,5), num_filter=32) 65 | pool2 = mx.symbol.Pooling(data=conv2, pool_type="avg", kernel=(2,2), stride=(1, 1)) 66 | relu2 = mx.symbol.Activation(data=pool2, act_type="relu") 67 | 68 | conv3 = mx.symbol.Convolution(data=relu2, kernel=(3,3), num_filter=32) 69 | pool3 = mx.symbol.Pooling(data=conv3, pool_type="avg", kernel=(2,2), stride=(1, 1)) 70 | relu3 = mx.symbol.Activation(data=pool3, act_type="relu") 71 | 72 | flatten = mx.symbol.Flatten(data = relu3) 73 | fc1 = mx.symbol.FullyConnected(data = flatten, num_hidden = 512) 74 | fc21 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 75 | fc22 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 76 | fc23 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 77 | fc24 = mx.symbol.FullyConnected(data = fc1, num_hidden = 10) 78 | fc2 = mx.symbol.Concat(*[fc21, fc22, fc23, fc24], dim = 0) 79 | label = mx.symbol.transpose(data = label) 80 | label = mx.symbol.Reshape(data = label, target_shape = (0, )) 81 | return mx.symbol.SoftmaxOutput(data = fc2, label = label, name = "softmax") 82 | ``` 83 | 84 | 上面这个网络要稍微解释一下。因为这个问题是一个有顺序的多label的图片分类问题。我们在fc1的层上面接了4个Full Connect层(fc21,fc22,fc23,fc24),用来对应不同位置的4个数字label。然后将它们Concat在一起。然后同时学习这4个label。目前用上面的网络训练,4位数字全部预测正确的精度可以达到95%左右(因为是无穷多的训练样本,所以只要能不断训练下去,精度还是可以提高的,只是我训练到95%左右就停止训练了)。 85 | 86 | 用CNN解决验证码识别有个问题,就是必须针对固定长度的验证码去做。如果长度不固定,或者是手写一行字的识别这种长度肯定不固定的问题,CNN就没办法了。这个时候就需要引入序列学习的模型了。 87 | 88 | ## 基于LSTM+CTC的验证码识别 89 | 90 | LSTM+CTC被广泛的用在语音识别领域把音频解码成汉字,从这个角度说,OCR其实就是把图片解码成汉字,并没有太本质的区别。而且在整个过程中,不需要提前知道究竟要解码成几个字。 91 | 92 | 这个算法的思路是这样的。假设要识别的图片是80x30的图片,里面是一个长度为k的数字验证码。那么我们可以沿着x轴对图片进行切分,切成n个图片,作为LSTM的n个输入。在最极端的例子里,n=80。那么就是把图片的每一列都作为输入。LSTM有n个输入就会有n个输出,而这n个输出可以通过CTC计算和k个验证码标签之间的Loss,然后进行反向传播。 93 | 94 | ![img](https://pic2.zhimg.com/66418cba4311abd02bcd2f4019093d81_b.png) 95 | 96 | 我们同样用python-captcha自动生成验证码作为训练样本,用如下的代码来定义网络结构: 97 | 98 | ```python 99 | 100 | def lstm_unroll(num_lstm_layer, seq_len, 101 | num_hidden, num_label): 102 | param_cells = [] 103 | last_states = [] 104 | for i in range(num_lstm_layer): 105 | state = LSTMState(c=mx.sym.Variable("l%d_init_c" % i), 106 | h=mx.sym.Variable("l%d_init_h" % i)) 107 | last_states.append(state) 108 | assert(len(last_states) == num_lstm_layer) 109 | 110 | # embeding layer 111 | data = mx.sym.Variable('data') 112 | label = mx.sym.Variable('label') 113 | wordvec = mx.sym.SliceChannel(data=data, num_outputs=seq_len, squeeze_axis=1) 114 | 115 | hidden_all = [] 116 | for seqidx in range(seq_len): 117 | hidden = wordvec[seqidx] 118 | for i in range(num_lstm_layer): 119 | next_state = lstm(num_hidden, indata=hidden, 120 | prev_state=last_states[i], 121 | param=param_cells[i], 122 | seqidx=seqidx, layeridx=i) 123 | hidden = next_state.h 124 | last_states[i] = next_state 125 | hidden_all.append(hidden) 126 | 127 | hidden_concat = mx.sym.Concat(*hidden_all, dim=0) 128 | pred = mx.sym.FullyConnected(data=hidden_concat, num_hidden=11) 129 | 130 | label = mx.sym.Reshape(data=label, target_shape=(0,)) 131 | label = mx.sym.Cast(data = label, dtype = 'int32') 132 | sm = mx.sym.WarpCTC(data=pred, label=label, label_length = num_label, input_length = seq_len) 133 | return sm 134 | ``` 135 | 136 | 这里有2点需要注意的: 137 | 138 | 1. 在一般的mxnet的lstm实现中,label需要转置,但是在warpctc的实现中不需要。 139 | 2. label需要是int32的格式,需要cast。 140 | 141 | 关于CTC Loss的重要性,我试过不用CTC的两个不同想法: 142 | 143 | 1. 用encode-decode模式。用80个输入做encode,然后decode成4个输出。实测效果很差。 144 | 2. 4个label每个copy20遍,从而变成80个label。实测也很差。 145 | 146 | 用ctc loss的体会就是,如果input的长度远远大于label的长度,比如我这里是80和4的关系。那么一开始的收敛会比较慢。在其中有一段时间cost几乎不变。此刻一定要有耐心,最终一定会收敛的。在ocr识别的这个例子上最终可以收敛到95%的精度。 147 | 148 | -------------------------------------------------------------------------------- /ML/RGB图像在CNN中如何进行convolution.md: -------------------------------------------------------------------------------- 1 | #RGB图像在CNN中如何进行convolution? 2 | 3 | 4 | 5 | 比如一副RGB图像,通过某一convolution layer,该layer共有96个3x3 filter,那请问我是把RGB每个channel 都和这96个filter 分别卷积,然后把RGB三个channel的结果(共96 x 3个结果)三三相加得到96个结果吗? 6 | 7 | 其实应该是96个三维的3*3*3的filter和H*W*3的图像的三维卷积。每个卷积的结果是一个H*W的二维的feature map,如果不做padding则长宽各减2。把这96个二维的feature map拼起来,就得到了这个卷积层的输出。 8 | 一般文献里描述filter size(比如你这里的3*3)的大小的时候,用的都是二维的大小,但其实真正在网络里做卷积的filter是三维的,因为第三个维度一般都等于输入层的第三个维度,所以就省略了。并不是像你说的那样是二维的filter。顺带一说,正是由于这样的特性,再加上filter一般都是正方形,因此一个filter在给定其输入的情况下,可以完全由正方形的变长描述,而这一性质在程序实现的时候也十分有用,cudaconvnet第一版的说明文档里对此也有提及。 9 | 你所说的用一个3*3的filter对RGB三个通道分别卷积再相加,等效为一个3*3*3的filter的卷积,该filter每一个二维slice是相同的,而一般来说三个slice应该不同。 10 | -------------------------------------------------------------------------------- /ML/基于深度学习的物体检测.md: -------------------------------------------------------------------------------- 1 | ## 基于深度学习的物体检测 2 | 3 | 4 | 5 | 首先简单介绍一下传统物体检测的方法和基于深度学习的物体检测方法。 6 | 7 | 传统方法使用滑动窗口的框架,把一张图分解成几百万个不同位置不同尺度的子窗口,针对每一个窗口使用分类器判断是否包含目标物体。传统方法针对不同的类别的物体,一般会设计不同的特征和分类算法,比如人脸检测的经典算法是Harr特征+Adaboosting分类器;行人检测的经典算法是HOG(histogram of gradients) + Support Vector Machine;一般性物体的检测的话是HOG的特征加上DPM(deformable part model)的算法。 8 | 9 | > 基于深度学习的物体检测的经典算法是RCNN系列: RCNN,fast RCNN (Ross Girshick),faster RCNN (少卿、凯明、孙剑、Ross)。这三个工作的核心思想是分别是:使用更好的CNN模型判断候选区域的类别;复用预计算的sharing feature map加快模型训练和物体检测的速度;进一步使用sharing feature map大幅提高计算候选区域的速度。其实基于深度学习的物体检测也可以看成对海量滑动窗口分类,只是用全卷积的方式。 10 | 11 | RCNN系列算法还是将物体检测分为两个步骤。现在还有一些工作是端到端(end-to-end)的物体检测,比如说YOLO(You Only Look Once: Unified, Real-Time Object Detection)和SSD(SSD: Single Shot MultiBox Detector)这样的算法。这两个算法号称和faster RCNN精度相似但速度更快。物体检测正负样本极端非均衡,two-stage cascade可以更好的应对非均衡。端到端学习是否可以超越faster RCNN还需要更多研究实验。 12 | 13 | 深度学习可以做到传统方法无法企及的精度,这是关键中的关键,如果说这个优点是1的话,其它的优点都是1后面的0。深度学习革命爆发在2011~2012年,11年的时候在语音识别领域有重大突破,12年的时候在图像识别领域有重大突破。深度学习革命,使得计算机视觉在很多应用领域达到了实用水平,催生了工业界的大量应用。这也是为什么在11年前,机器视觉&人工智能的博士生都是找不到工作的,但是12年之后,尤其是现在,都变成了被众多公司高薪争夺的宝贝。 14 | 15 | 另外深度学习成为标配,还有其它的优点。 16 | 17 | > 第一,深度学习算法的通用性很强,刚才提到的检测,在传统算法里面,针对不同的物体需要定制化不同的算法。相比来看,基于深度学习的算法更加通用,比如faster RCNN在人脸、行人、一般物体检测任务上都可以取得非常好的效果。 18 | > 19 | > 20 | > 21 | > 第二,深度学习获得的特征(feature)有很强的迁移能力。所谓特征迁移能力,指的是在A任务上学习到一些特征,在B任务上使用也可以获得非常好的效果。例如在ImageNet(物体为主)上学习到的特征在场景分类任务上也能取得非常好的效果。 22 | > 23 | > 24 | > 25 | > 第三, 工程开发、优化、维护成本低。深度学习计算主要是卷积和矩阵乘,针对这种计算优化,所有深度学习算法都可以提升性能。另外,通过组合现有的层(layer),我们可以实现大量复杂网络结构和一些算法,开发维护的成本低。想想同时开发、维护Boosting,Random Forest等算法是非常痛苦的一件事情。 26 | 27 | 28 | 29 | 简单来说,机器学习就是学习输入到输出的一个映射,传统方法使用浅层的简单映射,现在深度学习是多层的复合映射。深度学习有很多的自由度,学习目标和学习方法有很多种选择,网络结构层与层之间有无数的可能连接方式,每一层映射的具体形式到底是卷积,还是全连接,还是其它的形式,并没有限制,其实除了全连接和卷积之外,还可以用其它的映射形式,比如说去年ICCV上的一个工作:微软研究院用Random Forest做为新的映射形式。 30 | 31 | 深度学习的技术框架是一棵树形结构。 32 | 33 | 训练平台是树根,如caffe、tensorflow等。现在深度学习还处于实验科学阶段,实验效率很大程度上决定着研发效率,好的训练平台可以把实验周期从一个月缩短到一天,对于深度学习研发非常重要。 34 | 35 | 模型是树干。自06年提出深度学习概念,学术界花了六年时间才认识到模型结构的研究才是深度学习的重点。典型的成果有AlexNet、VGGNet、GoogleNet、ResNet等。学术界大家主要研究怎么把模型做的精度更好。在工业界我们还要考虑怎么把模型做得更快,更小。 36 | 37 | 在树干上有几个主干的枝丫,对应着计算机视觉里的核心任务,包括了检测、识别、分割、特征点定位、序列学习等五个大的任务,任何计算机视觉的具体的应用都可以由这五个任务组合而成。以人脸识别为例,人脸识别要完成整个流程,要涉及到人脸的检测、特征点定位,特征的提取&验证。这就包含了检测、特征点定位和识别三个部分。 38 | 39 | 我们在刚才提到的那五个重要的主干方向其实都投入了非常大的研究力量,一方面是保证我们在学术界的前沿有所突破,另一方面,针对我们一些重要应用也开发出了一整套与学术界并行的方法,能够做到十倍的加速和百倍模型的压缩,同时保持很好的精度。这个问题中提到的四篇论文主要是我们在这五个计算机视觉的核心任务上取得的一些研究方向的成果。其实我们除了在研究方向成果之外在工业实用方面有更大、更多的成果,比如我们的人脸检测在做到学术界最好结果的同时能做到300FPS的速度。人脸特征点的定位超过学术界最好结果的同时,做到3000FPS的速度。在学术界公开的论文中,我还没有看到这样的性能。 40 | 41 | 在深度学习领域有一个简单但又非常通用的原理。在学习时,指导信息越丰富、越精细,学习的效果一般来说也会越好。 42 | 举个简单的例子,在数据量充足的情况下,如果我对我图像类别的标注仅仅是动物、植物、场景的话,学习出来的模型和特征可能一般。但是如果把这些类别标记细化,比如最开始有十类数据,我们把它细化到一千类,例如把狗分成斑点狗、斗牛犬等,把猫分成波斯猫、大花猫等,通常来说可以学习到更好的模型和更加好的特征。 43 | 另一个例子是物体检测,如果在bounding box的基础上增加额外的监督信息通长会得到更好的结果。比如标注出人脸的眼睛、鼻子、嘴的位置,人脸的角度,种族性别男女等属性,做成一个多任务学习的算法的话,通常来说能得到更好的效果。 44 | 45 | 两个代表性工作可以参考:Joint cascade face detection and alignment,Facial landmark detection by deep multi-task learning。 46 | 有时候多个标注/任务是并列关系,可以通过Multi-Task Learning的框架来学习。另外一些情况,多个任务是递进关系,前一个任务的结果可以帮助后一个任务,例如将每一个人都独立的检测出来之后再分割每个人身体的Mask。合理利用这种递进关系,可以得到比并列关系更好的结果,这其实就是Instance segmentation的核心思想。因为同传统语义分割不同的是,传统语义分割只需要对物体类别进行分类,不需要区分不同的个体。物体分割(Instance segmentation)是既需要区分类别,又需要区分同一物体的个体,所以深度学习的网络需要学习到比之前语义分割任务更多的信息。这方面微软亚洲研究院的戴继峰做了非常开创性的工作。我们商汤科技石建萍高级研究员的工作也非常有创建性。通过多尺度局部区域融合的方法,端到端的实现了instance segmentation 物体类别与区分统一类别不同个体的信息。 -------------------------------------------------------------------------------- /ML/深度学习框架自动求导.md: -------------------------------------------------------------------------------- 1 | # 深度学习框架自动求导 2 | 3 | 推荐一个更好用的自动求导工具。[autograd](https://link.zhihu.com/?target=https%3A//github.com/HIPS/autograd) 4 | 5 | Just run pip install autograd 6 | 7 | 缺陷是,你需要特别注意,这个自动求导的功能指的是对函数第一个参数求导。 所以,所有需要求导的都得以第一个参数传进去 8 | 9 | 比如这个[A Step by Step Backpropagation Example](https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/), 可以写成 10 | 11 | ```python 12 | import autograd.numpy as np 13 | from autograd import grad 14 | 15 | def sigmoid(x): 16 | return 1.0/(np.exp(-x) + 1) 17 | 18 | def predict(params,input): 19 | (W1,B1),(W2,B2) = params 20 | hidden = sigmoid(np.dot(W1,input) + B1) 21 | output = sigmoid(np.dot(W2,hidden) + B2) 22 | return output 23 | 24 | def loss(params,input,target): 25 | return (0.5*(target-predict(params,input))**2).sum() 26 | 27 | loss_grad = grad(loss) 28 | 29 | def train(params, input, target): 30 | grad = loss_grad(params,input,target) 31 | return [(W-0.5*dW,B-0.5*dB) for ((dW,dB),(W,B)) in zip(grad,params)] 32 | 33 | W1 = np.array( 34 | [ [0.15,0.20], 35 | [0.25,0.30]]) 36 | 37 | B1 = 0.35 38 | 39 | W2 = np.array( 40 | [ [0.40,0.45], 41 | [0.50,0.55]]) 42 | 43 | B2 = 0.60 44 | 45 | PARAMS = [(W1,B1),(W2,B2)] 46 | INPUT = np.array([0.05,0.10]) 47 | TARGET = np.array([0.01,0.99]) 48 | 49 | while True: 50 | PARAMS = train(PARAMS,INPUT,TARGET) 51 | ``` 52 | 53 | 这可比一堆数学公式容易理解多了。 54 | 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blog 2 | My Blog using MarkDown 3 | 4 | There some topics: 5 | 6 | [**Code**](https://github.com/ForrestPi/Blog/tree/master/Code) 7 | 8 | There are some programming languages about C++ ,Java and so on 9 | 10 | [**ComputerVision**](https://github.com/ForrestPi/Blog/tree/master/ComputerVision) 11 | 12 | There are some methods and algorithoms about ComputerVision 13 | 14 | [**ML**](https://github.com/ForrestPi/Blog/tree/master/ML) 15 | 16 | There are some blogs about ML and DL -------------------------------------------------------------------------------- /RGB图像在CNN中如何进行convolution.md: -------------------------------------------------------------------------------- 1 | #RGB图像在CNN中如何进行convolution? 2 | 3 | 4 | 5 | 比如一副RGB图像,通过某一convolution layer,该layer共有96个3x3 filter,那请问我是把RGB每个channel 都和这96个filter 分别卷积,然后把RGB三个channel的结果(共96 x 3个结果)三三相加得到96个结果吗? 6 | 7 | 其实应该是96个三维的3*3*3的filter和H*W*3的图像的三维卷积。每个卷积的结果是一个H*W的二维的feature map,如果不做padding则长宽各减2。把这96个二维的feature map拼起来,就得到了这个卷积层的输出。 8 | 一般文献里描述filter size(比如你这里的3*3)的大小的时候,用的都是二维的大小,但其实真正在网络里做卷积的filter是三维的,因为第三个维度一般都等于输入层的第三个维度,所以就省略了。并不是像你说的那样是二维的filter。顺带一说,正是由于这样的特性,再加上filter一般都是正方形,因此一个filter在给定其输入的情况下,可以完全由正方形的变长描述,而这一性质在程序实现的时候也十分有用,cudaconvnet第一版的说明文档里对此也有提及。 9 | 你所说的用一个3*3的filter对RGB三个通道分别卷积再相加,等效为一个3*3*3的filter的卷积,该filter每一个二维slice是相同的,而一般来说三个slice应该不同。 10 | -------------------------------------------------------------------------------- /作品/一种高通量基因测序碱基荧光图像捕获系统装置及方法专利授权证书.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/作品/一种高通量基因测序碱基荧光图像捕获系统装置及方法专利授权证书.jpg -------------------------------------------------------------------------------- /作品/三位重构项目.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/作品/三位重构项目.pdf -------------------------------------------------------------------------------- /作品/中兴人工智能比赛-人脸认证.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/作品/中兴人工智能比赛-人脸认证.pdf -------------------------------------------------------------------------------- /作品/书——机器视觉组态软件Xavis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/作品/书——机器视觉组态软件Xavis.pdf -------------------------------------------------------------------------------- /作品/双目视觉动态目标测距技术研究与系统实现_终极打印版.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/作品/双目视觉动态目标测距技术研究与系统实现_终极打印版.doc -------------------------------------------------------------------------------- /作品/工业4.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForrestPi/Blog/12651436a835fe2e5f16047f0f7e3bf6e222db8f/作品/工业4.0.png --------------------------------------------------------------------------------