MilesCranmer commited on
Commit
ba6e296
1 Parent(s): ebce55f

Clean up and format example

Browse files
Files changed (1) hide show
  1. examples/pysr_demo.ipynb +87 -69
examples/pysr_demo.ipynb CHANGED
@@ -33,9 +33,7 @@
33
  "id": "COndi88gbDgO"
34
  },
35
  "source": [
36
- "**Run the following code if you need to install Julia**\n",
37
- "\n",
38
- "**(select all lines -> Option-/)**"
39
  ]
40
  },
41
  {
@@ -95,7 +93,14 @@
95
  },
96
  "outputs": [],
97
  "source": [
98
- "!pip install -Uq pysr pytorch_lightning"
 
 
 
 
 
 
 
99
  ]
100
  },
101
  {
@@ -106,13 +111,13 @@
106
  },
107
  "outputs": [],
108
  "source": [
109
- "# Required to get printing from Julia working in colab \n",
110
- "# (you don't need to normally do this)\n",
111
  "from julia import Julia\n",
 
112
  "julia = Julia(compiled_modules=False)\n",
113
  "from julia import Main\n",
114
  "from julia.tools import redirect_output_streams\n",
115
- "redirect_output_streams()"
 
116
  ]
117
  },
118
  {
@@ -123,7 +128,7 @@
123
  "source": [
124
  "Let's install the backend of PySR, and all required libraries. We will also precompile them so they are faster at startup.\n",
125
  "\n",
126
- "**This will take ~5 minutes.**"
127
  ]
128
  },
129
  {
@@ -139,7 +144,8 @@
139
  "outputs": [],
140
  "source": [
141
  "import pysr\n",
142
- "pysr.install()"
 
143
  ]
144
  },
145
  {
@@ -159,7 +165,7 @@
159
  "from torch.nn import functional as F\n",
160
  "from torch.utils.data import DataLoader, TensorDataset\n",
161
  "import pytorch_lightning as pl\n",
162
- "from sklearn.model_selection import train_test_split"
163
  ]
164
  },
165
  {
@@ -192,8 +198,8 @@
192
  "source": [
193
  "# Dataset\n",
194
  "np.random.seed(0)\n",
195
- "X = 2*np.random.randn(100, 5)\n",
196
- "y = 2.5382*np.cos(X[:, 3]) + X[:, 0]**2 - 2"
197
  ]
198
  },
199
  {
@@ -217,7 +223,7 @@
217
  " populations=30,\n",
218
  " procs=4,\n",
219
  " model_selection=\"best\",\n",
220
- ")"
221
  ]
222
  },
223
  {
@@ -246,12 +252,13 @@
246
  "source": [
247
  "# Learn equations\n",
248
  "model = PySRRegressor(\n",
249
- " niterations=30,\n",
250
- " binary_operators=[\"plus\", \"mult\"],\n",
251
- " unary_operators=[\"cos\", \"exp\", \"sin\"],\n",
252
- " **default_pysr_params)\n",
 
253
  "\n",
254
- "model.fit(X, y)"
255
  ]
256
  },
257
  {
@@ -275,7 +282,7 @@
275
  },
276
  "outputs": [],
277
  "source": [
278
- "model"
279
  ]
280
  },
281
  {
@@ -300,7 +307,7 @@
300
  },
301
  "outputs": [],
302
  "source": [
303
- "model.sympy()"
304
  ]
305
  },
306
  {
@@ -309,7 +316,7 @@
309
  "id": "EHIIPlmClltn"
310
  },
311
  "source": [
312
- "We can also view the SymPy of any other expression in the list, using the index of it in `model.equation`."
313
  ]
314
  },
315
  {
@@ -325,7 +332,7 @@
325
  },
326
  "outputs": [],
327
  "source": [
328
- "model.sympy(2)"
329
  ]
330
  },
331
  {
@@ -359,7 +366,7 @@
359
  },
360
  "outputs": [],
361
  "source": [
362
- "model.latex()"
363
  ]
364
  },
