[Python] AI 20 学習モデル・グラフへの情報追加

[macOS Catalina 10.15.7, Python 3.5.10]

学習モデルを作成した際の精度や誤差の推移に関するグラフにソースファイル名(右上)と学習時間(右下)を追加しました。学習時間については別途CSVに記録しておくと後で使えます。

Jupyter Notebookは使わず、pyenv-virtualenvの仮想環境を作成し、ソースファイルをターミナルにドラッグ&ドロップして実行しています。

import time,datetime,os

start = time.time()

def plot_loss_accuracy_graph(history):
	process_time = time.time() - start
	td = datetime.timedelta(seconds = process_time)
	dt_now = datetime.datetime.now()
	dt_now_str = dt_now.strftime('%y%m%d%H%M')

	image_loss ='{}_loss.png'.format(dt_now_str)
	image_accuracy ='{}_accuracy.png'.format(dt_now_str)

	fig = plt.figure()
	plt.plot(history.history['loss'], "-D", color="blue", label="train_loss", linewidth=2)
	plt.plot(history.history['val_loss'], "-D", color="black", label="val_loss", linewidth=2)
	plt.title('LOSS')
	fig.text(0.7, 0.95, os.path.basename(__file__))
	fig.text(0.8, 0.03, str(td))
	plt.xlabel('Epochs')
	plt.ylabel('Loss')
	plt.legend(loc='upper right')
	plt.tight_layout()
	fig.savefig(image_loss)

	fig2 = plt.figure()
	plt.plot(history.history['acc'],"-o", color="green", label="train_accuracy", linewidth=2)
	plt.plot(history.history['val_acc'],"-o",color="black", label="val_accuracy", linewidth=2)
	plt.title('ACCURACY')
	fig2.text(0.7, 0.95, os.path.basename(__file__))
	fig2.text(0.8, 0.03, str(td))
	plt.xlabel('Epochs')
	plt.ylabel('Accuracy')
	plt.legend(loc="lower right")
	plt.tight_layout()
	fig2.savefig(image_accuracy)

[Python] AI 19 KerasによるMNISTの画像学習 TensorFlow2

[macOS Catalina 10.15.7, Python 3.9.7]

これまでは教本に合わせてTensorFlowについては1で学習を進めてきましたが、最新技術にキャッチアップするためTensorFlow2を使ってみることにしました。

pip list, pyenv versionsは以下の通りです。ライブラリは最新バージョンで揃えました。

ネットではTensorFlow1とTensorFlow2, Kerasとtensorflow.kerasなど最新情報と陳腐化した情報が混在していてカオスな状況になっています。私を含め学習者はこれらの情報を慎重に取捨選択する必要があります。

Package                 Version
----------------------- ---------
absl-py                 0.14.1
astunparse              1.6.3
cachetools              4.2.4
certifi                 2021.10.8
charset-normalizer      2.0.7
clang                   5.0
cycler                  0.10.0
flatbuffers             1.12
gast                    0.4.0
google-auth             1.35.0
google-auth-oauthlib    0.4.6
google-pasta            0.2.0
grpcio                  1.41.0
h5py                    3.1.0
idna                    3.3
Keras                   2.4.3
Keras-Preprocessing     1.1.2
kiwisolver              1.3.2
Markdown                3.3.4
matplotlib              3.4.3
numpy                   1.19.5
oauthlib                3.1.1
opt-einsum              3.3.0
Pillow                  8.3.2
pip                     21.2.3
protobuf                3.18.1
pyasn1                  0.4.8
pyasn1-modules          0.2.8
pyparsing               2.4.7
python-dateutil         2.8.2
PyYAML                  5.4.1
requests                2.26.0
requests-oauthlib       1.3.0
rsa                     4.7.2
scipy                   1.7.1
setuptools              57.4.0
six                     1.15.0
tensorboard             2.6.0
tensorboard-data-server 0.6.1
tensorboard-plugin-wit  1.8.0
tensorflow              2.6.0
tensorflow-estimator    2.6.0
termcolor               1.1.0
torch                   1.9.1
typing-extensions       3.7.4.3
urllib3                 1.26.7
Werkzeug                2.0.2
wheel                   0.37.0
wrapt                   1.12.1
  system
  3.5.10
  3.7.4
  3.8.2
  3.8.3
  3.8.5
  3.8.6
  3.9.0
  3.9.2
  3.9.4
  3.9.5
  3.9.7
  3.9.7/envs/ai_study_3.9.7
