
지난 글에서는 전처리한 '고양시 전력데이터'에 대하여 각각 FFT 분석과 이상탐지 분석을 실시한 결과에 대해 정리하였습니다.
https://powderblue0.tistory.com/17
[Nilm] (4)-FFT와 이상탐지
지난 글에서는 데이터 선정 과정과 다운로드한 "대용량 데이터"를 어떻게 "다룰 수 있는 수준"까지 줄였는지에 대해 정리하였습니다. 아래에서 지난 글을 확인할 수 있으니 참고 바랍니다. https:/
powderblue0.tistory.com
이번 글에서는 본격적으로 모델 빌드 과정에 대해 서술해보도록 하겠습니다.
모델의 목표는 전체 전력에서 개별 전력을 분해해내는(=Nilm) 것이었습니다.
이러한 복잡한 모델을 만들 경우 아무것도 없는 상태부터 모델을 만드는 것이 아닌, 기존에 존재하는 모델을 참고 혹은 일부 참고하여 베이스라인을 미리 잡아두는 것이 적절합니다.
저의 경우 이전 '(3)-데이터 선정과 전처리'글에서 잠깐 언급했던 UNet 모델을 참고하였습니다. 결론적으로 말하면 성공적이었다고 할 수는 없으나, 모델 빌딩 과정과 과정에서 겪은 다양한 어려움 등에 대해 정리해두려고 합니다.
목차
- 참고논문 정리(Multi-task NILM Model)
- 1D CNN과 UNet은 무엇인가?
- 베이스라인 모델(Baseline Model)
- 데이터 전처리 과정
- 1D CNN 모델 만들기
- 1D CNN 모델 학습과정
- 1D CNN 모델학습 결과
참고논문 정리(Multi-task NILM Model)
모델 베이스라인에 참고한 논문은 Anthony Faustine의 UNet-NILM: A Deep Neural Network for Multi-tasks Appliances State Detection and Power Estimation in NILM 입니다. 전체 논문은 구글에 논문 제목 그대로 검색하거나 아래 링크에서 보실 수 있습니다.
https://dl.acm.org/doi/10.1145/3427771.3427859
UNet-NILM | Proceedings of the 5th International Workshop on Non-Intrusive Load Monitoring
Energy disaggregation, a.k.a. Non-Intrusive Load Monitoring, aims to separate the energy consumption of individual appliances from the readings of a mains power meter measuring the total energy consumption of, e.g., a whole house. Energy consumption of ...
dl.acm.org

이전에 Nilm에서의 분류와 회귀 과제 정의에 대해 다음과 같이 설명한 바 있습니다.
Nilm을 분류 문제로 바라볼 경우 ‘전력량 분해’는 전체 전력을 보고 ‘각 기기가 켜져 있는지, 혹은 꺼져 있는지’ 즉 ON/OFF 상태를 예측하는 이진 분류(Classification) 문제가 되고
Nilm을 회귀 문제로 바라볼 경우 ‘전력량 분해’는 전체 전력에서 ‘각 기기가 얼마만큼의 전력량을 사용하고 있는지’를 예측하는 회귀(Regression) 문제가 되는 것
이 논문에 소개된 UNet 모델의 핵심은, 제목 그대로 Regression과 Classification을 동시에 수행하는 Multi-task 모델을 만든 것에 있습니다. Abstract에 나온 부분을 그대로 인용하자면, appliances’ state detection and power estimation 라고 명시되어 있습니다.
또한 The UNet-NILM is a one-dimenstional CNN based on the U-Net architecture 라고도 서술되어 있는데, "1D CNN을 기반으로 (즉, 1D 버전의 컨볼루션 레이어를 사용) UNet 아키텍쳐에 맞게 모델을 설계한 것이다" 라고 이해하시면 될 것 같습니다. UNet모델을 기존의 CNN 모델과 비교한 결과 UNet 모델의 성능이 더 좋다는 것이 논문이 낸 결론입니다.
결론적으로 논문의 핵심 내용을 요약하자면
- 개별 전력량 예측(회귀)와 개별 기기 ON/OFF 여부(이진분류)를 모두 판단(Multi-task)하는 모델
- 기존 CNN모델과 비교했을 때, UNet 아키텍쳐의 모델이 더 성능이 좋음
이 되겠습니다.
이후 설명을 위해 개별 기기의 전력량 예측(회귀)는 Power Prediction, 개별 기기의 ON/OFF 상태 판정(이진분류)는 State Prediction이라고 부르겠습니다.
1D CNN과 UNet은 무엇인가?
말이 나온 김에 1D CNN과 UNet에 대해서도 정리해봅시다.
(1) 1D CNN이란?

