2
$\begingroup$

I am trying to deploy a XGBClassifier model using flask. After giving the values to the relevant fields on the webpage, the output is not being displayed. Below is my code:

train_x, test_x, train_y, test_y = train_test_split(data1, y, test_size = 0.2, 
random_state=69)

# IMPUTING NAN VALUES
train_x['JobType'].fillna(train_x['JobType'].value_counts().index[0], inplace = True) 
train_x['occupation'].fillna(train_x['occupation'].value_counts().index[0], inplace = True)

test_x['JobType'].fillna(train_x['JobType'].value_counts().index[0], inplace = True)
test_x['occupation'].fillna(train_x['occupation'].value_counts().index[0], inplace = True)

# SEPARATING CATEGORICAL VARIABLES
train_x_cat = train_x.select_dtypes(include = 'object')
train_x_num = train_x.select_dtypes(include = 'number')

test_x_cat = test_x.select_dtypes(include = 'object')
test_x_num = test_x.select_dtypes(include = 'number')

#ONE HOT ENCODING THE CATEGORICAL VARIABLES AND THEN CONCAT THEM TO NUMERICAL VARIABLES
ohe = OneHotEncoder(handle_unknown='ignore', sparse = False)
train_x_encoded = pd.DataFrame(ohe.fit_transform(train_x_cat))
train_x_encoded.columns = ohe.get_feature_names(train_x_cat.columns)

train_x_encoded = train_x_encoded.reset_index(drop = True)
train_x_num = train_x_num.reset_index(drop = True)
train_x1 = pd.concat([train_x_num, train_x_encoded], axis = 1)


test_x_encoded = pd.DataFrame(ohe.transform(test_x_cat))
test_x_encoded.columns = ohe.get_feature_names(test_x_cat.columns)

test_x_encoded = test_x_encoded.reset_index(drop = True)
test_x_num = test_x_num.reset_index(drop = True)
test_x1 = pd.concat([test_x_num, test_x_encoded], axis = 1)

#XGBC MODEL
model = XGBClassifier(random_state = 69)

#Hyperparameter tuning
def objective(trial):
    learning_rate = trial.suggest_float('learning_rate', 0.001, 0.01)
    n_estimators = trial.suggest_int('n_estimators', 10, 500)
    sub_sample = trial.suggest_float('sub_sample', 0.0, 1.0)
    max_depth = trial.suggest_int('max_depth', 1, 20)

    params = {'max_depth' : max_depth,
           'n_estimators' : n_estimators,
           'sub_sample' : sub_sample,
           'learning_rate' : learning_rate}

    model.set_params(**params)

    return np.mean(-1 * cross_val_score(model, train_x1, train_y,
                                    cv = 5, n_jobs = -1, scoring = 'neg_mean_squared_error'))

xgbc_study = optuna.create_study(direction = 'minimize')
xgbc_study.optimize(objective, n_trials = 10)

xgbc_study.best_params
optuna_rfc_mse = xgbc_study.best_value

model.set_params(**xgbc_study.best_params)
model.fit(train_x1, train_y)

This is my Flask (app.py) code:-

@app.route('/', methods = ['GET', 'POST'])
def main():
    if request.method == 'GET':
       return render_template('index.html')

    if request.method == "POST":
       AGE= request.form['age']
       JOBTYPE= request.form['JobType']
       EDUCATIONTYPE= request.form['EdType']
       MARITALSTATUS= request.form['maritalstatus']
       OCCUPATION= request.form['occupation']
       RELATIONSHIP= request.form['relationship']
       GENDER= request.form['gender']
       CAPITALGAIN= request.form['capitalgain']
       CAPITALLOSS= request.form['capitalloss']
       HOURSPERWEEK= request.form['hoursperweek']
    
       data = [[AGE, JOBTYPE, EDUCATIONTYPE, MARITALSTATUS, OCCUPATION, RELATIONSHIP, 
             GENDER, CAPITALGAIN, CAPITALLOSS, HOURSPERWEEK]]
    
       input_variables = pd.DataFrame(data, columns = ['age', 'JobType', 'EdType', 
                                                       'maritalstatus', 'occupation', 
                                                       'relationship', 'gender', 
                                                       'capitalgain', 'capitalloss', 
                                                       'hrsperweek'], 
                                                       dtype = 'float', index = ['input'])
    
       predictions = model.predict(input_variables)[0]
       print(predictions)
    
       return render_template('index.html', original_input = {'age':AGE, 'JobType':JOBTYPE, 
                                                              'EdType':EDUCATIONTYPE,
                                                           'maritalstatus':MARITALSTATUS, 
                                                           'occupation':OCCUPATION, 
                                                           'relationship':RELATIONSHIP, 
                                                           'gender':GENDER, 
                                                           'capitalgain':CAPITALGAIN,
                                                           'capitalloss':CAPITALLOSS, 
                                                           'hrsperweek':HOURSPERWEEK},
                                                            result = predictions)