* ai_study_3.9.7 (set by /Users/xxx/.python-version)
  anaconda3-2021.05
  jython-2.7.2

[Python] AI 18 学習環境の検討(付録 横棒グラフの作成)

AI学習環境を一旦Windows10に移していました。久しぶりに自作PCを起動するとWindows Update35日間自動更新停止の期限が切れていて勝手に更新され、案の定ブルースクリーン頻発状態になりました。

幸い直前のシステムイメージがあったので復元し、グループポリシーエディタで自動更新停止を無期限に設定して(Win10 Homeでは設定不可)、Macに舞い戻ってきました。自作erにとってWindows10のアップデートはmacOSやiOSのそれとは比較にならないほど危険です。

Windows10とRyzen CPU、あるいはマザボとの相性が悪いのか、原因を探る気も起きません。復旧までに半日を要し、散々な目に遭いました。Windows10はしばらく扱いたくないです。

前回記事でも書きましたが、Window10でGeForce 750Tiを使うとMac mini 2018よりもKerasの学習モデルを速く作成できました。このGPUは7年前に発売された古いものなので、新しいGPUを買おうかと思っていた矢先のブルースクリーン事案により、やはり安定しているMacで学習を続けることにしました。

調べてみるとApple M1のGPUとしての機能はNVIDIAの廉価なGPUと同レベルであることが分かりました。今秋に発売予定のM1X MacがGeForce 1050辺りを遥かに凌駕するのは確実でしょう。

M1X Mac miniが発売されるのであれば、ホビーユースのAI学習機としても買いだと思います。

import matplotlib.pyplot as plt

x = [1, 2, 3, 4]
y = [4868, 12765, 18230, 18260]
label_x = ["Mac mini 2018","GeForce 750Ti","GeForce 1050","Apple M1"]

image ='test.png'
fig = plt.figure()
colorlist = ['#2e8b57','#8a2be2','#8a2be2','#2e8b57']

plt.barh(x, y,color=colorlist,align="center")
plt.yticks(x, label_x)
plt.title('Geekbench OpenCL', fontsize=18)
plt.tick_params(labelsize=14)
plt.tight_layout()
plt.show()

fig.savefig(image)

[Python] AI 17 KerasによるMNISTの画像学習 Windows環境への移行

macOS Mojave以降はGPUプラットフォームCUDAが使えないため、やむなくAI学習環境をWindows10に移行しました。CPUだけでは学習速度が遅すぎるので。

今回の移行で前回コードの学習時間が7分から2分半に短縮されました。2014年発売のGeForce GTX 750 Tiを新たに使っています。前環境Mac mini 2018のCPUは3.0GHz 6コアIntel Core i5です。

750Tiのドライバはver.456.55で今のところ安定しています。これまではグラボに無関心でしたが、いいボードが欲しくなってきました。

Pythonは3.5から3.7.9に変更しました。pyenv-venvの仮想環境を使っています。 pyenv-venv ではPythonの同一バージョンで複数の環境が作れるので便利です。

CUDAのバージョンは10.0、cuDNNは7.6.0です。pip listは下図の通りです。

ネット情報は私含め執筆者各々のPC環境での情報、いわゆるおま環情報だらけです。あまり参考にならないどころか、下手すると泥沼にはまってしまいます。TensorFlowなど公式サイトの情報を参考に環境構築されることをお勧めします。

