python & tensorflow2 & deeplearning &音频处理 & 声学事件检测

文章目录

1 pycharm查看函数信息

按住ctrl键,将鼠标放到函数上,就会显示函数信息,点击进去可以查看函数源码。

3线性回归程序

要点:** y = model.predict(x_data)#预测输出** ** w,b = model.layers [0] .get_weights()#显示模型参数**

4理解卷积神经网络中的通道

在深度学习的算法学习中,都会提到channel这个概念。在一般的深度学习框架的conv2d中,如tensorflow,mxnet,通道都是必填的一个参数。

该如何理解?先看一看不同框架中的解释文档。

首先,是 tensorflow 中给出的,对于输入样本中 channels 的含义。一般的RGB图片,channels 数量是 3 (红、绿、蓝);而monochrome图片,channels 数量是 1 。

为了更直观的理解,下面举个例子,图片使用自 吴恩达老师的深度学习课程 。

如下图,假设现有一个为 6×6×36×6×3 的图片样本,使用 3×3×33×3×3 的卷积核(filter)进行卷积操作。此时输入图片的 channels 为 33 ,而卷积核中的 in_channels 与 需要进行卷积操作的数据的 channels 一致(这里就是图片样本,为3)。
在这里插入图片描述
接下来,进行卷积操作,卷积核中的27个数字与分别与样本对应相乘后,再进行求和,得到第一个结果。依次进行,最终得到 4×4 的结果。
在这里插入图片描述
上面步骤完成后,由于只有一个卷积核,所以最终得到的结果为 4×4×1 , out_channels 为 11 。

在实际应用中,都会使用多个卷积核。这里如果再加一个卷积核,就会得到 4×4×2的结果。

总结一下,把上面提到的 channels 分为三种:

1 最初输入的图片样本的 channels ,取决于图片类型,比如RGB;
2 卷积操作完成后输出的 out_channels取决于卷积核的数量此时的 out_channels 也会作为下一次卷积时的卷积核的 in_channels
3 卷积核中的 in_channels ,刚刚2中已经说了,就是上一次卷积的 out_channels ,如果是第一次做卷积,就是1中样本图片的 channels 。

eg:
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu = None, name = None)

第二个参数filter:

CNN卷积网络中的卷积核,要求是一个Tensor,类型和input类型相同,shape为[filter_height, filter_width, in_channels, out_channels]:

filter_height:卷积核的高度
filter_width:卷积核的宽度
in_channels:图像的通道数,input的in_channels相同
out_channels:卷积核的个数

5 mnist分类

import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense, Dropout,Activation
from keras.layers import Conv2D, MaxPool2D, Flatten
from keras.optimizers import Adam
from keras.utils import np_utils
from keras.datasets import mnist

def load_data():
    path = 'f://mnist//mnist.npz'
    f = np.load(path)                       #导入数据

    (x_train, y_train), (x_test, y_test) = (f['x_train'],f['y_train']),(f['x_test'],f['y_test'])
    #x_train, y_train = f['x_train'],f['y_train']
    #x_test, y_test = f['x_test'],f['y_test']

    number = 60000
    x_train = x_train[0:number]
    y_train = y_train[0:number]
    x_train = x_train.reshape(number, 28*28)
    x_test = x_test.reshape(x_test.shape[0], 28*28)
    x_train = x_train.astype('float32')            #类型转换
    x_test = x_test.astype('float32')

    y_train = np_utils.to_categorical(y_train,10)   #转化为独热码
    y_test = np_utils.to_categorical(y_test,10)

    x_train = x_train.reshape(-1,28,28,1)/255       #最后的那个1表示通道数,必须有
    x_test = x_test.reshape(-1,28,28,1)/255

    return (x_train, y_train),(x_test,y_test)

(x_train, y_train), (x_test,y_test) = load_data()

model = Sequential()
model.add(Conv2D(input_shape=(28,28,1),filters=32,kernel_size=5,strides=1,
                 padding='same',activation='relu'))
model.add(MaxPool2D(pool_size=2,strides=2,padding='same'))
model.add(Conv2D(kernel_size=5,filters=64,strides=1,padding='same',
                 activation='relu'))
model.add(MaxPool2D(pool_size=2,strides=2,padding='same'))
model.add(Flatten())
model.add(Dense(units=1024,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=10,activation='softmax'))

model.compile(loss='categorical_crossentropy',optimizer=Adam(lr=1e-4),metrics=['accuracy'])     #metrics计算准确率
model.fit(x_train,y_train,batch_size=64,epochs=10)

loss,acc = model.evaluate(x_test,y_test)

print('\nTest loss:',loss)
print('\nTest acc:',acc)

注意:loss,acc = model.evaluate(x_test,y_test) #在测试集测试准确率

model = load_model('model.h5')    #载入模型

model.fit(x_train,y_train,batch_size=64,epochs=1)  #继续训练

6 实验:使用卷积递归神经网络进行单通道和多通道声音事件检测。

   DCASE 2017真实声音事件检测获胜方法
6.1 遇到的问题:
6.1.1 ImportError: No module named 通用解决方法

