kaggle의 csv 파일을 다루려다 보니, dataset을 직접 구성해야할 일이 생겼다.


dataset을 다루는데에 여러가지 방법이 있는데,

대부분의 dataset은 파일이 크기 때문에 generator 형식이 제일 좋은 것같다.


하지만 csv 포멧으로는 그게 힘들어서 파일을 전부 읽은 다음 사용했다.

그런데 읽은 dataset을 이용하는 방법 또한 두 가지로 나뉘는것같다.

하나는 gpu 메모리에 올리고 사용하는 방법. 하나는 generator 형식으로 사용 데이터만 gpu에 올리는 방법

처음엔 잘 몰라서 전자를 선택했지만, 메모리 부족으로 후자를 택해야했다.


두 방법을 모두 정리하고자 글을 썼다.



1. csv 데이터 읽은 후, tf함수 from_tensor_slices로 사용하기

# train_x, train_y는 numpy 포멧 [데이터 수, value]로 구성.
# tf.data.Dataset.from_tensor_slices을 이용하면 대규모 데이터셋은 불리하다고한다
# 참고 : https://www.tensorflow.org/api_docs/python/tf/data/Dataset

dataset = tf.data.Dataset.from_tensor_slices((train_x, train_y))

dataset = dataset.batch(batch_size)
iterator = dataset.make_initializable_iterator()

_data = tf.placeholder(tf.float32, [None, cfg.INPUT_DATA_LEN])
_labels = tf.placeholder(tf.float32, [None, 1])

next_batch = iterator.get_next()
x = tf.placeholder(tf.float32, [None, 4991], 'input')
y = tf.placeholder(tf.float32, [None, 1], 'label')

y_pred = baseline.predict(x)
y_pred = tf.identity(y_pred, 'output')

mse = tf.reduce_mean(tf.square(y - y_pred))
#optimizer = tf.train.GradientDescentOptimizer(0.01)
optimizer = tf.train.AdamOptimizer(0.01)
grad_vars = optimizer.compute_gradients(mse)
capped_grad_vars = [(tf.clip_by_value(grad, -1., 1.), var) for grad, var in grad_vars]
train_op = optimizer.apply_gradients(capped_grad_vars)
saver = tf.train.Saver()
init = tf.global_variables_initializer()

print('train start')
with tf.Session() as sess:
    sess.run(init)
    #print('1')
    for i in range(step):
        sess.run(iterator.initializer, feed_dict={_data: train_x, _labels: train_y})
        iteration = 0
        #print('2')
        while True:
            try:
                train_x, train_y = sess.run(next_batch)

                sess.run(train_op, feed_dict={x:train_x, y:train_y})
                if iteration == 0:
                    loss = sess.run(mse, feed_dict={x:train_x, y:train_y})
                    print('step: {}, mse: {}'.format(i, loss))
                iteration += 1
            except tf.errors.OutOfRangeError:
                break
        if i % 100 == 0:
            if not i == 0:
                saver.save(sess, "./checkpoints/baseline_model", global_step=i)
                print('save model [{}]'.format(i))


2. csv 데이터 읽은 후, generator 만들어서 사용하기

2.1. generator를 새로 코딩 (발코딩인점은 감안.. generator가 핵심이고 나머진 안봐도됨)

import os
import pandas as pd
import numpy as np