Package              Version
-------------------- --------
absl-py              0.14.1
astor                0.8.1
cached-property      1.5.2
cycler               0.10.0
gast                 0.2.2
google-pasta         0.2.0
grpcio               1.41.0
h5py                 3.4.0
importlib-metadata   4.8.1
Keras                2.2.4
Keras-Applications   1.0.8
Keras-Preprocessing  1.1.2
kiwisolver           1.3.2
Markdown             3.3.4
matplotlib           3.0.2
numpy                1.21.2
opt-einsum           3.3.0
pip                  20.1.1
protobuf             3.18.1
pyparsing            2.4.7
python-dateutil      2.8.2
PyYAML               5.4.1
scipy                1.7.1
setuptools           47.1.0
six                  1.16.0
tensorboard          1.15.0
tensorflow-estimator 1.15.1
tensorflow-gpu       1.15.0
termcolor            1.1.0
typing-extensions    3.10.0.2
Werkzeug             2.0.2
wheel                0.37.0
wrapt                1.13.1
zipp                 3.6.0

[Python] AI 16 KerasによるMNISTの画像学習

教本を参考にKerasで手書き数字画像認識の学習をさせてみました。私の条件では7回目の学習で正解率が99.1%に達しサチりました。

調べてみるとAIフレームワークのTOP3はTensorflow(Google)、PyTorch(Facebook)、Keras(Google系)らしく、それらの中でもTensorflowとPyTorchが抜けた存在だとか。日本産のChainerは開発元がPyTorchを採用・移行し、開発中断となっています。

import matplotlib.pyplot as plt
import numpy as np
import keras
from keras.datasets import mnist
from keras import backend as Keras
from keras.models import load_model

NUM_CLASSES = 10
IMG_ROWS, IMG_COLS = 28, 28

def plot_image(data_location, predictions_array, real_teacher_labels, dataset):
	predictions_array, real_teacher_labels, img = predictions_array[data_location], real_teacher_labels[data_location], dataset[data_location]
	plt.grid(False)
	plt.xticks([])
	plt.yticks([])

	plt.imshow(img,cmap="coolwarm")

	predicted_label = np.argmax(predictions_array)
	# 文字の色:正解は緑、不正解は赤
	if predicted_label == real_teacher_labels:
		color = 'green'
	else:
		color = 'red'
	
	plt.xlabel("{} {:2.0f}% ({})".format(handwritten_number_names[predicted_label],
								100*np.max(predictions_array),
								handwritten_number_names[real_teacher_labels]),
								color=color)

def plot_teacher_labels_graph(data_location, predictions_array, real_teacher_labels):
	predictions_array, real_teacher_labels = predictions_array[data_location], real_teacher_labels[data_location]
	plt.grid(False)
	plt.xticks([])
	plt.yticks([])

	thisplot = plt.bar(range(10), predictions_array, color="#666666")
	plt.ylim([0, 1]) 
	predicted_label = np.argmax(predictions_array)

	thisplot[predicted_label].set_color('red')
	thisplot[real_teacher_labels].set_color('green')

def convertOneHotVector2Integers(one_hot_vector):
	return [np.where(r==1)[0][0] for r in one_hot_vector]

## データの前処理
handwritten_number_names= [str(num) for num in range(0,10)]
# handwritten_number_names = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] # 教本では分かりやすく記述している
(train_data, train_teacher_labels), (test_data, test_teacher_labels) = mnist.load_data()

if Keras.image_data_format() == 'channels_first':
	train_data = train_data.reshape(train_data.shape[0], 1, IMG_ROWS, IMG_COLS)
	test_data = test_data.reshape(test_data.shape[0], 1, IMG_ROWS, IMG_COLS)
	input_shape = (1, IMG_ROWS, IMG_COLS)
else:
	train_data = train_data.reshape(train_data.shape[0], IMG_ROWS, IMG_COLS, 1)
	test_data = test_data.reshape(test_data.shape[0], IMG_ROWS, IMG_COLS, 1)
	input_shape = (IMG_ROWS, IMG_COLS, 1)

train_data = train_data.astype('float32')
test_data = test_data.astype('float32')
print(test_data)

train_data /= 255 # 今回は検証なのでtrain_dataは使いません
test_data /= 255

test_teacher_labels = keras.utils.to_categorical(test_teacher_labels, NUM_CLASSES)
## データの前処理 終了

# 学習モデルの読み込み
model = load_model('keras-mnist-model.h5')