问题原因:
(1)该模块没有安装
(2)该模块已经安装,但是没有安装到python的搜索路径下
解决方案:
(1)如果是上面的原因1导致的,这个没什么说的,具体安装就行了,最常用安装方法:使用pip install 安装;
(2)如果是上面的原因2导致的。解决方法:将刚刚安装完的包,添加到Python添加默认模块搜索路径就行了。

方法②: 增加.pth文件【推荐
在site-packages添加一个路径文件(假设你现在的python默认是:/usr/local/lib/python2.7/),
在 /usr/local/lib/python2.7/site-packages 路径下 新建一个文件 “mypkpath.pth”,文件里面的内容是 你想要加入的模块文件所在的目录名称。
例如:
新建文件:/usr/local/lib/python2.7/site-packages/mypkpath.pth
该文件内容:/usr/lib/python2.6/site-packages/

6.1.2 keras之多GPU训练方法

将模型在多个GPU上复制

特别地,该函数用于单机多卡的数据并行支持,它按照下面的方式工作:
(1)将模型的输入分为多个子batch
(2)在每个设备上调用各自的模型,对各自的数据集运行
(3)将结果连接为一个大的batch(在CPU上)
例子:

from keras.utils import multi_gpu_model
 
# 将 `model` 复制到 8 个 GPU 上。
# 假定你的机器有 8 个可用的 GPU。
parallel_model = multi_gpu_model(model, gpus=2)
parallel_model.compile(loss='categorical_crossentropy',
                       optimizer='rmsprop')
 
# 这个 `fit` 调用将分布在 8 个 GPU 上。
# 由于 batch size 为 256,每个 GPU 将处理 32 个样本。
parallel_model.fit(x, y, epochs=20, batch_size=256)

表示使用两块GPU
如果想指定使用哪两块GPU,可以在开头添加如下语句

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "2,3"

注意
1)multi_gpu_model这个函数一定要放对位置,放在compile之前
2)若报错为:

TypeError: can’t pickle module objects

解决方法如下:
在这里插入图片描述
意思就是直接使用传入方法keras.utils.multi_gpu_model(model, gpus)中的model即可,而不要使用返回的parallel_model,即:

model.save('xxx.h5')
6.1.3 Tensorflow在Pycharm中报错 :找不到 libcublas.so.9.0

Pycharm中显示 :ImportError: libcublas.so.9.0: cannot open shared object file: No such file
可能原因,CUDA版本不对,安装对应版本的CUDA;如果匹配却仍然报错,那是因为cuda环境变量配置有误,pycharm找不到
解决办法:
1)在Pycharm中添加环境变量 ,右上角倒三角下拉,进入菜单Edit configurations,
2)打开重新添加环境变量 :Environment variables 那栏
3)增加:PYTHONUNBUFFERED=1; LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64;usr/local/lib
注:/usr/local/cuda-9.0/lib64需要改为在用户下cuda9的路径,系统的是cuda8,不兼容。即改为/data/guanyadong/cuda9/lib64,其他不用改
在这里插入图片描述
添加成功以后就可以正常运行了。这种方法的坏处是,每次新建文件,都需要手动添加环境变量。

6.1.4 import librosa时出问题

在这里插入图片描述

6.1.5 安装cudnn等包的另一种方法

在这里插入图片描述
点里面的+,搜索cudnn,等一会右下角会有特定版本的选择,这样安装多简单。

6.1.6 设置时设的是GPU运行,但实际上CPU在跑而GPU不跑

原因:可能cuda或cudnn有问题,所以只能使用CPU运行
先把tensorflow删了只留tensorflow-gpu(用6.1.5类似的方法),然后看能不能GPU运行,如果有bug提示是cudnn或者cuda的问题就好解决了,具体方法上面都说了。

6.1.7 找不到enum

原因:(1)enum改名成了enum34,有些比较老的代码还用的enum;
(2)安装了enum34以后pycharm还是找不到,先看下enum34的安装路径在这里插入图片描述
看到安装路径就明白了,在虚拟环境py2.7下用pip居然安装到了基本环境即python3.7中(好神奇的说),所以在py27的虚拟环境中当然找不到了,解决方法:参照6.1.1,添加路径

6.2 『开发技术』GPU训练加速原理

GPU是如何加速的呢?

我打算从两个方面来解答:

单个GPU较于CPU加速:
在训练网络中,其实大量的运算资源都消耗在了数值计算上面,大部分网络训练的过程都是1.计算loss,2.根据loss求梯度,3.再根据梯度更新参数(梯度下降原理)。无论在GPU还是CPU中,都是不断重复123步。但是由于CPU是通用计算单元(并不擅长数值运行),而GPU特长是图像处理(数值计算)。所以GPU更加适合训练网络,从而起到加速效果。

多GPU较于单GPU加速:
一般在GPU训练中,同一个GPU中,batch_size的大小,决定训练的速度,batch_size越小,训练一轮所需的步数(data_len/batch_size)就会越大,从而花费时间越多

多GPU数据并行加速原理:

