본문 바로가기

IT/Deeplearning

[Code Review/ self-driving lab] Udacity Self-driving Car - (2)

저번에 이어서 이번 포스팅은 pre-trained 모델의 코드를 살펴보려고합니다.


지난번 포스팅 :: [Code Review/ self-driving lab] Udacity Self-driving Car - (1)




1. Main 함수


@sio.on('connect')
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Remote Driving')
    parser.add_argument('model', type=str,
    help='Path to model definition json. Model weights should be on the same path.')
    args = parser.parse_args()
    with open(args.model, 'r') as jfile:
        model = model_from_json(json.load(jfile))

    model.compile("adam", "mse")
    weights_file = args.model.replace('json', 'h5')
    model.load_weights(weights_file)

    # wrap Flask application with engineio's middleware
    app = socketio.Middleware(sio, app)

    # deploy as an eventlet WSGI server
    eventlet.wsgi.server(eventlet.listen(('', 4567)), app)


- 먼저 함수 실행시, 입력된 파라미터값을 가져옵니다.

- 가져온 파라미터 (keras model json 파일)을 읽습니다.

- json으로부터 가져온 네트워크 정보를 통해서 모델을 컴파일합니다.

- 그리고 같은 path에 있는 모델의 weights파일을 load합니다.

:: 이러한 내용은 저자가 parser.add_argument란에 써둔 help = 'Path to model definition json. Model weights should be on the same path'라는 것을 통해서 Model.json과 Model의 weights파일인 model.h5파일이 같은 경로에 같은 이름으로 있어야한다는 것을 알 수 있습니다.

- 통신을 위한 middleware와 event를 등록합니다.


2. Keras Model Json 파일


여기서 Keras의 Model Json 파일의 구성은 다음과 같습니다.

"{
    \"class_name\": \"Sequential\",
    \"keras_version\": \"1.2.1\",
    \"config\": [
        {
            \"class_name\": \"Lambda\",
            \"config\":
            {
                \"name\": \"lambda_1\",
                \"output_shape_type\": \"raw\",
                \"input_dtype\": \"float32\",
                \"function_type\": \"lambda\",
                \"output_shape\": null,
                \"function\":
                [
                    \"\\u00e3\\u0001\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0001\\u0000\\u0000\\u0000\\u0002\\u0000\\u0000\\u0000S\\u0000\\u0000\\u0000s\\f\\u0000\\u0000\\u0000|\\u0000\\u0000d\\u0001\\u0000\\u001bd\\u0002\\u0000\\u0018S)\\u0003N\\u00e7\\u0000\\u0000\\u0000\\u0000\\u0000\\u00e0_@\\u00e7\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u00f0?\\u00a9\\u0000)\\u0001\\u00da\\u0001xr\\u0003\\u0000\\u0000\\u0000r\\u0003\\u0000\\u0000\\u0000\\u00faAC:/Users/AIP/Documents/changsub/PycharmProjects/untitled/model.py\\u00da\\b\\u009c\\u0000\\u0000\\u0000s\\u0000\\u0000\\u0000\\u0000\", null, null
                ],
                \"arguments\": {},
                \"batch_input_shape\": [null, 128, 128, 3],
                \"trainable\": true
            }
        }, mod
        {
            \"class_name\": \"Convolution2D\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"nb_col\": 3,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"relu\",
                \"name\": \"Conv1\",
                \"nb_row\": 3,
                \"nb_filter\": 32,
                \"W_constraint\": null,
                \"bias\": true,
                \"init\": \"glorot_uniform\",
                \"subsample\": [2, 2],
                \"border_mode\": \"same\",
                \"dim_ordering\": \"tf\"
            }
        },
        {
            \"class_name\": \"MaxPooling2D\",
            \"config\":
            {
                \"name\": \"maxpooling2d_1\",
                \"strides\": [2, 2],
                \"dim_ordering\": \"tf\",
                \"trainable\": true,
                \"border_mode\": \"same\",
                \"pool_size\": [2, 2]
            }
        },
        {
            \"class_name\": \"Convolution2D\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"nb_col\": 3,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"relu\",
                \"name\": \"Conv2\",
                \"nb_row\": 3,
                \"nb_filter\": 64,
                \"W_constraint\": null,
                \"bias\": true,
                \"init\": \"glorot_uniform\",
                \"subsample\": [2, 2],
                \"border_mode\": \"same\",
                \"dim_ordering\": \"tf\"
            }
        },
        {
            \"class_name\": \"MaxPooling2D\",
            \"config\":
            {
                \"name\": \"maxpooling2d_2\",
                \"strides\": [2, 2],
                \"dim_ordering\": \"tf\",
                \"trainable\": true,
                \"border_mode\": \"same\",
                \"pool_size\": [2, 2]
            }
        },
        {
            \"class_name\": \"Convolution2D\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"nb_col\": 3,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"relu\",
                \"name\": \"Conv3\",
                \"nb_row\": 3,
                \"nb_filter\": 128,
                \"W_constraint\": null,
                \"bias\": true,
                \"init\": \"glorot_uniform\",
                \"subsample\": [1, 1],
                \"border_mode\": \"same\",
                \"dim_ordering\": \"tf\"
            }
        },
        {
            \"class_name\": \"MaxPooling2D\",
            \"config\":
            {
                \"name\": \"maxpooling2d_3\",
                \"strides\": [2, 2],
                \"dim_ordering\": \"tf\",
                \"trainable\": true,
                \"border_mode\": \"same\",
                \"pool_size\": [2, 2]
            }
        },
        {
            \"class_name\": \"Convolution2D\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"nb_col\": 2,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"relu\",
                \"name\": \"Conv4\",
                \"nb_row\": 2,
                \"nb_filter\": 128,
                \"W_constraint\": null,
                \"bias\": true,
                \"init\": \"glorot_uniform\",
                \"subsample\": [1, 1],
                \"border_mode\": \"same\",
                \"dim_ordering\": \"tf\"
            }
        },
        {
            \"class_name\": \"Flatten\",
            \"config\":
            {
                \"name\": \"flatten_1\",
                \"trainable\": true
            }
        },
        {
            \"class_name\": \"Dropout\",
            \"config\":
            {
                \"name\": \"dropout_1\",
                \"trainable\": true,
                \"p\": 0.2
            }
        },
        {
            \"class_name\": \"Dense\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"input_dim\": 2048,
                \"output_dim\": 128,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"relu\",
                \"name\": \"FC1\",
                \"bias\": true,
                \"W_constraint\": null,
                \"init\": \"glorot_uniform\"
            }
        },
        {
            \"class_name\": \"Dropout\",
            \"config\":
            {
                \"name\": \"dropout_2\",
                \"trainable\": true,
                \"p\": 0.5
            }
        },
        {
            \"class_name\": \"Dense\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"input_dim\": 128,
                \"output_dim\": 128,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"relu\",
                \"name\": \"FC2\",
                \"bias\": true,
                \"W_constraint\": null,
                \"init\": \"glorot_uniform\"
            }
        },
        {
            \"class_name\": \"Dropout\",
            \"config\":
            {
                \"name\": \"dropout_3\",
                \"trainable\": true,
                \"p\": 0.5
            }
        },
        {
            \"class_name\": \"Dense\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"input_dim\": 128,
                \"output_dim\": 64,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"relu\",
                \"name\": \"FC3\",
                \"bias\": true,
                \"W_constraint\": null,
                \"init\": \"glorot_uniform\"
            }
        },
        {
            \"class_name\": \"Dense\",
            \"config\":
            {
                \"activity_regularizer\": null,
                \"b_constraint\": null,
                \"input_dim\": 64,
                \"output_dim\": 1,
                \"b_regularizer\": null,
                \"W_regularizer\": null,
                \"trainable\": true,
                \"activation\": \"linear\",
                \"name\": \"dense_1\",
                \"bias\": true,
                \"W_constraint\": null,
                \"init\": \"glorot_uniform\"
            }
        }
    ]
}"