# 予測実行
prediction_array = model.predict(test_data)

# 描画用検証データに変換
test_data = test_data.reshape(test_data.shape[0], IMG_ROWS, IMG_COLS)

# 100個のデータを予測(201-300)
NUM_ROWS = 10
NUM_COLS = 10
NUM_IMAGES = NUM_ROWS * NUM_COLS
START_LOC = 200

plt.figure(figsize=(2*NUM_COLS-4, 1*NUM_ROWS-2))
plt.subplots_adjust(wspace=0.4, hspace=0.4)
for i,num in enumerate(range(START_LOC,START_LOC + NUM_IMAGES)):
	plt.subplot(NUM_ROWS, 2*NUM_COLS, 2*i+1)
	plot_image(num, prediction_array,convertOneHotVector2Integers(test_teacher_labels), test_data)

	plt.subplot(NUM_ROWS, 2*NUM_COLS, 2*i+2)
	plot_teacher_labels_graph(num, prediction_array, convertOneHotVector2Integers(test_teacher_labels))
	_ = plt.xticks(range(10), handwritten_number_names, rotation=45)

plt.show()

[Python] AI 15 PyTorchによるMNISTとCIFER-10の画像学習

プログラムの構成自体はChainerと同じです。教本プログラムに使えるライブラリのバージョンは、torch 0.4.1, torchvision 0.2.2 でした

珍しくコードには問題はなかったですが、torchのバージョン調整に少し手間取りました。後で調べると教本に明記していました。
 1.5.1(文法違い) → 1.1.0(データセットなし) → 1.2.0(文法違い) → 0.4.1

CIFER-10のようなデータセットをベースにした学習モデルを使えば、ログインの際に画像を選んで認証をパスする作業を自動化できそうです。ただ正解率が9割を超えないと使い物にならないでしょう。

教本内で面白いリスト内包表記を見つけました。最初は意味がわかりませんでしたが、同じ数字を繰り返すといった内容です。個人的には長ったらしいので[0.]*10を使いますね。

# 教本
listA = list(0. for i in range(10))
# 他の表記
listA = [0. for i in range(10)]
listA = [0.]*10

print(listA)
--------------------------------------------------

出力
--------------------------------------------------
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

[Python] AI 14 Chainerによる動物認識学習モデル 描画読み込み

マウスで描いた動物や指定した画像ファイルを判定させるところでつまずきました。

描画判定ではボタンを押しても反応がなく、画像判定では画像確定ボタンを押すとブラウザが500 Internal Server Errorになりました。

JavaScriptファイルやHTMLファイルをチェック、Chromeのコンソールを確認し、さらにDockerのBashを起動してコンテナ内部のファイルを確認するなどしました。

結局、jpg化した描画ファイルを保存するディレクトリが作られていないことが原因でした。たった2行の追加で解決です。ここで足止めを食らっている読者の方は結構いそうです。

初級者泣かせの教本で今回も大分時間を使いましたが、DockerやJavaScriptのスキルアップにつながりました。AIを学ぶというよりも間違い探しの様相を呈してきました。モチベーションを維持できるのであれば、それも良しです。

この教本が出版された2019年6月時点でのライブラリのバージョンを調査しましたので、Dockerfileを載せておきます。リリースが6月に近すぎるバージョンは避けて、やや古めを選んでいます。

UPLOAD_FOLDER = './images'
# 以下2行を追加
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
FROM python:3.5-stretch

RUN mkdir -p /usr/src/app
ADD ./app /usr/src/app
RUN pip3 install --upgrade pip
RUN pip3 install requests==2.21.0
RUN pip3 install Flask==1.0.4
RUN pip3 install flask-cors==2.1.3
RUN pip3 install opencv-python==4.0.1.24
RUN pip3 install opencv-contrib-python==4.0.1.24
RUN pip3 install tensorflow==1.15
RUN pip3 install keras==2.2.4
RUN pip3 install chainer==5.0.0
RUN pip3 install Pillow==5.4.1
RUN apt-get update
RUN apt-get install -y libgl1-mesa-dev