假设一台机器上有k块GPU。给定需要训练的模型,每块GPU及其相应的显存将分别独立维护一份完整的模型参数。在模型训练的任意一次迭代中,给定一个随机小批量,我们将该批量中的样本划分成k份并分给每块显卡的显存一份。然后,每块GPU将根据相应显存所分到的小批量子集和所维护的模型参数分别计算模型参数的本地梯度。接下来,我们把k块显卡的显存上的本地梯度相加,便得到当前的小批量随机梯度。之后,每块GPU都使用这个小批量随机梯度分别更新相应显存所维护的那一份完整的模型参数。下图描绘了使用2块GPU的数据并行下的小批量随机梯度的计算。
在这里插入图片描述
使用2块GPU的数据并行下的小批量随机梯度的计算

我们回忆下梯度下降的过程,1.计算loss,2.根据loss求梯度,3.再根据梯度更新参数。

使用上述的多GPU数据并行方法,可以理解为把batch_size扩大了k倍,从而总的时间缩短为了k分之1,实现了多GPU计算训练。
其实每一个GPU上网络的参数都是相同的,因为都是从相同的loss做的更新。
假设单GPU和k个GPU的batch size相同,那么,单GPU一次epoch迭代的次数是多GPU的k倍,即单GPU更新参数的次数多。因此不能简单的认为多GPU和单GPU收敛到相同程度时,多GPU的收敛时间是单GPU收敛时间的k分之1

多GPU加速适用于数据量大的情况,假如本身程序用一个GPU都用不满,若强行分给多个GPU,训练速度会反而更慢(因为GPU之间传输信息的时间也是比较长的)

6.3 batch size设置技巧

样本量少的时候会带来很大的方差,而这个大方差恰好会导致梯度下降到很差的局部最优点(只是微微凸下去的最优点)和鞍点的时候不稳定,一不小心就因为一个大噪声的到来导致炸出了局部最优点。
与之相反的,当样本量很多时,方差很小,对梯度的估计要准确和稳定的多,因此反而在差劲的局部最优点和鞍点时反而容易自信的呆着不走了,从而导致神经网络收敛到很差的点上,跟出了bug一样的差劲。

batch的size设置的不能太大也不能太小,因此实际工程中最常用的就是mini-batch,一般size设置为几十或者几百。

GPU对2的幂次的batch可以发挥更佳的性能,因此设置成16、32、64、128…时往往要比设置为整10、整100的倍数时表现更优

6.3.1 mini-batch的几个好处 :

(1)提高了运行效率,相比batch-GD的每个epoch只更新一次参数,使用mini-batch可以在一个epoch中多次更新参数,加速收敛。
(2)解决了某些任务中,训练集过大,无法一次性读入内存的问题。
(3)虽然第一点是mini-batch提出的最初始的原因,但是后来人们发现,使用mini-batch还有个好处,即每次更新时由于没有使用全量数据而仅仅使用batch内数据,从而人为给训练带来了噪声,而这个操作却往往能够带领算法走出局部最优(鞍点)。理论证明参见COLT的这篇论文Escaping From Saddle Points-Online Stochastic Gradient for Tensor Decomposition。也就是说,曾经我们使用mini-batch主要是为了加快收敛和节省内存,同时也带来每次更新有些“不准”的副作用,但是现在的观点来看,这些“副作用”反而对我们的训练有着更多的增益,也变成mini-batch技术最主要的优点。

总结下来:批量大小过小,花费时间多,同时渐变震荡严重,不利于收敛;批量大小过大,不同程度的梯度方向没有任何变化,容易放置局部极小值

6.3.2批量选择方法

(1)当有足够的算力时,替换批量大小为32英寸小一些。(2)算力不够时,在效率和泛化性之间做折衷,尽量选择更小的批量大小。(3)当模型训练到尾声,想更精细化地提高成绩(某种论文实验/比赛到最后),有一个有用的技巧,就是设置批处理大小为1,即做纯SGD,慢慢把错误磨低。

7 tensorflow2.0学习

7.1 概述

在Keras API中总共有如下三大块:
在这里插入图片描述
在Modules中有构建训练模型各种必备的组件,如激活函数activations、损失函数losses、优化器optimizers等;在Class中有Sequential和Model两个类,它们用来堆叠模型;在Functions中有Input()函数,它用来实例化张量。

7.2 Modules

Modules中有activations、losses、optimizers等构建训练模型时各种必备的组件。下图就是Modules中有所的模块。
在这里插入图片描述
下面我们详细说说里面最常见的几个模块应该如何使用。

  1. 常用的数据集(datasets)

在TensorFlow2.0中,常用的数据集需要使用tf.keras.datasets来加载,在datasets中有如下数据集。

在这里插入图片描述
数据集我们可以像下面这样加载

(train_images,train_labels),(test_images,test_labels)= keras.datasets.fashion_mnist.load_data()

当然我们平时使用的数据集肯定不在于此,这些数据集都是些最基础的数据集。

  1. 神经网络层(Layers)

在构建深度学习网络模型时,我们需要定制各种各样的层结构。这时候就要用到layers了,下图是TensorFlow2.0中部分层,它们都是Layer的子类。

在这里插入图片描述
那么我们如何使用layer来构建模型呢?方法如下:

from tensorflow.keras import layers
layers.Conv2D()
layers.MaxPool2D()
layers.Flatten()
layers.Dense()
  1. 激活函数(Optimizers)

