Skip to content

Commit

Permalink
Merge pull request #8 from Boeing/hai-branch
Browse files Browse the repository at this point in the history
Added Fire, PDA and RTO models
  • Loading branch information
ethanenguyen authored Feb 5, 2024
2 parents 81d3a3f + 1e65dde commit cc8caaf
Show file tree
Hide file tree
Showing 14 changed files with 1,697 additions and 18 deletions.
Binary file modified img/sdr_classifier.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,224 changes: 1,224 additions & 0 deletions src/sdr_hazards_classification/data/Fire.csv

Large diffs are not rendered by default.

223 changes: 223 additions & 0 deletions src/sdr_hazards_classification/data/Parts_Departing_Aircraft.csv

Large diffs are not rendered by default.

141 changes: 141 additions & 0 deletions src/sdr_hazards_classification/data/Reject_To_Takeoff.csv

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3 changes: 3 additions & 0 deletions src/sdr_hazards_classification/prep_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
DEPRESSURIZATION = 'depressurization'
DEGRADED_CONTROLLABILITY= 'degraded-controllability'
CORROSION_LIMIT = 'corrosion-limit'
FIRE = 'fire'
PDA = 'pda'
RTO = 'rto'

LOG_FILE = os.getcwd() + "/logs"
if not os.path.exists(LOG_FILE):
Expand Down
20 changes: 16 additions & 4 deletions src/sdr_hazards_classification/sdr_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import numpy as np

from .prep_utils import PreprocessingUtils, DEPRESSURIZATION, DEGRADED_CONTROLLABILITY, CORROSION_LIMIT
from .prep_utils import PreprocessingUtils, DEPRESSURIZATION, DEGRADED_CONTROLLABILITY, CORROSION_LIMIT, FIRE, PDA, RTO
from .vectorizers import Vectorizers
import pandas as pd

Expand All @@ -27,6 +27,15 @@ def __init__(self, event_type="depressurization"):
elif event_type in DEPRESSURIZATION:
model_type = f"sdr-{DEPRESSURIZATION}.model"
model_config = f"sdr-{DEPRESSURIZATION}.config"
elif event_type in FIRE:
model_type = f"sdr-{FIRE}.model"
model_config = f"sdr-{FIRE}.config"
elif event_type in RTO:
model_type = f"sdr-{RTO}.model"
model_config = f"sdr-{RTO}.config"
elif event_type in PDA:
model_type = f"sdr-{PDA}.model"
model_config = f"sdr-{PDA}.config"
else: assert "Event type not supported!"

this_dir, this_filename = os.path.split(__file__) # Get path of data.pkl
Expand Down Expand Up @@ -121,8 +130,11 @@ def test_sdr_corrosion_limit(self):
if __name__ == "__main__":

#Load the trained model
model_api = SdrInferenceAPI(event_type='degraded-controllability')
model_api.test_sdr_degraded_controllability()
model_api = SdrInferenceAPI(event_type=CORROSION_LIMIT)
# model_api.test_sdr_degraded_controllability()
model_api.test_sdr_corrosion_limit()
model_api.test_sdr_depressurization_predictions()
# model_api.test_sdr_depressurization_predictions()

fire_model = SdrInferenceAPI(event_type=PDA)
text = """strong odor of smoke in the flight deck. troubleshooting showed main deck cargo pdu 9r motor burned, tripping the circuit-breaker. and 10r overheated. both pdu ' s removed and cover plate installed"""
print(fire_model.get_predictions([text]))
47 changes: 33 additions & 14 deletions src/sdr_hazards_classification/sdr_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
from os import path
import pickle
import traceback as tb
# Default column name in DataFrame
from sklearn.model_selection import cross_val_score
from sklearn.svm import SVC

from prep_utils import PreprocessingUtils, DEPRESSURIZATION, DEGRADED_CONTROLLABILITY, CORROSION_LIMIT
from prep_utils import PreprocessingUtils, DEPRESSURIZATION, DEGRADED_CONTROLLABILITY, CORROSION_LIMIT, FIRE, RTO, PDA
from vectorizers import Vectorizers