365
  {
@@ -389,7 +396,7 @@
389
  "ypredict_simpler = model.predict(X, 2)\n",
390
  "\n",
391
  "print(\"Default selection MSE:\", np.power(ypredict - y, 2).mean())\n",
392
- "print(\"Manual selection MSE for index 2:\", np.power(ypredict_simpler - y, 2).mean())"
393
  ]
394
  },
395
  {
@@ -423,7 +430,7 @@
423
  },
424
  "outputs": [],
425
  "source": [
426
- "y = X[:, 0]**4 - 2"
427
  ]
428
  },
429
  {
@@ -451,12 +458,13 @@
451
  "outputs": [],
452
  "source": [
453
  "model = PySRRegressor(\n",
454
- " niterations=5, populations=40,\n",
455
- " binary_operators=[\"plus\", \"mult\"],\n",
456
- " unary_operators=[\"cos\", \"exp\", \"sin\",\n",
457
- " \"quart(x) = x^4\"],\n",
458
- " extra_sympy_mappings={\"quart\": lambda x: x**4})\n",
459
- "model.fit(X, y) "
 
460
  ]
461
  },
462
  {
@@ -472,7 +480,7 @@
472
  },
473
  "outputs": [],
474
  "source": [
475
- "model.sympy()"
476
  ]
477
  },
478
  {
@@ -571,10 +579,10 @@
571
  "np.random.seed(0)\n",
572
  "N = 3000\n",
573
  "upper_sigma = 5\n",
574
- "X = 2*np.random.rand(N, 5)\n",
575
- "sigma = np.random.rand(N)*(5-0.1) + 0.1\n",
576
- "eps = sigma*np.random.randn(N)\n",
577
- "y = 5*np.cos(3.5*X[:, 0]) - 1.3 + eps"
578
  ]
579
  },
580
  {
@@ -601,7 +609,7 @@
601
  "source": [
602
  "plt.scatter(X[:, 0], y, alpha=0.2)\n",
603
  "plt.xlabel(\"$x_0$\")\n",
604
- "plt.ylabel(\"$y$\")"
605
  ]
606
  },
607
  {
@@ -621,7 +629,7 @@
621
  },
622
  "outputs": [],
623
  "source": [
624
- "weights = 1/sigma**2"
625
  ]
626
  },
627
  {
@@ -636,7 +644,7 @@
636
  },
637
  "outputs": [],
638
  "source": [
639
- "weights[:5]"
640
  ]
641
  },
642
  {
@@ -662,13 +670,13 @@
662
  "outputs": [],
663
  "source": [
664
  "model = PySRRegressor(\n",
665
- " loss='myloss(x, y, w) = w * abs(x - y)', # Custom loss function with weights.\n",
666
  " niterations=20,\n",
667
  " populations=20, # Use more populations\n",
668
  " binary_operators=[\"plus\", \"mult\"],\n",
669
- " unary_operators=[\"cos\"]\n",
670
  ")\n",
671
- "model.fit(X, y, weights=weights)"
672
  ]
673
  },
674
  {
@@ -692,7 +700,7 @@
692
  },
693
  "outputs": [],
694
  "source": [
695
- "model"
696
  ]
697
  },
698
  {
@@ -717,8 +725,10 @@
717
  },
718
  "outputs": [],
719
  "source": [
720
- "best_idx = model.equations_.query(f\"loss < {2 * model.equations_.loss.min()}\").score.idxmax()\n",
721
- "model.sympy(best_idx)"
 
 
722
  ]
723
  },
724
  {
@@ -753,7 +763,8 @@
753
  "outputs": [],
754
  "source": [
755
  "plt.scatter(X[:, 0], y, alpha=0.1)\n",
756
- "plt.scatter(X[:, 0], model.predict(X, index=best_idx));"
 
757
  ]
758
  },
759
  {
@@ -800,10 +811,10 @@
800
  "N = 100000\n",
801
  "Nt = 100\n",
802
  "X = 6 * np.random.rand(N, Nt, 5) - 3\n",
803
- "y_i = X[..., 0]**2 + 6*np.cos(2*X[..., 2])\n",
804
- "y = np.sum(y_i, axis=1)/y_i.shape[1]\n",
805
  "z = y**2\n",
806
- "X.shape, y.shape"
807
  ]
