Oisix ra daichi Creator's Blog(オイシックス・ラ・大地クリエイターズブログ)

オイシックス・ラ・大地株式会社のエンジニア・デザイナーが執筆している公式ブログです。

LSTMを用いた需要予測について

こんにちは。Oisix ra daichiで7ヶ月ほどインターンをしておりました池園です。普段は大学院で省電力高性能計算アーキテクチャ設計の研究をしています。今回は、インターンの最後に取り組みましたLSTMによる需要予測についてお話します。最後の方で少しだけOisix ra daichiでのインターンの内容や雰囲気についてお伝えできればと思います。

突然ですが、Oisix ra daichiでは商品を出荷しています(!?)。

しかし、ただ出荷するというわけではないのです。例えば、Oisixの商品の一つにkit Oisixというものがあります。

f:id:oitech:20190125173916j:plain

kit Oisixは、「20分で主菜と副菜が作れる必要な食材を必要な分だけ集めた食材セット」です。イメージ図は以下です。 f:id:oitech:20190125174027j:plain

kit Oisixがあれば、献立を考えなくてよくなり(選択肢から選ぶことになります)、料理やお買い物の時間を短縮できるというスグレモノというわけです。 また、レシピがついているので、料理があまり得意ではなかったり、初めてで勝手がわからない調理であったとしてもその調理方法を調べる時間を短縮できます。またお買い物の時間は、定期注文にすれば限りなく0に近づけられます。

このような便利なkit Oisixですが、袋に小分けしているため、出荷の前に梱包作業や商品の加工作業が必要となります。また、商品を加工するためには、その商品の材料を発注しなければなりません。ここで、ここで商品を出荷するためのスケジュールに関する重要な3つのキーワードがあります。

それは出荷日、締め日、発注です。

まず、出荷日は、お客様に対して倉庫から発送する日です。この日までに発注、入荷、加工、梱包まですべて完了させている必要があります。

Oisixではお客様ごとに締め日という期限があります。これは定期注文をご希望されているお客様に対して、定期出荷として送る品物を決めていただく期限になります。この期限までにお客様には商品を決めていただく、という形になっています。

発注は、出荷日から発注からの入荷、加工、梱包の作業を行う時間から逆算をして余裕を持って行う必要があります。

しかし、ここで問題があります。 締め日よりも発注を早くしなければならないのです!

f:id:oitech:20190125174238p:plain

例えば、上記のような火曜が出荷日で、月曜が締め日であったケースを考えます。 この場合には、発注の日曜の時点でどれだけkit Oisixが売れるのかを予測する必要があるのです。

ここで、注文の予測精度には高いものが要求されます。これは、生産回数によるコストや余り商品のコストが発生するからです。例えば、売れる数を実際の売れる数よりも多く予測してしまうと、廃棄となり廃棄コストが発生します。逆に少なく予測してしまうと、もう一度生産することになり生産レーンを作るコストが無駄にかかることになります。この「生産レーンを作るコスト」は無視できないほど大きく、大きくコストが増大する理由になります。

そこで、Oisix ra daichiではいくつかのロジックを用いて評価を行い、この需要予測精度を上げることができないか、というチャレンジをしていました。

今回は、その一つのロジックとしてLSTMを利用しました。LSTMはディープラーニングの手法の一つです。LSTMを用いた理由は注文の動向が時系列データである、という観察によるものです。

制作したアーキテクチャのイメージを示したのが、以下の図です。青がLSTMを表した図です。

f:id:oitech:20190125174217p:plain

コードとしては以下のようなものになります。 ライブラリはKeras 2.2.4, Tensorflow 1.8.0を利用しました。

model = Sequential()
model.add(LSTM(hidden_neurons_0,
  batch_input_shape=(None, length_of_sequences, in_neurons),
  return_sequences=True,
  unroll=True,
  recurrent_dropout=0.5,
  kernel_regularizer=regularizers.l2(0.0001)))
model.add(LayerNormalization())
model.add(LSTM(hidden_neurons_1,
  return_sequences=True,
  recurrent_dropout=0.5))
model.add(LayerNormalization())
model.add(LSTM(hidden_neurons_2, recurrent_dropout=0.5))
model.add(LayerNormalization())
model.add(Dense(out_neurons, activation='relu'))
model.compile(loss=’mean_squared_error’, optimizer=adam)

このコードをベースにして層の深さや入力の個数、などはある程度バリエーションをもたせてパラメータについて調査しました。パラメータ自動調整などのツールを用いて、パラメータの組み合わせについても試行しています。結果、いくつか提案されたアーキテクチャの中で最良値を吐き出すことがあるモデルになりました。

しかし、比較対象のロジックと比べて、時系列データの長さを調整する必要があり前処理が困難である、安定性には乏しい、など思っていた以上にロジックの複雑度が高く、採用は難しいのでは…?ということでした。

やはり実際の運用ベースで考えたときには、微量の改善と運用コストとの間トレードオフを考える必要がありことを再認識しました。また、ハイパーパラメータの調整などで知識が不足が露呈し、たくさん論文を読まなければならないということもまた再認識しました。

インターン全体を通して

Oisix ra daichiは、実際に商品を生産して販売しているということもあり多種多様な課題が散らばっていることが特徴だと思います。数ある課題のなかには、自分のやりたいことに近しい課題があるというイメージです。

データ分析チームの前では、アプリ制作チームでお世話になりました。Oisix ra daichi内でもやりたいことがあれば、それにより分野を横断していろいろなことを勉強する機会がある場でもあると思います。

コードについて親身になってレビューをしていただいたり、実際のプロダクトでテスト可能性や依存性を考えたアーキテクチャ設計について一緒に議論する場を設けてくださったり、美味しいお菓子をおすそ分けしてくださったりと大変お世話になりました。 ありがとうございます。

Oisix ra daichi Creator's Blogはオイシックス・ラ・大地株式会社のエンジニア・デザイナーが執筆している公式ブログです。

オイシックス・ラ・大地株式会社では一緒に働く仲間を募集しています