我是靠谱客的博主 深情早晨,最近开发中收集的这篇文章主要介绍学习分享——基于深度学习的NILM负荷分解(四)深度学习实现,代码讲解定义全局参数读取电器数据制作标签组合数据与标准化迭代器拆分数据迭代器建立简单网络来测试建立网络进行训练测试集,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

QQ群1070535031
跟随上一篇的思路,本篇我们来实现整个流程。

实验需求

跟随本文进行学习和实验,需要前面博文中的环境,以及提取出来的UK数据。(学习分享——基于深度学习的NILM负荷分解(二)电器数据提取)

本文的代码思路在上一篇,本文着重介绍代码实现相关。思路方面看一下(学习分享——基于深度学习的NILM负荷分解(三)深度学习处理,基础思路)

实验环境:
pycharm,python 3.6+,keras库,numpy库,matplotlib库
以及UKData。

定义全局参数

首先引用所有需要的库,如下:

import numpy as np
import os
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSprop
from keras.models import load_model

然后是定义一些全局参数:

# 全局参数定义
dimension = 5 #电器的个数
#电器id定义
fridge_id = 0
tv_id = 1
kettle_id = 2
microwave_id = 3
washerdryer_id = 4
#电器开启状态阈值
fridge_threshold = 20
tv_threshold = 20
kettle_threshold = 20
microwave_threshold = 10
washerdryer_threshold = 0
#消噪音阈值
air_threshold = 5

挨个介绍一下上面的参数

dimension :是我们训练的电器的类别个数。5个是当前初步试验所设。

电器id:是我们选择出的五种电器的自增长id。(这里我们选择:冰箱,电视,水壶微波炉和洗衣烘干机)

电器开启状态阈值:这个的作用是屏蔽一些干扰,即,低于该值时认为电器不开启。

消噪音阈值:总功的噪音去燥。将改值以下认为是噪音,忽略。

读取电器数据

fridge_data = np.load('UKData/Fridge freezer0.npy')
print(fridge_data.shape)
fridge_data = fridge_data[:1600000]
print(fridge_data.shape)
fridge_data = np.where(fridge_data > air_threshold,fridge_data,0)
television_data = np.load('UKData/Television0.npy')
print(television_data.shape)
television_data = television_data[:1600000]
print(television_data.shape)
television_data = np.where(television_data > air_threshold, television_data,0)
kettle_data = np.load('UKData/Kettle0.npy')
print(kettle_data.shape)
kettle_data = kettle_data[0:1600000]
print(kettle_data.mean)
kettle_data = np.where(kettle_data > air_threshold, kettle_data,0)
microwave_data = np.load('UKData/Microwave0.npy')
print(microwave_data.shape)
microwave_data = microwave_data[:1600000]
print(microwave_data.shape)
microwave_data = np.where(microwave_data > air_threshold, microwave_data,0)
washerdryer_data = np.load('UKData/Washer dryer0.npy')
print(washerdryer_data.shape)
washerdryer_data = washerdryer_data[:1600000]
print(washerdryer_data.shape)
washerdryer_data = np.where(washerdryer_data > air_threshold, washerdryer_data,0)

上面的代码,直接从之前我们读取出来的各个电器中,选择我们训练用的电器,读取出来,并取出相同长度(1600000)的数据(有用功)。同时将低于阈值air_threshold的进行取0操作,目的是去燥。

制作标签

def create_label(data, application_id, power_threshold, dimension):
labels = np.zeros((len(data), dimension))
for i, value in enumerate(data):
if value[0] > power_threshold:
labels[i,application_id] = 1
return labels

上面的方法,输入为数据,电器id,开启状态阈值,电器个数。
输出为,电器个数长度的一维数组。某时刻,对应电器开启时,对应id的位置为1,关闭时为0.

data是每一个时刻的负荷,label是每一个时刻的电器开启状态。

举例:label默认每一时刻是 [0,0,0,0,0],假如某时刻id为1的电器开启,则该时刻的label为 [0,1,0,0,0]

下面的代码是分别生成五个电器,每个电器的label

fridge_labels = create_label(fridge_data,fridge_id,fridge_threshold,dimension)
tv_labels = create_label(television_data,tv_id,tv_threshold,dimension)
kettle_labels = create_label(kettle_data,kettle_id,kettle_threshold,dimension)
microwave_labels = create_label(microwave_data,microwave_id,microwave_threshold,dimension)
washerdryer_labels = create_label(washerdryer_data,washerdryer_id,washerdryer_threshold,dimension)