808
  },
809
  {
@@ -843,6 +854,7 @@
843
  "hidden = 128\n",
844
  "total_steps = 50000\n",
845
  "\n",
 
846
  "def mlp(size_in, size_out, act=nn.ReLU):\n",
847
  " return nn.Sequential(\n",
848
  " nn.Linear(size_in, hidden),\n",
@@ -851,13 +863,14 @@
851
  " act(),\n",
852
  " nn.Linear(hidden, hidden),\n",
853
  " act(),\n",
854
- " nn.Linear(hidden, size_out))\n",
 
855
  "\n",
856
  "\n",
857
  "class SumNet(pl.LightningModule):\n",
858
  " def __init__(self):\n",
859
  " super().__init__()\n",
860
- " \n",
861
  " ########################################################\n",
862
  " # The same inductive bias as above!\n",
863
  " self.g = mlp(5, 1)\n",
@@ -865,11 +878,12 @@
865
  "\n",
866
  " def forward(self, x):\n",
867
  " y_i = self.g(x)[:, :, 0]\n",
868
- " y = torch.sum(y_i, dim=1, keepdim=True)/y_i.shape[1]\n",
869
  " z = self.f(y)\n",
870
  " return z[:, 0]\n",
 
871
  " ########################################################\n",
872
- " \n",
873
  " # PyTorch Lightning bookkeeping:\n",
874
  " def training_step(self, batch, batch_idx):\n",
875
  " x, z = batch\n",
@@ -882,14 +896,18 @@
882
  "\n",
883
  " def configure_optimizers(self):\n",
884
  " self.trainer.reset_train_dataloader()\n",
885
- " # self.train_dataloader.loaders # access it here.\n",
886
  "\n",
887
  " optimizer = torch.optim.Adam(self.parameters(), lr=self.max_lr)\n",
888
- " scheduler = {'scheduler': torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=self.max_lr,\n",
889
- " total_steps=self.total_steps,\n",
890
- " final_div_factor=1e4),\n",
891
- " 'interval': 'step'}\n",
892
- " return [optimizer], [scheduler]"
 
 
 
 
 
893
  ]
894
  },
895
  {
@@ -924,7 +942,7 @@
924
  "train_set = TensorDataset(X_train, z_train)\n",
925
  "train = DataLoader(train_set, batch_size=128, num_workers=2)\n",
926
  "test_set = TensorDataset(X_test, z_test)\n",
927
- "test = DataLoader(test_set, batch_size=256, num_workers=2)"
928
  ]
929
  },
930
  {
@@ -960,7 +978,7 @@
960
  "pl.seed_everything(0)\n",
961
  "model = SumNet()\n",
962
  "model.total_steps = total_steps\n",
963
- "model.max_lr = 1e-2"
964
  ]
965
  },
966
  {
@@ -984,7 +1002,7 @@
984
  },
985
  "outputs": [],
986
  "source": [
987
- "trainer = pl.Trainer(max_steps=total_steps, gpus=1, benchmark=True)"
988
  ]
989
  },
990
  {
@@ -1033,7 +1051,7 @@
1033
  },
1034
  "outputs": [],
1035
  "source": [
1036
- "trainer.fit(model, train_dataloaders=train, val_dataloaders=test)"
1037
  ]
1038
  },
1039
  {
@@ -1064,10 +1082,10 @@
1064
  "\n",
1065
  "X_for_pysr = Xt[idx]\n",
1066
  "y_i_for_pysr = model.g(X_for_pysr)[:, :, 0]\n",
1067
- "y_for_pysr = torch.sum(y_i_for_pysr, dim=1)/y_i_for_pysr.shape[1]\n",
1068
- "z_for_pysr = zt[idx] #Use true values.\n",
1069
  "\n",
1070
- "X_for_pysr.shape, y_i_for_pysr.shape"
1071
  ]
1072
  },
1073
  {
@@ -1102,9 +1120,9 @@
1102
  "model = PySRRegressor(\n",
1103
  " niterations=20,\n",
1104
  " binary_operators=[\"plus\", \"sub\", \"mult\"],\n",
1105
- " unary_operators=[\"cos\", \"square\", \"neg\"]\n",
1106
  ")\n",
1107
- "model.fit(X=tmpX[idx2], y=tmpy[idx2])"
1108
  ]