https://github.com/SRDdev/Dogs_vs_Cats-CNN
GitHub - SRDdev/Dogs_vs_Cats-CNN: Binary Image Classification . This project uses basic Machine Learning Algorithms to different
Binary Image Classification . This project uses basic Machine Learning Algorithms to differentiate between 🐱Cats & 🐶Dogs - GitHub - SRDdev/Dogs_vs_Cats-CNN: Binary Image Classification . This ...
github.com
위의 링크 참고하시면 조와요 ^^
기본적으로 CNN(Convolutional Neural Network)의 핵심은 특징 추출에 있습니다. 보통 컨볼루션을 설명하기 위해 이미지 분석을 예로 들고는 하는데, 가장 CNN 원리에 들어맞는 설명이기 때문입니다.
예를 들어 컨볼루션 레이어로 강아지 이미지를 학습하게 되면, 필터가 이동하면서 이미지의 특징(예를 들어 강아지의 귀, 코, 눈, 꼬리 등)을 잡아내고, "강아지 같다"라는 결론을 내는 것입니다.

이미지의 경우는 가로와 세로가 있기 때문에 2D CNN에 해당하고, 여기서 다루는 전력 데이터의 경우 가로x세로의 형태가 아니라 시간축을 기준으로 쭉 나열되어 있는 구조이기 때문에 1D CNN인 것입니다.
즉, 시간축을 따라 1차원적으로 필터가 지나가면서 특징을 잡아내게 (=특징 추출) 되는 것입니다.
(2) UNet이란?
UNet은 모델 아키텍쳐에 해당되는데, 여기서 아키텍쳐(Architecture)라는 것은 '어떤 구조를 가지는가' 즉 '모델의 설계도, 설계 방식'에 해당합니다.

