转自https://www.cnblogs.com/luxiao/p/5534393.html
1数据预处理之数据增强方法:
对于CNN输入的数据,常见的有三种处理方式:
1.Mean subtraction. 将数据的每一维特征都减去平均值。在numpy 中 X -= np.mean(X, axis = 0)
2.Normalization 归一化数据,使数据在相同尺度。 在numpy 中 X /= np.std(X, axis = 0)
3. PCA and Whitening. 首先均值化数据,然后求协方差矩阵。
X -= np.mean(X, axis = 0) //求均值
cov = np.dot( X.T, X) / X.shape[0] // 求协方差矩阵
U,S,V = np.linalg.svd(cov) //奇异值分解,其中 U 为特征向量,S为奇异值分解向量为特征向量的平方
Xrot = np.dot(X, U) //去除数据相关性
Xrot_reduced = np.dot(X, U[:,:100]) 降维到 100 维
Xwhite = Xrot / np. sqrt(s + 1e-5) //白化数据 1e-5 为防止除0
可视化数据:例子为CIFAR-10 images
左边第一张图片为CIFAR-10 中的49张图片(每张图片有3072个特征),第二张图片为3072特征向量中的前144个特征,第三张图片为通过PCA降维降到144维,使用的是图二中的前144维,第四张图片为白化后的图片。
常见的数据处理是 Mean substraction 和 Normalization.
权重的设置
陷阱:全零初始化 如果参数是全零,导致输出的结果相同,那么通过反向传播计算梯度也相同,那么参数也不会更新。
用较小的数随机化: W = 0.01* np.random.randn(D,H) randn 返回的样本满足标准正态分布.
标准化变量 1/sqrt(n) W = np.random.randn(n) / sqrt(n) 或者 W = np.random.randn(n) / sqrt(2.0/n)
初始化偏置项
很常见的是将偏置项设置为0,ReLu 激活函数有些人会设置为 0.01, 在实际中通常设置为 W = np. random.randn(n) * sqrt(2.0/n)
Batch Normalization
发现一个讲解Batch Normalization 的博客 详见http://blog.csdn.net/hjimce/article/details/50866313
正则化
有多种方法来防止神经网络的过拟合。
L2 范式 w = w + 1/2 λw2
L1 范式 w = w + λ|w| 向量各元素绝对值之和
L1会趋向于产生少量的特征,而其他的特征都是0,而L2会选择更多的特征,这些特征都会接近于0
Dropout
Dropout是指在模型训练时随机让网络某些隐含层节点的权重不工作,不工作的那些节点可以暂时认为不是网络结构的一部分,但是它的权重得保留下来(只是暂时不更新而已),因为下次样本输入时它可能又得工作了。如下图所示
主要参考CS231n 课程。
# -*- coding:utf-8 -*-
"""数据增强
1. 翻转变换 flip
2. 随机修剪 random crop
3. 色彩抖动 color jittering
4. 平移变换 shift
5. 尺度变换 scale
6. 对比度变换 contrast
7. 噪声扰动 noise
8. 旋转变换/反射变换 Rotation/reflection
"""
from PIL import Image, ImageEnhance, ImageOps, ImageFile
import numpy as np
import random
import threading, os, time
import logging
logger = logging.getLogger(__name__)
ImageFile.LOAD_TRUNCATED_IMAGES = True
class DataAugmentation:
"""
包含数据增强的八种方式
"""
def __init__(self):
pass
@staticmethod
def openImage(image):
return Image.open(image, mode="r")
@staticmethod
def randomRotation(image, mode=Image.BICUBIC):
"""
对图像进行随机任意角度(0~360度)旋转
:param mode 邻近插值,双线性插值,双三次B样条插值(default)
:param image PIL的图像image
:return: 旋转转之后的图像
"""
random_angle = np.random.randint(1, 360)
return image.rotate(random_angle, mode)
@staticmethod
def randomCrop(image):
"""
对图像随意剪切,考虑到图像大小范围(68,68),使用一个一个大于(36*36)的窗口进行截图
:param image: PIL的图像image
:return: 剪切之后的图像
"""
image_width = image.size[0]
image_height = image.size[1]
crop_win_size = np.random.randint(40, 68)
random_region = (
(image_width - crop_win_size) >> 1, (image_height - crop_win_size) >> 1, (image_width + crop_win_size) >> 1,
(image_height + crop_win_size) >> 1)
return image.crop(random_region)
@staticmethod
def randomColor(image):
"""
对图像进行颜色抖动
:param image: PIL的图像image
:return: 有颜色色差的图像image
"""
random_factor = np.random.randint(0, 31) / 10. # 随机因子
color_image = ImageEnhance.Color(image).enhance(random_factor) # 调整图像的饱和度
random_factor = np.random.randint(10, 21) / 10. # 随机因子
brightness_image = ImageEnhance.Brightness(color_image).enhance(random_factor) # 调整图像的亮度
random_factor = np.random.randint(10, 21) / 10. # 随机因1子
contrast_image = ImageEnhance.Contrast(brightness_image).enhance(random_factor) # 调整图像对比度
random_factor = np.random.randint(0, 31) / 10. # 随机因子
return ImageEnhance.Sharpness(contrast_image).enhance(random_factor) # 调整图像锐度
@staticmethod
def randomGaussian(image, mean=0.2, sigma=0.3):
"""
对图像进行高斯噪声处理
:param image:
:return:
"""
def gaussianNoisy(im, mean=0.2, sigma=0.3):
"""
对图像做高斯噪音处理
:param im: 单通道图像
:param mean: 偏移量
:param sigma: 标准差
:return:
"""
for _i in range(len(im)):
im[_i] += random.gauss(mean, sigma)
return im
# 将图像转化成数组
img = np.asarray(image)
img.flags.writeable = True # 将数组改为读写模式
width, height = img.shape[:2]
img_r = gaussianNoisy(img[:, :, 0].flatten(), mean, sigma)
img_g = gaussianNoisy(img[:, :, 1].flatten(), mean, sigma)
img_b = gaussianNoisy(img[:, :, 2].flatten(), mean, sigma)
img[:, :, 0] = img_r.reshape([width, height])
img[:, :, 1] = img_g.reshape([width, height])
img[:, :, 2] = img_b.reshape([width, height])
return Image.fromarray(np.uint8(img))
@staticmethod
def saveImage(image, path):
image.save(path)
def makeDir(path):
try:
if not os.path.exists(path):
if not os.path.isfile(path):
# os.mkdir(path)
os.makedirs(path)
return 0
else:
return 1
except Exception, e:
print str(e)
return -2
def imageOps(func_name, image, des_path, file_name, times=5):
funcMap = {"randomRotation": DataAugmentation.randomRotation,
"randomCrop": DataAugmentation.randomCrop,
"randomColor": DataAugmentation.randomColor,
"randomGaussian": DataAugmentation.randomGaussian
}
if funcMap.get(func_name) is None:
logger.error("%s is not exist", func_name)
return -1
for _i in range(0, times, 1):
new_image = funcMap[func_name](image)
DataAugmentation.saveImage(new_image, os.path.join(des_path, func_name + str(_i) + file_name))
opsList = {"randomRotation", "randomCrop", "randomColor", "randomGaussian"}
def threadOPS(path, new_path):
"""
多线程处理事务
:param src_path: 资源文件
:param des_path: 目的地文件
:return:
"""
if os.path.isdir(path):
img_names = os.listdir(path)
else:
img_names = [path]
for img_name in img_names:
print img_name
tmp_img_name = os.path.join(path, img_name)
if os.path.isdir(tmp_img_name):
if makeDir(os.path.join(new_path, img_name)) != -1:
threadOPS(tmp_img_name, os.path.join(new_path, img_name))
else:
print 'create new dir failure'
return -1
# os.removedirs(tmp_img_name)
elif tmp_img_name.split('.')[1] != "DS_Store":
# 读取文件并进行操作
image = DataAugmentation.openImage(tmp_img_name)
threadImage = [0] * 5
_index = 0
for ops_name in opsList:
threadImage[_index] = threading.Thread(target=imageOps,
args=(ops_name, image, new_path, img_name,))
threadImage[_index].start()
_index += 1
time.sleep(0.2)
if __name__ == '__main__':
threadOPS("/home/pic-image/train/12306train",
"/home/pic-image/train/12306train3")