import keras
# -*- encoding:utf-8 -*-
import numpy as np
from keras.models import Sequential
# 优化方法选用Adam(其实可选项有很多，如SGD)
from keras.optimizers import Adam
import random
from keras.models import load_model
from imblearn.over_sampling import RandomOverSampler
from keras.utils import np_utils
# 用于模型初始化，Conv2D模型初始化、Activation激活函数，MaxPooling2D是池化层
# Flatten作用是将多位输入进行一维化
# Dense是全连接层
from keras.layers import Conv2D, Activation, MaxPool2D, Flatten, Dense,Dropout,Input,MaxPooling2D,BatchNormalization,concatenate
from keras import regularizers
from keras.models import Model


def read_data(path):
    lines = []
    with open(path) as f:
        for x in range(300000): #380000
            lines.append(eval(f.readline().strip()))

    random.shuffle(lines)
    print('读取数据完毕')

    d=int(0.7*len(lines))

    train_x=[s[:-2] for s in lines[0:d]]
    train_y=[s[-1] for s in lines[0:d]]
    test_x=[s[:-2] for s in lines[d:]]
    test_y=[s[-1] for s in lines[d:]]

    print('转换数据完毕')

    ros = RandomOverSampler(random_state=0)
    X_resampled, y_resampled = ros.fit_sample(np.array(train_x), np.array(train_y))

    print('数据重采样完毕')

    return X_resampled,y_resampled,np.array(test_x),np.array(test_y)


train_x,train_y,test_x,test_y=read_data("D:\\data\\quantization\\stock18_18d_train_1.log")

train_x_a = train_x[:,:18*18]
train_x_a = train_x_a.reshape(train_x.shape[0], 18, 18, 1)
train_x_b = train_x[:, 18*18:18*18+2*18]
train_x_b = train_x_b.reshape(train_x.shape[0], 18, 2, 1)
train_x_c = train_x[:,18*18+2*18:]


def create_mlp(dim, regress=False):
    # define our MLP network
    model = Sequential()
    model.add(Dense(32, input_dim=dim, activation="relu"))
    model.add(Dense(32, activation="relu"))

    # check to see if the regression node should be added
    if regress:
        model.add(Dense(1, activation="linear"))

    # return our model
    return model


def create_cnn(width, height, depth, filters=(4, 6), kernel_size=(5, 6), regress=False, output=24):
    # initialize the input shape and channel dimension, assuming
    # TensorFlow/channels-last ordering
    inputShape = (width, height, 1)
    chanDim = -1

    # define the model input
    inputs = Input(shape=inputShape)

    x = inputs

    # CONV => RELU => BN => POOL
    x = Conv2D(32, kernel_size, strides=2, padding="same")(x)
    x = Activation("relu")(x)
    x = BatchNormalization(axis=chanDim)(x)
    # x = MaxPooling2D(pool_size=(2, 2))(x)
    # if width > 2:
    #     x = Conv2D(32, (10, 6), padding="same")(x)
    #     x = Activation("relu")(x)
    #     x = BatchNormalization(axis=chanDim)(x)

    # flatten the volume, then FC => RELU => BN => DROPOUT
    x = Flatten()(x)
    x = Dense(output)(x)
    x = Activation("relu")(x)
    x = BatchNormalization(axis=chanDim)(x)
    x = Dropout(0.2)(x)

    # apply another FC layer, this one to match the number of nodes
    # coming out of the MLP
    x = Dense(output)(x)
    x = Activation("relu")(x)

    # check to see if the regression node should be added
    if regress:
        x = Dense(1, activation="linear")(x)

    # construct the CNN
    model = Model(inputs, x)

    # return the CNN
    return model


# create the MLP and CNN models
mlp = create_mlp(train_x_c.shape[1], regress=False)
cnn_0 = create_cnn(18, 18, 1, kernel_size=(10, 6), regress=False, output=256)
cnn_1 = create_cnn(18, 2, 1, kernel_size=(10,2), regress=False, output=36)

# create the input to our final set of layers as the *output* of both
# the MLP and CNN
combinedInput = concatenate([mlp.output, cnn_0.output, cnn_1.output])

# our final FC layer head will have two dense layers, the final one
# being our regression head
x = Dense(512, activation="relu", kernel_regularizer=regularizers.l1(0.003))(combinedInput)
x = Dropout(0.2)(x)
x = Dense(512, activation="relu")(x)
x = Dense(512, activation="relu")(x)
# 在建设一层
x = Dense(5, activation="softmax")(x)

# our final model will accept categorical/numerical data on the MLP
# input and images on the CNN input, outputting a single value (the
# predicted price of the house)
model = Model(inputs=[mlp.input, cnn_0.input, cnn_1.input], outputs=x)


print("Starting training ")
# h = model.fit(train_x, train_y, batch_size=4096*2, epochs=500, shuffle=True)

# compile the model using mean absolute percentage error as our loss,
# implying that we seek to minimize the absolute percentage difference
# between our price *predictions* and the *actual prices*
opt = Adam(lr=1e-3, decay=1e-3 / 200)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=['accuracy'])

# train the model
print("[INFO] training model...")
model.fit(
    [train_x_c, train_x_a, train_x_b], train_y,
    # validation_data=([testAttrX, testImagesX], testY),
    # epochs=int(3*train_x_a.shape[0]/1300),
    epochs=100,
    batch_size=2048, shuffle=True)

test_x_a = test_x[:,:18*18]
test_x_a = test_x_a.reshape(test_x.shape[0], 18, 18, 1)
test_x_b = test_x[:, 18*18:18*18+2*18]
test_x_b = test_x_b.reshape(test_x.shape[0], 18, 2, 1)
test_x_c = test_x[:,18*18+2*18:]

# make predictions on the testing data
print("[INFO] predicting house prices...")
score  = model.evaluate([test_x_c, test_x_a, test_x_b], test_y)

print(score)
print('Test score:', score[0])
print('Test accuracy:', score[1])

path="18_18d_mix_seq.h5"
model.save(path)
model=None