import%20marimo%0A%0A__generated_with%20%3D%20%220.25.0%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%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%20The%20idea%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%20A%20line%20separates%20two%20decisions%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%20this%20simple%20rule%20matters%0A%0A%20%20%20%20The%20perceptron%20makes%20the%20relationship%20between%20features%2C%20weights%2C%20a%20boundary%2C%20and%20a%20final%20decision%20visible%20in%20its%20simplest%20form.%0A%0A%20%20%20%20%23%23%20What%20we%20will%20build%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_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%201.%20Compute%20a%20score%0A%0A%20%20%20%20For%20an%20input%20vector%20%24%5Cmathbf%20x%3D(x_1%2C%5Cldots%2Cx_d)%24%2C%20the%20perceptron%20stores%20one%20weight%20per%20feature%20and%20one%20bias%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%20w%3D(w_1%2C%5Cldots%2Cw_d)%2C%0A%20%20%20%20%5Cqquad%20b%5Cin%5Cmathbb%20R.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20It%20computes%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7Bz%3D%5Cmathbf%20w%5E%5Ctop%5Cmathbf%20x%2Bb%0A%20%20%20%20%3D%5Csum_%7Bj%3D1%7D%5E%7Bd%7Dw_jx_j%2Bb%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Each%20product%20%24w_jx_j%24%20is%20one%20feature's%20contribution.%20A%20positive%20weight%20makes%20larger%20feature%20values%20push%20the%20score%20upward.%20A%20negative%20weight%20pushes%20it%20downward.%20The%20bias%20moves%20the%20score%20without%20changing%20any%20feature.%0A%0A%20%20%20%20%23%23%23%20Numerical%20example%0A%0A%20%20%20%20Let%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%20x%3D(2%2C1)%2C%5Cqquad%0A%20%20%20%20%5Cmathbf%20w%3D(0.5%2C-0.25)%2C%5Cqquad%0A%20%20%20%20b%3D-0.4.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Then%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20z%3D(0.5)(2)%2B(-0.25)(1)-0.4%3D0.35.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%23%23%202.%20Apply%20a%20hard%20threshold%0A%0A%20%20%20%20The%20score%20becomes%20a%20class%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20%5Chat%20y%3D%0A%20%20%20%20%5Cbegin%7Bcases%7D%0A%20%20%20%201%2C%26z%5Cgeq0%2C%5C%5C%0A%20%20%20%200%2C%26z%3C0.%0A%20%20%20%20%5Cend%7Bcases%7D%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Because%20%24z%3D0.35%24%2C%20the%20example%20above%20is%20assigned%20to%20class%20%241%24.%0A%0A%20%20%20%20The%20output%20is%20only%20%240%24%20or%20%241%24.%20A%20score%20of%20%240.01%24%20and%20a%20score%20of%20%2410%24%20produce%20the%20same%20class.%20The%20perceptron%20does%20not%20interpret%20either%20score%20as%20a%20probability.%0A%0A%20%20%20%20%23%23%203.%20The%20score%20defines%20a%20boundary%0A%0A%20%20%20%20The%20decision%20changes%20where%20%24z%3D0%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%20w%5E%5Ctop%5Cmathbf%20x%2Bb%3D0.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20With%20two%20features%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20w_1x_1%2Bw_2x_2%2Bb%3D0.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20If%20%24w_2%5Cneq0%24%2C%20solve%20for%20%24x_2%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20x_2%3D-%5Cfrac%7Bw_1%7D%7Bw_2%7Dx_1-%5Cfrac%7Bb%7D%7Bw_2%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20This%20is%20a%20straight%20line.%20One%20side%20gives%20%24z%5Cgeq0%24%3B%20the%20other%20gives%20%24z%3C0%24.%0A%0A%20%20%20%20%23%23%204.%20Learn%20only%20from%20mistakes%0A%0A%20%20%20%20For%20one%20training%20example%20%24(%5Cmathbf%20x%2Cy)%24%2C%20define%20the%20correction%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20c%3D%5Ceta(y-%5Chat%20y)%2C%0A%20%20%20%20%24%24%0A%0A%20%20%20%20where%20%24%5Ceta%3E0%24%20is%20the%20learning%20rate.%20Update%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20%5Cmathbf%20w%5Cleftarrow%5Cmathbf%20w%2Bc%5Cmathbf%20x%2C%0A%20%20%20%20%5Cqquad%0A%20%20%20%20b%5Cleftarrow%20b%2Bc%0A%20%20%20%20%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20There%20are%20three%20cases%3A%0A%0A%20%20%20%20%7C%20Result%20%7C%20%24y-%5Chat%20y%24%20%7C%20Effect%20%7C%0A%20%20%20%20%7C---%7C---%3A%7C---%7C%0A%20%20%20%20%7C%20correct%20%7C%20%240%24%20%7C%20no%20update%20%7C%0A%20%20%20%20%7C%20missed%20positive%20%7C%20%241%24%20%7C%20increase%20the%20score%20for%20similar%20inputs%20%7C%0A%20%20%20%20%7C%20false%20positive%20%7C%20%24-1%24%20%7C%20decrease%20the%20score%20for%20similar%20inputs%20%7C%0A%0A%20%20%20%20%23%23%23%20One%20update%0A%0A%20%20%20%20Suppose%20%24y%3D1%24%2C%20%24%5Chat%20y%3D0%24%2C%20%24%5Ceta%3D0.1%24%2C%20%24%5Cmathbf%20x%3D(2%2C1)%24%2C%20and%20%24%5Cmathbf%20w%3D(0.5%2C-0.25)%24.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20c%3D0.1(1-0)%3D0.1%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%20w_%7Bnew%7D%0A%20%20%20%20%3D(0.5%2C-0.25)%2B0.1(2%2C1)%0A%20%20%20%20%3D(0.7%2C-0.15).%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20update%20moves%20the%20boundary%20so%20this%20positive%20example%20is%20more%20likely%20to%20fall%20on%20the%20positive%20side%20next%20time.%0A%0A%20%20%20%20%23%23%20What%20the%20learning%20rule%20can%20guarantee%0A%0A%20%20%20%20If%20a%20fixed%20straight%20boundary%20can%20perfectly%20separate%20the%20training%20classes%2C%20repeated%20perceptron%20updates%20eventually%20find%20a%20separating%20boundary.%20If%20no%20such%20boundary%20exists%2C%20the%20updates%20may%20continue%20to%20move%20without%20reaching%20zero%20mistakes.%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_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20code%20above%20applies%20the%20mistake-driven%20update%20one%20example%20at%20a%20time.%20The%20next%0A%20%20%20%20figure%20links%20three%20views%20of%20the%20same%20run%3A%20the%20boundary%20before%20learning%2C%20the%20final%0A%20%20%20%20boundary%2C%20and%20the%20number%20of%20mistakes%20remaining%20after%20each%20pass%20through%20the%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%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%20What%20the%20perceptron%20does%20not%20output%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%20Inspect%20mistakes%20and%20geometry%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%20Rule%20to%20remember%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%0A%20%20%20%20%23%23%20Previous%20and%20next%0A%0A%20%20%20%20-%20Previous%3A%20%5BMetrics%5D(%2Fconcepts%2Fmetrics)%20explains%20how%20binary%20decisions%20are%20evaluated.%0A%20%20%20%20-%20Next%3A%20%5BFrom%20Bernoulli%20to%20Log%20Loss%5D(%2Fconcepts%2Flog_loss)%20asks%20how%20a%20predicted%20probability%20should%20be%20scored.%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
c7ed9b45adab01b50d0bc27558ba596b