위의 그림은 논문에서 UNet 모델을 설명할 때 첨부한 그림인데, 말 그대로 구조가 U자 처럼 생겨서 U-Net이라고 불리는 것입니다.
정말 간단하게 정리하자면 UNet의 경우 밑으로 내려가면서는 정보를 압축(= 특징 추출, Encoder)를 하고 다시 올라가는 부분에서는 정보 복원(= 해상도 복원, Decoder)를 하는 구조(설계구조)를 가집니다.
그리고 여기서 Skip-Connection이라는 개념도 등장하는데, 여기서부터는 저도 잘 몰라서 이에 대한 자세한 설명의 경우 아래 글에 잘 정리되어 있는 것 같으니 참고하시면 좋겠습니다.
https://ai-bt.tistory.com/entry/U-Net-%EC%9D%98-%EC%9D%B4%ED%95%B4
U-Net 의 이해
U-Net은 이미지 분할(Image Segmentation) 문제를 해결하기 위해 개발된 합성곱 신경망(CNN) 기반의 모델이다. 이 모델은 2015년에 Olaf Ronneberger와 그의 동료들에 의해 의료 영상 분석을 위해 제안되었으며
ai-bt.tistory.com
베이스라인 모델(Baseline Model)
다시 처음으로 돌아가서, 저의 목적은 '전체 전력에서 개별 전력을 분해하는 모델을 만드는 것'이었습니다.
이걸 처음(제로베이스)부터 하나하나 만드는 게 아닌 다른 모델을 참고하여 가장 간단한 베이스라인(기본 모델)을 만들어 놓고, 점점 발전해나가자는 것이 목표였습니다.
이렇듯 모델 빌딩 과정에서 베이스라인(가장 기본이 되는 모델, 가장 가벼운 모델)을 만들어두는 것이 중요한 이유는
- 발전된 모델과의 비교 대상 → 성능 개선의 비교 기준
- 파이프라인 설정 → 이후 과정에서의 정상 작동 확인
- 디버깅의 용이성 → 에러의 정확한 원인 파악에 용이
등등... 이 있습니다.
생각해보면 애초에 처음부터 완벽한 새로운 모델을 만드는 것은 말도 안 되는 일입니다. 그래서 저는 베이스라인 모델로 UNet 모델이 아닌 참고논문에서의 비교자료로 쓰인 CNN1D 모델을 먼저 만들기로 하였습니다.
코드는 위 논문 UNet-NILM: A Deep Neural Network for Multi-tasks Appliances State Detection and Power Estimation in NILM의 저자 Anthony Faustine이 올려둔 것을 참고하였습니다.
https://github.com/sambaiga/UNETNiLM
GitHub - sambaiga/UNETNiLM
Contribute to sambaiga/UNETNiLM development by creating an account on GitHub.
github.com
요즘에는 이런 식으로 코드와 논문을 같이 공개하는(혹은, 공개해야 하는) 경우가 대다수입니다. 보통 논문(Paper)를 먼저 공개하고 이후에 코드를 공유하는 식으로 진행되니 공부하시는 분들은 잘 써먹으세여~~
데이터 전처리 과정
현재 데이터는 Pandas의 데이터프레임 형태로 존재합니다. 그리고 파이토치로 모델을 만들 것이기 때문에 이 시계열 전력 데이터(이전 글에서의 '고양시 전력데이터'를 그대로 사용합니다.)를 파치토치 텐서 형태로 바꿔줄 필요가 있습니다.
즉, 이전에 수행한 전처리에 더해 모델에 돌릴 수 있는 형태로 만드는 추가 전처리 과정이 필요합니다.
전체적인 추가 전처리 과정은 다음과 같습니다.
- 전체 전력량 기준으로 Min-Max Scaling
- Feature Data와 Target Data 만들기
- Pytorch 텐서 변환 과정
과정을 하나하나 정리하자면 다음과 같습니다.
(1) 전체 전력량 기준으로 Min-Max Scaling
대부분의 머신러닝 모델 학습 과정에서 스케일링은 필수적인 과정입니다. 적절한 스케일링을 통해 모델이 왜곡 없이 데이터를 받아들일 수 있게 해야 합니다.
스케일링의 방법은 여러가지가 존재하나 중요한 것은 모델이 왜곡없이(=다른 오해 없이) 받아들일 수 있는 형태로 하되 정보 손실을 최소화 하는 방법으로 스케일링 하는 것이 중요합니다. (누가 한 말은 아니고, 그냥 제 생각입니다...)
해당 전력 데이터의 경우 '전체 전력대비 개별 기기의 전력'이라는 정보를 유지하기 위해 전체 전력량을 기준으로 Min-Max Scaling을 선택하였습니다.
(2) Feature Data와 Target Data 만들기
모델을 만들기 전에 먼저 확실하게 정해두고 시작해야 하는 것이 있습니다.
- 모델이 해결해야 하는 과제가 무엇인지 (과제정의: 회귀인지, 분류인지)
- Feature와 Target이 각각 무엇인지
과제 정의의 경우 위에서 충분히 정의하였으니 Feature와 Target이 무엇이 될지를 명확히 하고 가야합니다.
즉, 모델이 무엇을 Input으로 받고 Output으로 무엇을 낼지를 정해줘야 한다는 것입니다. 해당 베이스라인 모델의 경우
- Input으로 전체 전력반의 active power(유효전력)을 받고
- Output으로 개별 기기의 유효전력(power)와 ON/OFF 상태(state)를 출력
해야 합니다. 예시로 Target Data를 만드는 과정은 다음과 같습니다.
# 개별 기기의 데이터
target_dfs = [df_ch02, df_ch03, df_ch07, df_ch09, df_ch10, df_ch23]
# 유효전력(power)와 ON/OFF 상태(state) 데이터
power_dfs = [
df[['date_time', 'active_power']].rename(columns={'active_power': f'power_{i}'})
for i, df in enumerate(target_dfs)]
state_dfs = [
df[['date_time', 'active_inactive']].rename(columns={'active_inactive': f'state_{i}'})
for i, df in enumerate(target_dfs)]
# 데이터셋 병합 과정
power_merged = power_dfs[0]
for df in power_dfs[1:]:
power_merged = pd.merge(power_merged, df, on='date_time', how='outer')
state_merged = state_dfs[0]
for df in state_dfs[1:]:
state_merged = pd.merge(state_merged, df, on='date_time', how='outer')
(3) Pytorch 텐서 변환과정
앞서 설명했듯 현재 데이터는 Pandas의 DataFrame 형태로 존재합니다.
딥러닝 모델은 파이토치를 사용해 만들 것이기 때문에 데이터를 적절한 텐서 형태로 만들어줘야 합니다. 구체적인 과정(파이프라인)은 다음과 같습니다.
- 우선 DataFrame을 array 형태로 변환
- 텐서로 바꿔주기 전에, 시계열 데이터를 시간 순서대로 train test split
- Windowing 과정: 시퀀스 단위 재배치
- 파이토치 텐서로 변환
각 과정에 대해 조금 더 자세히 설명해보자면
시계열 데이터이기 때문에 데이터를 섞어서(shuffle) train 데이터와 test 데이터를 나누는 것이 아닌, 시간 순서대로 split해줘야 합니다.
또한 여기서 말하는 Windowing 과정이란, 시계열 데이터를 “작은 조각의 학습 단위”로 쪼개는 작업입니다. 그리고 ‘시간에 따른 흐름’을 모델이 관찰할 수 있도록 이를 하나의 묶음(Sequence)로 만들어 줘야 합니다.
위에서 말한 ‘시퀀스 단위 재배치’는 이 시퀀스(묶음) 단위로 데이터를 재배치하는 과정을 뜻합니다.
1D CNN 모델 만들기
실제로 모델을 만드는 과정에서는 다음 코드를 참고하였습니다.
https://github.com/sambaiga/UNETNiLM/blob/master/src/net/layers.py
UNETNiLM/src/net/layers.py at master · sambaiga/UNETNiLM
Contribute to sambaiga/UNETNiLM development by creating an account on GitHub.
github.com
사실 파이토치로 모델 만드는 과정에서 쓰인 레이어들도 다 가져오려고 했는데, 각 레이어들이 너무 무거워서 모델이 돌아가다가 중간에 멈춰버리는 문제점이 있었습니다.
그래서 실제로 쓰이는 부분들만을 가져와서(조건절 코드의 생략 등) 간단하게 레이어들을 선언하고, 모델을 만들었습니다.
모델에 쓰이는 각 레이어는(코드 생략) 다음과 같습니다.
- MLPLayer: 완전 연결층 블록으로, Linear 층 및 활성화함수 포함
- Conv1D: 컨볼루션 레이어의 기본 단위
- Encoder: 위에서 선언한 Conv1D 레이어를 쌓아올려, 특징 추출의 역할을 함
이를 바탕으로 한 전체 모델은 다음과 같습니다.
class CNN1DModel(nn.Module):
def __init__(self, in_size=1,
output_size=12,
d_model=128,
dropout=0.01,
seq_len=9,
n_layers=5,
n_quantiles=1,
pool_filter=16):
super().__init__()
self.enc_net = Encoder(n_channels=in_size, n_kernels=d_model, n_layers=n_layers, seq_size=seq_len)
self.pool_filter = pool_filter
self.mlp_layer = MLPLayer(in_size=d_model*pool_filter, hidden_size=1024, output_size=None)
self.dropout = nn.Dropout(dropout)
self.pool_filter = pool_filter
self.n_quantiles = n_quantiles
self.fc_out_state = nn.Linear(1024, output_size*2)
self.fc_out_power = nn.Linear(1024, output_size*n_quantiles)
# 출력 제약: 전력은 0 이상만 나오도록 ReLU
self.power_act = nn.ReLU()
nn.init.xavier_normal_(self.fc_out_state.weight)
nn.init.xavier_normal_(self.fc_out_power.weight)
self.fc_out_state.bias.data.fill_(0)
self.fc_out_power.bias.data.fill_(0)
def forward(self, x):
x = x.permute(0,2,1)
B = x.size(0)
conv_out = self.dropout(self.enc_net(x))
conv_out = F.adaptive_avg_pool1d(conv_out, self.pool_filter).reshape(x.size(0), -1)
mlp_out = self.dropout(self.mlp_layer(conv_out))
states_logits = self.fc_out_state(mlp_out).reshape(B, 2, -1)
# 전력 출력 → Linear + ReLU
power_logits = self.fc_out_power(mlp_out)
power_logits = self.power_act(power_logits)
if self.n_quantiles > 1:
power_logits = power_logits.reshape(B, self.n_quantiles, -1)
return states_logits, power_logits
마지막 부분을 보시면 위에서의 설명대로 모델이 개별 기기의 ON/OFF 상태 예측(state_logits)와 개별 기기의 전력량 예측(power_logits)을 동시에 예측하는 Multi-task Model임을 확인할 수 있습니다.
1D CNN 모델 학습과정
(1) Feature Data 구조 변경
실제로 모델을 돌리는 과정에서는 이런저런 시행착오들이 존재하였습니다. 위에서 모델의 Feature Data(=Input)과 Target Data(=Output)에 대해 다음과 같이 정의하였습니다.
- Input으로 전체 전력반의 active power(유효전력)을 받고
- Output으로 개별 기기의 유효전력(power)와 ON/OFF 상태(state)를 출력
이때 Input으로 학습시킬 Feature Data의 일부는 다음과 같습니다. (전체 전력반의 유효전력)