组合数据与标准化

我们将五个电器的数据进行整合,有用功直接加在一起,变成每一个时刻有用功的和。

label标签也组合在一起,因为上面生成的标签,每个电器对应一列,所以直接相加即可。

sum_label = fridge_labels + tv_labels + kettle_labels + microwave_labels + washerdryer_labels
sum_data_num = fridge_data + television_data + kettle_data + microwave_data + washerdryer_data

然后可以画个图看一下,我们的label

#画图查看数据
epochs = range(1,len(sum_label[:,0])+1)
plt.plot(epochs,sum_label[:,0],label='fridge_labels')
plt.plot(epochs,sum_label[:,1],label='tv_labels')
plt.plot(epochs,sum_label[:,2],label='kettle_labels')
plt.plot(epochs,sum_label[:,3],label='microwave_labels')
plt.plot(epochs,sum_label[:,4],label='washerdryer_labels')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()

画出来是这样的,每个颜色就是开启

在这里插入图片描述

考虑到训练效率和效果,我们对数据进行归一化,如下:

mean = sum_data_num[:1600000].mean(axis=0)
sum_data = sum_data_num - mean
std = sum_data[:1600000].std(axis=0)
sum_data /= std

迭代器

我们只用了一个房间的160w的数据,但所用的数据量还是比较大的,为了之后更大量数据考虑。我们使用迭代器来进行数据输入,以减小内存的使用。每次迭代器来取数据输入训练迭代。

def generator(data, label, lookback, delay, min_index, max_index, shuffle=False, batch_size=128, step=1):
if max_index is None:
max_index = len(data) - delay - 1
i = min_index + lookback
while 1:
if shuffle:
rows = np.random.randint(min_index + lookback, max_index, size=batch_size)
else:
if i + batch_size >= max_index:
i = min_index + lookback
rows = np.arange(i, min(i + batch_size, max_index))
i += len(rows)
samples = np.zeros((len(rows),
lookback // step,
data.shape[-1]))
targets = np.zeros((len(rows),dimension))
for j, row in enumerate(rows):
indices = range(rows[j] - lookback, rows[j], step)
samples[j] = data[indices]
targets[j] = label[rows[j] + delay]
yield samples, targets

这一块逻辑可能有点复杂,慢慢看。

参数:
data:数据。
label:标签。
lookback:上一节提到的窗口大小,这里是往回看的窗口。
delay:预测后面几帧的结果(这里我们默认为0,因为是预测分解当前帧的结果,不需要往未来看)
min_index:从数据的哪一帧开始看
max_index:从数据的哪一帧结束
shuffle:是否随机
batch_size:迭代中每一个批量的个数
step:每取一次数据,向后跳几帧

这个方法的意思,就是取总的数据中的min_index到max_index这段范围中的数据,每个批量是batch_size,每次往回取lookback窗口大小的数据,取完一次向后跳step个再取下一次。shuffle为是否随机开始取的位置。
delay可以忽略。

实在看不懂的,可以群里面私聊我,或者等我开直播讲。

拆分数据迭代器

首先定义一些迭代器的超参
分别是窗口大小,向后跳的步伐,预测当前帧(delay=0),批量大小

lookback = 20
step = 1
delay = 0
batch_size = 128

具体每个参数的大小设置,我之后的文章,分析各个超参的作用和影响的时候,在做具体讲解。

然后就是定义各个迭代器:

train_gen = generator(sum_data,
sum_label,
lookback=lookback,
delay=delay,
min_index=0,
max_index=800000,
shuffle=True,
step=step,
batch_size=batch_size)
val_gen = generator(sum_data,
sum_label,
lookback=lookback,
delay=delay,
min_index=800001,
max_index=1200000,
step=step,
batch_size=batch_size)
test_gen = generator(sum_data,
sum_label,
lookback=lookback,
delay=delay,
min_index=1200001,
max_index=None,
step=step,
batch_size=batch_size)

一共是160w帧数据,我用取前80w作为训练,80-120w作为验证,120-160w作为测试。

训练集数据使用随机处理。

然后计算一下每次迭代运算批数

train_steps = 800000 // batch_size
val_steps = (1200000 - 800001 -lookback) // batch_size
test_steps = (len(sum_data) - 1200001 -lookback) // batch_size

建立简单网络来测试