1109
  },
1110
  {
@@ -1135,7 +1153,7 @@
1135
  },
1136
  "outputs": [],
1137
  "source": [
1138
- "model"
1139
  ]
1140
  },
1141
  {
 
33
  "id": "COndi88gbDgO"
34
  },
35
  "source": [
36
+ "**Run the following code to install Julia**"
 
 
37
  ]
38
  },
39
  {
 
93
  },
94
  "outputs": [],
95
  "source": [
96
+ "%pip install -Uq pysr pytorch_lightning"
97
+ ]
98
+ },
99
+ {
100
+ "cell_type": "markdown",
101
+ "metadata": {},
102
+ "source": [
103
+ "The following step is not normally required, but colab's printing is non-standard and we need to manually set it up PyJulia:\n"
104
  ]
105
  },
106
  {
 
111
  },
112
  "outputs": [],
113
  "source": [
 
 
114
  "from julia import Julia\n",
115
+ "\n",
116
  "julia = Julia(compiled_modules=False)\n",
117
  "from julia import Main\n",
118
  "from julia.tools import redirect_output_streams\n",
119
+ "\n",
120
+ "redirect_output_streams()\n"
121
  ]
122
  },
123
  {
 
128
  "source": [
129
  "Let's install the backend of PySR, and all required libraries. We will also precompile them so they are faster at startup.\n",
130
  "\n",
131
+ "**(This may take some time)**"
132
  ]
133
  },
134
  {
 
144
  "outputs": [],
145
  "source": [
146
  "import pysr\n",
147
+ "\n",
148
+ "pysr.install()\n"
149
  ]
150
  },
151
  {
 
165
  "from torch.nn import functional as F\n",
166
  "from torch.utils.data import DataLoader, TensorDataset\n",
167
  "import pytorch_lightning as pl\n",
168
+ "from sklearn.model_selection import train_test_split\n"
169
  ]
170
  },
171
  {
 
198
  "source": [
199
  "# Dataset\n",
200
  "np.random.seed(0)\n",
201
+ "X = 2 * np.random.randn(100, 5)\n",
202
+ "y = 2.5382 * np.cos(X[:, 3]) + X[:, 0] ** 2 - 2\n"
203
  ]
204
  },
205
  {
 
223
  " populations=30,\n",
224
  " procs=4,\n",
225
  " model_selection=\"best\",\n",
226
+ ")\n"
227
  ]
228
  },
229
  {
 
252
  "source": [
253
  "# Learn equations\n",
254
  "model = PySRRegressor(\n",
255
+ " niterations=30,\n",
256
+ " binary_operators=[\"plus\", \"mult\"],\n",
257
+ " unary_operators=[\"cos\", \"exp\", \"sin\"],\n",
258
+ " **default_pysr_params\n",
259
+ ")\n",
260
  "\n",
261
+ "model.fit(X, y)\n"
262
  ]
263
  },
264
  {
 
282
  },
283
  "outputs": [],
284
  "source": [
285
+ "model\n"
286
  ]
287
  },
288
  {
 
307
  },
308
  "outputs": [],
309
  "source": [
310
+ "model.sympy()\n"
311
  ]
312
  },
313
  {
 
316
  "id": "EHIIPlmClltn"
317
  },
318
  "source": [
319
+ "We can also view the SymPy of any other expression in the list, using the index of it in `model.equations_`."
320
  ]
321
  },
322
  {
 
332
  },
333
  "outputs": [],
334
  "source": [
335
+ "model.sympy(2)\n"
336
  ]
337
  },
338
  {
 
366
  },
367
  "outputs": [],
368
  "source": [
369
+ "model.latex()\n"
370
  ]
371
  },
372
  {
 
396
  "ypredict_simpler = model.predict(X, 2)\n",
397
  "\n",
398
  "print(\"Default selection MSE:\", np.power(ypredict - y, 2).mean())\n",
399
+ "print(\"Manual selection MSE for index 2:\", np.power(ypredict_simpler - y, 2).mean())\n"
400
  ]