class SVPC_Dataset():
    def __init__(self, dataDir, data_type='train', divide_value=None, divide_label=None, round=None, normaliza=False):
        self.dataDir = dataDir
        self.data_type = data_type

        if self.data_type == 'train':
            return self.read_train_data_from_csv(divide_value, divide_label, round, normaliza)
        else:
            return self.read_test_data_from_csv(divide_value, round, normaliza)
        print('data loaded')

    def read_train_data_from_csv(self, divide_value=None, divide_label=None, round=None, normaliza=False):
        df = pd.read_csv(self.dataDir, low_memory=False)
        label_df = df.iloc[:, 1]  # label column
        value_df = df.iloc[:, 2:]  # value column

        if divide_value is not None:
            value_df = value_df / divide_value  # 나누기
        if divide_label is not None:
            label_df = label_df / divide_value  # 나누기
        df = pd.concat([label_df, value_df], axis=1, sort=False)
        if round is not None:
            df = df.round(round)  # 소수점 제거
        if normaliza:
            df = (df - df.mean()) / (df.max() - df.min())
        self.x = np.array(df.values[:, 1:], dtype=np.float32)
        y = np.array(df.values[:, 0], dtype=np.float32)
        self.y = np.expand_dims(y, axis=1)

    def read_test_data_from_csv(self, divide_value=None, round=None, normaliza=False):
        df = pd.read_csv(self.dataDir, low_memory=False)
        id_df = df.iloc[:, 0]  # id column
        value_df = df.iloc[:, 1:]  # value column

        if divide_value is not None:
            value_df = value_df / divide_value  # 나누기
        if round is not None:
            value_df = value_df.round(round)  # 소수점 제거
        if normaliza:
            value_df = (value_df - value_df.mean()) / (value_df.max() - value_df.min())
        self.x = np.array(value_df.values, dtype=np.float32)
        id = np.array(id_df.values)
        self.id = np.expand_dims(id, axis=1)

    def __len__(self):
        return len(self.x)

    def __getitem__(self, idx):
        if self.data_type == 'train':
            return self.x[idx], self.y[idx]
        else:
            return self.x[idx], self.id[idx]

    def generator(self, batch_size=1):
        length = self.__len__()
        for n_idx in range(0, length, batch_size):
            yield self[n_idx:min(n_idx + batch_size, length)]

class Result_Writer():
    def __init__(self, outDir='./', fileName='model_result'):
        self.fileDir = os.path.join(outDir, fileName + '.csv')
        self.result_df = pd.DataFrame(columns=['ID', 'target'])

    def add_row(self, id, target):
        self.result_df = self.result_df.append({'ID':id, 'target':target}, ignore_index=True)

    def add_rows(self, ids, targets):
        for i in range(len(ids)):
            self.add_row(ids[i], targets[i])

    def save_to_csv(self):
        self.result_df.to_csv(self.fileDir, mode='w', header=False)

if __name__ == '__main__':
    db = SVPC_Dataset('./dataset/test.csv', 'test')
    for idx, (x, y) in enumerate(db.generator(3)):
        print(x)
        print(y)
        if idx > 5:
            break


2.2. generator를 통한 모델 학습

DB = dataset.SVPC_Dataset('./dataset/train.csv', 'train', divide_value=10000000, divide_label=10000, round=4, normaliza=False)

x = tf.placeholder(tf.float32, [None, 4991], 'input')
y = tf.placeholder(tf.float32, [None, 1], 'label')

y_pred = baseline.predict(x)
y_pred = tf.identity(y_pred, 'output')

mse = tf.reduce_mean(tf.square(y - y_pred))
#optimizer = tf.train.GradientDescentOptimizer(0.01)
optimizer = tf.train.AdamOptimizer(0.01)
grad_vars = optimizer.compute_gradients(mse)
capped_grad_vars = [(tf.clip_by_value(grad, -1., 1.), var) for grad, var in grad_vars]
train_op = optimizer.apply_gradients(capped_grad_vars)
saver = tf.train.Saver()
init = tf.global_variables_initializer()

print('train start')
with tf.Session() as sess:
    sess.run(init)
    #print('1')
    for step in range(steps):
        #print('2')
        for idx, (train_x, train_y) in enumerate(DB.generator(batch_size)):
            sess.run(train_op, feed_dict={x:train_x, y:train_y})
            if idx == 0:
                loss = sess.run(mse, feed_dict={x:train_x, y:train_y})
                print('step: {}, mse: {}'.format(step, loss))

        if step % 100 == 0:
            if not step == 0:
                saver.save(sess, "./checkpoints/baseline_model", global_step=step)
                print('save model [{}]'.format(step))


둘 다 ram에 data를 미리 다 올리고 사용하는 방법임.

(이것도 개선해야하는데, 당장은 방법을 모르겠음)


1번은 데이터 전부를 gpu에 올리는 듯함

그래서 크기가 작은 파일은 괜찮은데, 큰 파일에서는 메모리 초과 오류가 발생


2번은 ram에 있는 데이터를 batch_size만큼 씩 gpu에 올려서 사용

메모리 초과 오류가 발생하지 않음

+ Recent posts