在构建深度学习网络时,我们经常需要选择激活函数来使网络的表达能力更强。下面将介绍TensorFlow2.0中的激活函数及它们应该在TensorFlow2.0中该如何使用。下图是TensorFlow2.0中部分激活函数:
在这里插入图片描述

from tensorflow.keras import layers
layers.Conv2D(...,activation='relu')
layers.Dense(...,activation='softmax'
  1. 优化器(activations)

通常当我们准备好数据,设计好模型后,我们就需要选择一个合适的优化器(Optimizers)对模型进行优化。下面将介绍TensorFlow2.0中的优化器及他们应该在TensorFlow2.0中该如何使用。下图是TensorFlow2.0中所有的优化器,它们都是Optimizer的子类。

在这里插入图片描述
对于优化器的使用你可以像下面这样使用:

optimizers = tf.keras.optimizers.Adam()

optimizers = tf.keras.optimizers.SGD()
  1. 损失函数(Losses)

我们知道当我们设计好模型时我们需要优化模型,所谓的优化就是优化网络权值使损失函数值变小,但是损失函数变小是否能代表精度越高呢?那么多的损失函数,我们又该如何选择呢?接下来我们了解下在TensorFlow2.0中如何使用损失函数。下图是TensorFlow2.0中所有的损失函数,它们都是Loss的子类。
在这里插入图片描述

对于损失函数的使用你可以像下面这样使用:

loss = tf.keras.losses.SparseCategoricalCrossentropy()

loss = tf.keras.losses.mean_squared_error()
7.3 Class

在Class中有Sequential和Model两个类,它们分别是用来堆叠网络层和把堆叠好的层实例化可以训练的模型。

  1. Model

对于实例化Model有下面两种方法

(1).使用keras.Model API

import tensorflow as tf

inputs = tf.keras.Input(shape=(3,))

x=tf.keras.layers.Dense(4,activation=tf.nn.relu(inputs)

outputs=tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x)

model=tf.keras.Model(inputs=inputs, outputs=outputs)

(2).继承Model类

import tensorflow as tf

class MyModel(tf.keras.Model):

  def __init__(self):

    super(MyModel, self).__init__()

    self.dense1 = tf.keras.layers.Dense(4, activation=tf.nn.relu)

    self.dense2 = tf.keras.layers.Dense(5, activation=tf.nn.softmax)

  def call(self, inputs):

    x = self.dense1(inputs)

    return self.dense2(x)

model = MyModel()
  1. Sequential

在TensorFlow2.0中,我们可以使用Sequential模型。具体方式如下:

model = keras.Sequential()

model = model.add(layers.Conv2D(input_shape=(x_train.shape[1],x_train.shape[2],x_train.shape[3]),filters=32,kernel_size=(3,3), strides=(1,1), padding='valid',activation='relu'))

model.add(layers.MaxPool2D(pool_size=(2,2)))

model.add(layers.Flatten())model.add(layers.Dense(32,activation='relu'))

model.add(layers.Dense(10, activation='softmax'))

model.compile(optimizer=keras.optimizers.Adam(),loss=keras.losses.SparseCategoricalCrossentropy(),metrics=['accuracy'])
7.4 Functions
7.4.1 tensor操作
(1) tensor和numpy的转化
A = tf.convert_to_tensor(B)    #numpy->tensor
C = A.numpy()                   #tensor->numpy
(2) tf.transpose()

维度调换,对于二维张量可以理解为转置。多维张量的维度调换多用于图像处理领域

tf.transpose(
    a,              #a:表示需要变换的张量
    perm=None,      #perm:a的新的维度序列
    name='transpose',
    conjugate=False
)

例子:

import tensorflow as tf
import numpy as np
 
A=np.arange(12).reshape([2,3,2])
X=tf.transpose(A,[0,2,1])
Y=tf.transpose(A,[1,0,2])
with tf.Session() as sess:
    print("original:")
    print(A)
    print("transpose [0,2,1]:")
    print(sess.run(X))
    print("transpose [0,2,1]‘s shape:")
    print(X.get_shape().as_list())
    print("transpose [1,0,2]:")
    print(sess.run(Y))
    print("transpose [1,0,2]'s shape")
    print(Y.get_shape().as_list())

结果:


original:
[[[ 0  1]
  [ 2  3]
  [ 4  5]]
 
 [[ 6  7]
  [ 8  9]
  [10 11]]]
transpose [0,2,1]:
[[[ 0  2  4]
  [ 1  3  5]]
 
 [[ 6  8 10]
  [ 7  9 11]]]
transpose [0,2,1]‘s shape:
[2, 2, 3]
transpose [1,0,2]:
[[[ 0  1]
  [ 6  7]]
 
 [[ 2  3]
  [ 8  9]]
 
 [[ 4  5]
  [10 11]]]
transpose [1,0,2]'s shape
[3, 2, 2]
(3)expand_dim()增加维度
# 't' is a tensor of shape [2]
shape(expand_dims(t, 0)) ==> [1, 2]
shape(expand_dims(t, 1)) ==> [2, 1]
shape(expand_dims(t, -1)) ==> [2, 1]

# 't2' is a tensor of shape [2, 3, 5]
shape(expand_dims(t2, 0)) ==> [1, 2, 3, 5]
shape(expand_dims(t2, 2)) ==> [2, 3, 1, 5]
shape(expand_dims(t2, 3)) ==> [2, 3, 5, 1]
(4)tf.reshape重塑张量
# tensor 't' is [1, 2, 3, 4, 5, 6, 7, 8, 9]
# tensor 't' has shape [9]
reshape(t, [3, 3]) ==> [[1, 2, 3],
                        [4, 5, 6],
                        [7, 8, 9]]

# tensor 't' is [[[1, 1], [2, 2]],
#                [[3, 3], [4, 4]]]
# tensor 't' has shape [2, 2, 2]
reshape(t, [2, 4]) ==> [[1, 1, 2, 2],
                        [3, 3, 4, 4]]
(5)打印Tensor的值
tf.print(a)

注:不可能在没有运行图的情况下检查值。

(6)降低维度reduce系列

和 Numpy 中相应的用法完全一致

# 计算输入 tensor 所有元素的和,或者计算指定的轴所有元素的和
tf.reduce_sum(input_tensor, axis=None, keep_dims=False, name=None)
# 'x' is [[1, 1, 1]
#         [1, 1, 1]]
tf.reduce_sum(x) ==> 6
tf.reduce_sum(x, 0) ==> [2, 2, 2]
tf.reduce_sum(x, 1) ==> [3, 3]
tf.reduce_sum(x, 1, keep_dims=True) ==> [[3], [3]]  # 维度不缩减
tf.reduce_sum(x, [0, 1]) ==> 6
 
 
# 计算输入 tensor 所有元素的均值/最大值/最小值/积/逻辑与/或
# 或者计算指定的轴所有元素的均值/最大值/最小值/积/逻辑与/或(just like reduce_sum)
tf.reduce_mean(input_tensor, axis=None, keep_dims=False, name=None)
tf.reduce_max(input_tensor, axis=None, keep_dims=False, name=None)
tf.reduce_min(input_tensor, axis=None, keep_dims=False, name=None)
tf.reduce_prod(input_tensor, axis=None, keep_dims=False, name=None)
tf.reduce_all(input_tensor, axis=None, keep_dims=False, name=None)  # 全部满足条件
tf.reduce_any(input_tensor, axis=None, keep_dims=False, name=None) #至少有一个满足条件
(7)矩阵运算

求张量的范数(默认2)

tf.norm(tensor, ord=2, axis=-1, keep_dims=False, name=None)

构建一个单位矩阵

# 构建一个单位矩阵, 或者 batch 个矩阵,batch_shape 以 list 的形式传入
tf.eye(num_rows, num_columns=None, batch_shape=None, dtype=tf.float32, name=None)
# Construct one identity matrix.
tf.eye(2)
==> [[1., 0.],
     [0., 1.]] 
# Construct one 2 x 3 "identity" matrix
tf.eye(2, num_columns=3)
==> [[ 1.,  0.,  0.],
     [ 0.,  1.,  0.]]

(8)tf.assign()

tf.assign(A, new_number): 这个函数的功能主要是把A的值变为new_number
或 A.assign(new_number)
例如:

import tensorflow as tf;
 
A = tf.Variable(tf.constant(0.0), dtype=tf.float32)
with tf.Session() as sess:
	sess.run(tf.initialize_all_variables())
	print sess.run(A)
	sess.run(tf.assign(A, 10))
	print sess.run(A)

输出:

0.0
10.0

开始给A赋值为0,经过tf.assign函数后,把A的值变为10

7.4.2 模型与层的操作
(1) tf.keras.Input()

用来实例化Keras张量,用于搭建模型的第一层,有如下参数

tf.keras.Input(shape=None,batch_size=None,name=None,dtype=None,
               sparse=False,tensor=None, **kwargs)

具体使用方法如下:

x = Input(shape=(32,))
y = Dense(16, activation='softmax')(x)
model = Model(x, y)
(2) 获取模型某一层权重get_weights()

方法一:通过model.get_weights()先获取模型的全部参数(一个列表数组,第一层W,第一层b,第二层W,第二层b,…)。返回模型中所有权重张量的列表,类型为 Numpy 数组。

weights = model.get_weights() #获取整个网络模型的全部参数
print(weights [0].shape)  #第一层的w
print(weights [1].shape)  #第一层的b
print(weights [2].shape)  #第二层的w
print(weights [3].shape)  #第二层的b

方法二:layer.get_weights() :返回层的权重( numpy array)
通过get_layer()函数先获取要获取权重对应的层;接着通过get_weights()

model = load_model('vgg.h5')
layer1 = model.get_layer(index=2)
weights = layer1.get_weights()   #获取该层的参数W和b
(3)模型权重的保存和加载

只保存模型的权重:

model.save_weights('my_model_weights.h5')

如果需要在代码中初始化一个完全相同的模型,请使用:

model.load_weights('my_model_weights.h5')

如果需要加载权重到不同的网络结构(有些层一样)中,例如fine-tune或transfer-learning,可以通过层名字来加载模型:

model.load_weights('my_model_weights.h5', by_name=True)

例如:

"""
假如原模型为:
    model = Sequential()
    model.add(Dense(2, input_dim=3, name="dense_1"))
    model.add(Dense(3, name="dense_2"))
    ...
    model.save_weights(fname)
"""
# new model
model = Sequential()
model.add(Dense(2, input_dim=3, name="dense_1"))  # will be loaded
model.add(Dense(10, name="new_dense"))  # will not be loaded
 
# load weights from first model; will only affect the first layer, dense_1.
model.load_weights(fname, by_name=True)
(4)模型保存和加载
model.save('my_model.h5')  # creates a HDF5 file 'my_model.h5'

model = tf.keras.models.load_model('my_model.h5')

HDF5文件包含:模型的结构;模型的权重;训练配置(损失函数,优化器等);优化器的状态,以便于从上次训练中断的地方开始

(5)model.summary()需要注意的地方

需要先指定input_shape,或者你直接fit一遍它也能自动确定

model.build(input_shape=(None, 448, 448, 3))
model.summary()
(6)TimeDistributed(Dense)和Dense()层具有相同的结果(在某些情况下)

相同效果的情况: keras从版本2.0开始Dense默认仅应用于最后一个维度(例如,如果您应用于Dense(10)具有形状的输入,(n, m, o, p)您将获得具有形状的输出(n, m, o, 10)),因此这种情况下Dense与TimeDistributed(Dense)是等效的。

在其他情况下TimeDistributed(Dense)和Dense()层效果不同。
详情见:Keras 中 TimeDistributed 和 TimeDistributedDense 理解

7.4.3 模型训练
(1)回调函数Callbacks

回调函数是一组在训练的特定阶段被调用的函数集,你可以使用回调函数来观察训练过程中网络内部的状态和统计信息。通过传递回调函数列表到模型的.fit()中,即可在给定的训练阶段调用该函数集中的函数。

【Tips】虽然我们称之为回调“函数”,但事实上Keras的回调函数是一个类,回调函数只是习惯性称呼

keras.callbacks.Callback()

这是回调函数的抽象类,定义新的回调函数必须继承自该类

编写自己的回调函数
我们可以通过继承keras.callbacks.Callback编写自己的回调函数,回调函数通过类成员self.model访问访问,该成员是模型的一个引用。

这里是一个简单的保存每个batch的loss的回调函数:

class LossHistory(keras.callbacks.Callback):    #继承
    def on_train_begin(self, logs={}):
        self.losses = []

    def on_batch_end(self, batch, logs={}):     #重写on_batch_end
        self.losses.append(logs.get('loss'))
init_lr = 0.1  # 1.0

def lr_schedule(epoch):
    if epoch <= 10:
        return init_lr
    else:
        return init_lr * 0.85 ** (epoch - 10)

lr_schedule = callbacks.LearningRateScheduler(lr_schedule)  #学习率调整

early_stopping = callbacks.EarlyStopping(patience=10)       #早停

projection = PrototypeProjection(train_gen, freq=4)         #原型投影,频率为4

sgd = optimizers.SGD(learning_rate=init_lr, clipnorm=5.0)

pnet.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])