401
  },
402
  {
 
430
  },
431
  "outputs": [],
432
  "source": [
433
+ "y = X[:, 0] ** 4 - 2\n"
434
  ]
435
  },
436
  {
 
458
  "outputs": [],
459
  "source": [
460
  "model = PySRRegressor(\n",
461
+ " niterations=5,\n",
462
+ " populations=40,\n",
463
+ " binary_operators=[\"plus\", \"mult\"],\n",
464
+ " unary_operators=[\"cos\", \"exp\", \"sin\", \"quart(x) = x^4\"],\n",
465
+ " extra_sympy_mappings={\"quart\": lambda x: x**4},\n",
466
+ ")\n",
467
+ "model.fit(X, y)\n"
468
  ]
469
  },
470
  {
 
480
  },
481
  "outputs": [],
482
  "source": [
483
+ "model.sympy()\n"
484
  ]
485
  },
486
  {
 
579
  "np.random.seed(0)\n",
580
  "N = 3000\n",
581
  "upper_sigma = 5\n",
582
+ "X = 2 * np.random.rand(N, 5)\n",
583
+ "sigma = np.random.rand(N) * (5 - 0.1) + 0.1\n",
584
+ "eps = sigma * np.random.randn(N)\n",
585
+ "y = 5 * np.cos(3.5 * X[:, 0]) - 1.3 + eps\n"
586
  ]
587
  },
588
  {
 
609
  "source": [
610
  "plt.scatter(X[:, 0], y, alpha=0.2)\n",
611
  "plt.xlabel(\"$x_0$\")\n",
612
+ "plt.ylabel(\"$y$\")\n"
613
  ]
614
  },
615
  {
 
629
  },
630
  "outputs": [],
631
  "source": [
632
+ "weights = 1 / sigma[:, None] ** 2\n"
633
  ]
634
  },
635
  {
 
644
  },
645
  "outputs": [],
646
  "source": [
647
+ "weights[:5, 0]\n"
648
  ]
649
  },
650
  {
 
670
  "outputs": [],
671
  "source": [
672
  "model = PySRRegressor(\n",
673
+ " loss=\"myloss(x, y, w) = w * abs(x - y)\", # Custom loss function with weights.\n",
674
  " niterations=20,\n",
675
  " populations=20, # Use more populations\n",
676
  " binary_operators=[\"plus\", \"mult\"],\n",
677
+ " unary_operators=[\"cos\"],\n",
678
  ")\n",
679
+ "model.fit(X, y, weights=weights)\n"
680
  ]
681
  },
682
  {
 
700
  },
701
  "outputs": [],
702
  "source": [
703
+ "model\n"
704
  ]
705
  },
706
  {
 
725
  },
726
  "outputs": [],
727
  "source": [
728
+ "best_idx = model.equations_.query(\n",
729
+ " f\"loss < {2 * model.equations_.loss.min()}\"\n",
730
+ ").score.idxmax()\n",
731
+ "model.sympy(best_idx)\n"
732
  ]
733
  },
734
  {
 
763
  "outputs": [],
764
  "source": [
765
  "plt.scatter(X[:, 0], y, alpha=0.1)\n",
766
+ "y_prediction = model.predict(X, index=best_idx)\n",
767
+ "plt.scatter(X[:, 0], y_prediction)\n"
768
  ]
769
  },
770
  {
 
811
  "N = 100000\n",
812
  "Nt = 100\n",
813
  "X = 6 * np.random.rand(N, Nt, 5) - 3\n",
814
+ "y_i = X[..., 0] ** 2 + 6 * np.cos(2 * X[..., 2])\n",
815
+ "y = np.sum(y_i, axis=1) / y_i.shape[1]\n",
816
  "z = y**2\n",
817
+ "X.shape, y.shape\n"
818
  ]
819
  },
