오픈튜토리얼스 8.13 ~ 8.26  머신러닝야학에서 배운

레몬에이드 판매량 예측, 보스턴 집값 예측, 붓꽃 분류를 tensorflow.js로 만들었습니다.

오픈튜토리얼스 머신러닝야학 내용은 아래 링크를 참조해 주세요!

https://opentutorials.org/course/4570

 

Tensorflow 1 - 생활코딩

수업소개 이 수업은 코드로 딥러닝을 구현해보는 딥러닝 기초 수업입니다.  텐서플로우를 이용하여 가장 간단한 형태의 텐서플로우 딥러닝 모델을 작성합니다. 무엇을 넣을까가 아니라, 무엇

opentutorials.org

nodejs version: 12.18.3

tensorflow.js version: 2.3.0

 

전체 코드

  const bostonPriceCSV = tf.data.csv(
    'file://' + path.join(__dirname, '../data/boston.csv'),
    { columnConfigs: { medv: { isLabel: true } } }
  )

  // tf.data.Dataset 으로 변환
  const bostonPriceDataset = bostonPriceCSV.map(({ xs, ys }) => {
    return { xs: Object.values(xs), ys: Object.values(ys) }
  }).batch(32).shuffle(10)

  // 모델 생성
  const input = tf.input({ shape: [13] })

  let hidden = tf.layers.dense({ units: 8 }).apply(input)
  hidden = tf.layers.layerNormalization().apply(hidden)
  hidden = tf.layers.activation({ activation: 'selu' }).apply(hidden)

  hidden = tf.layers.dense({ units: 8 }).apply(hidden)
  hidden = tf.layers.layerNormalization().apply(hidden)
  hidden = tf.layers.activation({ activation: 'selu' }).apply(hidden)

  hidden = tf.layers.dense({ units: 8 }).apply(hidden)
  hidden = tf.layers.layerNormalization().apply(hidden)
  hidden = tf.layers.activation({ activation: 'selu' }).apply(hidden)

  const output = tf.layers.dense({ units: 1 }).apply(hidden)

  const model = tf.model({
    inputs: input,
    outputs: output
  })
  model.compile({ optimizer: tf.train.adam(0.001), loss: tf.losses.meanSquaredError })
  model.summary()

  // 모델 학습
  await model.fitDataset(bostonPriceDataset, {
    epochs: 1000
  })

  await model.fitDataset(bostonPriceDataset, {
    epochs: 10,
    callbacks: {
      onEpochEnd: async (epoch, logs) => {
        console.log(epoch + ':' + logs.loss);
      }
    }
  })

  // 테스트 데이터 생성
  const testDataset = await createTestDataSet(bostonPriceDataset, 0, 0, 5)

  // 보스터 집값 예측
  model.predict(testDataset.xs).print()
  testDataset.ys.print()
  model.getWeights()[0].print()

 


CSV 파일 읽어오기

레몬에이드 판매량 예측에서는 tf.data.csv 함수를 사용하지 않고 readCSV 함수를 만들어 사용했습니다.

tf.data.csv 함수는

'file://' + path.join(__dirname'../data/boston.csv') 같이 'file://'를 꼭 붙여 주어야 합니다..

path.join 안에 "file://" 을 넣으면 에러가 발생합니다..

참고로 tensorflow.js API Reference 에서 tf.data.csv 함수는 

https://storage.googleapis.com/tfjs-examples/multivariate-linear-regression/data/boston-housing-train.csv

와 같은 형태의 URI 절대 주소를 사용합니다.

 

columnConfigs 부분은 medv 열이 종속변수임을 알려줍니다. 

  const bostonPriceCSV = tf.data.csv(
    'file://' + path.join(__dirname, '../data/boston.csv'),
    { columnConfigs: { medv: { isLabel: true } } }
  )

  // tf.data.Dataset 으로 변환
  const bostonPriceDataset = bostonPriceCSV.map(({ xs, ys }) => {
    return { xs: Object.values(xs), ys: Object.values(ys) }
  }).batch(32).shuffle(10)

모델 학습을 위해 tf.data.Dataset으로 변환합니다. 배치 사이즈는 32이고 셔플 시드는 10으로 지정하였습니다.

batch와 shuffle을 한 이유는 학습 속도를 향상 시키기 위해서 입니다. 자세한 부분은 더 공부해야 합니다...ㅠㅠ

 


모델 만들기

한 히든 레이어를 3개로 나누었습니다. 활성화 함수는 swish를 사용하려 하였으나

tensorflow.js에 없어서 대신 selu를 사용하였습니다. 

BatchNormalization을 처음에 사용하였는데 데이터 크기가 작아서인지 정확도가 많이 떨어졌습니다.

그래서 LayerNormalization을 사용했는데 정확도가 향상되었습니다.

이 두 정규화도 차이점이 무엇인지 공부해야 합니다.