pnet.fit_generator(train_gen,
                   validation_data=test_gen,
                   epochs=25,
                   callbacks=[early_stopping, lr_schedule, projection],  #callbacks
                   shuffle=False)
7.5 构建高级模型
7.5.1模型子类化

通过对 tf.keras.Model 进行子类化,定义自己的前向传播来构建完全可自定义的模型。
init :创建层并将它们设置为类实例的属性
call: 定义前向传播

class MyModel(tf.keras.Model):
    def __init__(self, num_classes=10):
        super(MyModel, self).__init__(name='my_model')
        self.num_classes = num_classes
        self.layer1 = layers.Dense(32, activation='relu')      #__init__中建立层
        self.layer2 = layers.Dense(num_classes, activation='softmax')
    def call(self, inputs):
        h1 = self.layer1(inputs)
        out = self.layer2(h1)
        return out

model = MyModel(num_classes=10)
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),
             loss=tf.keras.losses.categorical_crossentropy,
             metrics=['accuracy'])

model.fit(train_x, train_y, batch_size=16, epochs=5)
7.5.2 自定义层

三个函数都是从tf.keras.layers.Layer处继承而来:
init():初始化成员变量;只初始化了输出数据的shape
build():对Layer进行初始化,都初始化了一些成员函数;在call()函数第一次执行时会被调用一次,这时候可以知道输入数据的shape输入数据的shape需要在build()函数中动态获取
call():在该layer被调用时执行。