820
  {
 
854
  "hidden = 128\n",
855
  "total_steps = 50000\n",
856
  "\n",
857
+ "\n",
858
  "def mlp(size_in, size_out, act=nn.ReLU):\n",
859
  " return nn.Sequential(\n",
860
  " nn.Linear(size_in, hidden),\n",
 
863
  " act(),\n",
864
  " nn.Linear(hidden, hidden),\n",
865
  " act(),\n",
866
+ " nn.Linear(hidden, size_out),\n",
867
+ " )\n",
868
  "\n",
869
  "\n",
870
  "class SumNet(pl.LightningModule):\n",
871
  " def __init__(self):\n",
872
  " super().__init__()\n",
873
+ "\n",
874
  " ########################################################\n",
875
  " # The same inductive bias as above!\n",
876
  " self.g = mlp(5, 1)\n",
 
878
  "\n",
879
  " def forward(self, x):\n",
880
  " y_i = self.g(x)[:, :, 0]\n",
881
+ " y = torch.sum(y_i, dim=1, keepdim=True) / y_i.shape[1]\n",
882
  " z = self.f(y)\n",
883
  " return z[:, 0]\n",
884
+ "\n",
885
  " ########################################################\n",
886
+ "\n",
887
  " # PyTorch Lightning bookkeeping:\n",
888
  " def training_step(self, batch, batch_idx):\n",
889
  " x, z = batch\n",
 
896
  "\n",
897
  " def configure_optimizers(self):\n",
898
  " self.trainer.reset_train_dataloader()\n",
 
899
  "\n",
900
  " optimizer = torch.optim.Adam(self.parameters(), lr=self.max_lr)\n",
901
+ " scheduler = {\n",
902
+ " \"scheduler\": torch.optim.lr_scheduler.OneCycleLR(\n",
903
+ " optimizer,\n",
904
+ " max_lr=self.max_lr,\n",
905
+ " total_steps=self.total_steps,\n",
906
+ " final_div_factor=1e4,\n",
907
+ " ),\n",
908
+ " \"interval\": \"step\",\n",
909
+ " }\n",
910
+ " return [optimizer], [scheduler]\n"
911
  ]
912
  },
913
  {
 
942
  "train_set = TensorDataset(X_train, z_train)\n",
943
  "train = DataLoader(train_set, batch_size=128, num_workers=2)\n",
944
  "test_set = TensorDataset(X_test, z_test)\n",
945
+ "test = DataLoader(test_set, batch_size=256, num_workers=2)\n"
946
  ]
947
  },
948
  {
 
978
  "pl.seed_everything(0)\n",
979
  "model = SumNet()\n",
980
  "model.total_steps = total_steps\n",
981
+ "model.max_lr = 1e-2\n"
982
  ]
983
  },
984
  {
 
1002
  },
1003
  "outputs": [],
1004
  "source": [
1005
+ "trainer = pl.Trainer(max_steps=total_steps, gpus=1, benchmark=True)\n"
1006
  ]
1007
  },
1008
  {
 
1051
  },
1052
  "outputs": [],
1053
  "source": [
1054
+ "trainer.fit(model, train_dataloaders=train, val_dataloaders=test)\n"
1055
  ]
1056
  },
1057
  {
 
1082
  "\n",
1083
  "X_for_pysr = Xt[idx]\n",
1084
  "y_i_for_pysr = model.g(X_for_pysr)[:, :, 0]\n",
1085
+ "y_for_pysr = torch.sum(y_i_for_pysr, dim=1) / y_i_for_pysr.shape[1]\n",
1086
+ "z_for_pysr = zt[idx] # Use true values.\n",
1087
  "\n",
1088
+ "X_for_pysr.shape, y_i_for_pysr.shape\n"
1089
  ]
1090
  },
1091
  {
 
1120
  "model = PySRRegressor(\n",
1121
  " niterations=20,\n",
1122
  " binary_operators=[\"plus\", \"sub\", \"mult\"],\n",
1123
+ " unary_operators=[\"cos\", \"square\", \"neg\"],\n",
1124
  ")\n",
1125
+ "model.fit(X=tmpX[idx2], y=tmpy[idx2])\n"
1126
  ]
1127
  },
1128
  {
 
1153
  },
1154
  "outputs": [],
1155
  "source": [
1156
+ "model\n"
1157
  ]
1158
  },
1159
  {