Как развернуть Pytorch в Python через REST API с Flask? - PullRequest
0 голосов
/ 28 марта 2020

Я работаю над AWS Sagemaker, и моя цель состоит в том, чтобы следовать этому учебнику из официальной документации Pytorch.

Исходная функция предсказания из учебника выше:

@app.route('/predict', methods=['POST'])
def predict():
    if request.method == 'POST':
        file = request.files['file']
        img_bytes = file.read()
        class_id, class_name = get_prediction(image_bytes=img_bytes)
        return jsonify({'class_id': class_id, 'class_name': class_name})

Я получил эту ошибку , поэтому я добавил «GET» как метод, как упомянуто в здесь. Я также упростил свой пример до его минимального выражения:

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/predict', methods=['GET','POST'])
def predict():
    if request.method == 'POST':
        return jsonify({'class_name': 'cat'})
    return 'OK'

if __name__ == '__main__':
    app.run()

Я выполняю запросы со следующим кодом:

import requests

resp = requests.post("https://catdogclassifier.notebook.eu-west-1.sagemaker.aws/proxy/5000/predict",
                     files={"file": open('/home/ec2-user/SageMaker/cat.jpg', 'rb')})

соответственно <Response [200]>, но соответственно json () возвращает JSONDecodeError: Expecting value: line 1 column 1 (char 0) Наконец, resp.url указывает мне на страница с надписью 'OK'.

Более того, это вывод dist.content

<!DOCTYPE HTML>

<html>
<head>
  <style type="text/css">

#loadingImage {
    margin: 10em auto;
    width: 234px;
    height: 238px;
    background-repeat: no-repeat;
    background-image: url(data:image/png;base64,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);

    -webkit-animation:spin 4s linear infinite;
    -moz-animation:spin 4s linear infinite;
    animation:spin 4s linear infinite;
}


@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }

  </style>
</head>

<body>

  <div id="loadingImage"></div>

<script type="text/javascript">



var RegionFinder = (function()
{
    function RegionFinder( location ) {
        this.location = location;
    }


    RegionFinder.prototype = {


        getURLWithRegion: function() {

            var isDynamicDefaultRegion = ifPathContains(this.location.pathname, "region/dynamic-default-region");

            var queryArgs = removeURLParameter(this.location.search, "region");

            var hashArgs = this.location.href.split("#")[1] || "";
            if (hashArgs) {
                hashArgs = "#" + hashArgs;
            }

            var region = this._getCurrentRegion();
            var newArgs = "region=" + region;
            if (_shouldAuth()) {
                newArgs = "needs_auth=true";
                region = "nil";
            }

            if (queryArgs &&
                queryArgs != "?") {
                queryArgs += "&" + newArgs;
            } else {
                queryArgs = "?" + newArgs;
            }



            if (!region) {

                var contactUs = "https://portal.aws.amazon.com/gp/aws/html-forms-controller/contactus/aws-report-issue1";

                alert("How embarrassing! There is something wrong with this URL, please contact AWS at " + contactUs);
            }

            var pathname = isDynamicDefaultRegion ?  "/console/home" : this.location.pathname;

            return this.location.protocol + "//" + _getRedirectHostFromAttributes() +
                pathname + queryArgs + hashArgs;
        },


        _getCurrentRegion: function() {

            return _getRegionFromHash( this.location ) ||
                   _getRegionFromAttributes();
        }
    };



    function ifPathContains(url, parameter) {
        return (url.indexOf(parameter) != -1);
    }


    function removeURLParameter(url, parameter) {
        var urlparts= url.split('?');
        if (urlparts.length>=2) {
            var prefix= encodeURIComponent(parameter);
            var pars= urlparts[1].split(/[&;]/g);
            //reverse iteration as may be destructive
            for (var i= pars.length; i-- > 0;) {
                if (pars[i].lastIndexOf(prefix, 0) !== -1) {
                    pars.splice(i, 1);
                }
            }
            url= urlparts[0]+'?'+pars.join('&');
            return url;
        } else {
            return url;
        }
    }


    function _getRegionFromAttributes() {
        return "eu-west-1";
    };

    function _shouldAuth() {
        return "";
    };

    function _getRedirectHostFromAttributes() {
        return "eu-west-1.console.aws.amazon.com";
    }


    function _getRegionFromHash( location ) {

        var hashArgs = "#" + (location.href.split("#")[1] || "");


        var hashRegionArg = "";


        var match = hashArgs.match("region=([a-zA-Z0-9-]+)");
        if (match && match.length > 1 && match[1]) {
            hashRegionArg = match[1];
        }
        return hashRegionArg;
    }

    return RegionFinder;
})();


var regionFinder = new RegionFinder( window.location );

window.location.href = regionFinder.getURLWithRegion();

</script>


</body>
</html>

Чего мне не хватает?

1 Ответ

1 голос
/ 02 апреля 2020

Похоже, что content вашего resp равно HTML в отличие от JSON; это, вероятно, является следствием того, как настроена конечная точка прокси-сервера *1003* сервера Jupyter, для которой вы пытаетесь выполнить POST (https://catdogclassifier.notebook.eu-west-1.sagemaker.aws/proxy/5000/predict).

Похоже, вы используете экземпляр ноутбука SageMaker , поэтому вы можете не иметь большого контроля над этой конфигурацией. Обходным путем может быть вместо развертывания сервера Flask в качестве конечной точки SageMaker , работающего вне JupyterLab, вместо того, чтобы непосредственно на экземпляре ноутбука.

Если вы хотите создать прототип с использованием только экземпляра ноутбука вы также можете просто полностью обойти прокси и просто вызвать свой маршрут Flask относительно localhost с другой вкладки ноутбука, в то время как сервер Flask работает на главной вкладке ноутбука:

import requests

resp = requests.post("https://localhost:5000/predict",
                     files={"file": open('/home/ec2-user/SageMaker/cat.jpg', 'rb')})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...