WORKDIR /usr/src/app
EXPOSE 5000
RUN export FLASK_ENV=development

[Python] AI 13 Chainerによる動物認識学習モデル 読み込みと実行

[macOS Catalina 10.15.7]

pyenvのPython3.5環境でコードを走らせています。Dockerを使う手もありますが、個人開発者にはメリットが薄いのと時間的学習コストが掛かりそうなので今回は見送りです。

この種のモデルでGPUを使う場合はCUDA(CuPy)をそれ用に設定するのですが、NVIDIAによるサポートはmacOS High Sierra 10.13で終了しています。 したがってMojave 10.14以降ではGPUなしの設定のみ可能になるようです。

学習してモデルを保存するところは先を急ぐため省略します。

前回までの手書き数字認識学習モデルでは新しいChainer(7.8.0)でも問題なかったものの、このモデルでは5.0.0にダウングレードしないと動きませんでした。

また教本にはh5ファイルの保存方法について説明がありましたが、読み込み方法の説明は抜けていました。さらに調べる際、Kerasの学習ファイルと混同してしまったため、解決するのに時間が掛かりました

この教本にはpipでインストールしたライブラリのバージョンがほとんど載っていません。正に鮮度が命といった感じです。ネット記事でもそうですが、pip listも合わせて載せていただきたいものです。

chainer (5.0.0)
Keras (2.2.4)
Keras-Applications (1.0.8)
Keras-Preprocessing (1.1.2)
matplotlib (3.0.3)
numpy (1.18.5)
opencv-python (4.4.0.42)
Pillow (7.2.0)
pip (9.0.1)
PyQt5 (5.15.2)
PyQt5-sip (12.9.0)
tensorboard (1.15.0)
tensorflow (1.15.0)
tensorflow-estimator (1.15.1)
from PIL import Image
import numpy as np
import chainer
import chainer.functions as F
import chainer.links as L
from chainer import serializers,Chain
from chainer.cuda import to_cpu

INPUT_WIDTH = 128
INPUT_HEIGHT = 128

def data_reshape(width_height_channel_image):
    image_array = np.array(width_height_channel_image)
    return image_array.transpose(2, 0, 1)

def convert_test_data(image_file_path, size, show=False):
    
    image = Image.open(image_file_path)

    # 共通の画像のリサイズ
    result_image = image.resize((INPUT_WIDTH, INPUT_HEIGHT), Image.LANCZOS)

    # 画像データの再形成
    image = data_reshape(result_image)

    # 型をfloat32に変換
    result = image.astype(np.float32)
    result = model.xp.asarray(result)

    # モデルに渡すデータフォーマットに変換
    result = result[None, ...]

    return result

class CNN(Chain):
  def __init__(self):
    super(CNN, self).__init__()

    with self.init_scope():
      self.conv1 = L.Convolution2D(None, out_channels=32, ksize=3, stride=1, pad=1)
      self.conv2 = L.Convolution2D(in_channels=32, out_channels=64, ksize=3, stride=1, pad=1)
      self.conv3 = L.Convolution2D(in_channels=64, out_channels=128, ksize=3, stride=1, pad=1)
      self.conv4 = L.Convolution2D(in_channels=128, out_channels=256, ksize=3, stride=1, pad=1)
      self.layer1 = L.Linear(None, 1000)
      self.layer2 = L.Linear(1000, 2)
  
  def __call__(self, input):
    func = F.max_pooling_2d(F.relu(self.conv1(input)), ksize=2, stride=2)
    func = F.max_pooling_2d(F.relu(self.conv2(func)), ksize=2, stride=2)
    func = F.max_pooling_2d(F.relu(self.conv3(func)), ksize=2, stride=2)
    func = F.max_pooling_2d(F.relu(self.conv4(func)), ksize=2, stride=2)
    func = F.dropout(F.relu(self.layer1(func)), ratio=0.80)
    func = self.layer2(func)
    return func