#双向循环网络
model = Sequential()
model.add(layers.Bidirectional(
layers.GRU(32,dropout=0.1), input_shape=(None,sum_data.shape[-1])))
model.add(layers.Dense(dimension,activation='sigmoid'))
model.compile(optimizer=RMSprop(), loss='binary_crossentropy',metrics=['acc'])
history = model.fit_generator(train_gen,
steps_per_epoch=train_steps,
epochs=2,
validation_data=val_gen,
validation_steps=val_steps)
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1,len(loss)+1)
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and Validation loss')
# plt.legend()
plt.show()
plt.clf() #清空图表
acc_values = history.history['acc']
val_acc_values
= history.history['val_acc']
plt.plot(epochs,acc_values,'bo',label='Training acc') #bo是蓝色圆点
plt.plot(epochs,val_acc_values,'b',label='Validation acc') #b是蓝色实线
plt.title('Training and validation accuracy')
plt.legend()
plt.show()

我这里使用的是keras的方式来做测试,双向GRU,链接一层全连接输出。

然后设置一下参数,优化器,以及输出,迭代2次。

训练结束我并没有存模型,因为上面这个网络只是测试一下,并不是我们既定的完整网络结构。

可以跑一下,看看上面的流程有没有问题。

跑完会绘制出两个图,一个是loss,一个是acc。

运行过程中如下:
在这里插入图片描述

静静等待2次迭代。
可以看到两次迭代,loss在下降收敛,准确率acc在上升。看验证acc会体现训练中的模型的鲁棒性。
在这里插入图片描述

在这里插入图片描述

建立网络进行训练

下面我提供我进行了一系列验证后,较优质的网络结构,供参考。

不过希望同学们,自行研究和实践各种网络结构的组合,包括各种超参的调整。

例如全连接网络,卷积网络,循环网络。以及上述网络的各种组合方式。

只有自己不断尝试,积累经验,才能设计和训练出更好的模型。

循环网络+一维卷积
model = Sequential()
model.add(layers.Conv1D(32, 5, activation='relu', input_shape=(None,sum_data.shape[-1])))
model.add(layers.MaxPooling1D(3))
model.add(layers.Conv1D(32, 5, activation='relu'))
model.add(layers.LSTM(32, dropout=0.1))
# model.add(layers.GlobalMaxPooling1D())
model.add(layers.Dense(dimension,activation='sigmoid'))
model.compile(optimizer=RMSprop(), loss='binary_crossentropy',metrics=['acc'])
history = model.fit_generator(train_gen,
steps_per_epoch=train_steps,
epochs=20,
validation_data=val_gen,
validation_steps=val_steps)
# model.save('model.h5') 
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1,len(loss)+1)
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and Validation loss')
# plt.legend()
plt.show()
plt.clf() #清空图表
acc_values = history.history['acc']
val_acc_values
= history.history['val_acc']
plt.plot(epochs,acc_values,'bo',label='Training acc') #bo是蓝色圆点
plt.plot(epochs,val_acc_values,'b',label='Validation acc') #b是蓝色实线
plt.title('Training and validation accuracy')
plt.legend()
plt.show()

我上述这个模型:一维卷积作用为提炼数据,LSTM(或双向LSTM)来学习变化规律,全连接层输出结果。

超参(例如每层的大小,卷积核,窗口大小等等等)和层数(可以两层lstm,可以最后两层全连接等地的的) 各种组合,需要尝试,欢迎大家来群里共同探讨实验结果。

测试集

最后跑测试集,进行在未参与训练的数据中进行预测。

测试集测试
test_loss, test_acc = model.evaluate_generator(test_gen,steps=test_steps)
print('test acc : ', test_acc)

有不懂的,或者想法问题,可以留言我。
或者QQ群1070535031

对于代码中的很多参数和用法,没有详细描述。后面我单独在写一篇来详说吧。

在这里插入图片描述

最后

以上就是深情早晨为你收集整理的学习分享——基于深度学习的NILM负荷分解(四)深度学习实现,代码讲解定义全局参数读取电器数据制作标签组合数据与标准化迭代器拆分数据迭代器建立简单网络来测试建立网络进行训练测试集的全部内容,希望文章能够帮你解决学习分享——基于深度学习的NILM负荷分解(四)深度学习实现,代码讲解定义全局参数读取电器数据制作标签组合数据与标准化迭代器拆分数据迭代器建立简单网络来测试建立网络进行训练测试集所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部