作者归档:yanjingang

小猪学Paddle—CNN图像识别之车牌识别

前天尝试了下cnn识别手写数字,今天开始试下车牌识别。车牌识别场景与手写数字识别非常相似,只是多了各省的简称和大写字母。那现在就开始吧!

车牌照片采集

抓取

从百度图片抓取100张车牌相关的图片

抓取图片代码:

vim download_image.py 
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 从百度图片下载车牌照片,用于训练素材
import re
import uuid
import requests
import os


class DownloadImages:
    def __init__(self, download_max, key_word):
        self.download_sum = 0
        self.download_max = download_max
        self.key_word = key_word
阅读全文

如何从汽车照片中扣出车牌?

为了做车牌识别训练,先单独研究下怎么从照片里扣出车牌区域。

大概思路:转化成灰度图、使用高斯平滑、中值滤波、Sobel边缘化检测、膨胀轮廓、腐蚀细节、轮廓筛选、保存轮廓区域原图。

代码如下:

vim cut_platenumber.py 
#!/usr/bin/env python
# coding=utf-8
# 从下载的图片里扣出车牌区域
# sh clear.sh && python cut_platenumber.py >log/cut_platenumber.log
import uuid
import os
import copy
import cv2
import numpy as np
import random

class CutPlateNumber:
    """从下载的图片里扣出车牌区域"""

    def
阅读全文

如何用python解析mnist图片

MNIST 数据集是一个手写数字识别训练数据集,来自美国国家标准与技术研究所National Institute of Standards and Technology (NIST)。训练集 (training set) 由来自 250 个不同人手写的数字构成,其中 50% 是高中学生,50% 来自人口普查局 (the Census Bureau) 的工作人员。测试集(test set) 也是同样比例的手写数字数据。

MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取, 它包含了四个部分:

  • Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解压后 47 MB, 包含 60,000 个样本)
  • Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解压后 60 KB, 包含 60,000 个标签)
  • Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解压后 7.8 MB, 包含 10,000 个样本)
  • Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解压后 10 KB, 包含 10,000 个标签)

因数据集是按特殊格式压缩存储的,所以如果在训练或应用模型时想看一下原图就会比较困难,本文讲解如果反向解析这个数据集。

mnist image图片集结构

可以看出在train-images.idx3-ubyte中,第一个数为32位的整数(魔数,图片类型的数),第二个数为32位的整数(图片的个数),第三和第四个也是32为的整数(分别代表图片的行数和列数),接下来的都是一个字节的无符号数(即像素,值域为0~255),因此,我们只需要依次获取魔数和图片的个数,然后获取图片的长和宽,最后逐个像素读取就可以了。

如何使用python解析数据呢? 首先需要安装python的图形处理库PIL,这个库支持像素级别的图像处理,对于学习数字图像处理有很大的帮助。安装完成之后,就可以进行图像的解析了。

sudo pip install Pillow   #PIL python image library

首先打开文件,然后分别读取魔数,图片个数,以及行数和列数,在struct中,可以看到,使用了’>IIII’,这是什么意思呢?意思就是使用大端规则,读取四个整形数(Integer),如果要读取一个字节,则可以用’>B’(当然,这里用没用大端规则都是一样的,因此只有两个或两个以上的字节才有用)。