// 모델 생성
  const input = tf.input({ shape: [13] })

  let hidden = tf.layers.dense({ units: 8 }).apply(input)
  hidden = tf.layers.layerNormalization().apply(hidden)
  hidden = tf.layers.activation({ activation: 'selu' }).apply(hidden)

  hidden = tf.layers.dense({ units: 8 }).apply(hidden)
  hidden = tf.layers.layerNormalization().apply(hidden)
  hidden = tf.layers.activation({ activation: 'selu' }).apply(hidden)

  hidden = tf.layers.dense({ units: 8 }).apply(hidden)
  hidden = tf.layers.layerNormalization().apply(hidden)
  hidden = tf.layers.activation({ activation: 'selu' }).apply(hidden)

  const output = tf.layers.dense({ units: 1 }).apply(hidden)

  const model = tf.model({
    inputs: input,
    outputs: output
  })
  model.compile({ optimizer: tf.train.adam(0.001), loss: tf.losses.meanSquaredError })
  model.summary()

optimizer는 adam으로 학습률은 0.001로 하였습니다. 손실함수는 평균 제곱근 편차를 사용했습니다.

 


모델 학습

여기서 파이썬에서 model.fit()을 사용하면 epoch 를 몇 번 학습시켰는지 알 수 있습니다.

하지만 자바스크립트에서는 콜백함수 onEpochEnd를 설정해야

한 epoch가 끝나고 epoch 순서와 손실을 알 수 있습니다.

여기서 tfjs-vis API를 프론트엔드에서 사용하면 실시간으로 진행 상황을 확인할 수 있습니다.

  // 모델 학습
  await model.fitDataset(bostonPriceDataset, {
    epochs: 1000
  })

  await model.fitDataset(bostonPriceDataset, {
    epochs: 10,
    callbacks: {
      onEpochEnd: async (epoch, logs) => {
        console.log(epoch + ':' + logs.loss);
      }
    }
  })

테스트 데이터 생성

따로 테스트 데이터셋을 준비해야하지만 기존 데이터셋에서 테스트 데이터를 생성하여 사용합니다...

// 테스트 데이터 생성
  const testDataset = await createTestDataSet(bostonPriceDataset, 0, 0, 5)

createTestDataSet은 기존 데이터셋에서 batchNumber와 범위를 정해 tensor들을 추출합니다.

tf.tidy 함수에서 생성된 tf는 함수 종료 후 없어져 메모리 활용도를 높입니다.

tf.gather 함수는 2차원 tensor에서 1차원 tensor들을 추출하는데 사용됩니다.

/**
   * features와 label을 tensor2d로 반환합니다.
   * @param {tf.data.Dataset} DataSet 
   * @param {Integer} batchNumber 
   * @param {Integer} start  
   * @param {Integer} end 
   */
const createTestDataSet = async (DataSet, batchNumber, start, end) => {
  if (start > end) {
    throw new Error("Error: 'start' is bigger than 'end'")
  }
  if (start < 0 || end < 0) {
    throw new Error("Error: 'start' and 'end' start from zero")
  }

  const dataArr = await DataSet.toArrayForTest()

  if (dataArr.length < batchNumber) {
    throw new Error("Error: Exceed batch number")
  }

  const batchSize = dataArr[batchNumber].xs.shape[0]
  if (end > batchSize) {
    throw new Error('Error: Exceed batch size')
  }

  let range = []
  for (let i = start; i < end; i++) {
    range.push(i)
  }
  const tensor1dRange = tf.tensor1d(range, 'int32')

  const xs = tf.tidy(() => {
    const tensor2dXs = dataArr[batchNumber].xs
    const XsTestDataset = tf.gather(tensor2dXs, tensor1dRange)
    return XsTestDataset
  })

  const ys = tf.tidy(() => {
    const tensor2dYs = dataArr[batchNumber].ys
    const YsTestDataset = tf.gather(tensor2dYs, tensor1dRange)
    return YsTestDataset
  })
  return { xs, ys }
}

보스턴 집값 예측

getweights()[0] 은 첫번째 레이어가 가지는 weights 값들입니다.

 

  // 보스터 집값 예측
  model.predict(testDataset.xs).print()
  testDataset.ys.print()
  model.getWeights()[0].print()

참조

https://js.tensorflow.org/api/latest/

 

TensorFlow.js | 자바스크립트 개발자를 위한 머신러닝

브라우저, Node.js 또는 Google Cloud Platform에서 모델을 학습시키고 배포합니다. TensorFlow.js는 자바스크립트 및 웹 개발을 위한 오픈소스 ML 플랫폼입니다.

www.tensorflow.org

공부할 점

1. batchNormalization, layerNormalization 차이점 알기

2. tfjs.vis 활용법 생각하기

'머신러닝' 카테고리의 다른 글

tensorflow.js 3) 붓꽃 분류하기  (0) 2020.08.28
tensorflow.js 1) 레몬에이드 판매량 예측  (0) 2020.08.27

+ Recent posts