【小白学PyTorch】21 Keras的API详解(上)卷积、激活、初始化、正则
【新闻】:机器学习炼丹术的粉丝的人工智能交流群已经建立,目前有目标检测、医学图像、时间序列等多个目标为技术学习的分群和水群唠嗑答疑解惑的总群,欢迎大家加炼丹兄为好友,加入炼丹协会。微信:cyx645016617.
参考目录:
我们对Keras应该已经有了一个直观、宏观的认识了。现在,我们来系统的学习一下Keras的一些关于网络层的API,本文的主要内容是围绕卷积展开的,包含以下的内容:
- 不同类型的卷积层;
- 不同的参数初始化方式;
- 不同的激活函数;
- 增加L1/L2正则;
- 不同的池化层;
- 多个Normalization层;
- 其他的常用层。
本文内容较多,对于API的学习了解即可。
1 Keras卷积层
Keras的卷积层和PyTorch的卷积层,都包括1D、2D和3D的版本,1D就是一维的,2D是图像,3D是立体图像。这里就用最常见的2D图像来做讲解,1D和3D和2D基本相同,不多赘述。
1.1 Conv2D
先看Conv2D
的所有参数:
tf.keras.layers.Conv2D(
filters,
kernel_size,
strides=(1, 1),
padding="valid",
data_format=None,
dilation_rate=(1, 1),
groups=1,
activation=None,
use_bias=True,
kernel_initializer="glorot_uniform",
bias_initializer="zeros",
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
**kwargs
)
先看一个简单的例子:
import tensorflow as tf
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
filters=2,kernel_size=3,
activation='relu',padding='same'
)
print(y(x).shape)
>>> (4, 28, 28, 2)
现在来看参数含义:
- filter: 一个int整数,输出特征图的通道数;
- kernel_size:一个int整数,卷积核大小;
- strides:一个整数或者是(a,b)这样的list,表示卷积核是否跳步;
- padding:
'valid'
表示没有padding,'same'
表示输出和输入特征图的尺寸相同;只有这两种选择 - data_format:
'channels_last'
或者是'channels_first'
。默认是'channels_last'
,表示特征图的最后一个维度是通道,(batch_size, height, width, channels) ;如果选择了'channels_first'
表示每一个样本的第一个维度是通道,所以特征图的格式和PyTorch的格式相同,(batch_size, channels, height, width)。 - dilation_rate:碰撞卷积的设置,默认是1,1就是一般的卷积。需要注意的是dilation_rate和stride目前不支持同时不为1,换句话说,如果要膨胀卷积的话,那么stride必须是1;
- groups;分组卷积;
- activation:这个表示,可以直接在卷积层后面设置一个激活层,比方说
'relu'
,这个在后面的章节会详细讲解目前Keras支持的所有激活层,如果什么都不填入,则不使用激活层 - use_bias:一个bool参数,True表示使用bias,默认是True;
- kernel_initializer:卷积核的初始化的方法,这个会在后面的章节详细讲解;
- bias_initializer:偏置的初始化的方法,这个会在后面的章节详细讲解;
- kernel_regularizer:卷积核的正则化的方法,在后面的章节会详细讲解;
- bias_regularizer:偏置的正则化的方法,在后面的章节会详细讲解;
1.2 SeparableConv2D
Keras直接提供了深度可分离卷积层,这个层其实包含两个卷积层(了解深度可分离卷积的应该都知道这个吧),一层是depthwise,一层是pointwise。
这个SeparableConv2D的参数也很多,与Conv2D有很多重复的参数,就不多加赘述了:
tf.keras.layers.SeparableConv2D(
filters,
kernel_size,
strides=(1, 1),
padding="valid",
data_format=None,
dilation_rate=(1, 1),
depth_multiplier=1,
activation=None,
use_bias=True,
depthwise_initializer="glorot_uniform",
pointwise_initializer="glorot_uniform",
bias_initializer="zeros",
depthwise_regularizer=None,
pointwise_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
depthwise_constraint=None,
pointwise_constraint=None,
bias_constraint=None,
**kwargs
)
参数详解:
- depth_multiplier:depthwise卷积之后,一般会增多通道数。比方说输入通道是16个,那么输出通道数64个,然后再输入到pointwise卷积层。这个depth_multiplier就是depthwise卷积层的通道数的扩增系数,在上面的例子中这个扩增系数是4;
- depthwise_initializer和pointwise_initializer不用多说,就是两个卷积层的卷积核的初始化的方法。
但是这个深度可分离卷积完全可以用一般的Conv2D来构建,所以其实在用到深度可分离卷积的时候,自己会重新构建一个这样的网络层
1.3 Conv2DTranspose
对于上采样,这种方法应该并不陌生。Transposed convolution有的时候也被称为Deconvolution去卷积
tf.keras.layers.Conv2DTranspose(
filters,
kernel_size,
strides=(1, 1),
padding="valid",
output_padding=None,
data_format=None,
dilation_rate=(1, 1),
activation=None,
use_bias=True,
kernel_initializer="glorot_uniform",
bias_initializer="zeros",
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
**kwargs
)
参数详解:
- output_padding:一个整数或者list,用来给输出的特征图增加一个padding的效果,默认是None,不添加padding;
对于去卷积,可能会比较生疏,这里多讲几个例子
1.3.1 去卷积的例子1
import tensorflow as tf
from tensorflow import keras
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = keras.layers.Conv2DTranspose(
filters=10,kernel_size=3,strides=1,padding='same')
print(y(x).shape)
>>> (4, 28, 28, 10)
但是假如我们去掉了padding=‘same’
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = keras.layers.Conv2DTranspose(
filters=10,kernel_size=3,strides=1)
print(y(x).shape)
>>> (4, 30, 30, 10)
这是因为去卷积的卷积核的中心是从原特征图的边界之外开始计算的。一个3乘3的卷积核,那么当卷积核的右下角与原特征图的左上角重合的时候,去卷积的就已经进行了一次运算,而一般的卷积是只有当卷积核的全部都与原特征图重合的时候,才进行计算的。(这里的讲解不太细致,因为之前在其他的文章中已经讲过去卷积的详细过程了)。
1.3.2 去卷积的例子2
现在把stride改成2
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = keras.layers.Conv2DTranspose(
filters=10,kernel_size=3,strides=2)
print(y(x).shape)
>>> (4, 57, 57, 10)
假如加上padding='same'
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = keras.layers.Conv2DTranspose(
filters=10,kernel_size=3,strides=2,padding='same')
print(y(x).shape)
>>> (4, 56, 56, 10)
所以一般情况下,使用的参数是strides=2,padding='same'
,这样特征图的尺寸就刚好放大一倍。
2 Keras参数初始化
把之前提到的简单的例子,增加卷积核和偏置的初始化:
import tensorflow as tf
input_shape = (4, 28, 28, 3)
initializer = tf.keras.initializers.RandomNormal(mean=0., stddev=1.)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
filters=2,kernel_size=3,
activation='relu',padding='same',
kernel_initializer=initializer,
bias_initializer=initializer
)
print(y(x).shape)
>>> (4, 28, 28, 2)
简单的说,就是先定义一个初始化器initializer,然后把这个初始化器作为参数传给Keras.Layers就行了。
2.1 正态分布
tf.keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)
2.2 均匀分布
tf.keras.initializers.RandomUniform(minval=-0.05, maxval=0.05, seed=None)
2.3 截尾正态分布
tf.keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)
基本和正态分布一样,但是如果随机的取值是在距离均值两个标准差的这个范围之外的,那么会重新取值。
换句话说,初始化的数值会被限制在均值正负两个标准差的范围内
2.4 常数
tf.keras.initializers.Zeros()
tf.keras.initializers.Ones()
2.5 Xavier/Glorot
tf.keras.initializers.GlorotNormal(seed=None)
这个本质是一个截尾正态分布,但是GlorotNormal(又称Xavier),是一个以0为均值,标准差计算公式是:$$std = \sqrt{\frac{2}{in+out}}$$
是in和out表示输入和输出神经元数目的数目。如果是之前已经学习过或者看过我写的关于Xavier初始化的论文笔记的朋友,可能会发现论文中使用的是一个均匀分布而不是正态分布。
均匀分布的初始化如下:
tf.keras.initializers.GlorotUniform(seed=None)
这个均匀分布是我们讲的:
\]
这个Xavier方法,也是Keras默认的初始化的方法
2.6 自定义初始化
当然,Keras也是支持自定义初始化的方法的。
import tensorflow as tf
class ExampleRandomNormal(tf.keras.initializers.Initializer):
def __init__(self, mean, stddev):
self.mean = mean
self.stddev = stddev
def __call__(self, shape, dtype=None)`:
return tf.random.normal(
shape, mean=self.mean, stddev=self.stddev, dtype=dtype)
def get_config(self): # To support serialization
return {'mean': self.mean, 'stddev': self.stddev}
关键就是在__call__
中返回一个和输入参数shape
大小相同的一个tf张量就行了。
3 Keras激活函数
基本支持了所有的常见激活函数。在卷积层的参数activation
中,可以输入relu,sigmoid,softmax等下面的字符串的形式,全部小写。
3.1 relu
tf.keras.activations.relu(x, alpha=0.0, max_value=None, threshold=0)
- alpha就是斜率,如果是0.1,则变成leakyReLU;
- max_value是ReLU的上界,如果是None则没有上界;
- threshold是ReLU的下界,小于下界的都会被置0,一般默认是0.
3.2 sigmoid
tf.keras.activations.sigmoid(x)
函数方程:
\]
3.3 softmax
tf.keras.activations.softmax(x, axis=-1)
3.4 softplus
tf.keras.activations.softplus(x)
计算公式:
\]
3.5 softsign
tf.keras.activations.softsign(x)
计算公式:
\]
3.6 tanh
tf.keras.activations.tanh(x)
计算公式:
\]
3.7 selu
tf.keras.activations.selu(x)
- 如果\(x>0\),返回\(scale \times x\);
- 如果\(x<0\),返回\(scale \times \alpha \times (e^x-1)\);
- scale和\(\alpha\)是事先设置的数值,alpha=1.67216214,scale=1.05070098
- 与elu激活函数类似,但是多了有个scale系数,\(selu=scale\times elu\)
- 2017年的一篇论文提出selu,elu是2016年提出的
4 Keras的L1/L2正则
正则化就比较简单,不是L1就是L2,再或者两者都有。
4.1 L1/L2正则
from tensorflow.keras import layers
from tensorflow.keras import regularizers
layer = layers.Dense(
units=64,
kernel_regularizer=regularizers.l1_l2(l1=1e-5, l2=1e-4),
)
这里的正则化,可以使用:
tf.keras.regularizers.l1_l2(l1=1e-5, l2=1e-4)
tf.keras.regularizers.l2(1e-4)
tf.keras.regularizers.l1(1e-5)
关于L1和L2的计算细节:
- L1:L1正则就是$$loss=L1\times sum(abs(x))$$
- L2:L1正则就是$$loss=L1\times sum(x^2)$$
4.2 自定义正则化
class MyRegularizer(tf.keras.regularizers.Regularizer):
def __init__(self, strength):
self.strength = strength
def __call__(self, x):
return self.strength * tf.reduce_sum(tf.square(x))
def get_config(self):
return {'strength': self.strength}
这个实现的是L2正则的。其中的get_config是用来保存模型数据的,不要的话也没事,只是不能序列化的保存模型(不用使用config或者json来存储模型)。
【小白学PyTorch】21 Keras的API详解(上)卷积、激活、初始化、正则的更多相关文章
- 【小白学PyTorch】21 Keras的API详解(下)池化、Normalization层
文章来自微信公众号:[机器学习炼丹术].作者WX:cyx645016617. 参考目录: 目录 1 池化层 1.1 最大池化层 1.2 平均池化层 1.3 全局最大池化层 1.4 全局平均池化层 2 ...
- 小白如何学习PyTorch】25 Keras的API详解(下)缓存激活,内存输出,并发解决
[新闻]:机器学习炼丹术的粉丝的人工智能交流群已经建立,目前有目标检测.医学图像.时间序列等多个目标为技术学习的分群和水群唠嗑答疑解惑的总群,欢迎大家加炼丹兄为好友,加入炼丹协会.微信:cyx6450 ...
- 【小白学AI】GBDT梯度提升详解
文章来自微信公众号:[机器学习炼丹术] 文章目录: 目录 0 前言 1 基本概念 2 梯度 or 残差 ? 3 残差过于敏感 4 两个基模型的问题 0 前言 先缕一缕几个关系: GBDT是gradie ...
- 【小白学PyTorch】20 TF2的eager模式与求导
[新闻]:机器学习炼丹术的粉丝的人工智能交流群已经建立,目前有目标检测.医学图像.时间序列等多个目标为技术学习的分群和水群唠嗑的总群,欢迎大家加炼丹兄为好友,加入炼丹协会.微信:cyx64501661 ...
- Java 8 Stream API详解--转
原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...
- hibernate学习(2)——api详解对象
1 Configuration 配置对象 /详解Configuration对象 public class Configuration_test { @Test //Configuration 用户 ...
- 转】Mahout推荐算法API详解
原博文出自于: http://blog.fens.me/mahout-recommendation-api/ 感谢! Posted: Oct 21, 2013 Tags: itemCFknnMahou ...
- Java8学习笔记(五)--Stream API详解[转]
为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 ...
- Android Developer -- Bluetooth篇 开发实例之四 API详解
http://www.open-open.com/lib/view/open1390879771695.html 这篇文章将会详细解析BluetoothAdapter的详细api, 包括隐藏方法, 每 ...
随机推荐
- HashMap位运算你可知一二
前置位运算知识 我们平时在写代码过程中用的位运算操作比较少,因为我们更关注于可读性而不是性能,如果为了性能而使用较多的位运算,我想我们的同事会疯掉.但在框架里位运算却非常常见,因为框架的性能是我们关注 ...
- nginx的gzip压缩
随着nginx的发展,越来越多的网站使用nginx,因此nginx的优化变得越来越重要,今天我们来看看nginx的gzip压缩到底是怎么压缩的呢? gzip(GNU-ZIP)是一种压缩技术.经过gzi ...
- 小程序开发-媒体组件image
image 图片组件,支持 JPG.PNG.SVG.WEBP.GIF 等格式,2.3.0 起支持云文件ID. 所有属性如下: Tips image组件默认宽度320px.高度240px image组件 ...
- 安装与激活PhpStrom
1.下载安装PHPstorm(https://pan.baidu.com/s/1nwK3ew5 密码dhtr) 2.运行 3.下一步选择中间,在http://idea.lanyus.com/ 上获取激 ...
- Java程序取MySQL的datetime字段,如何消除时间尾后讨厌的".0"
Problem: 直接取datetime字段的内容会有".0"后缀,如2020-05-03 18:21:39.0,虽无伤大雅但总觉得有些别扭. Solution:使用转化函数Dat ...
- zookeeper与分布式系统
1.1. 分布式系统基础知识 一个tomcat打天下的时代,不能说完全淘汰了,在一个管理系统,小型项目中还经常使用,这并不过分,出于成本的考虑,这反而值得提倡. 1.1.1. 分布式系统是什么 分 ...
- Intel-Pin的windows安装
环境安装 操作系统:windows10 需要环境: 1.Visual Studio Community 2019 Edition ( https://visualstudio.microsoft.c ...
- Python实现加密压缩成RAR或ZIP文件
博主在前两篇博文分别介绍了加密RAR文件的解压https://www.cnblogs.com/kangbazi666/p/13646308.html和加密ZIP文件的解压https://www.cnb ...
- axios post提交数据的三种请求方式
1.Content-Type: application/json import axios from 'axios' let data = {"code":"1234&q ...
- 《Offer一箩筐》2W字总结面试套路14问——不给例子的教程都是耍流氓!!
「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! Hi~ 这里是 ...