이때 발생한 문제점은 Feature로 넣어줘야 하는 데이터가 시계열 데이터 특성 상 너무 "세로로 긴" 형태였다는 것입니다.

실제로 확인해보면 데이터가 864,000개나 됩니다. 모델이 받는 데이터가 너무 길다보니 애초에 학습코드가 끊임없이 돌아가거나 돌아가다 멈추는 문제가 발생하였습니다.
이에 대한 해결로 30개의 데이터들을 합쳐 하나로 "옆으로 길게" 나열하는 방법을 선택하게 됩니다. 즉, 00시 00분 0.1초부터 00시 00분 3.0초까지의 데이터를 하나의 행으로 옆으로 나란히 세우는 겁니다. 이렇게 되면 Feature Data의 shape을 (864000,2)에서 (28800,31)로 바꿀 수 있게 됩니다.

사실 이건 교수님이 해주신 조언이었는데,
어차피 시간흐름에 따른 전력 흐름의 패턴을 찾는 것이 1D CNN모델의 역할이기 때문에, 이러한 "옆으로 긴" 형태로 바꿔줘도 무방할 것이라는 생각이었습니다.
(2) 모델 학습 코드
모델 학습 코드의 경우 여느 파이토치 모델학습 코드와 다를 것은 없습니다. 다만 위에서 설명하였듯이 Power Prediction과 State Prediction을 동시에 수행하는 모델이기 때문에 이에 대한 criterion을 각각 정의해줘야 합니다.
# 손실함수 및 optimizer 정의
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion_state = nn.CrossEntropyLoss() # 우선은 클래스가 2개인 다중분류로, CrossEntropyLoss 사용
criterion_power = nn.MSELoss()
num_epochs = 50 # epoch 개수 설정
total_losses = [] # loss 값 저장용
state_losses = []
power_losses = []
for epoch in range(num_epochs):
model.train()
optimizer.zero_grad()
states_logits, power_logits = model(x_train_tensor)
# 상태 예측 loss
state_loss = 0
for i in range(state_train_tensor.shape[1]): # 12개 가전
state_loss += criterion_state(states_logits[:, :, i], state_train_tensor[:, i])
state_loss /= state_train_tensor.shape[1]
# Loss 구하기
power_loss = criterion_power(power_logits, power_train_tensor)
total_loss = state_loss + power_loss
total_loss.backward()
optimizer.step()
total_losses.append(total_loss.item())
state_losses.append(state_loss.item())
power_losses.append(power_loss.item())
print(f"[{epoch+1}/{num_epochs}] total_loss: {total_loss.item():.4f}")
1D CNN 모델학습 결과
우선 train 데이터에 대해 학습 과정에서의 Loss 변화를 그려보면 다음과 같습니다.