My index.html code:-

<form action="{{ url_for('main') }}" method="POST">
    
    <div class="form_group">
    
        <legend>Input Variables</legend>
        
        <br>age<br>
        <input name="age" type="number" step="any" min="0" class="form 
        control" required>
        <br>
        <-- AND SO ON ALL THE INPUT ARE ADDED -->

        <br>
        <input type="submit" value="Submit" class="btn btn-primary">
        
    </div>
    
</form>
<br>

<div class="result" align="center">
    {% if result %} {% for variable, value in original_input.items() %}
    <b>{{ variable }}</b> : {{ value }} {% endfor %}
    <br>
    <br>
    <h1>Predicted Salary:</h1>
    <p style="font-size:50px">${{ result }}</p>
    {% endif %}
</div>

When I deploy it using Flask, give the values for each field on the webpage, it does not give me the predicted output. Instead it just refreshes with the output area blank as shown in red circle. I have to add an image because there's no other way to describe! enter image description here

Thanks in advance!

$\endgroup$
16
  • $\begingroup$ Possible duplicate of this solution stackoverflow.com/questions/66491801/… $\endgroup$
    – SrJ
    Aug 7, 2021 at 7:24
  • $\begingroup$ Yes but the solution given there don't work for me $\endgroup$
    – spectre
    Aug 7, 2021 at 7:25
  • $\begingroup$ Can you show the info table for input_variable dataframe by using input_variable.info() ? $\endgroup$
    – SrJ
    Aug 7, 2021 at 7:27
  • 1
    $\begingroup$ it is in you flask app. You need to submit some data and perhaps print it in the terminal. $\endgroup$
    – SrJ
    Aug 7, 2021 at 7:36
  • 1
    $\begingroup$ You have to use the same encoding method for train and test purpose. $\endgroup$
    – SrJ
    Aug 7, 2021 at 9:18

2 Answers 2

2
$\begingroup$

You have directly passed the request data into the model.

We must do the required pre-processing part i.e. OHE and Scaling etc.

If it worked in the past, it must be because the data would have been pure float for all features.

For doing pre-processing, we must have the training phase encoders and statistics.

Below is a toy example to show the should-be steps.

# save the model/encoders to disk/DB after training
pickle.dump(model, open(model.sav, 'wb'))
pickle.dump(ohe, open('ohe.sav', 'wb'))

# Load model in the Flask runtime [ Only once ]
model = pickle.load(open('model.sav', 'rb')) # Loaded the Model
ohe_test = pickle.load(open('ohe.sav', 'rb')) # Loaded the OHE
# Get x_mean, x_median, x_std from Database/Files [Where it was saved ]

##Post method for Predict
@app.route('/predict',methods=['POST'])
def predict_():

    # Get request param
    jsonData = flask.request.get_json(force=True)
    data = pd.Series(jsonData)

    #Pre-processing
    data.fillna(x_median,inplace=True) # Fill NA
    data  = (data - x_mean)/x_std # Scale
    data  = ohe_test.transform(data) # OHE

    # Make prediction
    pred = model.predict([data])
  
    # Prepare output
    res = {'pred':pred}

    return flask.Response(response=json.dumps(res), status=200, mimetype='application/json')

Note -

  • Handling of unknown categories is a separate task.
  • Intent is not to guide on model serving. There are dedicated Tools/Frameworks to build pipelines.
$\endgroup$
5
  • $\begingroup$ I already tried encoding in the flask file but it does not work. Also I have used the same code implementation on a regression model which had categorical features too. There it worked fine. $\endgroup$
    – spectre
    Aug 8, 2021 at 15:06
  • $\begingroup$ Kindly check the updated question $\endgroup$
    – spectre
    Aug 9, 2021 at 5:58
  • $\begingroup$ Please check the backend logs. This can be the front-end response for the backend error $\endgroup$
    – 10xAI
    Aug 9, 2021 at 8:58
  • $\begingroup$ How can I do that? I am new to this $\endgroup$
    – spectre
    Aug 9, 2021 at 11:30
  • $\begingroup$ Add loggers/print in your Flask code. $\endgroup$
    – 10xAI
    Aug 11, 2021 at 2:36
2
+25
$\begingroup$

There are a couple ways to fix your code.

One option is to write customs functions that contain the feature engineering code. Then call the functions before both training (model.fit) and prediction (model.predict).

Another option is use a framework that is designed to apply the appropriate transformations during training and prediction, an example is scikit-learn's Pipeline.

$\endgroup$
2
  • $\begingroup$ I have tried the above code with a Pipeline (which imputes and encodes) too but the result is same. Also I have used the same code for a regression model (which used decision tree regressor) and it worked fine $\endgroup$
    – spectre
    Aug 7, 2021 at 15:14
  • $\begingroup$ Kindly check the updated question $\endgroup$
    – spectre
    Aug 9, 2021 at 5:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.