반응형

Consuming TFRecord data

 

많은 데이터셋은 하나 이상의 파일로 분산되어 있다. tf.data.TextLineDataset은 하나 이상의 파일로부터 텍스트 라인을 추출하기 쉬운 방법을 제공한다. 하나 이상의 파일명을 전달하면, TextLineDataset은 이 파일들의 라인별로 하나의 문자값 요소를 만든다.

directory_url = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'
file_names = ['cowper.txt', 'derby.txt', 'butler.txt']

file_paths = [
    tf.keras.utils.get_file(file_name, directory_url + file_name)
    for file_name in file_names
]

Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt
819200/815980 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt
811008/809730 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt
811008/807992 [==============================] - 0s 0us/step

file_paths
['C:\\...\\.keras\\datasets\\cowper.txt',
 'C:\\...\\.keras\\datasets\\derby.txt',
 'C:\\...\\.keras\\datasets\\butler.txt']
dataset = tf.data.TextLineDataset(file_paths)

아래는 생성된 데이터셋에서 처음 5라인을 보여준다.

for line in dataset.take(5):
  print(line.numpy())

b"\xef\xbb\xbfAchilles sing, O Goddess! Peleus' son;"
b'His wrath pernicious, who ten thousand woes'
b"Caused to Achaia's host, sent many a soul"
b'Illustrious into Ades premature,'
b'And Heroes gave (so stood the will of Jove)'

>>> file_paths의 첫번째 파일인 cowper.txt의 처음 5라인을 출력한다.

>>> 처음 나타나는 UTF-8 BOM (참고 : https://brownbears.tistory.com/124 

>>> BOM 이란 문서 맨 앞에 보이지 않는 BYTE를 추가하여 문서의 인코딩을 알아낼 수 있는 방법

 

파일을 교대로 라인을 추출하기 위해서는 Dataset.interleave를 사용한다. 

interleave(
    map_func
, cycle_length=AUTOTUNE, block_length=1, num_parallel_calls=None,
    deterministic
=None
)
Args
map_func 데이터셋에 데이터셋 요소를 매핑하는 함수
cycle_length (Optional.) 동시에 처리되어지는 input elements의 수. 만약 지정되지 않으면, 그 값은 가능한 CPU 코어의 수로부터 파생되어진다. 만약 num_parallels_calls 인자가 tf.data.experimental.AUTOTUNE로 설정되면, cycle_length 인자 또한 최대 병렬 처리 수준을 식별한다. (자동으로 최대 병렬 처리가능한 수치로 설정한다는 의미일까?)
block_length (Optional.) 또다른 입력 요소 주기(cycle) 전에 각 입력 요소로부터 생성하기 위한 연이은 요소들의 수.
num_parallel_calls (Optional.) 만약 지정되면, 구현은 threadpool을 생성한다. 이는 비동기적이고 병렬적으로 순환 요소(cycle elements)로부터 입력을 가지고 오는데 사용된다. 기본적인 동작은 병렬처리 없이 동기적으로 순환 요소로부터 입력을 가져온다. 만약  tf.data.experimental.AUTOTUNE 값이 사용되면, 병렬 호출의 수는 가능한 CPU에 기초하여 동적으로 설정된다.
deterministic (Optional.) A boolean controlling whether determinism should be traded for performance by allowing elements to be produced out of order. If deterministic is None, the tf.data.Options.experimental_deterministic dataset option (True by default) is used to decide whether to produce elements deterministically.
Returns
Dataset A Dataset.

다음은 Dataset.interleave를 사용한 것으로, 3개의 파일이 차례로 나타난다.

# files_ds는 list 타입인 file_paths를 Dataset으로 변경한다.
files_ds = tf.data.Dataset.from_tensor_slices(file_paths)

lines_ds = files_ds.interleave(tf.data.TextLineDataset, cycle_length=3)

for i, line in enumerate(lines_ds.take(9)):
  if i % 3 == 0:
    print()
  print(line.numpy())

>>> 위 예에서 cycle_length의 수가 작은 경우, 예를 들면 2로 설정한 경우, 총 3개의 파일 중 2개에서만 읽어온다. 반대로 cycle_length 수가 더 큰 경우, 설정된 수와 상관없이 3개의 파일에서 차례로 읽어온다.

b"\xef\xbb\xbfAchilles sing, O Goddess! Peleus' son;"
b"\xef\xbb\xbfOf Peleus' son, Achilles, sing, O Muse,"
b'\xef\xbb\xbfSing, O goddess, the anger of Achilles son of Peleus, that brought'

b'His wrath pernicious, who ten thousand woes'
b'The vengeance, deep and deadly; whence to Greece'
b'countless ills upon the Achaeans. Many a brave soul did it send'

b"Caused to Achaia's host, sent many a soul"
b'Unnumbered ills arose; which many a soul'
b'hurrying down to Hades, and many a hero did it yield a prey to dogs and'

 

기본적으로 TextLineDatset은 각 파일의 모든 라인을 처리한다. 하지만 이것은 예를 들면, 헤더라인으로 시작하는 파일 또는 주석을 포함하는 파일에서는 바람직하지 않을 수 있다. 이런 경우, Dataset.skip() 또는 Dataset.fileter() 변환을 사용하여 제거할 수 있다. 

아래에서는 첫번째 라인은 skip하고 'survived' 컬럼이 1인 데이터만을 찾기 위해 filter를 사용한다.

titanic_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
titanic_lines = tf.data.TextLineDataset(titanic_file)

Downloading data from https://storage.googleapis.com/tf-datasets/titanic/train.csv
32768/30874 [===============================] - 0s 0us/step

for line in titanic_lines.take(10):
  print(line.numpy())

b'survived,sex,age,n_siblings_spouses,parch,fare,class,deck,embark_town,alone'
b'0,male,22.0,1,0,7.25,Third,unknown,Southampton,n'
b'1,female,38.0,1,0,71.2833,First,C,Cherbourg,n'
b'1,female,26.0,0,0,7.925,Third,unknown,Southampton,y'
b'1,female,35.0,1,0,53.1,First,C,Southampton,n'
b'0,male,28.0,0,0,8.4583,Third,unknown,Queenstown,y'
b'0,male,2.0,3,1,21.075,Third,unknown,Southampton,n'
b'1,female,27.0,0,2,11.1333,Third,unknown,Southampton,n'
b'1,female,14.0,1,0,30.0708,Second,unknown,Cherbourg,n'
b'1,female,4.0,1,1,16.7,Third,G,Southampton,n'

def survived(line):
  return tf.not_equal(tf.strings.substr(line, 0, 1), "0")

survivors = titanic_lines.skip(1).filter(survived)

 

for line in survivors.take(10):
  print(line.numpy())

b'1,female,38.0,1,0,71.2833,First,C,Cherbourg,n'
b'1,female,26.0,0,0,7.925,Third,unknown,Southampton,y'
b'1,female,35.0,1,0,53.1,First,C,Southampton,n'
b'1,female,27.0,0,2,11.1333,Third,unknown,Southampton,n'
b'1,female,14.0,1,0,30.0708,Second,unknown,Cherbourg,n'
b'1,female,4.0,1,1,16.7,Third,G,Southampton,n'
b'1,male,28.0,0,0,13.0,Second,unknown,Southampton,y'
b'1,female,28.0,0,0,7.225,Third,unknown,Cherbourg,y'
b'1,male,28.0,0,0,35.5,First,A,Southampton,y'
b'1,female,38.0,1,5,31.3875,Third,unknown,Southampton,n'

 

반응형

+ Recent posts