【代码】

import os
import time
import torch
import argparse

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from torch import nn
from tqdm import tqdm
from torch.utils.data import DataLoader
from torch.optim import Adam, RMSprop

from data.data_utils import CustomDataset, split_train_test, IrisDataset, SeriesDataset
from algo.net import LSTMPolicyNet, FCPolicyNet, GRUPolicyNet

parser = argparse.ArgumentParser()

parser.add_argument("-p", "--path", default="./data/data/", help="The path where data stored")
parser.add_argument("-d", "--debug", action="store_true", help="Enter debug mode.")
parser.add_argument("-r", "--restore", action="store_true", help="whether to restore model or not")
parser.add_argument("-m", "--model", choices=["lstm", "fc", "gru", "seq2seq"], default="lstm", help="Choose policy network")
args = parser.parse_args()

DATA_PATH = args.path
DEBUG = args.debug
RESTORE = args.restore
MODEL = args.model

ON_GPU = torch.cuda.is_available()
DEVICE = torch.device("cuda:0" if ON_GPU else "cpu")
MODEL_PATH = "./model/"
SAVE_PATH = os.path.join(MODEL_PATH, MODEL + "_" + time.strftime("%m%d_%H%M%S", time.localtime()) + ".pkl")

BATCH_SIZE = 64 # 样本批处理参数
NUM_EPOCHS = 25 # 召回率
LEARNING_RATE = 1e-3 #

SEQ_LEN = 4


def choose_model(model_name, input_size):
    if model_name == "lstm":
        model = LSTMPolicyNet(input_size=input_size, output_size=1, hidden_size=32, seq_len=SEQ_LEN)
    elif model_name == "fc":
        model = FCPolicyNet()
    elif model_name == "gru":
        model = GRUPolicyNet(input_size=input_size, output_size=1, hidden_size=32, seq_len=SEQ_LEN)
    elif model_name == "seq2seq":
        model = None

    return model


def load_latest_model():
    models = list(filter(lambda x: MODEL in x, os.listdir(MODEL_PATH)))
    model_path = os.path.join(MODEL_PATH, models[-1])
    print("load model from {}".format(model_path))
    model = torch.load(model_path)

    return model


def train():
    # dataset = CustomDataset(DATA_PATH, "2018")
    dataset = SeriesDataset(DATA_PATH, "2018", SEQ_LEN)
    print(len(dataset))

    # train_set, val_set = split_train_test(dataset)
    train_set = dataset
    # val_set = SeriesDataset(DATA_PATH, "2018", SEQ_LEN)
    val_set = SeriesDataset(DATA_PATH, "2017", SEQ_LEN)

    train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=False)
    val_loader = DataLoader(val_set, batch_size=BATCH_SIZE, shuffle=False)


    if RESTORE:
        model = load_latest_model()
    else:
        model = choose_model(MODEL, dataset.feature_size)
    
    model.to(DEVICE)

    criterion = nn.MSELoss()
    # criterion = nn.CrossEntropyLoss()

    optimizer = Adam(model.parameters(), lr=LEARNING_RATE)

    min_mse = float("inf")
    for epoch in range(NUM_EPOCHS):
        model.train()
        
        loss_sum = 0.0
        for feature, target in tqdm(train_loader, desc="Epoch {}".format(epoch)):
            feature = feature.to(DEVICE).float()
            # print(feature.size())
            # feature = feature.view(feature.size(0), -1)

            # print(feature.size())
            feature = torch.transpose(feature, 0, 1)
            target = target.to(DEVICE).float()

            output = model(feature)

            if DEBUG:
                print(output.detach().cpu().numpy())
                print(target.cpu().numpy())
                break

            loss = criterion(output, target)
            
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            loss_sum += output.size(0) * loss.item()
        
        training_loss = loss_sum / len(train_set)
        validation_loss = eval(model, criterion, val_loader, len(val_set))

        if validation_loss < min_mse:
            torch.save(model, SAVE_PATH)
            min_mse = validation_loss

        print("Training loss: {:.4f}, validation loss: {:.4f}.".format(training_loss, validation_loss))


def eval(model, criterion, data_loader, n_samples):
    model.eval()

    loss_sum = 0.0
    for feature, target in data_loader:
        feature = feature.to(DEVICE).float()
        # feature = feature.view(feature.size(0), -1)
        feature = torch.transpose(feature, 0, 1)
        target = target.to(DEVICE).float()

        output = model(feature)
        loss = criterion(output, target)

        loss_sum += output.size(0) * loss.item()


    return loss_sum / n_samples