prep_util = PreprocessingUtils()
Expand Down Expand Up @@ -106,30 +106,34 @@ def train_text_classifier(criteria, all_df , text_field, label_field, model_type
X_train = Vectorizers.transform_with_vectorizers(train_data, vectorizers)
model_config["vectorizers"] = vectorizers

model = None
sklearn_model = None
if model_config["model_name"] == "lg":
model = LogisticRegression(solver='liblinear', C=1e2, max_iter=200)
sklearn_model = LogisticRegression(solver='liblinear', C=1e2, max_iter=200)
elif model_config["model_name"] == "svm":
model = SVC(kernel='linear', C=1.0)
sklearn_model = SVC(kernel='linear', C=1.0)
elif model_config["model_name"] == "xgb":
from xgboost import XGBClassifier
model = XGBClassifier(n_estimators=500, max_depth=5, reg_alpha=.1)
sklearn_model = XGBClassifier(n_estimators=1000, max_depth=10, reg_alpha=.1)
else:
model_name = model_config["model_name"]
raise ValueError(f"Model '{model_name}' not supported")

# fit model
model.fit(X_train, train_labels)
print(f"Let's do CV for {type(sklearn_model).__name__}")
scores = cross_val_score(sklearn_model, X_train, train_labels, scoring= 'accuracy', cv=5)
print("%0.2f accuracy with a standard deviation of %0.2f" % (scores.mean(), scores.std()))

sklearn_model.fit(X_train, train_labels)

if evaluate_model:
# target_names = [criteria, 'Non-'+criteria]
target_name = le.inverse_transform(model.classes_)
predictions = TextClassifier.predict_sdr_labels(model, model_config, test_data)
target_name = le.inverse_transform(sklearn_model.classes_)
predictions = TextClassifier.predict_sdr_labels(sklearn_model, model_config, test_data)
print(classification_report(test_labels, predictions[0], target_names=target_name))
logging.info(msg=f'Performance:\n {classification_report(test_labels, predictions[0], target_names=target_name)}')
return model, model_config, test_data, test_labels
return sklearn_model, model_config, test_data, test_labels

return model, model_config
return sklearn_model, model_config

@staticmethod
def export_model(model, model_config, model_name, out_folder):
Expand Down Expand Up @@ -233,18 +237,33 @@ def release_model( **kwargs):

if args.event_type in DEPRESSURIZATION:
training_args = {'event_type': DEPRESSURIZATION,
'model_type': 'lg',
'model_type': args.model_type,
'target_name': ["depressurization", "non-depressurization"],
'training_path': "./data/Depressurization.csv"}
elif args.event_type in FIRE:
training_args = {'event_type': FIRE,
'model_type': args.model_type,
'target_name': ["fire", "non-fire"],
'training_path': "./data/Fire.csv"}
elif args.event_type in PDA:
training_args = {'event_type': PDA,
'model_type': args.model_type,
'target_name': ["pda", "non-pda"],
'training_path': "./data/Parts_Departing_Aircraft.csv"}
elif args.event_type in RTO:
training_args = {'event_type': RTO,
'model_type': args.model_type,
'target_name': ["rto", "non-rto"],
'training_path': "./data/Reject_To_Takeoff.csv"}
elif args.event_type in DEGRADED_CONTROLLABILITY:
training_args = {'event_type': DEGRADED_CONTROLLABILITY,
'model_type': 'xgb',
'model_type': args.model_type,
'target_name': ["degraded-controllability", "non-degraded"],
'training_path': "./data/Degraded_Controllability.csv"}
elif args.event_type in CORROSION_LIMIT:
training_args = {
'event_type': CORROSION_LIMIT,
'model_type': 'lg',
'model_type': args.model_type,
'target_name': ["beyond-limit", "no-corrosion", "no-limit", "within-limit", "within-beyond-limit"],
'training_path': "./data/Corrosion_Limit.csv"}
else:
Expand Down
57 changes: 57 additions & 0 deletions src/test/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ def load_controll_model(self, event_type="degraded-controllability"):
def load_corrosion_model(self, event_type="corrosion-limit"):
yield SdrInferenceAPI(event_type)

@pytest.fixture
def load_fire_model(self, event_type="fire"):
yield SdrInferenceAPI(event_type)

@pytest.fixture
def load_pda_model(self, event_type="pda"):
yield SdrInferenceAPI(event_type)

@pytest.fixture
def load_rto_model(self, event_type="rto"):
yield SdrInferenceAPI(event_type)

def test_depressurization_prediction_No(self, load_depressurization_model):

expect_result = np.array(["No", "No"])
Expand Down Expand Up @@ -97,6 +109,51 @@ def test_controllability_prediction_Yes(self, load_controll_model):
assert_array_equal(pred, expect_result)
assert np.all(np.array(probs) > 0.9)

def test_fire(self, load_fire_model):

expect_result = np.array(["No", "Yes", "No", "Yes"])

record = ["""RETURNED TO DEPARTURE DUE TO THE LEFT ENGINE OIL QUANTITY WAS DECREASING. REPLACED THE ENGINE.
Nature of Condition: WARNING INDICATION, FLUID LOSS Precautionary Procedure: UNSCHED LANDING Part Name: OIL SYSTEM Part Condition: LEAKING""",
"""burning electrical odor noticed in cabin from row 28 to back of aircraft. no signs of smoke noticed. odor approximately 1 hr out from landing. ran nr 1 and 2 engines independently with packs running. no smoke or any burning odor. checked reading lights iaw mcc for shorting and arcing. no signs of shorting and arcing. checked ovens and coffeemakers, no evidence of burning or arcing noted. nature of condition : smoke fumes odors sparks precautionary procedure : other part name : unknown part condition : odor.""",
"""CABIN ALTITUDE EICAS WARNING AT FL380. COMPLIED WITH QRH, DESCENDED TO FINAL ALTITUDE FL250. RECOVERED CABIN PRESSURE IN AUTO 2 AT CABIN ALTITUDE 7500. NORMAL DESCENT AND PRESSURE UNTIL LFPG. REPLACED THE NR 1 CPC IAW MM 21-31-02-4, TESTED OK. COMPLYED WITH CABIN PRESSURE DECAY CHECK IAW MM 05-51-24-2, TEST PASSED. Nature of Condition:
WARNING INDICATION Precautionary Procedure: O2 MASK DEPLOYED Part Name: CONTROLLER Part Condition: MALFUNCTIONED""",
"""on climbout the cockpit filled with smoke. the aircraft declared an emergency and returned to the airport. the smoke was observed coming from first officer ' s side. after aircraft returned to gate, mechanic found p6-12 circuit-breaker with evidence of being overheated and terminal connector burned. nature of condition : smoke fumes odors sparks precautionary procedure : unsched landing part name : circuit-breaker part condition : failed"""
]

pred, probs = load_fire_model.get_predictions(record)

assert_array_equal(pred, expect_result)
assert np.all(np.array(probs) > 0.9)

def test_pda(self, load_pda_model):
expect_result = np.array(["No", "Yes", "No", "Yes"])

record = ["""CABIN ALTITUDE EICAS WARNING AT FL380. COMPLIED WITH QRH, DESCENDED TO FINAL ALTITUDE FL250. RECOVERED CABIN PRESSURE IN AUTO 2 AT CABIN ALTITUDE 7500. NORMAL DESCENT AND PRESSURE UNTIL LFPG. REPLACED THE NR 1 CPC IAW MM 21-31-02-4, TESTED OK. COMPLYED WITH CABIN PRESSURE DECAY CHECK IAW MM 05-51-24-2, TEST PASSED. Nature of Condition:
WARNING INDICATION Precautionary Procedure: O2 MASK DEPLOYED Part Name: CONTROLLER Part Condition: MALFUNCTIONED""",
"""right engine pylon aft outboard side panel assembly is missing panel number 446al. the panel possibly departed during op eration of the aircraft. the airplane was removed from service ( grounded ) and a serviceable panel 446al was installed. the cause of the missing panel is unknown.""",
"""aircraft was not grounded : during climb, autopilot engaged for approximately one second then began to roll left,
followed by autopilot disconnect and aural warning on two attempts. replaced autopilot aileron switch iaw amm 22-11-12, operation check good.""",
"""( log 5515918 parts departing airplane ) during pre-flight discovered large panel missing forward of right main wheel well. maintenance reinstalled body panel 192br per amm 53-51."""]

pred, probs = load_pda_model.get_predictions(record)

assert_array_equal(pred, expect_result)
assert np.all(np.array(probs) > 0.9)

def test_rto(self, load_rto_model):
expect_result = np.array(["No", "Yes", "No", "Yes"])

record = ["""forward cargo bay, bs 478 - 500, stringer 26l found cracked. removed the damaged stringer section and fabricated a repair iaw srm 53-00-03, fig 201, repair 2. installed iaw srm 51-40-02. nature of condition : other precautionary procedure : none part name : stringer part condition : cracked""",
"""no airspeed on captains indicator, aborted takeoff and returned to blocks. inspected pitot tube and removed debris, op ' s and leak check good iaw amm 34-11-00. nature of condition : other precautionary procedure : aborted takeoff part name : pitot tube part condition : obstructed""",
"""during inspection, found a crack on the floor support between bs 277 and 294.5, rbl 1. maintenance replaced the floor support iaw srm 51-40-02.""",
"""during takeoff roll, the left thrust reverser warning light illuminated. aborted takeoff at approximately 40 knots. removed and replaced the engine accessory unit iaw amm 75-34-06. accomplished built in test equipment check iaw fim 78-31-00. system checked normal. nature of condition : warning indication precautionary procedure : aborted takeoff part name : accessory unit part condition : faulty"""]

pred, probs = load_rto_model.get_predictions(record)

assert_array_equal(pred, expect_result)
assert np.all(np.array(probs) > 0.9)

def test_corrosion_limit(self, load_corrosion_model):
expect_result = np.array(["Beyond Limit", "No Corrosion", "No Limit", "Within Limit", "Within_Beyond_Limit"])

Expand Down

0 comments on commit cc8caaf

Please sign in to comment.