ABOUT ME

-

Today
-
Yesterday
-
Total
-
choco@desktop:~/tistory
$ 정보처리기사 요점정리
1과목 2과목 3과목 4과목 5과목 실기

$ Linux Kernel
Power Management DVFS
  • 머신러닝 스터디 3주차 - Simple CNN 모델로 이미지 학습하기
    SW개발/머신러닝 2019. 3. 24. 15:32

    03/20


    교재(컴퓨터 비전과 딥러닝 - 라쟈링가파 샨무갸마니 p.97)


    개와 고양이를 예측하는 모델 훈련시키기 

    1. Kaggle에서 개와 고양이 이미지를 다운받는다.

    (https://www.kaggle.com/c/dogs-vs-cats/data)


    2. 다운받은 이미지 중에서 train 폴더에 있는 이미지의 일부만 사용한다.


    3. 교재의 simple cnn 코드를 활용해서 이미지 학습을 시킨다.


    # 이미지 데이터 출처 kaggle.com/c/dogs-vs-cats/data
    # tensorflow, pillow, SciPy
    print("==========================")
    print("====loading settings======")
    import tensorflow as tf
    import os
    import shutil
    work_dir = 'C:/Users/BY/Downloads/dogs-vs-cats/train/' #디렉토리 지정
    image_names = sorted(os.listdir(os.path.join(work_dir, 'train')))
    def copy_files(prefix_str, range_start, range_end, target_dir):
    image_paths = [os.path.join(work_dir, 'train', prefix_str+'.'+str(i)+'.jpg')
    for i in range(range_start, range_end)]
    dest_dir = os.path.join(work_dir, 'data', target_dir,prefix_str)
    os.makedirs(dest_dir)
    for image_path in image_paths:
    shutil.copy(image_path, dest_dir)


    # 실습을 위해 고양이와 개 이미지를 1,000개만 사용
    print("==========================")
    print("====copy image files======")
    copy_files('dog', 0, 10, 'train')
    copy_files('cat', 0, 10, 'train')
    copy_files('dog', 10, 14, 'test')
    copy_files('cat', 10, 14, 'test')


    # 간단한 CNN으로 벤치마킹. 교재의 simple_cnn 모델
    print("==========================")
    print("====define cnn model======")
    image_height, image_width = 150, 150
    train_dir = os.path.join(work_dir+'data/', 'train')
    test_dir = os.path.join(work_dir+'data/', 'test')
    no_classes = 2
    no_validation = 8 #800
    epochs = 2
    batch_size = 2 #200
    no_train = 20 #2000
    no_test = 8 #800
    input_shape = (image_height, image_width, 3)
    epoch_steps = no_train // batch_size # 여기가 0이 되어버리면
    # AttributeError: 'ProgbarLogger' object has no attribute 'log_values' 에러 발생
    test_steps = no_test // batch_size
    def simple_cnn(input_shape):
    model = tf.keras.models.Sequential()
    model.add(tf.keras.layers.Conv2D(
    filters=75, # 64
    kernel_size=(3,3),
    activation='relu',
    input_shape=input_shape
    ))
    model.add(tf.keras.layers.Conv2D(
    filters=150, # 128
    kernel_size=(3,3),
    activation='relu',
    ))
    model.add(tf.keras.layers.MaxPooling2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Dropout(rate=0.3))
    model.add(tf.keras.layers.Flatten())
    model.add(tf.keras.layers.Dense(units=32, activation='relu')) # 1024
    # tensorflow.python.framework.errors_impl.ResourceExhaustedError: OOM when allocating tensor with shape[799350,1024] and type float on /job:localhost/replica:0/task:0/device:CPU:0 by allocator cpu
    model.add(tf.keras.layers.Dropout(rate=0.3))
    model.add(tf.keras.layers.Dense(units=no_classes, activation='softmax'))
    model.compile(loss=tf.keras.losses.categorical_crossentropy,
    optimizer=tf.keras.optimizers.Adam(),
    metrics=['accuracy'])
    return model
    simple_cnn_model = simple_cnn(input_shape)
    # 한번에 이미지 묶음 하나씩만 로드.
    # tf.keras에 ImageDataGenerator라는 클래스는 필요할 때마다 이미지를 읽음
    generator_train = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1. /255)
    generator_test = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1. / 255)
    # 디렉터리로부터 이미지를 읽어오는 flow_from_directory 메소드
    train_images = generator_train.flow_from_directory(
    train_dir,
    batch_size = batch_size,
    target_size = (image_width, image_height))
    test_images = generator_test.flow_from_directory(
    test_dir,
    batch_size = batch_size,
    target_size = (image_width, image_height))
    # generator (생성기)는 모델을 학습시키기 위해 직접적으로 사용할 수 있다.
    print("==========================")
    print("====fitting cnn model=====")
    simple_cnn_model.fit_generator(
    train_images,
    steps_per_epoch=epoch_steps,
    epochs=epochs,
    validation_data=test_images,
    validation_steps=test_steps)


    코드 업로드 (https://github.com/BY1994/TIL/blob/master/Python/Tensorflow/07_Dogs_Cats_simple_cnn_keras.py)


    4. 학습 결과



    - 정확도는 거의 50% 안팎으로 나와서, 학습이 잘 되지 않았다.

    - Anaconda를 설치하지 않아서 tensorflow 외에 이미지 처리를 위한 pillow와 연산을 위한 SciPy를 직접 설치해줘야했다! (cmd로 pip install을 사용했다)

    - 또한 CPU의 부담이 너무 커서 python shell이 자꾸 죽었기 때문에 이미지는 교재의 가이드처럼 1000개를 사용하지 못하고 개수를 계속 줄여서 학습시켰다. 

    - shell을 죽지 않게 하는데 가장 큰 영향을 준 것은 model.add(tf.keras.layers.Dense(units=32, activation='relu')) 이 부분의 units가 원래 1024개였는데, 이것을 크게 줄였더니 코드가 정상적으로 실행되었다.

    - 교재의 코드는 변수가 하드코딩되어있기 때문에, 이미지의 개수를 다르게 할 경우 no_validation, batch_size, no_train, no_test를 일일히 바꾸어줘야한다.



    + 데이터셋 확장하기

    훈련 중 노이즈를 유발해서 데이터 셋의 크기를 늘린다.

    generator_train 부분의 코드만 변경하면 데이터셋 크기를 늘려서 학습시킬 수 있다.

    (https://github.com/BY1994/TIL/blob/master/Python/Tensorflow/08_Dogs_Cats_simple_cnn_keras_data_augmentation.py)



    + MNIST 데이터 API를 이용해 학습시키고 시각화 하기

    """
    텐서플로 레이어 API에서 제공하는 메소드 이용
    """
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    mnist_data = input_data.read_data_sets('MNIST_data', one_hot = True)
    input_size = 784
    no_classes = 10
    batch_size = 100
    total_batches = 200
    x_input = tf.placeholder(tf.float32, shape=[None, input_size])
    y_input = tf.placeholder(tf.float32, shape=[None, no_classes])
    # 텐서보드를 사용해 훈련 프로세스를 시각화
    # 변수의 통계를 시각화하려면 tf.summary에 변수의 통계값이 추가되어야한다.
    def add_variable_summary(tf_variable, summary_name):
    with tf.name_scope(summary_name + '_summary'):
    mean = tf.reduce_mean(tf_variable)
    tf.summary.scalar('Mean', mean)
    with tf.name_scope('standard_deviation'):
    standard_deviation = tf.sqrt(tf.reduce_mean(
    tf.square(tf_variable - mean)))
    tf.summary.scalar('StandardDeviation', standard_deviation)
    tf.summary.scalar('Maximum', tf.reduce_max(tf_variable))
    tf.summary.scalar('Minimum', tf.reduce_min(tf_variable))
    tf.summary.histogram('Histogram', tf_variable)
    # 이전 모델과 달리 MNIST 데이터를 정사각형 형태로 크기를 변경하고 2차원 이미지 형태로 사용
    # 이미지를 28 x 28 이미지 픽셀 크기로 변형
    x_input_reshape = tf.reshape(x_input, [-1, 28, 28, 1],
    name = 'input_reshape')
    # => 차원값이 -1이라는 것은 배치 크기가 임의의 수가 될 수 있음을 의미
    # => name은 텐서보드 그래프에 반영돼 쉽게 이해할 수 있음
    # 입력, 필터, 커널, 활성화가 정의된 2D 컨볼루션 레이어 정의
    def convolution_layer(input_layer, filters, kernel_size = [3, 3],
    activation = tf.nn.relu):
    layer = tf.layers.conv2d(
    inputs = input_layer,
    filters = filters,
    kernel_size = kernel_size,
    activation = activation,
    )
    add_variable_summary(layer, 'convolution')
    return layer
    # => kernel_size와 activation에 대한 디폴트 값을 줌
    # => 요약 데이터는 레이어에 추가되고, 해당 레이어는 반환됨
    # => 함수를 호출할 때마다 input_layer가 매개변수로 주입되어야함
    # 풀링 레이어에 대한 함수
    def pooling_layer(input_layer, pool_size = [2,2], strides = 2):
    layer = tf.layers.max_pooling2d(
    inputs = input_layer,
    pool_size = pool_size,
    strides = strides
    )
    add_variable_summary(layer,'pooling')
    return layer
    # => pool_size와 strides 디폴트 값이 주어지지만 필요한 경우 변경 가능
    # => 마찬가지로 레이어에 요약 데이터 추가됨
    # 밀집 레이어 정의
    def dense_layer(input_layer, units, activation=tf.nn.relu):
    layer = tf.layers.dense(
    inputs = input_layer,
    units = units,
    activation = activation
    )
    add_variable_summary(layer, 'dense')
    return layer
    # => activation에 대한 기본값을 갖고 있으며, 변수 요약 데이터 추가
    # 레이어들은 그래프로 연결되었으며, 아직 초기화되기 전이다.
    # 첫번째 컨볼루션 레이어에서 샘플링된 특성을 더 나은 특성으로 변환하기 위해
    # 새로운 컨볼루션 레이어 추가 가능
    convolution_layer_1 = convolution_layer(x_input_reshape, 64)
    pooling_layer_1 = pooling_layer(convolution_layer_1)
    convolution_layer_2 = convolution_layer(pooling_layer_1, 128)
    pooling_layer_2 = pooling_layer(convolution_layer_2)
    flattened_pool = tf.reshape(pooling_layer_2, [-1, 5*5*128],
    name='flattened_pool')
    dense_layer_bottleneck = dense_layer(flattened_pool, 1024)
    # => 컨볼루션 레이어 간의 유일한 차이점은 필터 크기
    # => 커널과 스트라이드 매개변수 값을 선택하는 것은 임의이며 경험에 의해 선택
    # => 밀집 레이어 API는 단일 차원의 벡터를 특정 개수의 숨겨진 유닛(1024개)에 매핑시킨다.
    # => 숨겨진 레이어는 ReLU 활성화 함수로 이어져 비선형 연산이 되다.
    # 드롭아웃 확률을 가진 드롭아웃 레이어
    # 훈련 모드는 드롭아웃 적용 여부에 따라 True 또는 False로 설정할 수 있으며, 훈련을 위해
    # True로 설정한다. 하지만 정확도 계산시 해당 값이 변경되어야해서 부울 값을 저장해둔다.
    dropout_bool = tf.placeholder(tf.bool)
    dropout_layer = tf.layers.dropout(
    inputs = dense_layer_bottleneck,
    rate = 0.4,
    training = dropout_bool
    )
    # 드롭아웃 레이어를 로짓이라는 밀집 레이어에 주입
    # 로짓은 클래스 개수로 이어지는 활성화 함수를 가진 마지막 레이어
    logits = dense_layer(dropout_layer, no_classes)
    # 이전처럼 로짓이 소프트맥스 레이어를 통과한 후 교차 엔트로피 계산을 수행
    # 텐서보드의 좀 더 나은 시각화를 위해 이름 범주에 추가
    with tf.name_scope('loss'):
    softmax_cross_entropy = tf.nn.softmax_cross_entropy_with_logits(
    labels=y_input, logits=logits)
    loss_operation = tf.reduce_mean(softmax_cross_entropy, name='loss')
    tf.summary.scalar('loss', loss_operation)
    # 손실 함수를 tf.train API의 메소드를 이용해 최적화
    with tf.name_scope('optimiser'):
    optimiser = tf.train.AdamOptimizer().minimize(loss_operation)
    # 정확한 예측값과 정확도 계산을 위해 이름 범주를 추가
    # 정확도에 대한 스칼라 요약 데이터도 추가
    with tf.name_scope('accuray'):
    with tf.name_scope('correct_prediction'):
    predictions = tf.argmax(logits, 1)
    correct_predictions = tf.equal(predictions, tf.argmax(y_input, 1))
    with tf.name_scope('accuracy'):
    accuracy_operation = tf.reduce_mean(
    tf.cast(correct_predictions, tf.float32))
    tf.summary.scalar('accuracy', accuracy_operation)
    # 세션을 시작하고 변수를 초기화
    session = tf.Session()
    session.run(tf.global_variables_initializer())
    # 요약 데이터를 모두 합쳐야하며, 훈련 요약 데이터와 테스팅 요약 데이터를 작성
    # 하기 위한 파일도 정의
    merged_summary_operation = tf.summary.merge_all()
    train_summary_writer = tf.summary.FileWriter('/tmp/train', session.graph)
    test_summary_writer = tf.summary.FileWriter('/tmp/test')
    # 배치에서 데이터가 로드되고 훈련을 시작
    test_images, test_labels = mnist_data.test.images, mnist_data.test.labels
    for batch_no in range(total_batches):
    mnist_batch = mnist_data.train.next_batch(batch_size)
    train_images, train_labels = mnist_batch[0], mnist_batch[1]
    _, merged_summary = session.run([optimiser, merged_summary_operation],
    feed_dict={
    x_input: train_images,
    y_input: train_labels,
    dropout_bool: True
    })
    train_summary_writer.add_summary(merged_summary, batch_no)
    if batch_no % 10 == 0:
    merged_summary, _ = session.run([merged_summary_operation,
    accuracy_operation], feed_dict={
    x_input: test_images,
    y_input: test_labels,
    dropout_bool: False
    })
    test_summary_writer.add_summary(merged_summary, batch_no)

    (코드 업로드: https://github.com/BY1994/TIL/blob/master/Python/Tensorflow/05_MNIST_Multilayer_convolution.py)


    위의 코드를 실행시킨 후, cmd 창에서 다음과 같은 주소로 이동한다.

    => tensorboard --logdir=/tmp/train을 하면 training 과 관련된 시각화 결과를,

    tensorboard --logdir=/tmp/test를 하면 test와 관련된 시각화 결과를 볼 수 있다.


    그리고 브라우저에서 localhost:6006 을 입력하면 시각화된 결과물을 확인할 수 있다.


    이는 Scalar 탭의 결과물이고, Graph 탭에서는 다음과 같은 모델의 시각화를 볼 수 있다.






    댓글

Designed by Tistory.