뭔가...문제가 있다는 걸 바로 볼 수 있는데 딱 봐도 State Loss는 둘째치고 Power Loss가 땅바닥을 기어다니는걸로 봐서 Power Prediction에 문제가 있다는 것을 알 수 있습니다. 문제점을 자세히 살펴보고 정리해본다면 다음과 같습니다.
문제점 #1. R-squared 음수 출력
여기서 무엇이 문제인지 자세히 살펴봅시다.
우선은 State Prediction과 Power Prediction에 대해 평가지표를 각각 출력해 보았습니다. 설명한 바와 같이 전자의 경우는 분류 문제이고 후자의 경우는 회귀 문제이기 때문에, 평가지표를 다르게 해야 합니다.
State Prediction의 평가지표는 다음과 같습니다.

물론 Precision, Recall, F1-score는 낮지만 Accuracy만을 따졌을 떄는 조금은 봐줄 만한 점수가 나왔습니다.
애초에 본 모델은 가장 기본적인 '베이스라인 모델'이므로 어느 정도의 성능은 기대하겠지만 평가지표에서 관찰해야 할 것은 "모델의 성능이 얼마나 정확한가?"를 볼 것이 아니라 "모델이 내가 원하는 방향으로 돌아가고 있는가?"를 따져야 합니다. Accuracy가 0.7은 넘었으므로 State Prediction은 적당히 작동되는 걸로 볼 수 있습니다.
그런데 문제는 Power Prediciton의 평가지표를 출력해보면 R-squared가 음수가 나오는 처참한 결과가 나옵니다...

