From 3dcafddb8c951d54d309256bf12b99d2bf2d4e86 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Tue, 5 Mar 2019 11:29:30 +0330 Subject: [PATCH] refactor(data): include latitude longitude in columns, not indices --- .floydexpt | 1 + .floydignore | 19 ++++++++++ checkpoints/b.hdf5 | Bin 60288 -> 16464 bytes data.py | 19 +++++----- demo.py | 19 ++++++++++ draw.py | 6 +-- floyd.yml | 23 ++++++++++++ nn.py | 25 ++++++++----- predict.py | 30 ++++++++------- requirements.txt | 2 +- tracks | 89 +++++++++++++++++++++++++++++++++++++++++++++ utils.py | 29 +++++++++++---- 12 files changed, 220 insertions(+), 42 deletions(-) create mode 100644 .floydexpt create mode 100644 .floydignore create mode 100644 demo.py create mode 100644 floyd.yml create mode 100644 tracks diff --git a/.floydexpt b/.floydexpt new file mode 100644 index 0000000..c12b4a2 --- /dev/null +++ b/.floydexpt @@ -0,0 +1 @@ +{"name": "world", "namespace": "mdibaiee", "family_id": "prj_HzeYYJXLyy2otH6W"} \ No newline at end of file diff --git a/.floydignore b/.floydignore new file mode 100644 index 0000000..d388b74 --- /dev/null +++ b/.floydignore @@ -0,0 +1,19 @@ +maps +logs +checkpoints.* +geodata +*.p + +# Directories and files to ignore when uploading code to floyd + +.git +.eggs +eggs +lib +lib64 +parts +sdist +var +*.pyc +*.swp +.DS_Store diff --git a/checkpoints/b.hdf5 b/checkpoints/b.hdf5 index 86e478f82fc920f60361cb9ddc57a700c967b925..ef053039992d7ac1d5ae770a2be2fe4b1df633e5 100644 GIT binary patch delta 4133 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 QCOqGu`|Uq+4CA~12M@z=1poj5 literal 60288 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 Iw6hldFE)H<{Qv*} diff --git a/data.py b/data.py index aa86898..9164740 100644 --- a/data.py +++ b/data.py @@ -46,9 +46,8 @@ for year in range(MIN_YEAR, MAX_YEAR + 1): for s in SEASONS: temp_precip_columns += ['temp_{}_{}'.format(s, year), 'precip_{}_{}'.format(s, year)] -columns = ['biome_num', 'biome_name', 'elevation', 'distance_to_water'] + temp_precip_columns -indices = ['longitude', 'latitude'] -final_data = pd.DataFrame(index=indices, columns=columns) +columns = ['longitude', 'latitude', 'biome_num', 'biome_name', 'elevation', 'distance_to_water'] + temp_precip_columns +final_data = pd.DataFrame(columns=columns) def get_point_information(longitude, latitude): item = {} @@ -57,6 +56,8 @@ def get_point_information(longitude, latitude): if ecoregion.empty: return False + item['longitude'] = longitude + item['latitude'] = latitude item['biome_num'] = ecoregion.BIOME_NUM.iloc[0] item['biome_name'] = ecoregion.BIOME_NAME.iloc[0] @@ -100,18 +101,18 @@ def get_point_information(longitude, latitude): return item -data_indices = [] -data_map = {} +data = {} for col in columns: - data_map[col] = {} + data[col] = [] -i = 0 +# i = 0 start_time = time.time() for longitude in range(-179, 179): print('-', end='') for latitude in range(-89, 89): + # generate data and save to file d = get_point_information(longitude, latitude) if d == False: @@ -119,7 +120,7 @@ for longitude in range(-179, 179): continue for key, value in d.items(): - data_map[key][(longitude, latitude)] = value + data[key].append(value) print('+', end='') @@ -128,7 +129,7 @@ for longitude in range(-179, 179): print("--- Calculations: %s seconds ---" % (time.time() - start_time)) start_time = time.time() -df = pd.DataFrame(data_map) +df = pd.DataFrame(data) print("--- Generating DataFrame: %s seconds ---" % (time.time() - start_time)) print(df) start_time = time.time() diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..2750630 --- /dev/null +++ b/demo.py @@ -0,0 +1,19 @@ +import pandas as pd +from utils import * + +df = pd.read_pickle('data_final.p') +df.to_csv('data_final.csv') + +print('DataFrame:') +print(df) + +dataset_size, features, output_size, _ = dataframe_to_dataset_biomes(df) +print('Biomes dataset:\n - size: {}\n - inputs: {}\n - outputs: {}\n'.format(dataset_size, features, output_size)) + +dataset_size, features, output_size, _ = dataframe_to_dataset_temp_precip(df) +print('Temp/Precip dataset:\n - size: {}\n - inputs: {}\n - outputs: {}\n'.format(dataset_size, features, output_size)) + +# print('Normalized Data:') +# print(normalize_df(df)) + +# normalize_df(df).to_csv('data_normalized.csv') diff --git a/draw.py b/draw.py index 8dde7c5..0fe46a6 100644 --- a/draw.py +++ b/draw.py @@ -10,8 +10,8 @@ def draw(df, path=None): biome_numbers = df['biome_num'].unique() # biome_names = df['biome_name'].unique() - for (longitude, latitude), row in df.iterrows(): - p = Point(longitude, latitude) + for i, row in df.iterrows(): + p = Point(row.longitude, row.latitude) if row.biome_num in biomes: biomes[row.biome_num].append(p) else: @@ -55,5 +55,5 @@ def draw(df, path=None): plt.show() if __name__ == "__main__": - df = pd.read_pickle('data_final.p') + df = pd.read_pickle('data.p') draw(df) diff --git a/floyd.yml b/floyd.yml new file mode 100644 index 0000000..4c5c966 --- /dev/null +++ b/floyd.yml @@ -0,0 +1,23 @@ +# see: https://docs.floydhub.com/floyd_config +# All supported configs: +# +#machine: cpu +#env: tensorflow-1.8 +#input: +# - destination: input +# source: foo/datasets/yelp-food/1 +# - foo/datasets/yelp-food-test/1:test +#description: this is a test +#max_runtime: 3600 +#command: python train.py + +# You can also define multiple tasks to use with --task argument: +# +#task: +# evaluate: +# machine: gpu +# command: python evaluate.py +# +# serve: +# machine: cpu +# mode: serve diff --git a/nn.py b/nn.py index 4618307..c10bab7 100644 --- a/nn.py +++ b/nn.py @@ -14,12 +14,14 @@ from utils import * RANDOM_SEED = 1 -tf.enable_eager_execution() +print(tf.__version__) + +# tf.enable_eager_execution() tf.set_random_seed(RANDOM_SEED) np.random.seed(RANDOM_SEED) -df = pd.read_pickle('data_final.p') +df = pd.read_pickle('data.p') class Model(): def __init__(self, name, batch_size=16, shuffle_buffer_size=500, learning_rate=0.001, epochs=1): @@ -40,17 +42,21 @@ class Model(): (training, test) = (self.dataset.take(self.TRAIN_SIZE).batch(self.batch_size).repeat(), self.dataset.skip(self.TRAIN_SIZE).batch(self.batch_size).repeat()) + print('dataset: size={}, train={}, test={}'.format(dataset_size, self.TRAIN_SIZE, self.TEST_SIZE)) + print('input_size={}'.format(features)) + self.dataset_size = dataset_size self.features = features self.output_size = output_size self.training = training self.test = test - def create_model(self, layers, out_activation): + def create_model(self, layers, out_activation=None): params = { 'kernel_initializer': 'lecun_uniform', 'bias_initializer': 'zeros', } + # dropout = keras.layersDropout(0.2, input_shape=[self.features]) self.model = keras.Sequential([ keras.layers.Dense(layers[0], activation=tf.nn.elu, input_shape=[self.features], **params) ] + [ @@ -60,7 +66,7 @@ class Model(): ]) def compile(self, loss='mse', metrics=['accuracy'], optimizer=tf.train.AdamOptimizer): - # self.model.load_weights(self.path) + self.model.load_weights(self.path) optimizer = optimizer(self.learning_rate) self.model.compile(loss=loss, @@ -79,7 +85,7 @@ class Model(): self.model.summary() checkpoint = keras.callbacks.ModelCheckpoint(self.path, monitor='acc', verbose=1, mode='max') - tensorboard = keras.callbacks.TensorBoard(log_dir='./logs') + tensorboard = keras.callbacks.TensorBoard(log_dir='./logs', update_freq='epoch') # map_callback = keras.callbacks.LambdaCallback(on_epoch_end=self.map_callback) self.model.fit( @@ -95,16 +101,17 @@ class Model(): return np.argmax(self.model.predict(a), axis=1) A = Model('a', epochs=2) -B = Model('b', learning_rate=0.005, epochs=100) +B = Model('b', learning_rate=0.001, epochs=450) def compile_b(): B.prepare_dataset(df, dataframe_to_dataset_biomes) - B.create_model([64, 128], tf.nn.softmax) + B.create_model([32], tf.nn.softmax) B.compile(loss='sparse_categorical_crossentropy') def compile_a(): A.prepare_dataset(df, dataframe_to_dataset_temp_precip) A.create_model([(4, tf.nn.elu)]) + # A.create_model([]) # linear model A.compile(metrics=['accuracy', 'mae']) if __name__ == "__main__": @@ -118,5 +125,5 @@ if __name__ == "__main__": # print(np.unique(predictions)) # print('loss: {}, evaluation: {}'.format(*B.evaluate())) - compile_a() - A.train() + # compile_a() + # A.train() diff --git a/predict.py b/predict.py index eb93ee3..a2f2960 100644 --- a/predict.py +++ b/predict.py @@ -1,7 +1,7 @@ import numpy as np from utils import * -from nn import B +from nn import B, compile_b from draw import draw import time @@ -10,16 +10,14 @@ def chunker(seq, size): year = MAX_YEAR - 1 -df = pd.read_pickle('data_final.p') -latitude = np.array(df.index.get_level_values(1)) -df.loc[:, 'latitude'] = pd.Series(latitude, index=df.index) +df = pd.read_pickle('data.p') compile_b() for change in range(0, 1): print('TEMPERATURE MODIFICATION OF {}'.format(change)) - inputs = ['elevation', 'distance_to_water'] + inputs = ['latitude', 'longitude', 'elevation', 'distance_to_water'] for season in SEASONS: inputs += [ @@ -27,22 +25,28 @@ for change in range(0, 1): 'precip_{}_{}'.format(season, year) ] - inputs += ['latitude'] - + # print(inputs) frame = df[inputs] - print(frame.head()) + # print(frame.head()) for season in SEASONS: frame.loc[:, 'temp_{}_{}'.format(season, year)] += change - columns = ['biome_num'] + columns = ['latitude', 'longitude', 'biome_num'] new_data = pd.DataFrame(columns=columns) + for i, chunk in enumerate(chunker(frame, B.batch_size)): - input_data = normalize_ndarray(chunk.values) + if chunk.shape[0] < B.batch_size: + continue + input_data = normalize_ndarray(chunk.loc[:, chunk.columns != 'longitude'].values) out = B.predict(input_data) - new_index = np.concatenate((chunk.index.values, new_data.index.values)) - new_data = new_data.reindex(new_index) - new_data.loc[chunk.index.values, 'biome_num'] = out + f = pd.DataFrame({ + 'longitude': chunk.loc[:, 'longitude'], + 'latitude': chunk.loc[:, 'latitude'], + 'biome_num': out + }, columns=columns) + new_data = new_data.append(f) + print(new_data) draw(new_data) diff --git a/requirements.txt b/requirements.txt index 7586e77..3cc402f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,6 @@ matplotlib==3.0.2 descartes==1.1.0 pysal==2.0.0 rasterio==1.0.15 -tensorflow==1.12.0 +tensorflow==1.13.1 Cartopy==0.17.0 numpy==1.16.1 diff --git a/tracks b/tracks new file mode 100644 index 0000000..2ebbd79 --- /dev/null +++ b/tracks @@ -0,0 +1,89 @@ +Layer (type) Output Shape Param # +================================================================= +Group 1 +----------------------------------------------------------------- +dense (Dense) (None, 128) 1536 +_________________________________________________________________ +dense_1 (Dense) (None, 256) 33024 +_________________________________________________________________ +dense_2 (Dense) (None, 14) 3598 +----------------------------------------------------------------- +Total params: 38,158 +1 Epoch: loss: 0.3822 - acc: 0.8684 +Learning rate: 0.005 +================================================================= + +Group 2 +----------------------------------------------------------------- +dense (Dense) (None, 32) 384 +_________________________________________________________________ +dense_1 (Dense) (None, 64) 2112 +_________________________________________________________________ +dense_2 (Dense) (None, 32) 2080 +_________________________________________________________________ +dense_3 (Dense) (None, 14) 462 +----------------------------------------------------------------- +Total params: 5,038 +1 Epoch: loss: 0.3760 - acc: 0.8678 @ 20minutes +Stopped converging, loss increasing +Learning rate: 0.005 +================================================================= + +Group 3 +----------------------------------------------------------------- +dense (Dense) (None, 16) 192 +_________________________________________________________________ +dense_1 (Dense) (None, 32) 544 +_________________________________________________________________ +dense_2 (Dense) (None, 16) 528 +_________________________________________________________________ +dense_3 (Dense) (None, 14) 238 +----------------------------------------------------------------- +Total params: 1,502 +1 Epoch: loss: 0.3702 - acc: 0.8671 @ 12minutes +10 Epochs: loss: 0.3280 - acc: 0.8815 +Stopped converging after 5 epochs, was oscillating +Learning rate: 0.005 +================================================================= + +Group 4 +_________________________________________________________________ +dense (Dense) (None, 12) 144 +_________________________________________________________________ +dense_1 (Dense) (None, 14) 182 +_________________________________________________________________ +Total params: 326 +1 Epoch: loss: 0.4412 - acc: 0.8457 @ 10m +60 Epochs: loss: 0.4146 - acc: 0.8546 +Stopped converging +Learning rate: 0.005 +================================================================= + +Group 5 +_________________________________________________________________ +dense (Dense) (None, 12) 144 +_________________________________________________________________ +dense_1 (Dense) (None, 14) 182 +_________________________________________________________________ +Total params: 326 +1 Epoch: loss: 0.5057 - acc: 0.8268 @ 10m +15 epoch: loss: 0.4240 - acc: 0.8481 +Stopped converging +Learning rate: 0.001 +================================================================= + +Group 6 +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +dense (Dense) (None, 24) 288 +_________________________________________________________________ +dense_1 (Dense) (None, 14) 350 +_________________________________________________________________ +Total params: 638 +1 Epoch: loss: 0.4520 - acc: 0.8416 @ 12m +30 epochs: loss: 0.3562 - acc: 0.8691, still converging +stopped converging after 100 epochs +Learning rate: 0.001 + + diff --git a/utils.py b/utils.py index b2804f2..116aae3 100644 --- a/utils.py +++ b/utils.py @@ -3,7 +3,7 @@ import tensorflow as tf import pandas as pd from constants import * -inputs = ['elevation', 'distance_to_water'] +inputs = ['elevation', 'distance_to_water', 'latitude'] output = 'biome_num' def normalize(v): @@ -18,7 +18,7 @@ def normalize_ndarray(ar): def normalize_df(df): for col in df.columns: - df.loc[col] = normalize(df[col]) + df.loc[col] = normalize_ndarray(df[col]) return df @@ -29,9 +29,24 @@ def dataframe_to_dataset_biomes(df): # 3 for latitude, elevation and distance_to_water columns = 11 + # make biomes uniformly distributed so each biome has enough data to avoid a biased dataset + biome_shares = df.groupby(['biome_num']).agg({ 'biome_num': lambda x: x.count() / df.shape[0] }) + max_share = np.max(biome_shares['biome_num']) + dsize = df.shape[0] + max_share_count = int(max_share * dsize) + + for biome_num in biome_shares.index: + share = biome_shares.values[biome_num][0] + share_count = int(share * dsize) + diff = max_share_count - share_count + rows = df.loc[df['biome_num'] == biome_num] + diff_ratio = int(diff / rows.shape[0]) + df = pd.concat([df] + [rows] * diff_ratio, ignore_index=True) + + # print(df.groupby(['biome_num']).agg({ 'biome_num': lambda x: x.count() / df.shape[0] })) + tf_inputs = np.empty((0, columns)) tf_output = np.empty((0)) - latitude = np.array(df.index.get_level_values(1)) for year in range(MIN_YEAR, MAX_YEAR + 1): local_inputs = list(inputs) @@ -43,7 +58,6 @@ def dataframe_to_dataset_biomes(df): local_df = df[local_inputs] - local_df.loc[:, 'latitude'] = pd.Series(latitude, index=local_df.index) tf_inputs = np.concatenate((tf_inputs, local_df.values), axis=0) tf_output = np.concatenate((tf_output, df[output].values), axis=0) @@ -62,7 +76,6 @@ def dataframe_to_dataset_temp_precip(df): tf_inputs = np.empty((0, columns)) tf_output = np.empty((0, 2)) - latitude = np.array(df.index.get_level_values(1)) for year in range(MIN_YEAR, MAX_YEAR + 1): local_inputs = list(inputs) @@ -70,7 +83,6 @@ def dataframe_to_dataset_temp_precip(df): for idx, season in enumerate(SEASONS): season_index = idx / len(season) local_df = df[local_inputs] - local_df.loc[:, 'latitude'] = pd.Series(latitude, index=local_df.index) local_df.loc[:, 'season'] = pd.Series(np.repeat(season_index, rows), index=local_df.index) local_df.loc[:, 'year'] = pd.Series(np.repeat(year, rows), index=local_df.index) @@ -79,7 +91,10 @@ def dataframe_to_dataset_temp_precip(df): tf_output = np.concatenate((tf_output, df[output].values), axis=0) tf_inputs = tf.cast(normalize_ndarray(tf_inputs), tf.float32) - tf_output = tf.cast(normalize_ndarray(tf_output), tf.float32) + tf_output = tf.cast(tf_output, tf.float32) return int(tf_inputs.shape[0]), 5, 2, tf.data.Dataset.from_tensor_slices((tf_inputs, tf_output)) + +# df = pd.read_pickle('data.p') +# print(dataframe_to_dataset_biomes(df))