例子:

class MyDenseLayer(tf.keras.layers.Layer):
  def __init__(self, num_outputs):
    super(MyDenseLayer, self).__init__()
    self.num_outputs = num_outputs

  def build(self, input_shape):
    self.kernel = self.add_variable("kernel",
                                    shape=[int(input_shape[-1]),
                                           self.num_outputs])

  def call(self, input):
    return tf.matmul(input, self.kernel)

layer = MyDenseLayer(10)

通过对 tf.keras.layers.Layer 进行子类化并实现以下方法来创建自定义层:

build:创建层的权重。使用 add_weight 方法添加权重。

call:定义前向传播。

import tensorflow as tf
from tensorflow.keras.layers import Layer as KerasLayer ###################

from prosenet.ops import distance_matrix


class Prototypes(KerasLayer):                          ####################
    """
    The 'Prototypes Layer' as a tf.keras Layer.
    """
    def __init__(self, k, dmin=1.0, Ld=0.01, Lc=0.01, Le=0.1, **kwargs):
        """
        Parameters
        ----------
        k : int
            Number of prototype vectors to create.
        dmin : float, optional
            Threshold to determine whether two prototypes are close, default=1.0.
            For "diversity" regularization. See paper section 3.2 for details.
        Ld : float, optional
            Weight for "diversity" regularization loss, default=0.01.
        Lc : float, optional
            Weight for "clustering" regularization loss, default=0.01.
        Le : float, optional
            Weight for "evidence" regularization loss, default=0.1.
        **kwargs
            Additional arguments for base `Layer` constructor (name, etc.)
        """
        super(Prototypes, self).__init__(**kwargs)
        self.k = k
        self.dmin = dmin
        self.Ld, self.Lc, self.Le = Ld, Lc, Le


    def build(self, input_shape):                                     #定义层
        # Create prototypes as weight variable
        # NOTE: had to add constraint to keep gradients from exploding

        self.d = input_shape[-1]

        # Makes sense to use same `initializer` as LSTM ?
        self.prototypes = self.add_weight(
            name='prototypes',
            shape=(1, self.k, self.d),
            initializer='glorot_uniform',                         #参数初始化方式
            constraint=lambda w: tf.clip_by_value(w, -1., 1.),    #约束
            trainable=True
        )


    def call(self, x, training=None):                            # 定义前向传播
        """Forward pass."""

        # L2 distances b/t encodings and prototypes
        x = tf.expand_dims(x, -2)
        d2 = tf.norm(x - self.prototypes, ord=2, axis=-1)

        # Losses only computed `if training`
        if training:
            dLoss = self.Ld * self._diversity_term()
            cLoss = self.Lc * tf.reduce_sum(tf.reduce_min(d2, 0))
            eLoss = self.Le * tf.reduce_sum(tf.reduce_min(d2, 1))
        else:
            dLoss, cLoss, eLoss = 0., 0., 0.

        self.add_loss(dLoss)
        self.add_loss(cLoss, inputs=True)
        self.add_loss(eLoss, inputs=True)

        # Return exponentially squashed distances
        return tf.exp(-d2)