무엇이 문제인지 몰라서 이것저것 인터넷을 뒤져 봤는데, 저의 상황에 맞는 정확한 답을 찾을 수는 없었습니다.
https://bluediary8.tistory.com/159
테스트 데이터에서 회귀 모델의 결정계수가(R2) 음수가 나오는 이유
회귀 모델의 결정계수(R2)는 회귀 모델의 성능 지표로서 사용이 가능하며, 다음과 같이 쓸 수 있습니다. R2의 범위는 0부터 1사이라는 것을 수식만 봐도 알 수 있는데, 테스트 데이터에서 R2를 뽑아
bluediary8.tistory.com
문제점 #2. Power가 모든 지점에서 0인 문제
문제의 원인을 찾기 위해 모델의 출력값을 관찰해보기로 했습니다. 실제로 모델이 낸 답이 무엇인지를 확인해보니, 왜 R-squared가 음수값이 나왔는지를 알 수 있었습니다.
다음은 TV의 경우에 대해, test 데이터에 대해 모델이 낸 State Prediction과 Power Prediction의 답입니다.


두 그래프를 비교해보면 무엇이 문제인지를 바로 알 수 있는데,
모델이 TV가 켜져있는지 or 꺼져있는지는 어느 정도로 예측하는 반면, TV가 사용한 전력량에 대해서는 모두 0으로 예측하고 있다는 것입니다. 다른 모든 기기에 대해 확인해보았을 때도, ON/OFF 상태는 적절한 수준으로 예측하고 있는 반면 각 기기가 사용하는 전력량은 모두 0으로 예측하고 있었습니다.
모델이 낸 Power Prediction에 대한 답이 모두 0인 상황에서, R-squared를 계산하면 음수가 나오는 것은 당연한 결과였을 것입니다. (R-squared의 계산 공식에 비추어 볼 때)
모델의 문제가 아니라 데이터의 문제가 아닐까도 생각해 보았습니다. 실제 데이터(정답 데이터)에서 TV의 사용 전력량이 0이었기 때문에 모델도 TV의 사용 전력량을 0으로 예측한 것이 아닐까요?

그렇지만 실제 TV의 데이터는 다음과 같이, 명확한 전력량 사용이 존재하는 형태였습니다.
즉, 제가 만든 베이스라인 모델은
- 개별 기기의 ON/OFF 상태는 어느 정도로 적절하게 예측하지만,
- 개별 기기의 전력량은 모두 0으로 예측하는 (= 개별 기기의 전력량은 파악하지 못하는)
상황인 것입니다.
여기까지 제가 만든 Nilm의 1D CNN 베이스라인 모델에 대해
모델의 참고 논문부터 간단한 이론, 모델 빌드 과정, 그리고 모델의 학습결과까지를 정리하였습니다.
결론부터 말씀드리자면 저는 결국 모델이 왜 Power Prediction에 실패하는지에 대한 원인을 찾아내지 못했습니다. 그래서 다른 해결 방안으로 참고논문에서 모델학습에 사용한 UKDALE 데이터를 사용하여, 데이터 보완을 진행하는 방안을 선택하였습니다.
다음 글에서는 이 UKDALE 데이터에 대해 조금 더 자세히 정리해보도록 하겠습니다.
'Nilm 및 전력예측' 카테고리의 다른 글
| [Nilm] (6)-UK-DALE 데이터 (0) | 2026.01.31 |
|---|---|
| [Nilm] (4)-FFT와 이상탐지 (0) | 2026.01.28 |
| [Nilm] (3)-데이터 선정과 전처리 (0) | 2026.01.25 |
| [Nilm] (2)-데이터에 대한 이해 (2) | 2026.01.25 |
| [Nilm] (1)-NILM 기술의 이해 (2) | 2025.07.02 |