def plot_predictions():
    model = load_latest_model()
    model.to(DEVICE)
    model.eval()

    dataset = SeriesDataset(DATA_PATH, "2017", SEQ_LEN)

    data_loader = DataLoader(dataset, batch_size=64)

    t = []
    o = []

    for feature, target in tqdm(data_loader):
        feature = feature.to(DEVICE).float()
        feature = torch.transpose(feature, 0, 1)
        target = target.to(DEVICE).float()
        
        output = model(feature)

        t.append(target.cpu().numpy())
        o.append(output.squeeze().detach().cpu().numpy())

    target = np.hstack(t)
    output = np.hstack(o)

    target = target * dataset.std + dataset.mean
    output = output * dataset.std + dataset.mean
    
    x = np.linspace(1, len(target), num=len(target))

    # print(target.shape, output.shape)

    plt.plot(x, target, label="target", linewidth=0.8)
    plt.plot(x, output, label="output", linewidth=0.8)
    plt.legend()

    plt.show()


if __name__ == "__main__":
    # train()
    plot_predictions()
import os
import torch

import numpy as np
import pandas as pd

from torch.utils.data import DataLoader, Dataset, random_split
from sklearn.datasets import load_iris
from sklearn.preprocessing import OneHotEncoder, LabelEncoder

class CustomDataset(Dataset):

    def __init__(self, path, year, seq_len=24):
        super().__init__()
        feature, target = load_data(path, year)
        self.feature = feature
        self.target = target
        self.seq_len = seq_len

    def __getitem__(self, index):
        pre_feature = self.feature[index + self.seq_len : index + self.seq_len * 2, :]
        pre_target = np.expand_dims(self.target[index : index + self.seq_len], axis=1)

        # print(pre_feature.shape, pre_target.shape)
        feature = np.concatenate([self.feature[index : index + self.seq_len, :], pre_target], axis=1)
        target = self.target[index + self.seq_len]
        
        print(type(feature), type(target))
        return feature, target

    def __len__(self):
        return self.feature.shape[0] - self.seq_len


class SeriesDataset(Dataset):

    def __init__(self, path, year, seq_len=20):
        super().__init__()
        self.data = load_data(path, year)
        self.feature = None
        self.target = None
        self.seq_len = seq_len

        self.construct_feature_and_target()
        self.mean, self.std = self.normlize()
        self.feature_size = self.feature.shape[1]

    def __getitem__(self, index):
        feature = self.feature[index : index + self.seq_len, :]
        target = self.target[index + self.seq_len]

        return feature, target

    def __len__(self):
        return self.feature.shape[0] - self.seq_len
        
    def construct_feature_and_target(self):
        output = self.data[0]
        waterhead = self.data[1]
        program = self.data[2]
        datetime_index = pd.to_datetime(output["time"])

        # output = np.expand_dims(output["data"].values, axis=1)
        # waterhead = np.expand_dims(waterhead["data"].values, axis=1)
        # program = np.expand_dims(program["data"].values, axis=1)
        # time_feature = generate_time_stamp(datetime_index)
        # print(type(output["data"])) # <class 'pandas.core.series.Series'>
        print(type(output["data"]))  # <class 'pandas.core.series.Series'>
        output = np.expand_dims(output["data"].values[:-96], axis=1) #-96指到倒数第96行
        waterhead = np.expand_dims(waterhead["data"].values[96:], axis=1)
        program = np.expand_dims(program["data"].values[96:], axis=1)
        time_feature = generate_time_stamp(datetime_index)[96:, :]

        print(output.shape)
        print(waterhead.shape)
        print(program.shape)
        print(time_feature.shape)

        # print([x.shape for x in [output, waterhead, program, time_feature]])
        
        self.target = np.squeeze(program)
        self.feature = np.concatenate([output, waterhead, program, time_feature], axis=1) #axis=0是在行上增加,axis=1是在列上增加

    def normlize(self):
        feature_mean = np.mean(self.feature[:, :3], axis=0) # 均值    Q:为嘛是3
        feature_std = np.std(self.feature[:, :3], axis=0)   # 标准差

        target_mean = feature_mean[2]    # Q:target和feature有啥不一样?
        target_std = feature_std[2]

        time_max = np.max(self.feature[:, 3:], axis=0)
        time_min = np.min(self.feature[:, 3:], axis=0)        

        self.feature[:, :3] = (self.feature[:, :3] - feature_mean) / (feature_std + 1e-7)
        self.feature[:, 3:] = (self.feature[:, 3:] - time_min) / (time_max - time_min)
        self.target = (self.target - target_mean) / (target_std + 1e-7)

        return target_mean, target_std


class Seq2seqDataset(Dataset):
    pass


class IrisDataset(Dataset):

    def __init__(self):
        super().__init__()
        iris = load_iris(True)
        
        self.feature = iris[0]
        self.target = iris[1]
        print(self.feature.shape)
        print(self.target.shape)

    def __getitem__(self, index):
        feature = self.feature[index, :]
        target = self.target[index]

        return feature, target

    def __len__(self):
        return self.feature.shape[0]