if __name__ == '__main__':
    model = L.Classifier(CNN())
    serializers.load_hdf5("chainer-dogscats-model.h5", model)
    
    image_path = '1.jpg'
    Image.open(image_path)

    # 学習時と同じ画像のサイズに変換
    test_data= convert_test_data(test_image_url, (INPUT_WIDTH, INPUT_HEIGHT))

    with chainer.using_config('train', False), chainer.using_config(
                'enable_backprop', False):
        test_teacher_labels = model.predictor(test_data)
        test_teacher_labels = to_cpu(test_teacher_labels.array)
        test_teacher_label = test_teacher_labels.argmax(axis=1)[0]
        if test_teacher_label == 0:
            retval = '猫'
        else:
            retval = '犬'

    print(retval)

[Python] AI 12 Chainer + MNISTによる深層学習 Flaskベースアプリの導入 その3 Dockerfile

前回のDockerfileでdocker-composeファイルを走らせたところ、またエラーが発生しました。

調べてみるとTensorFlowはバージョン1を使っており、その場合PythonとKerasが新しいバージョンだと動かないということが判明しました。以下のようにDockerfileを修正しました。Pythonは元の3.5に戻しました。Kerasは2.3.1はNG、2.2.4でOKでした。

教本が発行された2019年6月時点では良書だったのかもしれませんが、2021年10月現在かなりのコードがライブラリの相性により、まともに動かなくなっています。こんなに早く風化するとは、AIの世界はシビアですね。先端技術ですから後方互換は考えないということでしょう。

2019年ならまだまだ新しいと思って購入したものの、のんびり楽しむどころかビシビシ鍛えられています。この本でプログラミング初心者が独習するのはちょっと厳しいかと思います。

FROM python:3.5-stretch

RUN mkdir -p /usr/src/app
ADD ./app /usr/src/app
RUN pip3 install --upgrade pip
RUN pip3 install requests
RUN pip3 install Flask
RUN pip3 install flask-cors
RUN pip3 install opencv-python
RUN pip3 install opencv-contrib-python
RUN pip3 install tensorflow==1.15
RUN pip3 install keras==2.2.4
RUN pip3 install chainer
RUN pip3 install Pillow
RUN apt-get update
RUN apt-get install -y libgl1-mesa-dev

WORKDIR /usr/src/app
EXPOSE 5000
RUN export FLASK_ENV=development
Chainer Dogs & Cats model is loaded.
Chainer MNIST model is loaded.
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 26, 26, 32)        320       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 24, 24, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 64)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 12, 12, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 9216)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 128)               1179776   
_________________________________________________________________
dropout_2 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                1290      
=================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
 _________________________________________________________________
Keras MNIST model is loaded.
TensorFlow Flower model is loaded.
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

[Python] AI 11 Chainer + MNISTによる深層学習 Flaskベースアプリの導入 その2

前回の続きです。

macOSではapt-getコマンドを使えないという理由でDockerの使用を一旦断念しましたが、DockerコンテナはDebianベースなのでDockerfileにコマンドを書き込めば良いということに気付きました。Dockerを扱い始めたばかりのド素人には少々難易度が高かったです。

そもそもが仮想環境の構築であってmacOSではないということを理解していませんでした

DockerfileのFROMをPython3.5から最新(3.9)に変更し、コマンドを3行追記しました。これで先に進むことができましたが、しばらくしてまたエラーになりました。

このエラーについては著者のGitHubに注意事項として記されていたので、適切に対処すればクリアできそうです。

思いがけずDockerに関するスキルアップができたのは収穫でした。

2021/10/5追記:Dockerfileを次回記事で更新しています。

FROM python:3

RUN mkdir -p /usr/src/app
ADD ./app /usr/src/app
RUN pip3 install --upgrade pip
RUN pip3 install requests
RUN pip3 install Flask
RUN pip3 install flask-cors
RUN pip3 install opencv-python
RUN pip3 install opencv-contrib-python
RUN pip3 install tensorflow
RUN pip3 install keras
RUN pip3 install chainer
RUN pip3 install Pillow
RUN apt-get update
RUN apt-get install -y libgl1-mesa-dev

WORKDIR /usr/src/app
EXPOSE 5000
RUN export FLASK_ENV=development