- 위의 Json파일은 네트워크의 정보를 가지고 있습니다. 

:: 예를들어, 어떤 activation function을 사용하는지, Convolution인지 Fully connected layer인지, input dimension과 output dimension은 몇인지, Convolution이라면 Stride와 Padding은 몇으로 주는지, Regularizer는 사용하는지, 등등의 정보를 담고있습니다. 이러한 내용은 아래의 Keras 코드 안의 Network코드와 비교해서 보면, 이해하기가 더 쉽습니다.


def network_model():
    """
    designed with 4 convolutional layer & 3 fully connected layer
    weight init : glorot_uniform
    activation func : relu
    pooling : maxpooling
    used dropout
    """

    model = Sequential()
    model.add(Lambda(lambda x: x / 127.5 - 1.0, input_shape=(Rows, Cols, 3)))
    model.add(Convolution2D(32, 3, 3, border_mode='same', subsample=(2, 2), activation='relu', name='Conv1'))
    #model.add(BatchNormalization())
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, border_mode='same'))
    model.add(Convolution2D(64, 3, 3, border_mode='same', subsample=(2, 2), activation='relu', name='Conv2'))
    #model.add(BatchNormalization())
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, border_mode='same'))
    model.add(Convolution2D(128, 3, 3, border_mode='same', subsample=(1, 1), activation='relu', name='Conv3'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=None, border_mode='same'))
    #model.add(BatchNormalization())
    model.add(Convolution2D(128, 2, 2, border_mode='same', subsample=(1, 1), activation='relu', name='Conv4'))
    #model.add(BatchNormalization())
    model.add(Flatten())
    model.add(Dropout(0.2))
    model.add(Dense(128, activation='relu', name='FC1'))
    model.add(Dropout(0.5))
    model.add(Dense(128, activation='relu', name='FC2'))
    model.add(Dropout(0.5))
    model.add(Dense(64, activation='relu', name='FC3'))
    model.add(Dense(1))
    model.summary()
    return model


- 위의 Json 파일과 비교하면, Model,json의 파일이 Keras의 Model부분에 대한 정보를 담고있다는 것을 알수있습니다. 이를 통해서 Keras에서 모델을 Json으로 읽어허 해당 모델을 컴파일 할 수 있는 것으로 보입니다.


여기까지가 pre-trained model을 사용했을 때, 코드 리뷰의 끝입니다.

해당 코드의 Nvidia 논문 End to End Learning for Self-Driving Cars을 보면 구조가 같다는 것을 확인할 수 있습니다.