import%20marimo%0A%0A__generated_with%20%3D%20%220.23.16%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20METADATA%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22id%22%3A%20%22perceptron%22%2C%0A%20%20%20%20%20%20%20%20%22name%22%3A%20%22The%20Perceptron%22%2C%0A%20%20%20%20%20%20%20%20%22kind%22%3A%20%22concept%22%2C%0A%20%20%20%20%20%20%20%20%22difficulty%22%3A%20%22beginner%22%2C%0A%20%20%20%20%20%20%20%20%22status%22%3A%20%22complete%22%2C%0A%20%20%20%20%20%20%20%20%22topics%22%3A%20%5B%22neural_networks%22%2C%20%22perceptron%22%5D%2C%0A%20%20%20%20%20%20%20%20%22related_models%22%3A%20%5B%22logistic_regression%22%2C%20%22mlp%22%5D%2C%0A%20%20%20%20%20%20%20%20%22prerequisites%22%3A%20%5B%5D%2C%0A%20%20%20%20%7D%0A%20%20%20%20mo.md(f%22%23%20%7BMETADATA%5B'name'%5D%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20In%20one%20sentence%0A%0A%20%20%20%20A%20perceptron%20adds%20weighted%20inputs%20and%20turns%20the%20result%20into%20one%20of%20two%20decisions.%0A%0A%20%20%20%20%23%23%20Mental%20model%0A%0A%20%20%20%20Imagine%20a%20small%20weighted%20vote.%20Each%20feature%20votes%20for%20or%20against%20class%201%2C%20the%20bias%20shifts%20the%20threshold%2C%20and%20the%20sign%20of%20the%20final%20score%20decides%20the%20class.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Ctext%7Bscore%7D%20%3D%20w_1x_1%20%2B%20w_2x_2%20%2B%20b%0A%20%20%20%20%5Cqquad%0A%20%20%20%20%5Chat%20y%20%3D%20%5Cmathbb%7B1%7D%5B%5Ctext%7Bscore%7D%20%5Cgeq%200%5D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%23%23%20Why%20it%20matters%0A%0A%20%20%20%20The%20perceptron%20is%20the%20simplest%20useful%20neural%20unit.%20An%20MLP%20keeps%20the%20same%20weighted-sum%20idea%2C%20adds%20smooth%20nonlinear%20activations%2C%20and%20connects%20many%20units%20in%20layers.%0A%0A%20%20%20%20%23%23%20Experiment%0A%0A%20%20%20%20**Question%3A**%20how%20can%20a%20model%20learn%20a%20separating%20line%20by%20correcting%20only%20its%20mistakes%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20rng%20%3D%20np.random.default_rng(7)%0A%20%20%20%20class_zero%20%3D%20rng.normal(loc%3D(-1.25%2C%20-0.85)%2C%20scale%3D(0.55%2C%200.5)%2C%20size%3D(28%2C%202))%0A%20%20%20%20class_one%20%3D%20rng.normal(loc%3D(1.1%2C%200.95)%2C%20scale%3D(0.6%2C%200.55)%2C%20size%3D(28%2C%202))%0A%20%20%20%20features%20%3D%20np.vstack(%5Bclass_zero%2C%20class_one%5D)%0A%20%20%20%20targets%20%3D%20np.concatenate(%5Bnp.zeros(len(class_zero))%2C%20np.ones(len(class_one))%5D)%0A%0A%20%20%20%20initial_weights%20%3D%20np.array(%5B-0.35%2C%200.2%5D)%0A%20%20%20%20initial_bias%20%3D%200.15%0A%20%20%20%20weights%20%3D%20initial_weights.copy()%0A%20%20%20%20bias%20%3D%20initial_bias%0A%20%20%20%20learning_rate%20%3D%200.18%0A%20%20%20%20mistakes%20%3D%20%5B%5D%0A%20%20%20%20boundaries%20%3D%20%5B(weights.copy()%2C%20bias)%5D%0A%0A%20%20%20%20for%20_epoch%20in%20range(12)%3A%0A%20%20%20%20%20%20%20%20epoch_mistakes%20%3D%200%0A%20%20%20%20%20%20%20%20for%20point%2C%20target%20in%20zip(features%2C%20targets)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20prediction%20%3D%20float(point%20%40%20weights%20%2B%20bias%20%3E%3D%200)%0A%20%20%20%20%20%20%20%20%20%20%20%20correction%20%3D%20learning_rate%20*%20(target%20-%20prediction)%0A%20%20%20%20%20%20%20%20%20%20%20%20weights%20%2B%3D%20correction%20*%20point%0A%20%20%20%20%20%20%20%20%20%20%20%20bias%20%2B%3D%20correction%0A%20%20%20%20%20%20%20%20%20%20%20%20epoch_mistakes%20%2B%3D%20int(prediction%20!%3D%20target)%0A%20%20%20%20%20%20%20%20mistakes.append(epoch_mistakes)%0A%20%20%20%20%20%20%20%20boundaries.append((weights.copy()%2C%20bias))%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20bias%2C%0A%20%20%20%20%20%20%20%20class_one%2C%0A%20%20%20%20%20%20%20%20class_zero%2C%0A%20%20%20%20%20%20%20%20features%2C%0A%20%20%20%20%20%20%20%20initial_bias%2C%0A%20%20%20%20%20%20%20%20initial_weights%2C%0A%20%20%20%20%20%20%20%20mistakes%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20plt%2C%0A%20%20%20%20%20%20%20%20weights%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(%0A%20%20%20%20bias%2C%0A%20%20%20%20class_one%2C%0A%20%20%20%20class_zero%2C%0A%20%20%20%20features%2C%0A%20%20%20%20initial_bias%2C%0A%20%20%20%20initial_weights%2C%0A%20%20%20%20mistakes%2C%0A%20%20%20%20np%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20weights%2C%0A)%3A%0A%20%20%20%20from%20matplotlib.patches%20import%20Circle%2C%20FancyArrowPatch%2C%20FancyBboxPatch%0A%0A%20%20%20%20ink%20%3D%20%22%2317324D%22%0A%20%20%20%20blue%20%3D%20%22%234C78A8%22%0A%20%20%20%20coral%20%3D%20%22%23E76F51%22%0A%20%20%20%20gold%20%3D%20%22%23E9C46A%22%0A%20%20%20%20paper%20%3D%20%22%23FAF7F0%22%0A%20%20%20%20grid_color%20%3D%20%22%23DCE3E8%22%0A%0A%20%20%20%20fig%2C%20axes%20%3D%20plt.subplots(1%2C%203%2C%20figsize%3D(15%2C%204.7)%2C%20facecolor%3Dpaper)%0A%20%20%20%20for%20axis%20in%20axes%3A%0A%20%20%20%20%20%20%20%20axis.set_facecolor(paper)%0A%0A%20%20%20%20%23%201%20%E2%80%94%20anatomy%20of%20one%20perceptron%0A%20%20%20%20ax%20%3D%20axes%5B0%5D%0A%20%20%20%20ax.set(xlim%3D(0%2C%2010)%2C%20ylim%3D(0%2C%208))%0A%20%20%20%20ax.axis(%22off%22)%0A%20%20%20%20input_positions%20%3D%20%5B(1.2%2C%206.1%2C%20r%22%24x_1%24%22)%2C%20(1.2%2C%203.9%2C%20r%22%24x_2%24%22)%2C%20(1.2%2C%201.7%2C%20%22bias%22)%5D%0A%20%20%20%20for%20x_pos%2C%20y_pos%2C%20label%20in%20input_positions%3A%0A%20%20%20%20%20%20%20%20node%20%3D%20Circle((x_pos%2C%20y_pos)%2C%200.48%2C%20facecolor%3D%22white%22%2C%20edgecolor%3Dblue%2C%20linewidth%3D2)%0A%20%20%20%20%20%20%20%20ax.add_patch(node)%0A%20%20%20%20%20%20%20%20ax.text(x_pos%2C%20y_pos%2C%20label%2C%20ha%3D%22center%22%2C%20va%3D%22center%22%2C%20color%3Dink%2C%20fontsize%3D11)%0A%20%20%20%20%20%20%20%20arrow%20%3D%20FancyArrowPatch(%0A%20%20%20%20%20%20%20%20%20%20%20%20(x_pos%20%2B%200.52%2C%20y_pos)%2C%20(4.15%2C%204.0)%2C%20arrowstyle%3D%22-%7C%3E%22%2C%20mutation_scale%3D13%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20linewidth%3D1.7%2C%20color%3Dblue%2C%20connectionstyle%3D%22arc3%2Crad%3D0.0%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20ax.add_patch(arrow)%0A%20%20%20%20ax.text(2.8%2C%205.65%2C%20r%22%24w_1%24%22%2C%20color%3Dblue%2C%20fontsize%3D10)%0A%20%20%20%20ax.text(2.8%2C%203.85%2C%20r%22%24w_2%24%22%2C%20color%3Dblue%2C%20fontsize%3D10)%0A%20%20%20%20ax.text(2.8%2C%202.15%2C%20r%22%241%24%22%2C%20color%3Dblue%2C%20fontsize%3D10)%0A%20%20%20%20sum_box%20%3D%20FancyBboxPatch((4.15%2C%203.1)%2C%202.15%2C%201.8%2C%20boxstyle%3D%22round%2Cpad%3D0.2%22%2C%20facecolor%3Dgold%2C%20edgecolor%3Dink)%0A%20%20%20%20ax.add_patch(sum_box)%0A%20%20%20%20ax.text(5.23%2C%204.0%2C%20%22weighted%5Cnsum%22%2C%20ha%3D%22center%22%2C%20va%3D%22center%22%2C%20color%3Dink%2C%20fontsize%3D11)%0A%20%20%20%20ax.add_patch(FancyArrowPatch((6.35%2C%204.0)%2C%20(7.45%2C%204.0)%2C%20arrowstyle%3D%22-%7C%3E%22%2C%20mutation_scale%3D13%2C%20color%3Dink%2C%20linewidth%3D1.7))%0A%20%20%20%20output%20%3D%20Circle((8.35%2C%204.0)%2C%200.85%2C%20facecolor%3Dcoral%2C%20edgecolor%3Dink%2C%20linewidth%3D1.5)%0A%20%20%20%20ax.add_patch(output)%0A%20%20%20%20ax.text(8.35%2C%204.0%2C%20%220%20or%201%22%2C%20ha%3D%22center%22%2C%20va%3D%22center%22%2C%20color%3D%22white%22%2C%20fontsize%3D11%2C%20weight%3D%22bold%22)%0A%20%20%20%20ax.set_title(%221.%20A%20weighted%20vote%22%2C%20color%3Dink%2C%20fontsize%3D14%2C%20loc%3D%22left%22%2C%20pad%3D12)%0A%0A%20%20%20%20%23%202%20%E2%80%94%20the%20learned%20decision%20boundary%0A%20%20%20%20ax%20%3D%20axes%5B1%5D%0A%20%20%20%20x_min%2C%20x_max%20%3D%20features%5B%3A%2C%200%5D.min()%20-%200.8%2C%20features%5B%3A%2C%200%5D.max()%20%2B%200.8%0A%20%20%20%20y_min%2C%20y_max%20%3D%20features%5B%3A%2C%201%5D.min()%20-%200.8%2C%20features%5B%3A%2C%201%5D.max()%20%2B%200.8%0A%20%20%20%20xx%2C%20yy%20%3D%20np.meshgrid(np.linspace(x_min%2C%20x_max%2C%20250)%2C%20np.linspace(y_min%2C%20y_max%2C%20250))%0A%20%20%20%20region%20%3D%20(weights%5B0%5D%20*%20xx%20%2B%20weights%5B1%5D%20*%20yy%20%2B%20bias%20%3E%3D%200).astype(float)%0A%20%20%20%20ax.contourf(xx%2C%20yy%2C%20region%2C%20levels%3D%5B-0.5%2C%200.5%2C%201.5%5D%2C%20colors%3D%5B%22%23D9E8F5%22%2C%20%22%23F8D9CF%22%5D%2C%20alpha%3D0.72)%0A%20%20%20%20ax.scatter(class_zero%5B%3A%2C%200%5D%2C%20class_zero%5B%3A%2C%201%5D%2C%20s%3D42%2C%20color%3Dblue%2C%20edgecolor%3D%22white%22%2C%20linewidth%3D0.8%2C%20label%3D%22class%200%22)%0A%20%20%20%20ax.scatter(class_one%5B%3A%2C%200%5D%2C%20class_one%5B%3A%2C%201%5D%2C%20s%3D42%2C%20color%3Dcoral%2C%20edgecolor%3D%22white%22%2C%20linewidth%3D0.8%2C%20label%3D%22class%201%22)%0A%20%20%20%20line_x%20%3D%20np.array(%5Bx_min%2C%20x_max%5D)%0A%20%20%20%20initial_line%20%3D%20-(initial_weights%5B0%5D%20*%20line_x%20%2B%20initial_bias)%20%2F%20initial_weights%5B1%5D%0A%20%20%20%20learned_line%20%3D%20-(weights%5B0%5D%20*%20line_x%20%2B%20bias)%20%2F%20weights%5B1%5D%0A%20%20%20%20ax.plot(line_x%2C%20initial_line%2C%20linestyle%3D%22--%22%2C%20color%3D%22%238D99AE%22%2C%20linewidth%3D1.7%2C%20label%3D%22before%20learning%22)%0A%20%20%20%20ax.plot(line_x%2C%20learned_line%2C%20color%3Dink%2C%20linewidth%3D2.4%2C%20label%3D%22learned%20boundary%22)%0A%20%20%20%20ax.set(xlim%3D(x_min%2C%20x_max)%2C%20ylim%3D(y_min%2C%20y_max)%2C%20xlabel%3Dr%22feature%20%24x_1%24%22%2C%20ylabel%3Dr%22feature%20%24x_2%24%22)%0A%20%20%20%20ax.set_title(%222.%20One%20line%2C%20two%20regions%22%2C%20color%3Dink%2C%20fontsize%3D14%2C%20loc%3D%22left%22%2C%20pad%3D12)%0A%20%20%20%20ax.legend(frameon%3DFalse%2C%20fontsize%3D8%2C%20loc%3D%22lower%20right%22)%0A%0A%20%20%20%20%23%203%20%E2%80%94%20mistake-driven%20learning%0A%20%20%20%20ax%20%3D%20axes%5B2%5D%0A%20%20%20%20epochs%20%3D%20np.arange(1%2C%20len(mistakes)%20%2B%201)%0A%20%20%20%20ax.bar(epochs%2C%20mistakes%2C%20color%3D%5Bcoral%20if%20value%20else%20blue%20for%20value%20in%20mistakes%5D%2C%20width%3D0.72)%0A%20%20%20%20ax.plot(epochs%2C%20mistakes%2C%20color%3Dink%2C%20linewidth%3D1.2%2C%20marker%3D%22o%22%2C%20markersize%3D4)%0A%20%20%20%20ax.set(xlabel%3D%22training%20epoch%22%2C%20ylabel%3D%22classification%20mistakes%22%2C%20xticks%3Depochs)%0A%20%20%20%20ax.set_title(%223.%20Correct%20only%20the%20mistakes%22%2C%20color%3Dink%2C%20fontsize%3D14%2C%20loc%3D%22left%22%2C%20pad%3D12)%0A%20%20%20%20ax.text(%0A%20%20%20%20%20%20%20%200.5%2C%200.9%2C%20%22mistake%20%E2%86%92%20move%20the%20line%5Cncorrect%20%E2%86%92%20no%20update%22%2C%20transform%3Dax.transAxes%2C%0A%20%20%20%20%20%20%20%20ha%3D%22center%22%2C%20va%3D%22top%22%2C%20color%3Dink%2C%20fontsize%3D11%2C%0A%20%20%20%20%20%20%20%20bbox%3D%7B%22boxstyle%22%3A%20%22round%2Cpad%3D0.55%22%2C%20%22facecolor%22%3A%20%22white%22%2C%20%22edgecolor%22%3A%20grid_color%7D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20for%20axis%20in%20axes%5B1%3A%5D%3A%0A%20%20%20%20%20%20%20%20axis.grid(color%3Dgrid_color%2C%20linewidth%3D0.8%2C%20alpha%3D0.75)%0A%20%20%20%20%20%20%20%20axis.set_axisbelow(True)%0A%20%20%20%20%20%20%20%20axis.spines%5B%5B%22top%22%2C%20%22right%22%5D%5D.set_visible(False)%0A%20%20%20%20%20%20%20%20axis.spines%5B%5B%22left%22%2C%20%22bottom%22%5D%5D.set_color(%22%239AAAB5%22)%0A%20%20%20%20fig.suptitle(%22The%20perceptron%3A%20score%2C%20separate%2C%20correct%22%2C%20x%3D0.04%2C%20y%3D1.04%2C%20ha%3D%22left%22%2C%20color%3Dink%2C%20fontsize%3D18%2C%20weight%3D%22bold%22)%0A%20%20%20%20plt.tight_layout()%0A%20%20%20%20fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Common%20mistake%0A%0A%20%20%20%20Calling%20the%20perceptron%20a%20tiny%20probability%20model.%20Its%20hard%20threshold%20returns%20a%20class%2C%20not%20a%20calibrated%20probability%2C%20and%20one%20perceptron%20can%20draw%20only%20a%20straight%20decision%20boundary.%0A%0A%20%20%20%20%23%23%20Diagnosis%0A%0A%20%20%20%20Plot%20the%20data%20and%20the%20decision%20boundary.%20If%20no%20straight%20line%20can%20separate%20the%20classes%2C%20more%20training%20will%20not%20solve%20the%20representation%20problem.%0A%0A%20%20%20%20%23%23%20Practical%20rule%0A%0A%20%20%20%20Use%20the%20perceptron%20to%20understand%20weighted%20sums%2C%20thresholds%2C%20and%20mistake-driven%20learning.%20Move%20to%20layered%20networks%20when%20the%20useful%20boundary%20must%20be%20nonlinear.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
ccd9014459f5cc48e6783572a1020cbe