7.6 tensorflow2张量的数学运算

参考:TensorFlow2.0:张量的数学运算

8 python学习

8.1 python方法
8.1.1 python字符串格式化方法——format函数

format用法(可以接受不限个参数,位置可以不按顺序
注意:外是引号,内是大括号,.format
例3:设置指定位置,按默认顺序

>>> "{} {}".format("hello","world")
'hello world'

例4:设置指定位置

"{0} {1}".format("hello","world")
'hello world'

例5:设置指定位置

>>>{1} {0} {1}.format("hello","world")
>'world hello world'
8.1.2 for循环中常用的——enumerate() 函数

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

>>>seq = ['one', 'two', 'three']
>>> for i, element in enumerate(seq):
...     print i, element
... 
0 one
1 two
2 three
8.2 numpy的方法
8.2.1 np.linalg.norm(求范数)

1、linalg=linear(线性)+algebra(代数),norm则表示范数。
2、函数参数
x_norm=np.linalg.norm(x, ord=None, axis=None, keepdims=False)
①x: 表示矩阵(也可以是一维)
②ord:范数类型

8.2.2 数组拼接

在这里插入图片描述

8.2.3 数组复制的坑——np.copy()

复制数组时一定要用np.copy(),如果直接用等号将旧数组赋值给新数组,那么改变新数组会影响旧数组。

import numpy as np 

# numpy 数组的复制和 python的list数组的复制是不同的
# 对于python的数组, 可以通过索引,完全复制新的数组
a = [1,2,3,4]
b = a[:]
#这里的 a 和 b是两个完全独立的数组,但是对于numpy并非如此

a_np = np.array([1,2,3,4])
b_np = a[:]
a_np[1] = 100
print(a_np)
print(b_np)
print(type(a_np))
print(type(b_np))
# 这里输出的a_np和b_np都是1, 100, 3, 4
# 要想完全复制a_np,要通过调用copy()
# 实际上这里的b_np并不是np数组,而是python的list
c_np = a_np.copy()
a_np[2] = 100
print(a_np)
print(c_np)
print(type(a_np))
print(type(c_np))
# 这里的输出结果是不同的,
# a_np是1, 100, 100, 4
# c_np是1, 100, 3, 4
8.2.4 获得数组的最大、小值索引

**np.unravel_index(a.argmax(), a.shape)**用法:
a.argmax()用于得出数组全局最大值序号;
np.unravel_index()用于将最大值序号转化为坐标。

a = np.array([[1, 2, 3],
              [4, 5, 6]])
print(a.argmax())                             #最大值是第几个
index = np.unravel_index(a.argmax(), a.shape) #最大值在数组中的位置
print(index)

输出:

5
(1, 2)

对于二维数组:

import numpy as np
a = np.array([[1, 2, 3],
              [4, 5, 6]])
index = np.unravel_index(a.argmax(), a.shape)
print(index)
>>>(1, 2)

三维数组:

import numpy as np
a = np.array([[[1, 2, 3],
              [4, 5, 6]]])
index = np.unravel_index(a.argmax(), a.shape)
print(index)
>>>(0, 1, 2)

一句话搞定,获得二维或多维数组最值的索引。

argmin()的用法

用来检索数组中最小值的位置,并返回其下标值。同理,argmax()函数就是用来检索最大值的下标,与argmin()函数用法相同。在argmin()函数的标准语法中,numpy.argmin(a, axis=None, out=None),其中的axis参数为默认和给定值时输出情况是不一样的。

在没有指定axis值的情况下,默认为None。在默认情况下,就相当于将n维的arry平铺在一起。举个简单的例子,当二维arry([1,2,3],[4,5,6])平铺开来就是([1,2,3,4,5,6])。

a =  np.array([[2,5,6],[7,6,1]])

print(np.argmin(a))

对于这个二维arry来说,它的最小值是1,而1的下标为5,所以最后输出的值就是5。
当axis = 1时,按照方向来,对于[2,5,6]来说最小值的下标是0,对于[7,6,1]来说最小值的下标是2。所以,最后输出的值就是[0,2]。
当axis = 0时,这时按照方向来,[2,7],[5,6],[6,1]分别在一个轴上,所以检索每个轴上的最小值,并返回下标,最后就可以得到输出值[0,0,1]。

8.2.5 np.unique( )去除数组中的重复数字

该函数是去除数组中的重复数字,并进行排序之后输出。
在这里插入图片描述

8.2.6 reshape的坑——IndexError: invalid index to scalar variable.

生成了一个长度为10的一维数组,然后使用reshape转换成2x5的矩阵,但是在取矩阵值的时候出现索引错误

import numpy as np
a = np.arange(0,10)
a.reshape(2,5)
a[1][1]

原因:数组a经过reshape后,a中的内容没有变,需要重新赋值

import numpy as np
a = np.arange(0,10)
b = a.reshape(2,5)
b[1][1]
6

输出了正确值

8.2.7 np.where()——获取数组中指定元素的索引位置
import numpy as np
a = np.array([1,2,3,4,5,6,6,7,6])
b = np.where(a == 6)
# b = np.argwhere(a ==6 )
print(b)

9 音频处理

9.1 ffmpeg用法
9.1.1 剪切音视频
ffmpeg -i /data/video/1.mp4 -ss 00:00:05.000 -to 00:00:06.000 -strict -2 /data/video/splt.mp4 

注:报错提示:The encoder ‘acc’ is experimental codecs are not enabled, add ‘-strict -2’ if you want to use it
在这里插入图片描述

9.1.2 从视频中提取音频

提取为mp3格式

ffmpeg -i huoying.mp4 -f mp3 -ar 16000 -ac 1 huoying.mp3
//huoying.mp4 视频文件
//-f mp3 mp3编码
//-ar 16000 音频采样率16000
//-ac 1 输出通道数1
//huoying.mp3输出的音频文件

提取为wav格式

ffmpeg -i huoying.mp4 -f wav -ar 16000 huoying.wav
9.2 librosa
9.2.1 librosa遇到的坑

10 声学事件检测

10.1 检测指标(TP,FP,TN,FN,精确率召回率等直观图)

在这里插入图片描述
声学事件检测中的ER指标参照了语音识别中的ER计算方法。
ER的计算方法:(帧级别)在这里插入图片描述
代码实现有两种方式:
法一:

def er_overall_framewise(O, T):  #O为参考标签,T为实际输出的标签
    
    if len(O.shape) == 3:
        O,T = utils.reshape_3Dto2D(O), utils.reshape_3Dto2D(T)
        
    FP = np.logical_and(T == 0, O == 1).sum(1)
    FN = np.logical_and(T == 1, O == 0).sum(1)

    S = np.minimum(FP, FN).sum()
    D = np.maximum(0, FN-FP).sum()
    I = np.maximum(0, FP-FN).sum()

    Nref = T.sum()
    ER = (S+D+I) / (Nref + 0.0)
    return ER

法二:与法一计算的方式不同,但结果一样

def er_overall_framewise(O, T):
    #这是错误的方法
    # if len(O.shape) == 3:
    #     O, T = utils.reshape_3Dto2D(O), utils.reshape_3Dto2D(T)
    # TP = ((2 * T - O) == 1).sum()
    # Nref, Nsys = T.sum(), O.sum()
    # ER = (max(Nref, Nsys) - TP) / (Nref + 0.0)

    #这是正确的方法
    if len(O.shape) == 3:
        O, T = utils.reshape_3Dto2D(O), utils.reshape_3Dto2D(T)
    TP = ((2 * T - O) == 1).sum(1)
    Nref, Nsys = T.sum(1), O.sum(1)
    a = np.vstack((Nref, Nsys))
    b = np.amax(a, axis = 0)
    Nref1 = T.sum()
    ER = (b - TP).sum() / (Nref1 + 0.0)
    return ER
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值