mirror of
https://github.com/socathie/circomlib-ml.git
synced 2026-01-07 21:24:01 -05:00
* feat: `Poly` renamed to `ZeLU` with scaling implemented * fix: assertion in `ZeLU` * feat: `AveragePooling2D` with scaling * feat: `BatchNorm` with scaling * feat: `Conv1D` with scaling * feat: `Conv2D` with scaling * feat: `Dense` with scaling * fix: assertion in `Dense` * feat: `GlobalAveragePooling2D` with scaling * feat: input-only `ArgMax` * feat: input-only `Flatten2D` * feat: input-only `GlobalMaxPooling2D` * feat: input-only `MaxPooling2D` * feat: input-only `ReLU` * test: precision up to 36 decimals * chore: clean up * test: model1 with 36 decimals * fix: ReLU should use `p//2` as threshold * test: clean up * test: mnist model with 18 decimals * build: Update package.json version to 2.0.0 * chore: Update README with warning message
553 lines
18 KiB
Plaintext
553 lines
18 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"p = 21888242871839275222246405745257275088548364400416034343698204186575808495617"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from tensorflow.keras.layers import Input, MaxPooling2D\n",
|
|
"from tensorflow.keras import Model\n",
|
|
"import numpy as np"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"inputs = Input(shape=(5,5,3))\n",
|
|
"x = MaxPooling2D(pool_size=2)(inputs)\n",
|
|
"model = Model(inputs, x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Model: \"model\"\n",
|
|
"_________________________________________________________________\n",
|
|
" Layer (type) Output Shape Param # \n",
|
|
"=================================================================\n",
|
|
" input_1 (InputLayer) [(None, 5, 5, 3)] 0 \n",
|
|
" \n",
|
|
" max_pooling2d (MaxPooling2D (None, 2, 2, 3) 0 \n",
|
|
" ) \n",
|
|
" \n",
|
|
"=================================================================\n",
|
|
"Total params: 0\n",
|
|
"Trainable params: 0\n",
|
|
"Non-trainable params: 0\n",
|
|
"_________________________________________________________________\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"model.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"array([[[[0.44076837, 0.4645178 , 0.88532658],\n",
|
|
" [0.98571178, 0.36091035, 0.37878294],\n",
|
|
" [0.09039054, 0.43555648, 0.70723494],\n",
|
|
" [0.75087575, 0.46161156, 0.27621923],\n",
|
|
" [0.3658674 , 0.76096207, 0.85368763]],\n",
|
|
"\n",
|
|
" [[0.53353854, 0.18599507, 0.85547589],\n",
|
|
" [0.83705565, 0.3310797 , 0.42121576],\n",
|
|
" [0.97948862, 0.58870474, 0.022469 ],\n",
|
|
" [0.40446888, 0.15924946, 0.39474075],\n",
|
|
" [0.39336331, 0.83113873, 0.58711273]],\n",
|
|
"\n",
|
|
" [[0.00324599, 0.84351736, 0.65574229],\n",
|
|
" [0.00423293, 0.09477659, 0.85111496],\n",
|
|
" [0.84792575, 0.32417744, 0.52031854],\n",
|
|
" [0.78577668, 0.63963473, 0.66767045],\n",
|
|
" [0.6838523 , 0.40963437, 0.296101 ]],\n",
|
|
"\n",
|
|
" [[0.25513283, 0.21434056, 0.139309 ],\n",
|
|
" [0.61281984, 0.77039643, 0.3830965 ],\n",
|
|
" [0.52747206, 0.60847264, 0.60792949],\n",
|
|
" [0.63030064, 0.5966706 , 0.05825615],\n",
|
|
" [0.78633397, 0.4404418 , 0.30296519]],\n",
|
|
"\n",
|
|
" [[0.4233433 , 0.2882031 , 0.85232675],\n",
|
|
" [0.60716483, 0.95202431, 0.39592074],\n",
|
|
" [0.55245804, 0.00922525, 0.50775513],\n",
|
|
" [0.65796373, 0.01939091, 0.10486254],\n",
|
|
" [0.06172721, 0.64735306, 0.22485494]]]])"
|
|
]
|
|
},
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"X = np.random.rand(1,5,5,3)\n",
|
|
"X"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"1/1 [==============================] - 0s 29ms/step\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"2023-10-23 21:44:15.505331: W tensorflow/tsl/platform/profile_utils/cpu_utils.cc:128] Failed to get CPU frequency: 0 Hz\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"array([[[[0.98571175, 0.4645178 , 0.88532656],\n",
|
|
" [0.9794886 , 0.58870476, 0.7072349 ]],\n",
|
|
"\n",
|
|
" [[0.61281985, 0.84351736, 0.851115 ],\n",
|
|
" [0.8479257 , 0.6396347 , 0.6676704 ]]]], dtype=float32)"
|
|
]
|
|
},
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"y = model.predict(X)\n",
|
|
"y"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"X_in = [[[int(X[0][i][j][k]*1e36) for k in range(3)] for j in range(5)] for i in range(5)]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def MaxPooling2DInt(nRows, nCols, nChannels, poolSize, strides, input):\n",
|
|
" Input = [[[str(input[i][j][k] % p) for k in range(nChannels)] for j in range(nCols)] for i in range(nRows)]\n",
|
|
" out = [[[str(max(input[i*strides + x][j*strides + y][k] for x in range(poolSize) for y in range(poolSize)) % p) for k in range(nChannels)] for j in range((nCols - poolSize) // strides + 1)] for i in range((nRows - poolSize) // strides + 1)]\n",
|
|
" return Input, out"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[[['985711776216457240221750775571808256',\n",
|
|
" '464517795839652376609037137683152896',\n",
|
|
" '885326582306963556558255153072832512'],\n",
|
|
" ['979488619923621857462245439242764288',\n",
|
|
" '588704741840418336217153490575687680',\n",
|
|
" '707234940167889112717525758819434496']],\n",
|
|
" [['612819836329411865644509177766215680',\n",
|
|
" '843517362609097245279278883187720192',\n",
|
|
" '851114962252709222552843081379479552'],\n",
|
|
" ['847925751912674500468804749306626048',\n",
|
|
" '639634733901388366288661852182282240',\n",
|
|
" '667670451847854954465177838892875776']]]"
|
|
]
|
|
},
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"X_in, out = MaxPooling2DInt(5, 5, 3, 2, 2, X_in)\n",
|
|
"out"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"in_json = {\n",
|
|
" \"in\": X_in,\n",
|
|
" \"out\": out\n",
|
|
"}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import json"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"with open(\"maxPooling2D_input.json\", \"w\") as f:\n",
|
|
" json.dump(in_json, f)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"inputs = Input(shape=(10,10,3))\n",
|
|
"x = MaxPooling2D(pool_size=2, strides=3)(inputs)\n",
|
|
"model = Model(inputs, x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Model: \"model_1\"\n",
|
|
"_________________________________________________________________\n",
|
|
" Layer (type) Output Shape Param # \n",
|
|
"=================================================================\n",
|
|
" input_2 (InputLayer) [(None, 10, 10, 3)] 0 \n",
|
|
" \n",
|
|
" max_pooling2d_1 (MaxPooling (None, 3, 3, 3) 0 \n",
|
|
" 2D) \n",
|
|
" \n",
|
|
"=================================================================\n",
|
|
"Total params: 0\n",
|
|
"Trainable params: 0\n",
|
|
"Non-trainable params: 0\n",
|
|
"_________________________________________________________________\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"model.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"array([[[[0.9790171 , 0.49837833, 0.23951505],\n",
|
|
" [0.85478487, 0.10183569, 0.57204256],\n",
|
|
" [0.12906496, 0.12259599, 0.61308313],\n",
|
|
" [0.68956844, 0.27468499, 0.73800473],\n",
|
|
" [0.97031435, 0.65275678, 0.57039273],\n",
|
|
" [0.48422669, 0.62184484, 0.12322611],\n",
|
|
" [0.45518299, 0.70342415, 0.77375435],\n",
|
|
" [0.1334539 , 0.78283045, 0.48137776],\n",
|
|
" [0.97002355, 0.70346344, 0.04099013],\n",
|
|
" [0.34556716, 0.30939804, 0.12870492]],\n",
|
|
"\n",
|
|
" [[0.55049916, 0.15188193, 0.514953 ],\n",
|
|
" [0.07403779, 0.906408 , 0.20947497],\n",
|
|
" [0.57003003, 0.93417836, 0.09306473],\n",
|
|
" [0.17917856, 0.67291796, 0.4088607 ],\n",
|
|
" [0.10408118, 0.55822855, 0.62854813],\n",
|
|
" [0.20925919, 0.68269696, 0.60650138],\n",
|
|
" [0.94999975, 0.12429107, 0.41003125],\n",
|
|
" [0.16150869, 0.35470003, 0.54676562],\n",
|
|
" [0.14792857, 0.78346031, 0.25734593],\n",
|
|
" [0.89233997, 0.28742825, 0.13791151]],\n",
|
|
"\n",
|
|
" [[0.79274313, 0.99061523, 0.68711779],\n",
|
|
" [0.57504418, 0.32618382, 0.16722838],\n",
|
|
" [0.09678065, 0.3591776 , 0.62750915],\n",
|
|
" [0.68795545, 0.01609884, 0.97099217],\n",
|
|
" [0.23381142, 0.84909675, 0.88405792],\n",
|
|
" [0.73191384, 0.98947014, 0.52221912],\n",
|
|
" [0.89714287, 0.03510341, 0.20639419],\n",
|
|
" [0.38323203, 0.16914071, 0.41209687],\n",
|
|
" [0.13122496, 0.53340704, 0.60455243],\n",
|
|
" [0.71565705, 0.67219914, 0.92696397]],\n",
|
|
"\n",
|
|
" [[0.55416618, 0.74973965, 0.59748271],\n",
|
|
" [0.10440772, 0.32236564, 0.92791157],\n",
|
|
" [0.41841302, 0.27220821, 0.61662229],\n",
|
|
" [0.7338952 , 0.37152599, 0.31517472],\n",
|
|
" [0.20252929, 0.67581558, 0.34286098],\n",
|
|
" [0.01504774, 0.04681701, 0.14321044],\n",
|
|
" [0.3653292 , 0.25028834, 0.33848712],\n",
|
|
" [0.29191385, 0.34659568, 0.98273622],\n",
|
|
" [0.50778695, 0.7199723 , 0.05608854],\n",
|
|
" [0.72340647, 0.76685192, 0.37388969]],\n",
|
|
"\n",
|
|
" [[0.52331559, 0.62356855, 0.26878584],\n",
|
|
" [0.15838795, 0.90184899, 0.23912789],\n",
|
|
" [0.41272637, 0.7610872 , 0.12672697],\n",
|
|
" [0.70626725, 0.98208145, 0.60164227],\n",
|
|
" [0.35664872, 0.41128872, 0.09382977],\n",
|
|
" [0.70544007, 0.82240552, 0.90325495],\n",
|
|
" [0.72007321, 0.24536308, 0.60690892],\n",
|
|
" [0.48655372, 0.46328671, 0.60648263],\n",
|
|
" [0.18854088, 0.45044603, 0.69043293],\n",
|
|
" [0.1217475 , 0.655353 , 0.87733639]],\n",
|
|
"\n",
|
|
" [[0.02353603, 0.18097275, 0.19114613],\n",
|
|
" [0.72104431, 0.65310589, 0.48925075],\n",
|
|
" [0.26145721, 0.95118427, 0.64482692],\n",
|
|
" [0.08753618, 0.2596348 , 0.53771786],\n",
|
|
" [0.07314132, 0.06774864, 0.34392025],\n",
|
|
" [0.16282229, 0.95993633, 0.79667906],\n",
|
|
" [0.74674627, 0.53217006, 0.65900082],\n",
|
|
" [0.87522692, 0.13258819, 0.16230994],\n",
|
|
" [0.44525752, 0.67365898, 0.51766928],\n",
|
|
" [0.72182701, 0.43780393, 0.98069118]],\n",
|
|
"\n",
|
|
" [[0.25691084, 0.11661927, 0.67618617],\n",
|
|
" [0.66069801, 0.9045992 , 0.86337172],\n",
|
|
" [0.08042041, 0.78517436, 0.69269604],\n",
|
|
" [0.44734739, 0.30140176, 0.18295808],\n",
|
|
" [0.07556447, 0.4891693 , 0.20302939],\n",
|
|
" [0.22243138, 0.65584446, 0.56134481],\n",
|
|
" [0.91535994, 0.429726 , 0.89466843],\n",
|
|
" [0.25180203, 0.12145168, 0.26456649],\n",
|
|
" [0.56398398, 0.18346371, 0.034341 ],\n",
|
|
" [0.37802503, 0.22614985, 0.85292929]],\n",
|
|
"\n",
|
|
" [[0.19171201, 0.46156136, 0.78027617],\n",
|
|
" [0.1697258 , 0.36865057, 0.30921552],\n",
|
|
" [0.63491691, 0.76223827, 0.91491496],\n",
|
|
" [0.68871028, 0.86998105, 0.79183476],\n",
|
|
" [0.50452778, 0.27036477, 0.19829515],\n",
|
|
" [0.82527008, 0.35258264, 0.42346427],\n",
|
|
" [0.73552096, 0.76506646, 0.50324396],\n",
|
|
" [0.08392757, 0.11886597, 0.31341576],\n",
|
|
" [0.42816313, 0.8535268 , 0.59585608],\n",
|
|
" [0.00429868, 0.66229572, 0.07715835]],\n",
|
|
"\n",
|
|
" [[0.95901268, 0.85618315, 0.47768876],\n",
|
|
" [0.66614175, 0.08345771, 0.80790147],\n",
|
|
" [0.29208239, 0.4360204 , 0.18332789],\n",
|
|
" [0.28169483, 0.63096452, 0.96729756],\n",
|
|
" [0.07859661, 0.92728092, 0.80810303],\n",
|
|
" [0.97020859, 0.87780948, 0.83993202],\n",
|
|
" [0.68006058, 0.68787335, 0.70198168],\n",
|
|
" [0.31865081, 0.97290491, 0.13625889],\n",
|
|
" [0.80537841, 0.03953296, 0.16870381],\n",
|
|
" [0.90864186, 0.54762421, 0.71436361]],\n",
|
|
"\n",
|
|
" [[0.19054836, 0.34380661, 0.68153459],\n",
|
|
" [0.16505021, 0.0412163 , 0.36928843],\n",
|
|
" [0.38454084, 0.30131942, 0.29021317],\n",
|
|
" [0.74076099, 0.97099106, 0.30053946],\n",
|
|
" [0.62869618, 0.12455381, 0.62562719],\n",
|
|
" [0.91303674, 0.39900546, 0.92873058],\n",
|
|
" [0.7949276 , 0.00620029, 0.17023317],\n",
|
|
" [0.40570501, 0.1780136 , 0.19150324],\n",
|
|
" [0.56676977, 0.84413934, 0.73247166],\n",
|
|
" [0.0028076 , 0.26181396, 0.70691029]]]])"
|
|
]
|
|
},
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"X = np.random.rand(1,10,10,3)\n",
|
|
"X"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"1/1 [==============================] - 0s 21ms/step\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"array([[[[0.9790171 , 0.906408 , 0.5720426 ],\n",
|
|
" [0.9703143 , 0.67291796, 0.73800474],\n",
|
|
" [0.94999975, 0.7828305 , 0.77375436]],\n",
|
|
"\n",
|
|
" [[0.5541662 , 0.901849 , 0.9279116 ],\n",
|
|
" [0.7338952 , 0.9820815 , 0.60164225],\n",
|
|
" [0.7200732 , 0.46328673, 0.98273623]],\n",
|
|
"\n",
|
|
" [[0.660698 , 0.9045992 , 0.86337173],\n",
|
|
" [0.6887103 , 0.86998105, 0.7918348 ],\n",
|
|
" [0.9153599 , 0.76506644, 0.89466846]]]], dtype=float32)"
|
|
]
|
|
},
|
|
"execution_count": 16,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"y = model.predict(X)\n",
|
|
"y"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"X_in = [[[int(X[0][i][j][k]*1e36) for k in range(3)] for j in range(10)] for i in range(10)]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[[['979017099491110018942067312821272576',\n",
|
|
" '906408000806632452114797174150135808',\n",
|
|
" '572042560577051270101001688850628608'],\n",
|
|
" ['970314350513558277989324779994218496',\n",
|
|
" '672917960272193945175567190387064832',\n",
|
|
" '738004729474624730341896972922781696'],\n",
|
|
" ['949999745668024165489517038806237184',\n",
|
|
" '782830451141896167400921576545189888',\n",
|
|
" '773754352982266439136539456512720896']],\n",
|
|
" [['554166181126147404440246990770536448',\n",
|
|
" '901848991352918850169033731149398016',\n",
|
|
" '927911571088135929200009259356520448'],\n",
|
|
" ['733895199634136636354978553303924736',\n",
|
|
" '982081449688638090663868389740511232',\n",
|
|
" '601642265832659125360941789945528320'],\n",
|
|
" ['720073208604618054954869080641765376',\n",
|
|
" '463286712794445136678401315688153088',\n",
|
|
" '982736221843810664156369288039497728']],\n",
|
|
" [['660698008644203700473074429819092992',\n",
|
|
" '904599195577579897660922571020828672',\n",
|
|
" '863371715944324158495051960144625664'],\n",
|
|
" ['688710284469165685404738243641999360',\n",
|
|
" '869981053223066390571414093008207872',\n",
|
|
" '791834758925232104719097862035603456'],\n",
|
|
" ['915359938539886757509738228069957632',\n",
|
|
" '765066456516048413755703502695301120',\n",
|
|
" '894668431976368139307673421153828864']]]"
|
|
]
|
|
},
|
|
"execution_count": 18,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"X_in, out = MaxPooling2DInt(10, 10, 3, 2, 3, X_in)\n",
|
|
"out"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"in_json = {\n",
|
|
" \"in\": X_in,\n",
|
|
" \"out\": out\n",
|
|
"}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"with open(\"maxPooling2D_stride_input.json\", \"w\") as f:\n",
|
|
" json.dump(in_json, f)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "sklearn",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.9.16"
|
|
},
|
|
"orig_nbformat": 4
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2
|
|
}
|