def load_data(path, year):
    paths = os.listdir(path)
    paths = list(filter(lambda x: ".csv" in x, paths))

    data_files = []
    
    for p in paths:
        if year in p:
            data_files.append(p)
    
    output = None
    waterhead = None
    program = None

    for f in data_files:
        if "output" in f:
            output = os.path.join(path, f)
        elif "waterhead" in f:
            waterhead = os.path.join(path, f)
        else:
            program = os.path.join(path, f)

    # feature_series = concat_feature(output, waterhead, program)
    # targets = pd.read_csv(program, names=["time", "data"])["data"].values[96:]

    output = pd.read_csv(output, names=["time", "data"])
    waterhead = pd.read_csv(waterhead, names=["time", "data"])
    program = pd.read_csv(program, names=["time", "data"])

    return output, waterhead, program


def generate_time_stamp(dt_index, onehot_encode=False):
    months = dt_index.dt.month.values.astype(np.int).reshape(-1, 1)
    days = dt_index.dt.day.values.astype(np.int).reshape(-1, 1)
    hours = dt_index.dt.hour.values.astype(np.int).reshape(-1, 1)
    minutes = dt_index.dt.minute.values.astype(np.int).reshape(-1, 1)

    if onehot_encode:
        encoder = OneHotEncoder(categories="auto")

        months = encoder.fit_transform(months).toarray()
        days = encoder.fit_transform(days).toarray()
        hours = encoder.fit_transform(hours).toarray()
        minutes = encoder.fit_transform(minutes).toarray()

    time_feature = np.concatenate([months, days, hours, minutes], axis=1).astype(np.float)

    return time_feature


def convert_to_ndarray(file, require_time_stamp=False):
    df = pd.read_csv(file, names=["time", "data"])
    
    if require_time_stamp:
        df["time"] = pd.to_datetime(df["time"])
        temp_df = pd.DataFrame(columns=["month", "day", "hour", "minute", "data"])

        temp_df["month"] = df["time"].dt.month
        temp_df["day"] = df["time"].dt.day
        temp_df["hour"] = df["time"].dt.hour
        temp_df["minute"] = df["time"].dt.minute
        temp_df["data"] = df["data"]

        temp_arr = temp_df.values

        temp_list = []
        for i in range(1, temp_arr.shape[0] - 15, 15):
            temp_list.append(np.expand_dims(temp_arr[i:i+15, :], axis=1))

        temp_arr = np.concatenate(temp_list, axis=1)
    else:
        temp_arr = pd.Series(data=df["data"]).values

        temp_list = []
        for i in range(1, temp_arr.shape[0] - 15, 15):
            temp_list.append(np.expand_dims(np.expand_dims(temp_arr[i:i+15], axis=1), axis=2))

        temp_arr = np.concatenate(temp_list, axis=1)

    return temp_arr

def concat_feature(output, waterhead, program):
    output_df = pd.read_csv(output, names=["time", "data"])
    waterhead_df = pd.read_csv(waterhead, names=["time", "data"])
    # program_df = pd.read_csv(program, names=["time", "data"])

    output = pd.Series(data=output_df["data"])
    waterhead = pd.Series(data=waterhead_df["data"])
    output.index = pd.to_datetime(output_df["time"])
    waterhead.index = pd.to_datetime(waterhead_df["time"])
    # program = pd.Series(data=program_df["data"])
    # program.index = pd.to_datetime(program_df["time"])

    year_days = pd.date_range(start=waterhead.index[0] + pd.Timedelta(days=1), end=waterhead.index[-1], freq="D")

    features = []
    for day in year_days:
        pre_day = (day - pd.Timedelta(days=1)).strftime("%Y-%m-%d")
        cur_day = day.strftime("%Y-%m-%d")
        feature = np.tile(np.concatenate([output[pre_day], waterhead[cur_day]], axis=0), reps=(96, 1))
        features.append(feature)
        # break

    features = np.vstack(features)    

    return features


def split_train_test(dataset, ratio=0.8):
    length = len(dataset)
    train_len = int(length * ratio)
    test_len = length - train_len
    split_list = [train_len, test_len]

    train_set, test_set = random_split(dataset, split_list)

    return train_set, test_set


if __name__ == "__main__":

    dataset = SeriesDataset("./data/", "2017")
    # dataset = CustomDataset("./data/", "2018")
    feature, _ = dataset.__getitem__(1)
    _, target = dataset.__getitem__(0)
    # feature = dataset.__getitem__(len(dataset) - 1)
    print(feature, target)
    # print(len(dataset))
    # print(feature.dtype)
    # print(target)
    

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值