什么是大端规则呢?不懂的可以百度一下,这个不再赘述(http://baike.baidu.com/link?url=Bgg8b0vRr3b_SeGyOl8U4DmAbIQT9swGuNtD_21ctEI_NliqsQ-mKF73YT90EILF2EQy50mEua_M4z6Cma3rmK)

然后对于每张图片,先创建一张空白的图片,其中的’L’代表这张图片是灰度图,最后逐个像素读取,然后写进空白图片里,最后保存图片,就可以了

mnist label标签集结构

可以发现,与上面的非常相似,只不过这里每一个字节变成了标签而已(标签大小为0~9)

读取图片和标签数据

根据上述结构的分析,我们可以通过python将mnist的图片和对应label解析出来:

程序源代码如下:

vim read_mnist.py 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 读取mnist数据集的图片和label,并生成以序号+label命名的图片
import os
import platform
import numpy
import subprocess
from PIL import Image

#mnist训练集目录
mnist_path = '/home/work/paddle/sample/recognize_digits/train/data/mnist/'
train_image
阅读全文

小猪学Paddle—CNN图像识别之手写数字

前段时间忙了好一阵,终于有时间继续学习了,今天开始通过paddlepaddle的手写数字识别看一下简单的cnn图像识别模型是怎么训练出来的。

概述

手写识别属于典型的图像分类问题,比较简单,示例使用MNIST数据集,它包含7w个如下图所示的手写数字图片和对应的人工标注数值。图片是28×28的像素矩阵,标签则对应着0~9的10个数字。每张图片都经过了大小归一化和居中处理。

MNIST图片示例

MNIST数据集格式说明

标签集前8个字节是magic和数目,后面每个字节代表数字0-9的标签;

图像集前16字节是一些数据集信息,包括magic、图像数目、行数和列数,后面每个字节代表每个像素点,连续取出28*28个字节按顺序就可以组成28*28的图片。

模型介绍

定义:

X是输入:MNIST图片是28×28 的二维图像,为了进行计算,我们将其转化为784维向量,即X=(x0,x1,…,x783)。
Y是输出:分类器的输出是10类数字(0-9),即Y=(y0,y1,…,y9),每一维yi代表图片分类为第i类数字的概率。
L是图片的真实标签:L=(l0,l1,…,l9)也是10维,但只有一维为1,其他都为0。

最简单的Softmax回归模型是先将输入层经过一个全连接层得到的特征,然后直接通过softmax 函数进行多分类[9]。

输入层的数据X传到输出层,在激活操作之前,会乘以相应的权重 W ,并加上偏置变量 b 。

对于有 N个类别的多分类问题,指定 N 个输出节点,N 维结果向量经过softmax将归一化为 N 个[0,1]范围内的实数值,分别表示该样本属于这 N 个类别的概率。此处的 yi 即对应该图片为数字 的预测概率。

详细介绍请参考维基百科激活函数

下图为softmax回归的网络图,图中权重用蓝线表示、偏置用红线表示、+1代表偏置参数的系数为1。

softmax回归网络结构图

Softmax回归模型采用了最简单的两层神经网络,即只有输入层和输出层,因此其拟合能力有限。为了达到更好的识别效果,我们考虑在输入层和输出层中间加上若干个隐藏层[10]。

经过第一个隐藏层,可以得到 H1=ϕ(W1X+b1),其中ϕ代表激活函数,常见的有sigmoid、tanh或ReLU等函数。

经过第二个隐藏层,可以得到 H2=ϕ(W2H1+b2)

最后,再经过输出层,得到的Y=softmax(W3H2+b3),即为最后的分类结果向量。

下图为多层感知器的网络结构图,图中权重用蓝线表示、偏置用红线表示、+1代表偏置参数的系数为1。

多层感知器网络结构图

在多层感知器模型中,将图像展开成一维向量输入到网络中,忽略了图像的位置和结构信息,而卷积神经网络能够更好的利用图像的结构信息。LeNet-5是一个较简单的卷积神经网络。图4显示了其结构:输入的二维图像,先经过两次卷积层到池化层,再经过全连接层,最后使用softmax分类作为输出层。下面我们主要介绍卷积层和池化层。

LeNet-5卷积神经网络结构

卷积层

卷积层是卷积神经网络的核心基石。在图像识别里我们提到的卷积是二维卷积,即离散二维滤波器(也称作卷积核)与二维图像做卷积操作,简单的讲是二维滤波器滑动到二维图像上所有位置,并在每个位置上与该像素点及其领域像素点做内积。卷积操作被广泛应用与图像处理领域,不同卷积核可以提取不同的特征,例如边沿、线性、角等特征。在深层卷积神经网络中,通过卷积操作可以提取出图像低级到复杂的特征。

卷积层

卷积过程动画

上图是一个卷积计算过程的示例图,输入图像大小为H=5,W=5,D=3,即5×5大小的3通道(RGB,也称作深度)彩色图像。这个示例图中包含两(用K表示)组卷积核,即图中滤波器W0和W1。在卷积计算中,通常对不同的输入通道采用不同的卷积核,如图示例中每组卷积核包含(D=3)个3×3(用F×F表示)大小的卷积核。另外,这个示例中卷积核在图像的水平方向(W方向)和垂直方向(H方向)的滑动步长为2(用S表示);对输入图像周围各填充1(用P表示)个0,即图中输入层原始数据为蓝色部分,灰色部分是进行了大小为1的扩展,用0来进行扩展。经过卷积操作得到输出为3×3×2(用Ho×Wo×K表示)大小的特征图,即3×3大小的2通道特征图,其中Ho计算公式为:Ho=(H−F+2×P)/S+1,Wo同理。 而输出特征图中的每个像素,是每组滤波器与输入图像每个特征图的内积再求和,再加上偏置bo,偏置通常对于每个输出特征图是共享的。输出特征图o[:,:,0]中的最后一个−2计算如上图右下角公式所示。

在卷积操作中卷积核是可学习的参数,经过上面示例介绍,每层卷积的参数大小为D×F×F×K。在多层感知器模型中,神经元通常是全部连接,参数较多。而卷积层的参数较少,这也是由卷积层的主要特性即局部连接和共享权重所决定。

局部连接:每个神经元仅与输入神经元的一块区域连接,这块局部区域称作感受野(receptive field)。在图像卷积操作中,即神经元在空间维度(spatial dimension,即上图示例H和W所在的平面)是局部连接,但在深度上是全部连接。对于二维图像本身而言,也是局部像素关联较强。这种局部连接保证了学习后的过滤器能够对于局部的输入特征有最强的响应。局部连接的思想,也是受启发于生物学里面的视觉系统结构,视觉皮层的神经元就是局部接受信息的。

权重共享:计算同一个深度切片的神经元时采用的滤波器是共享的。例如图4中计算o[:,:,0]的每个每个神经元的滤波器均相同,都为W0,这样可以很大程度上减少参数。共享权重在一定程度上讲是有意义的,例如图片的底层边缘特征与特征在图中的具体位置无关。但是在一些场景中是无意的,比如输入的图片是人脸,眼睛和头发位于不同的位置,希望在不同的位置学到不同的特征 (参考斯坦福大学公开课)。请注意权重只是对于同一深度切片的神经元是共享的,在卷积层,通常采用多组卷积核提取不同特征,即对应不同深度切片的特征,不同深度切片的神经元权重是不共享。另外,偏重对同一深度切片的所有神经元都是共享的。

通过介绍卷积计算过程及其特性,可以看出卷积是线性操作,并具有平移不变性(shift-invariant),平移不变性即在图像每个位置执行相同的操作。卷积层的局部连接和权重共享使得需要学习的参数大大减小,这样也有利于训练较大卷积神经网络。

池化层

池化层

池化是非线性下采样的一种形式,主要作用是通过减少网络的参数来减小计算量,并且能够在一定程度上控制过拟合。通常在卷积层的后面会加上一个池化层。池化包括最大池化、平均池化等。其中最大池化是用不重叠的矩形框将输入层分成不同的区域,对于每个矩形框的数取最大值作为输出层,如上图所示。

更详细的关于卷积神经网络的具体知识可以参考斯坦福大学公开课图像分类教程。

训练

注:本次学习代码使用Fluid API,一种接近Pytorch和Tensorflow的开发习惯。使用前需要先升级自己的paddlepaddle。

下边是训练过程的代码和自己的理解,有错误欢迎指正:

vim train/train_fluid.py 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
import platform
import subprocess
from PIL import Image
import numpy
import paddle
import paddle.fluid as fluid
try:
    from paddle.fluid.contrib.trainer import *
    from paddle.fluid.contrib.inferencer import *
except ImportError:
阅读全文

LSM VS B-Tree

存储引擎类型 功能 应用
hash 增删改、随机读、顺序扫描 Key-Value存储系统
B-Tree 增删改、随机读、顺序扫描 关系型数据库
LSM 增删改、随机读、顺序扫描 分布式存储系统,如cassandra、google LevelDB

B-Tree
缓存管理

缓存管理的核心在于置换算法,置换算法常见的有FIFO(First In First Out),LRU(Least Recently Used)。关系型数据库在LRU的基础上,进行了改进,主要使用LIRS(Low 阅读全文

如何搭建一个ssdb高可用集群

概述

ssdb是一个大规模持久化kv存储,类似redis,只是存储介质增加了ssd+sata,适合写入redis数据和qps规模较大,数据读取占比较小,想降低redis内存服务器购买成本,同时使读写性能上损失小些。有朋友公司使用了1T+的ssdb,想实现高可用方案,一直比较忙… 这两天终于有空研究了一下,给一个简单的多主水平分片+主从热备+读写分离代理解决方案

SSDB

SSDB 是一个 C/C++ 语言开发的高性能 NoSQL 数据库, 支持 KV, list, map(hash), zset(sorted set) 等数据结构, 用来替代或者与 Redis 配合存储十亿级别列表的数据。

特点:

1.底层的LevelDB使用LSM存储引擎,相比与关系数据库的B-Tree,写性能更好,而牺牲了部分的读性能。适合写多读少的场景,或读热key相对集中,缓存命中率较高的场景。

2.LSM树整个结构不是有序的,所以不知道数据在什么地方,需要从每个小的有序结构中做二分查询,找到了就返回,找不到就继续找下一个有序结构。在缓存命中率较低时,磁盘读取性能较差。故单个分片容量不宜过大,否则磁盘读性能不可接受

github:https://github.com/ideawu/ssdb

SSDB中文手册:http://ssdb.io/zh_cn/

SSDB入门基础:https://github.com/ideawu/ssdb-docs/blob/master/pdf/SSDB%E5%85%A5%E9%97%A8%E5%9F%BA%E7%A1%80.pdf

TwemProxy

twemproxy是搭建分布式集群的重要组件之一,它的分片功能,可以轻松地对redis/mecache集群进行水平扩展。同时对于代码稍加改造,我们就可以得到能读写分离的redis集群,这大大将提高了redis集群的性能。而ssdb兼容redis协议,故它也能用在为ssdb做水平分片。

一个简单的twemproxy+ssdb架构方案:

LVS用于解决大负载时twemproxy可能成为性能瓶颈的问题,各twemproxy配置一摸一样,和任意算法负载。LVS可以用HAproxy代替。

Twemproxy配置ssdb多主hash水平分片,并配置读写分离代理。

SSDB配置1主多从,实现热备和读写分离。

github:https://github.com/twitter/twemproxy/

twemproxy架构分析:https://www.cnblogs.com/onlyac/p/6262096.html

安装

安装SSDB单实例

#安装依赖
su root
yum install autoconf automake gcc+ gcc-c++ libtool jemalloc snappy snappy-devel -y
autoconf -V

#编译安装ssdb
mkdir /home/work/ssdb/
wget --no-check-certificate https://github.com/ideawu/ssdb/archive/master.zip -O ssdb-master.zip
unzip ssdb-master.zip
cd ssdb-master
make 
make install PREFIX=/home/work/ssdb
cp ./tools/ssdb.sh
阅读全文

三大主流软件负载均衡器对比(LVS vs Nginx vs Haproxy)

LVS:
1、抗负载能力强。抗负载能力强、性能高,能达到F5硬件的60%;对内存和cpu资源消耗比较低
2、工作在网络4层,通过vrrp协议转发(仅作分发之用),具体的流量由linux内核处理,因此没有流量的产生。
2、稳定性、可靠性好,自身有完美的热备方案;(如:LVS+Keepalived)
阅读全文

工程师如何高效学习

背景

最近群里内经常有工程师(尤其是工作经验浅的)会问我同一个问题:如何快速高效学习?大家似乎都很焦虑,渴望通过高效学习来提升自己,快速成长。

基于自己的实践和思考,我总结了这篇文章,希望对大家有所启发。

原则

阅读全文

成长之路—团队力量与个人成长

一、在一个人的成功中,个人奋斗和团队的重要性和关系是怎么摆的?

我们每个人在学生时代学了很多年,其实个人能力已经有了很强的积累。但是应该说到工作以后,你才真正体会到团队的作用到底有多大。

学生时代只要你自己努力,然后把考试成绩考的很高,你就是一个好学生。但是做一个人类进化历史的对比, 阅读全文

nginx配置https

最近做点小程序,服务端api必须是https域名,配置方法如下:

创建ssh证书

自己生成CA证书:(自己生成的根证书浏览器不认,会提示不安全,但https可访问)
cd /home/openssl
openssl genrsa -des3 -passout pass:123456 -out test.pem 2048  #生成RSA私钥
openssl rsa -passin pass:123456 -in test.pem -out test.key  #提取密钥中的公钥
openssl req -new -key test.key
阅读全文

成长之路—抓大放小

“干工作要注意抓大放小,太过于陷入细节难成大事。”

“干工作要注重抓小防大,不注意细节,问题累加最终酿成大祸。”

上面的说法似乎都有道理,都是职场老手、职场精英的经验总结,有些甚至都有血的教训。但听了这些话后,似乎更加不知道该怎么干了。

阅读全文

深入理解PHP7内核之zval

PHP7已经发布, 如承诺, 我也要开始这个系列的文章的编写, 主要想通过文章让大家理解到PHP7的巨大性能提升背后到底我们做了什么, 今天我想先和大家聊聊zval的变化. 在讲zval变化的之前我们先来看看zval在PHP5下面是什么样子

zval回顾

在PHP5的时候, zval的定义如下:

  1. struct _zval_struct {
  2.      union {
  3.           long lval;
  4.           double dval;
  5.           struct {
  6.                char *val;
  7.                int len;
  8.           } str;
  9.           HashTable *ht;
  10.           zend_object_value obj;
  11.           zend_ast *ast;
  12.      } value;
  13.      zend_uint refcount__gc;
  14.      zend_uchar type;
  15.      zend_uchar is_ref__gc;
  16. };

对PHP5内核有了解的同学应该对这个结构比较熟悉, 因为zval可以表示一切PHP中的数据类型, 阅读全文

大数据分析新秀Pulsar vs Kafka

一年一度由世界知名科技媒体 InfoWorld 评选的 Bossie Awards 于 9 月 26 日公布,本次 Bossie Awards 评选出了最佳数据库与数据分析平台奖、最佳软件开发工具奖、最佳机器学习项目奖等多个奖项。在 最佳开源数据库与数据分析平台奖 中,之前曾连续两年入选的 Kafka 意外滑铁卢落选,取而代之的是新兴项目 Pulsar。Bossie Awards 中对 Pulsar 点评如下:“Pulsar 旨在取代 Apache Kafka 多年的主宰地位。Pulsar 在很多情况下提供了比 Kafka 更快的吞吐量和更低的延迟,并为开发人员提供了一组兼容的 API,让他们可以很轻松地从 Kafka 切换到 Pulsar。Pulsar 的最大优点在于它提供了比 Apache Kafka 更简单明了、更健壮的一系列操作功能,特别在解决可观察性、地域复制和多租户方面的问题。在运行大型 Kafka 集群方面感觉有困难的企业可以考虑转向使用 Pulsar。”

AI 前线近一年发布了不少 Pulsar 的技术文章,我们经常被问到一个问题:Apache Pulsar 和 Apache Kafka 到底有什么不同?今天,万众期待的对比文终于来了! 本文将详述 Pulsar 和 Kafka 消息模型之间的区别,以及 Pulsar 与 Kafka 在系统架构设计方面的差异。

在用户选择一个消息系统时,消息模型是用户首先考虑的事情。消息模型应涵盖以下 阅读全文

安全加密算法选择指南

用途 推荐使用的安全的密码算法 常见的不安全的密码算法
对称加密 AES(密钥长度>=128bits) DES、3DES、RC2、RC4
哈希算法 SHA256或以上 MD5、SHA1
非对称加密 RSA(密钥长度>=2048bits) RSA(密钥长度<=1024bits)
数字签名 RSA(密钥长度>=2048bits) RSA(密钥长度<=1024bits)
密钥交换 DH(密钥长度>=2048bits) DH(密钥长度<=1024bits)

备注:

1. AES不建议使用ECB(同样的明文总是会产生相同的密文),推荐使用CBC模式。

2. 应注意编码及加密的区别,例如base64属于编码而不属于加密。

3. 加解密中建议使用安全随机数,如java.security.SecureRandom,类Unix系统 (包括OS X):  /dev/random;不安全随机数如C标准函数random(),java.util.Random()。

阅读全文