def test_retrieval_of_classifier_training_jobs_from_exploration_attributes( self): """Test the get_classifier_training_job method.""" exp_id = u'1' next_scheduled_check_time = datetime.datetime.utcnow() state_name = u'टेक्स्ट' algorithm_id = feconf.INTERACTION_CLASSIFIER_MAPPING['TextInput'][ 'algorithm_id'] algorithm_version = feconf.INTERACTION_CLASSIFIER_MAPPING['TextInput'][ 'algorithm_version'] job_id = self._create_classifier_training_job( algorithm_id, 'TextInput', exp_id, 1, next_scheduled_check_time, [], state_name, feconf.TRAINING_JOB_STATUS_NEW, {}, algorithm_version) classifier_models.StateTrainingJobsMappingModel.create( exp_id, 1, state_name, {algorithm_id: job_id}) classifier_training_job = ( classifier_services.get_classifier_training_job( exp_id, 1, state_name, algorithm_id)) self.assertIsNotNone(classifier_training_job) self.assertEqual(classifier_training_job.exp_id, exp_id) self.assertEqual(classifier_training_job.exp_version, 1) self.assertEqual(classifier_training_job.state_name, state_name) self.assertEqual(classifier_training_job.job_id, job_id) # Test that method returns a list with None as elements when job does # not exist. false_state_name = 'false_name' classifier_training_job = ( classifier_services.get_classifier_training_job( exp_id, 1, false_state_name, algorithm_id)) self.assertIsNone(classifier_training_job)
def test_reverted_exploration_maintains_classifier_model_mapping( self) -> None: """Test if the classifier model mapping is maintained when an exploration is reverted. """ state_name = 'Home' exploration = exp_fetchers.get_exploration_by_id(self.exp_id) interaction_id = exploration.states[state_name].interaction.id algorithm_id = feconf.INTERACTION_CLASSIFIER_MAPPING[interaction_id][ 'algorithm_id'] # Make changes to the exploration. change_list = [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'title', 'new_value': 'A new title' }) ] with self.swap(feconf, 'ENABLE_ML_CLASSIFIERS', True): exp_services.update_exploration( # type: ignore[no-untyped-call] feconf.SYSTEM_COMMITTER_ID, self.exp_id, change_list, '') current_exploration = exp_fetchers.get_exploration_by_id(self.exp_id) # Store the job before reverting the exploration. old_job = classifier_services.get_classifier_training_job( self.exp_id, current_exploration.version, state_name, algorithm_id) # Ruling out the possibility of None for mypy type checking. assert old_job is not None old_job_id = old_job.job_id # Revert the exploration. with self.swap(feconf, 'ENABLE_ML_CLASSIFIERS', True): exp_services.revert_exploration( # type: ignore[no-untyped-call] feconf.SYSTEM_COMMITTER_ID, self.exp_id, current_exploration.version, current_exploration.version - 1) # Verify if classifier model mapping is maintained using the job ID. reverted_exploration = exp_fetchers.get_exploration_by_id(self.exp_id) self.assertEqual(reverted_exploration.version, current_exploration.version + 1) new_job = classifier_services.get_classifier_training_job( self.exp_id, reverted_exploration.version, state_name, algorithm_id) # Ruling out the possibility of None for mypy type checking. assert new_job is not None new_job_id = new_job.job_id self.assertEqual(old_job_id, new_job_id)
def test_trained_classifier_handler(self): # Normal end-to-end test. self.post_blob('/ml/trainedclassifierhandler', self.payload_proto.SerializeToString(), expected_status_int=200) classifier_training_job = ( classifier_services.get_classifier_training_job( self.exp_id, self.exploration.version, 'Home', self.algorithm_id)) self.assertIsNotNone(classifier_training_job) classifier_data = ( self._get_classifier_data_from_classifier_training_job( classifier_training_job)) self.assertEqual(json.loads(classifier_data.model_json), self.classifier_data) self.assertEqual(classifier_training_job.status, feconf.TRAINING_JOB_STATUS_COMPLETE)
def test_get_trained_classifier_handler(self): self.post_blob('/ml/trainedclassifierhandler', self.payload_proto.SerializeToString(), expected_status_int=200) classifier_training_job = ( classifier_services.get_classifier_training_job( self.exp_id, self.exploration.version, 'Home', self.algorithm_id)) params = { 'exploration_id': self.exp_id, 'exploration_version': self.exploration.version, 'state_name': 'Home', } response = self.get_json('/ml/trainedclassifierhandler', params=params, expected_status_int=200) self.assertEqual(response['gcs_filename'], classifier_training_job.classifier_data_filename)
def setUp(self): super(TrainedClassifierHandlerTests, self).setUp() self.exp_id = 'exp_id1' self.title = 'Testing Classifier storing' self.category = 'Test' yaml_path = os.path.join(feconf.TESTS_DATA_DIR, 'string_classifier_test.yaml') with python_utils.open_file(yaml_path, 'r') as yaml_file: self.yaml_content = yaml_file.read() self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.signup('*****@*****.**', 'mod') assets_list = [] with self.swap(feconf, 'ENABLE_ML_CLASSIFIERS', True): exp_services.save_new_exploration_from_yaml_and_assets( feconf.SYSTEM_COMMITTER_ID, self.yaml_content, self.exp_id, assets_list) self.exploration = exp_fetchers.get_exploration_by_id(self.exp_id) self.algorithm_id = feconf.INTERACTION_CLASSIFIER_MAPPING[ self.exploration.states['Home'].interaction.id]['algorithm_id'] self.algorithm_version = feconf.INTERACTION_CLASSIFIER_MAPPING[ self.exploration.states['Home'].interaction. id]['algorithm_version'] self.classifier_data = { '_alpha': 0.1, '_beta': 0.001, '_prediction_threshold': 0.5, '_training_iterations': 25, '_prediction_iterations': 5, '_num_labels': 10, '_num_docs': 12, '_num_words': 20, '_label_to_id': { 'text': 1 }, '_word_to_id': { 'hello': 2 }, '_w_dp': [], '_b_dl': [], '_l_dp': [], '_c_dl': [], '_c_lw': [], '_c_l': [], } classifier_training_job = ( classifier_services.get_classifier_training_job( self.exp_id, self.exploration.version, 'Home', self.algorithm_id)) self.assertIsNotNone(classifier_training_job) self.job_id = classifier_training_job.job_id # TODO(pranavsid98): Replace the three commands below with # mark_training_job_pending after Giritheja's PR gets merged. classifier_training_job_model = ( classifier_models.ClassifierTrainingJobModel.get(self.job_id, strict=False)) classifier_training_job_model.status = ( feconf.TRAINING_JOB_STATUS_PENDING) classifier_training_job_model.update_timestamps() classifier_training_job_model.put() self.job_result = (training_job_response_payload_pb2. TrainingJobResponsePayload.JobResult()) self.job_result.job_id = self.job_id classifier_frozen_model = ( text_classifier_pb2.TextClassifierFrozenModel()) classifier_frozen_model.model_json = json.dumps(self.classifier_data) self.job_result.text_classifier.CopyFrom(classifier_frozen_model) self.payload_proto = ( training_job_response_payload_pb2.TrainingJobResponsePayload()) self.payload_proto.job_result.CopyFrom(self.job_result) self.payload_proto.vm_id = feconf.DEFAULT_VM_ID self.secret = feconf.DEFAULT_VM_SHARED_SECRET self.payload_proto.signature = classifier_services.generate_signature( python_utils.convert_to_bytes(self.secret), python_utils.convert_to_bytes( self.payload_proto.job_result.SerializeToString()), self.payload_proto.vm_id) self.payload_for_fetching_next_job_request = { 'vm_id': feconf.DEFAULT_VM_ID, 'message': json.dumps({}) } self.payload_for_fetching_next_job_request['signature'] = ( classifier_services.generate_signature( python_utils.convert_to_bytes(self.secret), python_utils.convert_to_bytes( self.payload_for_fetching_next_job_request['message']), self.payload_for_fetching_next_job_request['vm_id']))