You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_cli_runtime.py 68 kB

first commit Former-commit-id: 08bc23ba02cffbce3cf63962390a65459a132e48 [formerly 0795edd4834b9b7dc66db8d10d4cbaf42bbf82cb] [formerly b5010b42541add7e2ea2578bf2da537efc457757 [formerly a7ca09c2c34c4fc8b3d8e01fcfa08eeeb2cae99d]] [formerly 615058473a2177ca5b89e9edbb797f4c2a59c7e5 [formerly 743d8dfc6843c4c205051a8ab309fbb2116c895e] [formerly bb0ea98b1e14154ef464e2f7a16738705894e54b [formerly 960a69da74b81ef8093820e003f2d6c59a34974c]]] [formerly 2fa3be52c1b44665bc81a7cc7d4cea4bbf0d91d5 [formerly 2054589f0898627e0a17132fd9d4cc78efc91867] [formerly 3b53730e8a895e803dfdd6ca72bc05e17a4164c1 [formerly 8a2fa8ab7baf6686d21af1f322df46fd58c60e69]] [formerly 87d1e3a07a19d03c7d7c94d93ab4fa9f58dada7c [formerly f331916385a5afac1234854ee8d7f160f34b668f] [formerly 69fb3c78a483343f5071da4f7e2891b83a49dd18 [formerly 386086f05aa9487f65bce2ee54438acbdce57650]]]] Former-commit-id: a00aed8c934a6460c4d9ac902b9a74a3d6864697 [formerly 26fdeca29c2f07916d837883983ca2982056c78e] [formerly 0e3170d41a2f99ecf5c918183d361d4399d793bf [formerly 3c12ad4c88ac5192e0f5606ac0d88dd5bf8602dc]] [formerly d5894f84f2fd2e77a6913efdc5ae388cf1be0495 [formerly ad3e7bc670ff92c992730d29c9d3aa1598d844e8] [formerly 69fb3c78a483343f5071da4f7e2891b83a49dd18]] Former-commit-id: 3c19c9fae64f6106415fbc948a4dc613b9ee12f8 [formerly 467ddc0549c74bb007e8f01773bb6dc9103b417d] [formerly 5fa518345d958e2760e443b366883295de6d991c [formerly 3530e130b9fdb7280f638dbc2e785d2165ba82aa]] Former-commit-id: 9f5d473d42a435ec0d60149939d09be1acc25d92 [formerly be0b25c4ec2cde052a041baf0e11f774a158105d] Former-commit-id: 9eca71cb73ba9edccd70ac06a3b636b8d4093b04
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680
  1. import contextlib
  2. import json
  3. import gzip
  4. import io
  5. import logging
  6. import os.path
  7. import pickle
  8. import random
  9. import shutil
  10. import sys
  11. import tempfile
  12. import traceback
  13. import unittest
  14. import pandas
  15. COMMON_PRIMITIVES_DIR = os.path.join(os.path.dirname(__file__), 'common-primitives')
  16. # NOTE: This insertion should appear before any code attempting to resolve or load primitives,
  17. # so the git submodule version of `common-primitives` is looked at first.
  18. sys.path.insert(0, COMMON_PRIMITIVES_DIR)
  19. TEST_PRIMITIVES_DIR = os.path.join(os.path.dirname(__file__), 'data', 'primitives')
  20. sys.path.insert(0, TEST_PRIMITIVES_DIR)
  21. from common_primitives.column_parser import ColumnParserPrimitive
  22. from common_primitives.construct_predictions import ConstructPredictionsPrimitive
  23. from common_primitives.dataset_to_dataframe import DatasetToDataFramePrimitive
  24. from common_primitives.no_split import NoSplitDatasetSplitPrimitive
  25. from common_primitives.random_forest import RandomForestClassifierPrimitive
  26. from common_primitives.train_score_split import TrainScoreDatasetSplitPrimitive
  27. from test_primitives.random_classifier import RandomClassifierPrimitive
  28. from test_primitives.fake_score import FakeScorePrimitive
  29. from d3m import cli, index, runtime, utils
  30. from d3m.container import dataset as dataset_module
  31. from d3m.contrib.primitives.compute_scores import ComputeScoresPrimitive
  32. from d3m.metadata import base as metadata_base, pipeline as pipeline_module, pipeline_run as pipeline_run_module, problem as problem_module
  33. TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
  34. PROBLEM_DIR = os.path.join(TEST_DATA_DIR, 'problems')
  35. DATASET_DIR = os.path.join(TEST_DATA_DIR, 'datasets')
  36. PIPELINE_DIR = os.path.join(TEST_DATA_DIR, 'pipelines')
  37. class TestCLIRuntime(unittest.TestCase):
  38. def setUp(self):
  39. self.test_dir = tempfile.mkdtemp()
  40. def tearDown(self):
  41. shutil.rmtree(self.test_dir)
  42. @classmethod
  43. def setUpClass(cls):
  44. to_register = {
  45. 'd3m.primitives.data_transformation.dataset_to_dataframe.Common': DatasetToDataFramePrimitive,
  46. 'd3m.primitives.classification.random_forest.Common': RandomForestClassifierPrimitive,
  47. 'd3m.primitives.classification.random_classifier.Test': RandomClassifierPrimitive,
  48. 'd3m.primitives.data_transformation.column_parser.Common': ColumnParserPrimitive,
  49. 'd3m.primitives.data_transformation.construct_predictions.Common': ConstructPredictionsPrimitive,
  50. 'd3m.primitives.evaluation.no_split_dataset_split.Common': NoSplitDatasetSplitPrimitive,
  51. 'd3m.primitives.evaluation.compute_scores.Test': FakeScorePrimitive,
  52. 'd3m.primitives.evaluation.train_score_dataset_split.Common': TrainScoreDatasetSplitPrimitive,
  53. # We do not have to load this primitive, but loading it here prevents the package from loading all primitives.
  54. 'd3m.primitives.evaluation.compute_scores.Core': ComputeScoresPrimitive,
  55. }
  56. # To hide any logging or stdout output.
  57. with utils.silence():
  58. for python_path, primitive in to_register.items():
  59. index.register_primitive(python_path, primitive)
  60. def _call_cli_runtime(self, arg):
  61. logger = logging.getLogger('d3m.runtime')
  62. with utils.silence():
  63. with self.assertLogs(logger=logger) as cm:
  64. # So that at least one message is logged.
  65. logger.warning("Debugging.")
  66. cli.main(arg)
  67. # We skip our "debugging" message.
  68. return cm.records[1:]
  69. def _call_cli_runtime_without_fail(self, arg):
  70. try:
  71. return self._call_cli_runtime(arg)
  72. except Exception as e:
  73. self.fail(traceback.format_exc())
  74. def _assert_valid_saved_pipeline_runs(self, pipeline_run_save_path):
  75. with open(pipeline_run_save_path, 'r') as f:
  76. for pipeline_run_dict in list(utils.yaml_load_all(f)):
  77. try:
  78. pipeline_run_module.validate_pipeline_run(pipeline_run_dict)
  79. except Exception as e:
  80. self.fail(traceback.format_exc())
  81. def _validate_previous_pipeline_run_ids(self, pipeline_run_save_path):
  82. ids = set()
  83. prev_ids = set()
  84. with open(pipeline_run_save_path, 'r') as f:
  85. for pipeline_run_dict in list(utils.yaml_load_all(f)):
  86. ids.add(pipeline_run_dict['id'])
  87. if 'previous_pipeline_run' in pipeline_run_dict:
  88. prev_ids.add(pipeline_run_dict['previous_pipeline_run']['id'])
  89. self.assertTrue(
  90. prev_ids.issubset(ids),
  91. 'Some previous pipeline run ids {} are not in the set of pipeline run ids {}'.format(prev_ids, ids)
  92. )
  93. def test_fit_multi_input(self):
  94. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  95. arg = [
  96. '',
  97. 'runtime',
  98. 'fit',
  99. '--input',
  100. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  101. '--input',
  102. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  103. '--problem',
  104. os.path.join(PROBLEM_DIR, 'iris_problem_1/problemDoc.json'),
  105. '--pipeline',
  106. os.path.join(PIPELINE_DIR, 'multi-input-test.json'),
  107. '--expose-produced-outputs',
  108. self.test_dir,
  109. '-O',
  110. pipeline_run_save_path,
  111. ]
  112. self._call_cli_runtime_without_fail(arg)
  113. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  114. self._assert_standard_output_metadata()
  115. def test_fit_without_problem(self):
  116. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  117. fitted_pipeline_path = os.path.join(self.test_dir, 'fitted-pipeline')
  118. output_csv_path = os.path.join(self.test_dir, 'output.csv')
  119. arg = [
  120. '',
  121. 'runtime',
  122. 'fit',
  123. '--input',
  124. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  125. '--input',
  126. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  127. '--pipeline',
  128. os.path.join(PIPELINE_DIR, 'multi-input-test.json'),
  129. '--save',
  130. fitted_pipeline_path,
  131. '--expose-produced-outputs',
  132. self.test_dir,
  133. '--output',
  134. output_csv_path,
  135. '-O',
  136. pipeline_run_save_path,
  137. ]
  138. self._call_cli_runtime_without_fail(arg)
  139. self.assertEqual(utils.list_files(self.test_dir), [
  140. 'fitted-pipeline',
  141. 'output.csv',
  142. 'outputs.0/data.csv',
  143. 'outputs.0/metadata.json',
  144. 'pipeline_run.yml',
  145. 'steps.0.produce/data.csv',
  146. 'steps.0.produce/metadata.json',
  147. 'steps.1.produce/data.csv',
  148. 'steps.1.produce/metadata.json',
  149. 'steps.2.produce/data.csv',
  150. 'steps.2.produce/metadata.json'
  151. ])
  152. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  153. self._assert_standard_output_metadata()
  154. self._assert_prediction_sum(prediction_sum=11225, outputs_path='outputs.0/data.csv')
  155. self._assert_prediction_sum(prediction_sum=11225, outputs_path='output.csv')
  156. def test_produce_without_problem(self):
  157. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  158. fitted_pipeline_path = os.path.join(self.test_dir, 'fitted-no-problem-pipeline')
  159. output_csv_path = os.path.join(self.test_dir, 'output.csv')
  160. arg = [
  161. '',
  162. 'runtime',
  163. 'fit',
  164. '--input',
  165. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  166. '--input',
  167. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  168. '--pipeline',
  169. os.path.join(PIPELINE_DIR, 'multi-input-test.json'),
  170. '--save',
  171. fitted_pipeline_path,
  172. ]
  173. self._call_cli_runtime_without_fail(arg)
  174. arg = [
  175. '',
  176. 'runtime',
  177. 'produce',
  178. '--test-input',
  179. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  180. '--test-input',
  181. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  182. '--output',
  183. output_csv_path,
  184. '--fitted-pipeline',
  185. fitted_pipeline_path,
  186. '--expose-produced-outputs',
  187. self.test_dir,
  188. '-O',
  189. pipeline_run_save_path,
  190. ]
  191. self._call_cli_runtime_without_fail(arg)
  192. self.assertEqual(utils.list_files(self.test_dir), [
  193. 'fitted-no-problem-pipeline',
  194. 'output.csv',
  195. 'outputs.0/data.csv',
  196. 'outputs.0/metadata.json',
  197. 'pipeline_run.yml',
  198. 'steps.0.produce/data.csv',
  199. 'steps.0.produce/metadata.json',
  200. 'steps.1.produce/data.csv',
  201. 'steps.1.produce/metadata.json',
  202. 'steps.2.produce/data.csv',
  203. 'steps.2.produce/metadata.json'
  204. ])
  205. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  206. self._assert_standard_output_metadata()
  207. self._assert_prediction_sum(prediction_sum=11008, outputs_path='outputs.0/data.csv')
  208. self._assert_prediction_sum(prediction_sum=11008, outputs_path='output.csv')
  209. def test_fit_produce_without_problem(self):
  210. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  211. output_csv_path = os.path.join(self.test_dir, 'output.csv')
  212. arg = [
  213. '',
  214. 'runtime',
  215. 'fit-produce',
  216. '--input',
  217. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  218. '--input',
  219. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  220. '--test-input',
  221. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  222. '--test-input',
  223. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  224. '--pipeline',
  225. os.path.join(PIPELINE_DIR, 'multi-input-test.json'),
  226. '--output',
  227. output_csv_path,
  228. '--expose-produced-outputs',
  229. self.test_dir,
  230. '-O',
  231. pipeline_run_save_path,
  232. ]
  233. self._call_cli_runtime_without_fail(arg)
  234. self.assertEqual(utils.list_files(self.test_dir), [
  235. 'output.csv',
  236. 'outputs.0/data.csv',
  237. 'outputs.0/metadata.json',
  238. 'pipeline_run.yml',
  239. 'steps.0.produce/data.csv',
  240. 'steps.0.produce/metadata.json',
  241. 'steps.1.produce/data.csv',
  242. 'steps.1.produce/metadata.json',
  243. 'steps.2.produce/data.csv',
  244. 'steps.2.produce/metadata.json'
  245. ])
  246. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  247. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  248. self._assert_standard_output_metadata()
  249. self._assert_prediction_sum(prediction_sum=11008, outputs_path='outputs.0/data.csv')
  250. self._assert_prediction_sum(prediction_sum=11008, outputs_path='output.csv')
  251. def test_nonstandard_fit_without_problem(self):
  252. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  253. fitted_pipeline_path = os.path.join(self.test_dir, 'fitted-pipeline')
  254. arg = [
  255. '',
  256. 'runtime',
  257. 'fit',
  258. '--input',
  259. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  260. '--pipeline',
  261. os.path.join(PIPELINE_DIR, 'semi-standard-pipeline.json'),
  262. '--save',
  263. fitted_pipeline_path,
  264. '--expose-produced-outputs',
  265. self.test_dir,
  266. '--not-standard-pipeline',
  267. '-O',
  268. pipeline_run_save_path,
  269. ]
  270. self._call_cli_runtime_without_fail(arg)
  271. self.assertEqual(utils.list_files(self.test_dir), [
  272. 'fitted-pipeline',
  273. 'outputs.0/data.csv',
  274. 'outputs.0/metadata.json',
  275. 'outputs.1/data.csv',
  276. 'outputs.1/metadata.json',
  277. 'pipeline_run.yml',
  278. 'steps.0.produce/data.csv',
  279. 'steps.0.produce/metadata.json',
  280. 'steps.1.produce/data.csv',
  281. 'steps.1.produce/metadata.json',
  282. ])
  283. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  284. self._assert_standard_output_metadata()
  285. self._assert_prediction_sum(prediction_sum=10710, outputs_path='outputs.0/data.csv')
  286. self._assert_nonstandard_output(outputs_name='outputs.1')
  287. def test_nonstandard_produce_without_problem(self):
  288. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  289. fitted_pipeline_path = os.path.join(self.test_dir, 'fitted-pipeline')
  290. arg = [
  291. '',
  292. 'runtime',
  293. 'fit',
  294. '--input',
  295. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  296. '--pipeline',
  297. os.path.join(PIPELINE_DIR, 'semi-standard-pipeline.json'),
  298. '--save',
  299. fitted_pipeline_path,
  300. '--not-standard-pipeline'
  301. ]
  302. self._call_cli_runtime_without_fail(arg)
  303. arg = [
  304. '',
  305. 'runtime',
  306. 'produce',
  307. '--test-input',
  308. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  309. '--fitted-pipeline',
  310. fitted_pipeline_path,
  311. '--expose-produced-outputs',
  312. self.test_dir,
  313. '-O',
  314. pipeline_run_save_path,
  315. ]
  316. self._call_cli_runtime_without_fail(arg)
  317. self.assertEqual(utils.list_files(self.test_dir), [
  318. 'fitted-pipeline',
  319. 'outputs.0/data.csv',
  320. 'outputs.0/metadata.json',
  321. 'outputs.1/data.csv',
  322. 'outputs.1/metadata.json',
  323. 'pipeline_run.yml',
  324. 'steps.0.produce/data.csv',
  325. 'steps.0.produce/metadata.json',
  326. 'steps.1.produce/data.csv',
  327. 'steps.1.produce/metadata.json'
  328. ])
  329. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  330. self._assert_standard_output_metadata()
  331. self._assert_prediction_sum(prediction_sum=12106, outputs_path='outputs.0/data.csv')
  332. self._assert_nonstandard_output(outputs_name='outputs.1')
  333. def test_nonstandard_fit_produce_without_problem(self):
  334. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  335. arg = [
  336. '',
  337. 'runtime',
  338. 'fit-produce',
  339. '--input',
  340. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  341. '--test-input',
  342. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  343. '--pipeline',
  344. os.path.join(PIPELINE_DIR, 'semi-standard-pipeline.json'),
  345. '--expose-produced-outputs',
  346. self.test_dir,
  347. '--not-standard-pipeline',
  348. '-O',
  349. pipeline_run_save_path,
  350. ]
  351. self._call_cli_runtime_without_fail(arg)
  352. self.assertEqual(utils.list_files(self.test_dir), [
  353. 'outputs.0/data.csv',
  354. 'outputs.0/metadata.json',
  355. 'outputs.1/data.csv',
  356. 'outputs.1/metadata.json',
  357. 'pipeline_run.yml',
  358. 'steps.0.produce/data.csv',
  359. 'steps.0.produce/metadata.json',
  360. 'steps.1.produce/data.csv',
  361. 'steps.1.produce/metadata.json',
  362. ])
  363. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  364. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  365. self._assert_standard_output_metadata()
  366. self._assert_prediction_sum(prediction_sum=12106, outputs_path='outputs.0/data.csv')
  367. self._assert_nonstandard_output(outputs_name='outputs.1')
  368. def test_fit_produce_multi_input(self):
  369. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  370. arg = [
  371. '',
  372. 'runtime',
  373. 'fit-produce',
  374. '--input',
  375. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  376. '--input',
  377. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  378. '--problem',
  379. os.path.join(PROBLEM_DIR, 'iris_problem_1/problemDoc.json'),
  380. '--test-input',
  381. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  382. '--test-input',
  383. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  384. '--pipeline',
  385. os.path.join(PIPELINE_DIR, 'multi-input-test.json'),
  386. '--expose-produced-outputs',
  387. self.test_dir,
  388. '-O',
  389. pipeline_run_save_path,
  390. ]
  391. self._call_cli_runtime_without_fail(arg)
  392. self.assertEqual(utils.list_files(self.test_dir), [
  393. 'outputs.0/data.csv',
  394. 'outputs.0/metadata.json',
  395. 'pipeline_run.yml',
  396. 'steps.0.produce/data.csv',
  397. 'steps.0.produce/metadata.json',
  398. 'steps.1.produce/data.csv',
  399. 'steps.1.produce/metadata.json',
  400. 'steps.2.produce/data.csv',
  401. 'steps.2.produce/metadata.json',
  402. ])
  403. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  404. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  405. self._assert_standard_output_metadata()
  406. self._assert_prediction_sum(prediction_sum=11008, outputs_path='outputs.0/data.csv')
  407. def test_fit_score(self):
  408. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  409. arg = [
  410. '',
  411. 'runtime',
  412. 'fit-score',
  413. '--input',
  414. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  415. '--problem',
  416. os.path.join(PROBLEM_DIR, 'iris_problem_1/problemDoc.json'),
  417. '--test-input',
  418. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  419. '--score-input',
  420. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  421. '--pipeline',
  422. os.path.join(PIPELINE_DIR, 'random-forest-classifier.yml'),
  423. '--scores',
  424. os.path.join(self.test_dir, 'scores.csv'),
  425. '-O',
  426. pipeline_run_save_path,
  427. ]
  428. self._call_cli_runtime_without_fail(arg)
  429. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  430. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  431. dataframe = pandas.read_csv(os.path.join(self.test_dir, 'scores.csv'))
  432. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed'])
  433. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0]])
  434. def test_fit_score_without_problem(self):
  435. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  436. arg = [
  437. '',
  438. 'runtime',
  439. 'fit-score',
  440. '--input',
  441. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  442. '--test-input',
  443. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  444. '--score-input',
  445. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  446. '--pipeline',
  447. os.path.join(PIPELINE_DIR, 'random-classifier.yml'),
  448. '--scoring-pipeline',
  449. os.path.join(PIPELINE_DIR, 'fake_compute_score.yml'),
  450. # this argument has no effect
  451. '--metric',
  452. 'F1_MACRO',
  453. '--metric',
  454. 'ACCURACY',
  455. '--scores',
  456. os.path.join(self.test_dir, 'scores.csv'),
  457. '-O',
  458. pipeline_run_save_path,
  459. ]
  460. logging_records = self._call_cli_runtime_without_fail(arg)
  461. self.assertEqual(len(logging_records), 1)
  462. self.assertEqual(logging_records[0].msg, "Not all provided hyper-parameters for the scoring pipeline %(pipeline_id)s were used: %(unused_params)s")
  463. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  464. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  465. dataframe = pandas.read_csv(os.path.join(self.test_dir, 'scores.csv'))
  466. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed'])
  467. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0]])
  468. @staticmethod
  469. def _get_iris_dataset_path():
  470. return os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json')
  471. @staticmethod
  472. def _get_iris_problem_path():
  473. return os.path.join(PROBLEM_DIR, 'iris_problem_1/problemDoc.json')
  474. @staticmethod
  475. def _get_random_forest_pipeline_path():
  476. return os.path.join(PIPELINE_DIR, 'random-forest-classifier.yml')
  477. @staticmethod
  478. def _get_no_split_data_pipeline_path():
  479. return os.path.join(PIPELINE_DIR, 'data-preparation-no-split.yml')
  480. @staticmethod
  481. def _get_train_test_split_data_pipeline_path():
  482. return os.path.join(PIPELINE_DIR, 'data-preparation-train-test-split.yml')
  483. def _get_pipeline_run_save_path(self):
  484. return os.path.join(self.test_dir, 'pipeline_run.yml')
  485. def _get_predictions_path(self):
  486. return os.path.join(self.test_dir, 'predictions.csv')
  487. def _get_scores_path(self):
  488. return os.path.join(self.test_dir, 'scores.csv')
  489. def _get_pipeline_rerun_save_path(self):
  490. return os.path.join(self.test_dir, 'pipeline_rerun.yml')
  491. def _get_rescores_path(self):
  492. return os.path.join(self.test_dir, 'rescores.csv')
  493. def _fit_iris_random_forest(
  494. self, *, predictions_path=None, fitted_pipeline_path=None, pipeline_run_save_path=None
  495. ):
  496. if pipeline_run_save_path is None:
  497. pipeline_run_save_path = self._get_pipeline_run_save_path()
  498. arg = [
  499. '',
  500. 'runtime',
  501. 'fit',
  502. '--input',
  503. self._get_iris_dataset_path(),
  504. '--problem',
  505. self._get_iris_problem_path(),
  506. '--pipeline',
  507. self._get_random_forest_pipeline_path(),
  508. '-O',
  509. pipeline_run_save_path
  510. ]
  511. if predictions_path is not None:
  512. arg.append('--output')
  513. arg.append(predictions_path)
  514. if fitted_pipeline_path is not None:
  515. arg.append('--save')
  516. arg.append(fitted_pipeline_path)
  517. self._call_cli_runtime_without_fail(arg)
  518. def _fit_iris_random_classifier_without_problem(self, *, fitted_pipeline_path):
  519. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  520. arg = [
  521. '',
  522. 'runtime',
  523. 'fit',
  524. '--input',
  525. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  526. '--pipeline',
  527. os.path.join(PIPELINE_DIR, 'random-classifier.yml'),
  528. '-O',
  529. pipeline_run_save_path
  530. ]
  531. if fitted_pipeline_path is not None:
  532. arg.append('--save')
  533. arg.append(fitted_pipeline_path)
  534. self._call_cli_runtime_without_fail(arg)
  535. def test_fit(self):
  536. pipeline_run_save_path = self._get_pipeline_run_save_path()
  537. fitted_pipeline_path = os.path.join(self.test_dir, 'fitted-pipeline')
  538. self._fit_iris_random_forest(
  539. fitted_pipeline_path=fitted_pipeline_path, pipeline_run_save_path=pipeline_run_save_path
  540. )
  541. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  542. self.assertTrue(os.path.isfile(fitted_pipeline_path))
  543. self.assertTrue(os.path.isfile(pipeline_run_save_path))
  544. def test_evaluate(self):
  545. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  546. scores_path = os.path.join(self.test_dir, 'scores.csv')
  547. arg = [
  548. '',
  549. 'runtime',
  550. 'evaluate',
  551. '--input',
  552. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  553. '--problem',
  554. os.path.join(PROBLEM_DIR, 'iris_problem_1/problemDoc.json'),
  555. '--pipeline',
  556. os.path.join(PIPELINE_DIR, 'random-forest-classifier.yml'),
  557. '--data-pipeline',
  558. os.path.join(PIPELINE_DIR, 'data-preparation-no-split.yml'),
  559. '--scores',
  560. scores_path,
  561. '--metric',
  562. 'ACCURACY',
  563. '--metric',
  564. 'F1_MACRO',
  565. '-O',
  566. pipeline_run_save_path
  567. ]
  568. self._call_cli_runtime_without_fail(arg)
  569. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  570. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  571. dataframe = pandas.read_csv(scores_path)
  572. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed', 'fold'])
  573. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0, 0], ['F1_MACRO', 1.0, 1.0, 0, 0]])
  574. def test_evaluate_without_problem(self):
  575. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  576. scores_path = os.path.join(self.test_dir, 'scores.csv')
  577. arg = [
  578. '',
  579. 'runtime',
  580. 'evaluate',
  581. '--input',
  582. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  583. '--pipeline',
  584. os.path.join(PIPELINE_DIR, 'random-classifier.yml'),
  585. '--data-pipeline',
  586. os.path.join(PIPELINE_DIR, 'data-preparation-no-split.yml'),
  587. '--scoring-pipeline',
  588. os.path.join(PIPELINE_DIR, 'fake_compute_score.yml'),
  589. # this argument has no effect
  590. '--metric',
  591. 'ACCURACY',
  592. '--scores',
  593. scores_path,
  594. '-O',
  595. pipeline_run_save_path
  596. ]
  597. logging_records = self._call_cli_runtime_without_fail(arg)
  598. self.assertEqual(len(logging_records), 1)
  599. self.assertEqual(logging_records[0].msg, "Not all provided hyper-parameters for the scoring pipeline %(pipeline_id)s were used: %(unused_params)s")
  600. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  601. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  602. dataframe = pandas.read_csv(scores_path)
  603. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed', 'fold'])
  604. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0, 0]])
  605. def test_score(self):
  606. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  607. fitted_pipeline_path = os.path.join(self.test_dir, 'iris-pipeline')
  608. self._fit_iris_random_forest(fitted_pipeline_path=fitted_pipeline_path)
  609. self.assertTrue(os.path.isfile(fitted_pipeline_path))
  610. scores_path = os.path.join(self.test_dir, 'scores.csv')
  611. arg = [
  612. '',
  613. 'runtime',
  614. 'score',
  615. '--fitted-pipeline',
  616. fitted_pipeline_path,
  617. '--test-input',
  618. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  619. '--score-input',
  620. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  621. '--scores',
  622. scores_path,
  623. '--metric',
  624. 'F1_MACRO',
  625. '--metric',
  626. 'ACCURACY',
  627. '-O',
  628. pipeline_run_save_path,
  629. ]
  630. self._call_cli_runtime_without_fail(arg)
  631. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  632. self.assertTrue(os.path.isfile(scores_path), 'scores were not generated')
  633. dataframe = pandas.read_csv(scores_path)
  634. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed'])
  635. self.assertEqual(dataframe.values.tolist(), [['F1_MACRO', 1.0, 1.0, 0], ['ACCURACY', 1.0, 1.0, 0]])
  636. def test_score_without_problem_without_metric(self):
  637. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  638. fitted_pipeline_path = os.path.join(self.test_dir, 'iris-pipeline')
  639. self._fit_iris_random_classifier_without_problem(fitted_pipeline_path=fitted_pipeline_path)
  640. self.assertTrue(os.path.isfile(fitted_pipeline_path))
  641. scores_path = os.path.join(self.test_dir, 'scores.csv')
  642. arg = [
  643. '',
  644. 'runtime',
  645. 'score',
  646. '--fitted-pipeline',
  647. fitted_pipeline_path,
  648. '--test-input',
  649. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  650. '--score-input',
  651. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  652. '--scoring-pipeline',
  653. os.path.join(PIPELINE_DIR, 'fake_compute_score.yml'),
  654. '--scores',
  655. scores_path,
  656. '-O',
  657. pipeline_run_save_path,
  658. ]
  659. self._call_cli_runtime_without_fail(arg)
  660. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  661. self.assertTrue(os.path.isfile(scores_path), 'scores were not generated')
  662. dataframe = pandas.read_csv(scores_path)
  663. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed'])
  664. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0]])
  665. def test_score_without_problem(self):
  666. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  667. fitted_pipeline_path = os.path.join(self.test_dir, 'iris-pipeline')
  668. self._fit_iris_random_classifier_without_problem(fitted_pipeline_path=fitted_pipeline_path)
  669. self.assertTrue(os.path.isfile(fitted_pipeline_path))
  670. scores_path = os.path.join(self.test_dir, 'scores.csv')
  671. arg = [
  672. '',
  673. 'runtime',
  674. 'score',
  675. '--fitted-pipeline',
  676. fitted_pipeline_path,
  677. '--test-input',
  678. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  679. '--score-input',
  680. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  681. '--scoring-pipeline',
  682. os.path.join(PIPELINE_DIR, 'fake_compute_score.yml'),
  683. # this argument has no effect
  684. '--metric',
  685. 'ACCURACY',
  686. '--scores',
  687. scores_path,
  688. '-O',
  689. pipeline_run_save_path,
  690. ]
  691. logging_records = self._call_cli_runtime_without_fail(arg)
  692. self.assertEqual(len(logging_records), 1)
  693. self.assertEqual(logging_records[0].msg, "Not all provided hyper-parameters for the scoring pipeline %(pipeline_id)s were used: %(unused_params)s")
  694. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  695. self.assertTrue(os.path.isfile(scores_path), 'scores were not generated')
  696. dataframe = pandas.read_csv(scores_path)
  697. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed'])
  698. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0]])
  699. def test_produce(self):
  700. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  701. fitted_pipeline_path = os.path.join(self.test_dir, 'iris-pipeline')
  702. self._fit_iris_random_forest(fitted_pipeline_path=fitted_pipeline_path)
  703. self.assertTrue(os.path.isfile(fitted_pipeline_path))
  704. arg = [
  705. '',
  706. 'runtime',
  707. 'produce',
  708. '--fitted-pipeline',
  709. fitted_pipeline_path,
  710. '--test-input',
  711. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  712. '-O',
  713. pipeline_run_save_path,
  714. ]
  715. self._call_cli_runtime_without_fail(arg)
  716. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  717. def test_score_predictions(self):
  718. predictions_path = os.path.join(self.test_dir, 'predictions.csv')
  719. self._fit_iris_random_forest(predictions_path=predictions_path)
  720. self.assertTrue(os.path.isfile(predictions_path))
  721. scores_path = os.path.join(self.test_dir, 'scores.csv')
  722. arg = [
  723. '',
  724. 'runtime',
  725. 'score-predictions',
  726. '--score-input',
  727. os.path.join(DATASET_DIR, 'iris_dataset_1/datasetDoc.json'),
  728. '--problem',
  729. os.path.join(PROBLEM_DIR, 'iris_problem_1/problemDoc.json'),
  730. '--predictions',
  731. predictions_path,
  732. '--metric',
  733. 'ACCURACY',
  734. '--metric',
  735. 'F1_MACRO',
  736. '--scores',
  737. scores_path,
  738. ]
  739. self._call_cli_runtime_without_fail(arg)
  740. self.assertTrue(os.path.isfile(scores_path), 'scores were not generated')
  741. dataframe = pandas.read_csv(scores_path)
  742. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized'])
  743. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0], ['F1_MACRO', 1.0, 1.0]])
  744. def test_sklearn_dataset_fit_produce(self):
  745. self._create_sklearn_iris_problem_doc()
  746. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  747. arg = [
  748. '',
  749. 'runtime',
  750. 'fit-produce',
  751. '--input',
  752. 'sklearn://iris',
  753. '--input',
  754. 'sklearn://iris',
  755. '--problem',
  756. os.path.join(self.test_dir, 'problemDoc.json'),
  757. '--test-input',
  758. 'sklearn://iris',
  759. '--test-input',
  760. 'sklearn://iris',
  761. '--pipeline',
  762. os.path.join(PIPELINE_DIR, 'multi-input-test.json'),
  763. '--expose-produced-outputs',
  764. self.test_dir,
  765. '-O',
  766. pipeline_run_save_path,
  767. ]
  768. self._call_cli_runtime_without_fail(arg)
  769. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  770. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  771. self.assertEqual(utils.list_files(self.test_dir), [
  772. 'outputs.0/data.csv',
  773. 'outputs.0/metadata.json',
  774. 'pipeline_run.yml',
  775. 'problemDoc.json',
  776. 'steps.0.produce/data.csv',
  777. 'steps.0.produce/metadata.json',
  778. 'steps.1.produce/data.csv',
  779. 'steps.1.produce/metadata.json',
  780. 'steps.2.produce/data.csv',
  781. 'steps.2.produce/metadata.json'
  782. ])
  783. self._assert_standard_output_metadata(prediction_type='numpy.int64')
  784. self._assert_prediction_sum(prediction_sum=10648, outputs_path='outputs.0/data.csv')
  785. def test_sklearn_dataset_fit_produce_without_problem(self):
  786. output_csv_path = os.path.join(self.test_dir, 'output.csv')
  787. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  788. fitted_pipeline_path = os.path.join(self.test_dir, 'fitted-pipeline')
  789. arg = [
  790. '',
  791. 'runtime',
  792. 'fit-produce',
  793. '--input',
  794. 'sklearn://iris',
  795. '--test-input',
  796. 'sklearn://iris',
  797. '--pipeline',
  798. os.path.join(PIPELINE_DIR, 'random-classifier.yml'),
  799. '--save',
  800. fitted_pipeline_path,
  801. '--output',
  802. output_csv_path,
  803. '--expose-produced-outputs',
  804. self.test_dir,
  805. '-O',
  806. pipeline_run_save_path,
  807. ]
  808. self._call_cli_runtime_without_fail(arg)
  809. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  810. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  811. self.assertEqual(utils.list_files(self.test_dir), [
  812. 'fitted-pipeline',
  813. 'output.csv',
  814. 'outputs.0/data.csv',
  815. 'outputs.0/metadata.json',
  816. 'pipeline_run.yml',
  817. 'steps.0.produce/data.csv',
  818. 'steps.0.produce/metadata.json',
  819. 'steps.1.produce/data.csv',
  820. 'steps.1.produce/metadata.json',
  821. 'steps.2.produce/data.csv',
  822. 'steps.2.produce/metadata.json',
  823. ])
  824. self._assert_standard_output_metadata(prediction_type='numpy.int64')
  825. self._assert_prediction_sum(prediction_sum=10648, outputs_path='outputs.0/data.csv')
  826. self._assert_prediction_sum(prediction_sum=10648, outputs_path='output.csv')
  827. def _create_sklearn_iris_problem_doc(self):
  828. with open(os.path.join(PROBLEM_DIR, 'iris_problem_1/problemDoc.json'), 'r', encoding='utf8') as problem_doc_file:
  829. problem_doc = json.load(problem_doc_file)
  830. problem_doc['inputs']['data'][0]['datasetID'] = 'sklearn://iris'
  831. with open(os.path.join(self.test_dir, 'problemDoc.json'), 'x', encoding='utf8') as problem_doc_file:
  832. json.dump(problem_doc, problem_doc_file)
  833. def test_sklearn_dataset_evaluate(self):
  834. self._create_sklearn_iris_problem_doc()
  835. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  836. scores_path = os.path.join(self.test_dir, 'scores.csv')
  837. arg = [
  838. '',
  839. 'runtime',
  840. 'evaluate',
  841. '--input',
  842. 'sklearn://iris',
  843. '--problem',
  844. os.path.join(self.test_dir, 'problemDoc.json'),
  845. '--pipeline',
  846. os.path.join(PIPELINE_DIR, 'random-forest-classifier.yml'),
  847. '--data-pipeline',
  848. os.path.join(PIPELINE_DIR, 'data-preparation-no-split.yml'),
  849. '--scores',
  850. scores_path,
  851. '--metric',
  852. 'ACCURACY',
  853. '--metric',
  854. 'F1_MACRO',
  855. '-O',
  856. pipeline_run_save_path
  857. ]
  858. self._call_cli_runtime_without_fail(arg)
  859. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  860. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  861. dataframe = pandas.read_csv(scores_path)
  862. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed', 'fold'])
  863. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0, 0], ['F1_MACRO', 1.0, 1.0, 0, 0]])
  864. def test_sklearn_dataset_evaluate_without_problem(self):
  865. pipeline_run_save_path = os.path.join(self.test_dir, 'pipeline_run.yml')
  866. scores_path = os.path.join(self.test_dir, 'scores.csv')
  867. arg = [
  868. '',
  869. 'runtime',
  870. 'evaluate',
  871. '--input',
  872. 'sklearn://iris',
  873. '--pipeline',
  874. os.path.join(PIPELINE_DIR, 'random-classifier.yml'),
  875. '--data-pipeline',
  876. os.path.join(PIPELINE_DIR, 'data-preparation-no-split.yml'),
  877. '--scoring-pipeline',
  878. os.path.join(PIPELINE_DIR, 'fake_compute_score.yml'),
  879. # this argument has no effect
  880. '--metric',
  881. 'ACCURACY',
  882. '--scores',
  883. scores_path,
  884. '-O',
  885. pipeline_run_save_path
  886. ]
  887. logging_records = self._call_cli_runtime_without_fail(arg)
  888. self.assertEqual(len(logging_records), 1)
  889. self.assertEqual(logging_records[0].msg, "Not all provided hyper-parameters for the scoring pipeline %(pipeline_id)s were used: %(unused_params)s")
  890. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  891. self._validate_previous_pipeline_run_ids(pipeline_run_save_path)
  892. dataframe = pandas.read_csv(scores_path)
  893. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'normalized', 'randomSeed', 'fold'])
  894. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, 1.0, 0, 0]])
  895. def _assert_prediction_sum(self, prediction_sum, outputs_path):
  896. if prediction_sum is not None:
  897. with open(os.path.join(self.test_dir, outputs_path), 'r') as csv_file:
  898. self.assertEqual(sum([int(v) for v in list(csv_file)[1:]]), prediction_sum)
  899. def _assert_standard_output_metadata(self, outputs_name='outputs.0', prediction_type='str'):
  900. with open(os.path.join(self.test_dir, outputs_name, 'metadata.json'), 'r') as metadata_file:
  901. metadata = json.load(metadata_file)
  902. self.assertEqual(
  903. metadata,
  904. [
  905. {
  906. "selector": [],
  907. "metadata": {
  908. "dimension": {
  909. "length": 150,
  910. "name": "rows",
  911. "semantic_types": ["https://metadata.datadrivendiscovery.org/types/TabularRow"],
  912. },
  913. "schema": "https://metadata.datadrivendiscovery.org/schemas/v0/container.json",
  914. "semantic_types": ["https://metadata.datadrivendiscovery.org/types/Table"],
  915. "structural_type": "d3m.container.pandas.DataFrame",
  916. },
  917. },
  918. {
  919. "selector": ["__ALL_ELEMENTS__"],
  920. "metadata": {
  921. "dimension": {
  922. "length": 1,
  923. "name": "columns",
  924. "semantic_types": ["https://metadata.datadrivendiscovery.org/types/TabularColumn"],
  925. }
  926. },
  927. },
  928. {"selector": ["__ALL_ELEMENTS__", 0],
  929. "metadata": {"name": "predictions", "structural_type": prediction_type}},
  930. ],
  931. )
  932. def _assert_nonstandard_output(self, outputs_name='outputs.1'):
  933. with open(os.path.join(self.test_dir, outputs_name, 'data.csv'), 'r') as csv_file:
  934. output_dataframe = pandas.read_csv(csv_file, index_col=False)
  935. learning_dataframe = pandas.read_csv(
  936. os.path.join(DATASET_DIR, 'iris_dataset_1/tables/learningData.csv'), index_col=False)
  937. self.assertTrue(learning_dataframe.equals(output_dataframe))
  938. with open(os.path.join(self.test_dir, outputs_name, 'metadata.json'), 'r') as metadata_file:
  939. metadata = json.load(metadata_file)
  940. self.assertEqual(
  941. metadata,
  942. [
  943. {
  944. "metadata": {
  945. "dimension": {
  946. "length": 150,
  947. "name": "rows",
  948. "semantic_types": [
  949. "https://metadata.datadrivendiscovery.org/types/TabularRow"
  950. ]
  951. },
  952. "schema": "https://metadata.datadrivendiscovery.org/schemas/v0/container.json",
  953. "semantic_types": [
  954. "https://metadata.datadrivendiscovery.org/types/Table"
  955. ],
  956. "structural_type": "d3m.container.pandas.DataFrame"
  957. },
  958. "selector": []
  959. },
  960. {
  961. "metadata": {
  962. "dimension": {
  963. "length": 6,
  964. "name": "columns",
  965. "semantic_types": [
  966. "https://metadata.datadrivendiscovery.org/types/TabularColumn"
  967. ]
  968. }
  969. },
  970. "selector": [
  971. "__ALL_ELEMENTS__"
  972. ]
  973. },
  974. {
  975. "metadata": {
  976. "name": "d3mIndex",
  977. "semantic_types": [
  978. "http://schema.org/Integer",
  979. "https://metadata.datadrivendiscovery.org/types/PrimaryKey"
  980. ],
  981. "structural_type": "str"
  982. },
  983. "selector": [
  984. "__ALL_ELEMENTS__",
  985. 0
  986. ]
  987. },
  988. {
  989. "metadata": {
  990. "name": "sepalLength",
  991. "semantic_types": [
  992. "http://schema.org/Float",
  993. "https://metadata.datadrivendiscovery.org/types/Attribute"
  994. ],
  995. "structural_type": "str"
  996. },
  997. "selector": [
  998. "__ALL_ELEMENTS__",
  999. 1
  1000. ]
  1001. },
  1002. {
  1003. "metadata": {
  1004. "name": "sepalWidth",
  1005. "semantic_types": [
  1006. "http://schema.org/Float",
  1007. "https://metadata.datadrivendiscovery.org/types/Attribute"
  1008. ],
  1009. "structural_type": "str"
  1010. },
  1011. "selector": [
  1012. "__ALL_ELEMENTS__",
  1013. 2
  1014. ]
  1015. },
  1016. {
  1017. "metadata": {
  1018. "name": "petalLength",
  1019. "semantic_types": [
  1020. "http://schema.org/Float",
  1021. "https://metadata.datadrivendiscovery.org/types/Attribute"
  1022. ],
  1023. "structural_type": "str"
  1024. },
  1025. "selector": [
  1026. "__ALL_ELEMENTS__",
  1027. 3
  1028. ]
  1029. },
  1030. {
  1031. "metadata": {
  1032. "name": "petalWidth",
  1033. "semantic_types": [
  1034. "http://schema.org/Float",
  1035. "https://metadata.datadrivendiscovery.org/types/Attribute"
  1036. ],
  1037. "structural_type": "str"
  1038. },
  1039. "selector": [
  1040. "__ALL_ELEMENTS__",
  1041. 4
  1042. ]
  1043. },
  1044. {
  1045. "metadata": {
  1046. "name": "species",
  1047. "semantic_types": [
  1048. "https://metadata.datadrivendiscovery.org/types/CategoricalData",
  1049. "https://metadata.datadrivendiscovery.org/types/SuggestedTarget",
  1050. "https://metadata.datadrivendiscovery.org/types/Attribute"
  1051. ],
  1052. "structural_type": "str"
  1053. },
  1054. "selector": [
  1055. "__ALL_ELEMENTS__",
  1056. 5
  1057. ]
  1058. }
  1059. ]
  1060. )
  1061. def _assert_pipeline_runs_equal(self, pipeline_run_save_path1, pipeline_run_save_path2):
  1062. with open(pipeline_run_save_path1, 'r') as f:
  1063. pipeline_runs1 = list(utils.yaml_load_all(f))
  1064. with open(pipeline_run_save_path2, 'r') as f:
  1065. pipeline_runs2 = list(utils.yaml_load_all(f))
  1066. self.assertEqual(len(pipeline_runs1), len(pipeline_runs2))
  1067. for pipeline_run1, pipeline_run2 in zip(pipeline_runs1, pipeline_runs2):
  1068. self.assertTrue(pipeline_run_module.PipelineRun.json_structure_equals(pipeline_run1, pipeline_run2))
  1069. def test_pipeline_run_json_structure_equals(self):
  1070. pipeline_run_save_path1 = os.path.join(self.test_dir, 'pipeline_run1.yml')
  1071. self._fit_iris_random_forest(pipeline_run_save_path=pipeline_run_save_path1)
  1072. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path1)
  1073. pipeline_run_save_path2 = os.path.join(self.test_dir, 'pipeline_run2.yml')
  1074. self._fit_iris_random_forest(pipeline_run_save_path=pipeline_run_save_path2)
  1075. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path2)
  1076. self._assert_pipeline_runs_equal(pipeline_run_save_path1, pipeline_run_save_path2)
  1077. def _cache_pipeline_for_rerun(self, pipeline_path, cache_dir=None):
  1078. """make pipeline searchable by id in test_dir"""
  1079. with open(pipeline_path, 'r') as f:
  1080. pipeline = utils.yaml_load(f)
  1081. if cache_dir is None:
  1082. cache_dir = self.test_dir
  1083. temp_pipeline_path = os.path.join(cache_dir, pipeline['id'] + '.yml')
  1084. with open(temp_pipeline_path, 'w') as f:
  1085. utils.yaml_dump(pipeline, f)
  1086. @staticmethod
  1087. def _generate_seed():
  1088. return random.randint(2**31, 2**32-1)
  1089. def test_fit_rerun(self):
  1090. dataset_path = self._get_iris_dataset_path()
  1091. problem_path = self._get_iris_problem_path()
  1092. pipeline_path = self._get_random_forest_pipeline_path()
  1093. pipeline_run_save_path = self._get_pipeline_run_save_path()
  1094. problem = problem_module.get_problem(problem_path)
  1095. inputs = [dataset_module.get_dataset(dataset_path)]
  1096. with open(pipeline_path) as f:
  1097. pipeline = pipeline_module.Pipeline.from_yaml(f)
  1098. hyperparams = [{}, {}, {'n_estimators': 19}, {}]
  1099. random_seed = self._generate_seed()
  1100. with utils.silence():
  1101. fitted_pipeline, predictions, fit_result = runtime.fit(
  1102. pipeline, inputs, problem_description=problem, hyperparams=hyperparams,
  1103. random_seed=random_seed, context=metadata_base.Context.TESTING,
  1104. )
  1105. with open(pipeline_run_save_path, 'w') as f:
  1106. fit_result.pipeline_run.to_yaml(f)
  1107. self._cache_pipeline_for_rerun(pipeline_path)
  1108. pipeline_rerun_save_path = self._get_pipeline_rerun_save_path()
  1109. rerun_arg = [
  1110. '',
  1111. '--pipelines-path',
  1112. self.test_dir,
  1113. 'runtime',
  1114. '--datasets',
  1115. TEST_DATA_DIR,
  1116. 'fit',
  1117. '--input-run',
  1118. pipeline_run_save_path,
  1119. '--output-run',
  1120. pipeline_rerun_save_path,
  1121. ]
  1122. self._call_cli_runtime_without_fail(rerun_arg)
  1123. self._assert_valid_saved_pipeline_runs(pipeline_rerun_save_path)
  1124. self._assert_pipeline_runs_equal(pipeline_run_save_path, pipeline_rerun_save_path)
  1125. def test_produce_rerun(self):
  1126. dataset_path = self._get_iris_dataset_path()
  1127. problem_path = self._get_iris_problem_path()
  1128. pipeline_path = self._get_random_forest_pipeline_path()
  1129. pipeline_run_save_path = self._get_pipeline_run_save_path()
  1130. fitted_pipeline_path = os.path.join(self.test_dir, 'iris-pipeline')
  1131. self._fit_iris_random_forest(fitted_pipeline_path=fitted_pipeline_path)
  1132. self.assertTrue(os.path.isfile(fitted_pipeline_path))
  1133. arg = [
  1134. '',
  1135. 'runtime',
  1136. 'produce',
  1137. '--fitted-pipeline',
  1138. fitted_pipeline_path,
  1139. '--test-input',
  1140. dataset_path,
  1141. '--output-run',
  1142. pipeline_run_save_path,
  1143. ]
  1144. self._call_cli_runtime_without_fail(arg)
  1145. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  1146. self._cache_pipeline_for_rerun(pipeline_path)
  1147. pipeline_rerun_save_path = self._get_pipeline_rerun_save_path()
  1148. rerun_arg = [
  1149. '',
  1150. '--pipelines-path',
  1151. self.test_dir,
  1152. 'runtime',
  1153. '--datasets',
  1154. TEST_DATA_DIR,
  1155. 'produce',
  1156. '--fitted-pipeline',
  1157. fitted_pipeline_path,
  1158. '--input-run',
  1159. pipeline_run_save_path,
  1160. '--output-run',
  1161. pipeline_rerun_save_path,
  1162. ]
  1163. self._call_cli_runtime_without_fail(rerun_arg)
  1164. self._assert_valid_saved_pipeline_runs(pipeline_rerun_save_path)
  1165. self._assert_pipeline_runs_equal(pipeline_run_save_path, pipeline_rerun_save_path)
  1166. def _assert_scores_equal(self, scores_path, rescores_path):
  1167. scores = pandas.read_csv(scores_path)
  1168. rescores = pandas.read_csv(rescores_path)
  1169. self.assertTrue(scores.equals(rescores), '\n{}\n\n{}'.format(scores, rescores))
  1170. def _assert_scores_equal_pipeline_run(self, scores_path, pipeline_run_save_path):
  1171. scores = pandas.read_csv(scores_path)
  1172. scores.drop('fold', axis=1, inplace=True, errors='ignore')
  1173. scores_no_seed = scores.drop('randomSeed', axis=1, errors='ignore')
  1174. with open(pipeline_run_save_path) as f:
  1175. # TODO: always use -1?
  1176. pipeline_run = list(utils.yaml_load_all(f))[-1]
  1177. self.assertEqual(pipeline_run['run']['phase'], metadata_base.PipelineRunPhase.PRODUCE.name)
  1178. # TODO: clean up preprocessing?
  1179. pipeline_run_scores_df = pandas.DataFrame(pipeline_run['run']['results']['scores'])
  1180. # TODO: is it possible to make pipeline run schema more compatible with scores csv schema?
  1181. pipeline_run_scores_df['metric'] = pipeline_run_scores_df['metric'].map(lambda cell: cell['metric'])
  1182. pipeline_run_scores_df = pipeline_run_scores_df[scores_no_seed.columns.tolist()]
  1183. pandas.testing.assert_frame_equal(scores_no_seed, pipeline_run_scores_df)
  1184. self.assertEqual(scores['randomSeed'].iloc[0], pipeline_run['random_seed'])
  1185. def test_score_rerun(self):
  1186. dataset_path = self._get_iris_dataset_path()
  1187. problem_path = self._get_iris_problem_path()
  1188. pipeline_path = self._get_random_forest_pipeline_path()
  1189. pipeline_run_save_path = self._get_pipeline_run_save_path()
  1190. fitted_pipeline_path = os.path.join(self.test_dir, 'iris-pipeline')
  1191. scores_path = os.path.join(self.test_dir, 'scores.csv')
  1192. random_seed = self._generate_seed()
  1193. metrics = runtime.get_metrics_from_list(['ACCURACY', 'F1_MACRO'])
  1194. scoring_params = {'add_normalized_scores': 'false'}
  1195. scoring_random_seed = self._generate_seed()
  1196. problem = problem_module.get_problem(problem_path)
  1197. inputs = [dataset_module.get_dataset(dataset_path)]
  1198. with open(pipeline_path) as f:
  1199. pipeline = pipeline_module.Pipeline.from_yaml(f)
  1200. with open(runtime.DEFAULT_SCORING_PIPELINE_PATH) as f:
  1201. scoring_pipeline = pipeline_module.Pipeline.from_yaml(f)
  1202. with utils.silence():
  1203. fitted_pipeline, predictions, fit_result = runtime.fit(
  1204. pipeline, inputs, problem_description=problem, random_seed=random_seed,
  1205. context=metadata_base.Context.TESTING,
  1206. )
  1207. with open(fitted_pipeline_path, 'wb') as f:
  1208. pickle.dump(fitted_pipeline, f)
  1209. predictions, produce_result = runtime.produce(fitted_pipeline, inputs)
  1210. scores, score_result = runtime.score(
  1211. predictions, inputs, scoring_pipeline=scoring_pipeline,
  1212. problem_description=problem, metrics=metrics, predictions_random_seed=random_seed,
  1213. context=metadata_base.Context.TESTING, scoring_params=scoring_params,
  1214. random_seed=scoring_random_seed
  1215. )
  1216. self.assertFalse(score_result.has_error(), score_result.error)
  1217. scores.to_csv(scores_path)
  1218. runtime.combine_pipeline_runs(
  1219. produce_result.pipeline_run, scoring_pipeline_run=score_result.pipeline_run, score_inputs=inputs,
  1220. metrics=metrics, scores=scores
  1221. )
  1222. with open(pipeline_run_save_path, 'w') as f:
  1223. produce_result.pipeline_run.to_yaml(f)
  1224. self.assertTrue(os.path.isfile(fitted_pipeline_path))
  1225. self.assertTrue(os.path.isfile(scores_path), 'scores were not generated')
  1226. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  1227. dataframe = pandas.read_csv(scores_path)
  1228. self.assertEqual(list(dataframe.columns), ['metric', 'value', 'randomSeed'])
  1229. self.assertEqual(dataframe.values.tolist(), [['ACCURACY', 1.0, random_seed], ['F1_MACRO', 1.0, random_seed]])
  1230. self._cache_pipeline_for_rerun(pipeline_path)
  1231. pipeline_rerun_save_path = self._get_pipeline_rerun_save_path()
  1232. rescores_path = self._get_rescores_path()
  1233. rerun_arg = [
  1234. '',
  1235. '--pipelines-path',
  1236. self.test_dir,
  1237. 'runtime',
  1238. '--datasets',
  1239. TEST_DATA_DIR,
  1240. 'score',
  1241. '--fitted-pipeline',
  1242. fitted_pipeline_path,
  1243. '--input-run',
  1244. pipeline_run_save_path,
  1245. '--output-run',
  1246. pipeline_rerun_save_path,
  1247. '--scores',
  1248. rescores_path,
  1249. ]
  1250. self._call_cli_runtime_without_fail(rerun_arg)
  1251. self.assertTrue(os.path.isfile(pipeline_rerun_save_path))
  1252. self._assert_valid_saved_pipeline_runs(pipeline_rerun_save_path)
  1253. self._assert_scores_equal(scores_path, rescores_path)
  1254. self._assert_scores_equal_pipeline_run(scores_path, pipeline_rerun_save_path)
  1255. self._assert_pipeline_runs_equal(pipeline_run_save_path, pipeline_rerun_save_path)
  1256. def test_fit_produce_rerun(self):
  1257. dataset_path = self._get_iris_dataset_path()
  1258. problem_path = self._get_iris_problem_path()
  1259. pipeline_path = self._get_random_forest_pipeline_path()
  1260. pipeline_run_save_path = self._get_pipeline_run_save_path()
  1261. hyperparams = [{}, {}, {'n_estimators': 19}, {}]
  1262. random_seed = self._generate_seed()
  1263. problem = problem_module.get_problem(problem_path)
  1264. inputs = [dataset_module.get_dataset(dataset_path)]
  1265. with open(pipeline_path) as f:
  1266. pipeline = pipeline_module.Pipeline.from_yaml(f)
  1267. with utils.silence():
  1268. fitted_pipeline, predictions, fit_result = runtime.fit(
  1269. pipeline, inputs, problem_description=problem, hyperparams=hyperparams,
  1270. random_seed=random_seed, context=metadata_base.Context.TESTING,
  1271. )
  1272. predictions, produce_result = runtime.produce(fitted_pipeline, inputs)
  1273. with open(pipeline_run_save_path, 'w') as f:
  1274. fit_result.pipeline_run.to_yaml(f)
  1275. produce_result.pipeline_run.to_yaml(f, appending=True)
  1276. self._cache_pipeline_for_rerun(pipeline_path)
  1277. pipeline_rerun_save_path = self._get_pipeline_rerun_save_path()
  1278. rerun_arg = [
  1279. '',
  1280. '--pipelines-path',
  1281. self.test_dir,
  1282. '--strict-digest',
  1283. 'runtime',
  1284. '--datasets',
  1285. TEST_DATA_DIR,
  1286. 'fit-produce',
  1287. '--input-run',
  1288. pipeline_run_save_path,
  1289. '--output-run',
  1290. pipeline_rerun_save_path,
  1291. ]
  1292. self._call_cli_runtime_without_fail(rerun_arg)
  1293. self._assert_valid_saved_pipeline_runs(pipeline_rerun_save_path)
  1294. self._assert_pipeline_runs_equal(pipeline_run_save_path, pipeline_rerun_save_path)
  1295. def test_fit_score_rerun(self):
  1296. dataset_path = self._get_iris_dataset_path()
  1297. problem_path = self._get_iris_problem_path()
  1298. pipeline_path = self._get_random_forest_pipeline_path()
  1299. pipeline_run_save_path = self._get_pipeline_run_save_path()
  1300. scores_path = self._get_scores_path()
  1301. hyperparams = [{}, {}, {'n_estimators': 19}, {}]
  1302. random_seed = self._generate_seed()
  1303. metrics = runtime.get_metrics_from_list(['ACCURACY', 'F1_MACRO'])
  1304. scoring_params = {'add_normalized_scores': 'false'}
  1305. scoring_random_seed = self._generate_seed()
  1306. problem = problem_module.get_problem(problem_path)
  1307. inputs = [dataset_module.get_dataset(dataset_path)]
  1308. with open(pipeline_path) as f:
  1309. pipeline = pipeline_module.Pipeline.from_yaml(f)
  1310. with open(runtime.DEFAULT_SCORING_PIPELINE_PATH) as f:
  1311. scoring_pipeline = pipeline_module.Pipeline.from_yaml(f)
  1312. with utils.silence():
  1313. fitted_pipeline, predictions, fit_result = runtime.fit(
  1314. pipeline, inputs, problem_description=problem, hyperparams=hyperparams,
  1315. random_seed=random_seed, context=metadata_base.Context.TESTING,
  1316. )
  1317. self.assertFalse(fit_result.has_error(), fit_result.error)
  1318. predictions, produce_result = runtime.produce(fitted_pipeline, inputs)
  1319. self.assertFalse(produce_result.has_error(), produce_result.error)
  1320. scores, score_result = runtime.score(
  1321. predictions, inputs, scoring_pipeline=scoring_pipeline,
  1322. problem_description=problem, metrics=metrics,
  1323. predictions_random_seed=fitted_pipeline.random_seed,
  1324. context=metadata_base.Context.TESTING, scoring_params=scoring_params, random_seed=scoring_random_seed
  1325. )
  1326. self.assertFalse(score_result.has_error(), score_result.error)
  1327. scores.to_csv(scores_path)
  1328. runtime.combine_pipeline_runs(
  1329. produce_result.pipeline_run, scoring_pipeline_run=score_result.pipeline_run, score_inputs=inputs,
  1330. metrics=metrics, scores=scores
  1331. )
  1332. with open(pipeline_run_save_path, 'w') as f:
  1333. fit_result.pipeline_run.to_yaml(f)
  1334. produce_result.pipeline_run.to_yaml(f, appending=True)
  1335. self._assert_valid_saved_pipeline_runs(pipeline_run_save_path)
  1336. self._cache_pipeline_for_rerun(pipeline_path)
  1337. pipeline_rerun_save_path = self._get_pipeline_rerun_save_path()
  1338. rescores_path = self._get_rescores_path()
  1339. rerun_arg = [
  1340. '',
  1341. '--pipelines-path',
  1342. self.test_dir,
  1343. '--strict-digest',
  1344. 'runtime',
  1345. '--datasets',
  1346. TEST_DATA_DIR,
  1347. 'fit-score',
  1348. '--input-run',
  1349. pipeline_run_save_path,
  1350. '--scores',
  1351. rescores_path,
  1352. '--output-run',
  1353. pipeline_rerun_save_path,
  1354. ]
  1355. self._call_cli_runtime_without_fail(rerun_arg)
  1356. self._assert_valid_saved_pipeline_runs(pipeline_rerun_save_path)
  1357. self._assert_scores_equal(scores_path, rescores_path)
  1358. self._assert_scores_equal_pipeline_run(scores_path, pipeline_rerun_save_path)
  1359. self._assert_pipeline_runs_equal(pipeline_run_save_path, pipeline_rerun_save_path)
  1360. def test_evaluate_rerun(self):
  1361. dataset_path = self._get_iris_dataset_path()
  1362. problem_path = self._get_iris_problem_path()
  1363. pipeline_path = self._get_random_forest_pipeline_path()
  1364. data_pipeline_path = self._get_train_test_split_data_pipeline_path()
  1365. pipeline_run_save_path = self._get_pipeline_run_save_path()
  1366. scores_path = self._get_scores_path()
  1367. hyperparams = [{}, {}, {'n_estimators': 19}, {}]
  1368. random_seed = self._generate_seed()
  1369. metrics = runtime.get_metrics_from_list(['ACCURACY', 'F1_MACRO'])
  1370. scoring_params = {'add_normalized_scores': 'false'}
  1371. scoring_random_seed = self._generate_seed()
  1372. data_params = {'shuffle': 'true', 'stratified': 'true', 'train_score_ratio': '0.59'}
  1373. data_random_seed = self._generate_seed()
  1374. problem = problem_module.get_problem(problem_path)
  1375. inputs = [dataset_module.get_dataset(dataset_path)]
  1376. with open(pipeline_path) as f:
  1377. pipeline = pipeline_module.Pipeline.from_yaml(f)
  1378. with open(data_pipeline_path) as f:
  1379. data_pipeline = pipeline_module.Pipeline.from_yaml(f)
  1380. with open(runtime.DEFAULT_SCORING_PIPELINE_PATH) as f:
  1381. scoring_pipeline = pipeline_module.Pipeline.from_yaml(f)
  1382. with utils.silence():
  1383. dummy_runtime_environment = pipeline_run_module.RuntimeEnvironment(worker_id='dummy worker id')
  1384. all_scores, all_results = runtime.evaluate(
  1385. pipeline, inputs, data_pipeline=data_pipeline, scoring_pipeline=scoring_pipeline,
  1386. problem_description=problem, data_params=data_params, metrics=metrics,
  1387. context=metadata_base.Context.TESTING, scoring_params=scoring_params,
  1388. hyperparams=hyperparams, random_seed=random_seed,
  1389. data_random_seed=data_random_seed, scoring_random_seed=scoring_random_seed,
  1390. runtime_environment=dummy_runtime_environment,
  1391. )
  1392. self.assertEqual(len(all_scores), 1)
  1393. scores = runtime.combine_folds(all_scores)
  1394. scores.to_csv(scores_path)
  1395. if any(result.has_error() for result in all_results):
  1396. self.fail([result.error for result in all_results if result.has_error()][0])
  1397. with open(pipeline_run_save_path, 'w') as f:
  1398. for i, pipeline_run in enumerate(all_results.pipeline_runs):
  1399. pipeline_run.to_yaml(f, appending=i>0)
  1400. self._cache_pipeline_for_rerun(pipeline_path)
  1401. self._cache_pipeline_for_rerun(data_pipeline_path)
  1402. pipeline_rerun_save_path = self._get_pipeline_rerun_save_path()
  1403. rescores_path = self._get_rescores_path()
  1404. rerun_arg = [
  1405. '',
  1406. '--pipelines-path',
  1407. self.test_dir,
  1408. 'runtime',
  1409. '--datasets',
  1410. TEST_DATA_DIR,
  1411. 'evaluate',
  1412. '--input-run',
  1413. pipeline_run_save_path,
  1414. '--output-run',
  1415. pipeline_rerun_save_path,
  1416. '--scores',
  1417. rescores_path,
  1418. ]
  1419. self._call_cli_runtime_without_fail(rerun_arg)
  1420. self._assert_valid_saved_pipeline_runs(pipeline_rerun_save_path)
  1421. self._assert_scores_equal(scores_path, rescores_path)
  1422. self._assert_scores_equal_pipeline_run(scores_path, pipeline_rerun_save_path)
  1423. self._assert_pipeline_runs_equal(pipeline_run_save_path, pipeline_rerun_save_path)
  1424. # See: https://gitlab.com/datadrivendiscovery/d3m/issues/406
  1425. # TODO: Test rerun validation code (that we throw exceptions on invalid pipeline runs).
  1426. # TODO: Test rerun with multiple inputs (non-standard pipeline).
  1427. # TODO: Test rerun without problem description.
  1428. # TODO: Test evaluate rerun with data split file.
  1429. def test_validate_gzipped_pipeline_run(self):
  1430. # First, generate the pipeline run file
  1431. pipeline_run_save_path = self._get_pipeline_run_save_path()
  1432. gzip_pipeline_run_save_path = '{pipeline_run_save_path}.gz'.format(pipeline_run_save_path=pipeline_run_save_path)
  1433. fitted_pipeline_path = os.path.join(self.test_dir, 'fitted-pipeline')
  1434. self._fit_iris_random_forest(
  1435. fitted_pipeline_path=fitted_pipeline_path, pipeline_run_save_path=pipeline_run_save_path
  1436. )
  1437. # Second, gzip the pipeline run file
  1438. with open(pipeline_run_save_path, 'rb') as file_in:
  1439. with gzip.open(gzip_pipeline_run_save_path, 'wb') as file_out:
  1440. shutil.copyfileobj(file_in, file_out)
  1441. os.remove(pipeline_run_save_path)
  1442. # Third, ensure that calling 'pipeline-run validate' on the gzipped pipeline run file is successful
  1443. arg = [
  1444. '',
  1445. 'pipeline-run',
  1446. 'validate',
  1447. gzip_pipeline_run_save_path,
  1448. ]
  1449. self._call_cli_runtime_without_fail(arg)
  1450. def test_help_message(self):
  1451. arg = [
  1452. '',
  1453. 'runtime',
  1454. 'fit',
  1455. '--version',
  1456. ]
  1457. with io.StringIO() as buffer:
  1458. with contextlib.redirect_stderr(buffer):
  1459. with self.assertRaises(SystemExit):
  1460. cli.main(arg)
  1461. help = buffer.getvalue()
  1462. self.assertTrue('usage: d3m runtime fit' in help, help)
  1463. if __name__ == '__main__':
  1464. unittest.main()

全栈的自动化机器学习系统,主要针对多变量时间序列数据的异常检测。TODS提供了详尽的用于构建基于机器学习的异常检测系统的模块,它们包括:数据处理(data processing),时间序列处理( time series processing),特征分析(feature analysis),检测算法(detection algorithms),和强化模块( reinforcement module)。这些模块所提供的功能包括常见的数据预处理、时间序列数据的平滑或变换,从时域或频域中抽取特征、多种多样的检测算