import%20marimo%0A%0A__generated_with%20%3D%20%220.24.0%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0Awith%20app.setup%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20tensorflow%20as%20tf%0A%20%20%20%20from%20tensorflow%20import%20keras%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20PointNet%20%E9%A2%A8%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A7%E7%82%B9%E7%BE%A4%E5%88%86%E9%A1%9E%0A%0A%20%20%20%20%E5%85%83%20notebook%20%E3%81%AF%20ModelNet10%20%E3%82%92%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%97%E3%81%A6%20TensorBoard%20%E3%81%A7%E5%AD%A6%E7%BF%92%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82%0A%20%20%20%20%E3%81%93%E3%81%AE%E7%89%88%E3%81%A7%E3%81%AF%E5%A4%A7%E5%AE%B9%E9%87%8F%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%82%84%20UI%20%E4%BE%9D%E5%AD%98%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%E3%81%9F%E3%82%81%E3%80%81%E7%90%83%E3%83%BB%E7%AB%8B%E6%96%B9%E4%BD%93%E3%83%BB%E5%86%86%E6%9F%B1%E3%83%BB%E5%86%86%E9%8C%90%E3%81%AE%E5%90%88%E6%88%90%E7%82%B9%E7%BE%A4%E3%82%92%E8%87%AA%E5%89%8D%E7%94%9F%E6%88%90%E3%81%97%E3%81%BE%E3%81%99%E3%80%82%0A%20%20%20%20PointNet%20%E3%81%AE%E8%A6%81%E7%82%B9%E3%81%A7%E3%81%82%E3%82%8B%20%60Conv1D%20%2B%20GlobalMaxPooling%20%2B%20T-Net%60%20%E3%81%AF%E6%AE%8B%E3%81%97%E3%81%A4%E3%81%A4%E3%80%81%E7%9F%AD%E6%99%82%E9%96%93%E3%81%A7%20export%20%E3%81%A7%E3%81%8D%E3%82%8B%E6%95%99%E6%9D%90%E3%81%AB%E6%95%B4%E3%81%88%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20tf.keras.utils.set_random_seed(1234)%0A%20%20%20%20device_name%20%3D%20%22%2FGPU%3A0%22%20if%20tf.config.list_physical_devices(%22GPU%22)%20else%20%22%2FCPU%3A0%22%0A%20%20%20%20pd.DataFrame(%7B%22item%22%3A%20%5B%22tensorflow%22%2C%20%22device%22%5D%2C%20%22value%22%3A%20%5Btf.__version__%2C%20device_name%5D%7D)%0A%20%20%20%20return%20(device_name%2C)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20def%20rotation_matrix(rng)%3A%0A%20%20%20%20%20%20%20%20angle_z%20%3D%20rng.uniform(0.0%2C%202.0%20*%20np.pi)%0A%20%20%20%20%20%20%20%20angle_x%20%3D%20rng.uniform(-0.4%2C%200.4)%0A%20%20%20%20%20%20%20%20cz%2C%20sz%20%3D%20np.cos(angle_z)%2C%20np.sin(angle_z)%0A%20%20%20%20%20%20%20%20cx%2C%20sx%20%3D%20np.cos(angle_x)%2C%20np.sin(angle_x)%0A%20%20%20%20%20%20%20%20rot_z%20%3D%20np.array(%5B%5Bcz%2C%20-sz%2C%200.0%5D%2C%20%5Bsz%2C%20cz%2C%200.0%5D%2C%20%5B0.0%2C%200.0%2C%201.0%5D%5D)%0A%20%20%20%20%20%20%20%20rot_x%20%3D%20np.array(%5B%5B1.0%2C%200.0%2C%200.0%5D%2C%20%5B0.0%2C%20cx%2C%20-sx%5D%2C%20%5B0.0%2C%20sx%2C%20cx%5D%5D)%0A%20%20%20%20%20%20%20%20return%20rot_z%20%40%20rot_x%0A%0A%20%20%20%20def%20sample_sphere(num_points%2C%20rng)%3A%0A%20%20%20%20%20%20%20%20points%20%3D%20rng.normal(size%3D(num_points%2C%203))%0A%20%20%20%20%20%20%20%20return%20points%20%2F%20np.linalg.norm(points%2C%20axis%3D1%2C%20keepdims%3DTrue)%0A%0A%20%20%20%20def%20sample_cube(num_points%2C%20rng)%3A%0A%20%20%20%20%20%20%20%20points%20%3D%20rng.uniform(-1.0%2C%201.0%2C%20size%3D(num_points%2C%203))%0A%20%20%20%20%20%20%20%20faces%20%3D%20rng.integers(0%2C%203%2C%20size%3Dnum_points)%0A%20%20%20%20%20%20%20%20signs%20%3D%20rng.choice(%5B-1.0%2C%201.0%5D%2C%20size%3Dnum_points)%0A%20%20%20%20%20%20%20%20points%5Bnp.arange(num_points)%2C%20faces%5D%20%3D%20signs%0A%20%20%20%20%20%20%20%20return%20points%0A%0A%20%20%20%20def%20sample_cylinder(num_points%2C%20rng)%3A%0A%20%20%20%20%20%20%20%20theta%20%3D%20rng.uniform(0.0%2C%202.0%20*%20np.pi%2C%20size%3Dnum_points)%0A%20%20%20%20%20%20%20%20z%20%3D%20rng.uniform(-1.0%2C%201.0%2C%20size%3Dnum_points)%0A%20%20%20%20%20%20%20%20return%20np.column_stack(%5Bnp.cos(theta)%2C%20np.sin(theta)%2C%20z%5D)%0A%0A%20%20%20%20def%20sample_cone(num_points%2C%20rng)%3A%0A%20%20%20%20%20%20%20%20theta%20%3D%20rng.uniform(0.0%2C%202.0%20*%20np.pi%2C%20size%3Dnum_points)%0A%20%20%20%20%20%20%20%20height%20%3D%20rng.uniform(0.0%2C%201.0%2C%20size%3Dnum_points)%0A%20%20%20%20%20%20%20%20radius%20%3D%201.0%20-%20height%0A%20%20%20%20%20%20%20%20return%20np.column_stack(%5Bradius%20*%20np.cos(theta)%2C%20radius%20*%20np.sin(theta)%2C%202.0%20*%20height%20-%201.0%5D)%0A%0A%20%20%20%20shape_generators%20%3D%20%7B%22sphere%22%3A%20sample_sphere%2C%20%22cube%22%3A%20sample_cube%2C%20%22cylinder%22%3A%20sample_cylinder%2C%20%22cone%22%3A%20sample_cone%7D%0A%20%20%20%20return%20rotation_matrix%2C%20shape_generators%0A%0A%0A%40app.cell%0Adef%20_(rotation_matrix%2C%20shape_generators)%3A%0A%20%20%20%20def%20make_dataset(samples_per_class%2C%20num_points%2C%20seed)%3A%0A%20%20%20%20%20%20%20%20rng%20%3D%20np.random.default_rng(seed)%0A%20%20%20%20%20%20%20%20clouds%2C%20labels%20%3D%20%5B%5D%2C%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20label%2C%20generator%20in%20enumerate(shape_generators.values())%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20_%20in%20range(samples_per_class)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20points%20%3D%20generator(num_points%2C%20rng)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20points%20%3D%20points%20%40%20rotation_matrix(rng).T%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20points%20%3D%20points%20%2B%20rng.normal(scale%3D0.02%2C%20size%3Dpoints.shape)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20clouds.append(points.astype(np.float32))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20labels.append(label)%0A%20%20%20%20%20%20%20%20return%20np.stack(clouds)%2C%20np.array(labels%2C%20dtype%3Dnp.int64)%0A%0A%20%20%20%20class_names%20%3D%20list(shape_generators)%0A%20%20%20%20train_points%2C%20train_labels%20%3D%20make_dataset(80%2C%20256%2C%201234)%0A%20%20%20%20test_points%2C%20test_labels%20%3D%20make_dataset(20%2C%20256%2C%204321)%0A%20%20%20%20return%20class_names%2C%20test_labels%2C%20test_points%2C%20train_labels%2C%20train_points%0A%0A%0A%40app.cell%0Adef%20_(class_names%2C%20train_points)%3A%0A%20%20%20%20_fig%20%3D%20plt.figure(figsize%3D(10%2C%208))%0A%20%20%20%20for%20idx%2C%20class_name%20in%20enumerate(class_names%2C%20start%3D1)%3A%0A%20%20%20%20%20%20%20%20_axis%20%3D%20_fig.add_subplot(2%2C%202%2C%20idx%2C%20projection%3D%223d%22)%0A%20%20%20%20%20%20%20%20_points%20%3D%20train_points%5B(idx%20-%201)%20*%2080%5D%0A%20%20%20%20%20%20%20%20_axis.scatter(_points%5B%3A%2C%200%5D%2C%20_points%5B%3A%2C%201%5D%2C%20_points%5B%3A%2C%202%5D%2C%20s%3D4)%0A%20%20%20%20%20%20%20%20_axis.set_title(class_name)%0A%20%20%20%20%20%20%20%20_axis.set_axis_off()%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(test_labels%2C%20test_points%2C%20train_labels%2C%20train_points)%3A%0A%20%20%20%20train_dataset%20%3D%20tf.data.Dataset.from_tensor_slices((train_points%2C%20train_labels)).shuffle(len(train_points)%2C%20seed%3D1234).batch(32).prefetch(tf.data.AUTOTUNE)%0A%20%20%20%20test_dataset%20%3D%20tf.data.Dataset.from_tensor_slices((test_points%2C%20test_labels)).batch(32).prefetch(tf.data.AUTOTUNE)%0A%20%20%20%20return%20test_dataset%2C%20train_dataset%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20def%20conv_bn(x%2C%20filters)%3A%0A%20%20%20%20%20%20%20%20x%20%3D%20keras.layers.Conv1D(filters%2C%20kernel_size%3D1%2C%20padding%3D%22valid%22)(x)%0A%20%20%20%20%20%20%20%20x%20%3D%20keras.layers.BatchNormalization(momentum%3D0.0)(x)%0A%20%20%20%20%20%20%20%20return%20keras.layers.Activation(%22relu%22)(x)%0A%0A%20%20%20%20def%20dense_bn(x%2C%20units)%3A%0A%20%20%20%20%20%20%20%20x%20%3D%20keras.layers.Dense(units)(x)%0A%20%20%20%20%20%20%20%20x%20%3D%20keras.layers.BatchNormalization(momentum%3D0.0)(x)%0A%20%20%20%20%20%20%20%20return%20keras.layers.Activation(%22relu%22)(x)%0A%0A%20%20%20%20class%20OrthogonalRegularizer(keras.regularizers.Regularizer)%3A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20num_features%2C%20l2reg%3D0.001)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.num_features%20%3D%20num_features%0A%20%20%20%20%20%20%20%20%20%20%20%20self.l2reg%20%3D%20l2reg%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eye%20%3D%20tf.eye(num_features)%0A%0A%20%20%20%20%20%20%20%20def%20__call__(self%2C%20weights)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20matrix%20%3D%20tf.reshape(weights%2C%20(-1%2C%20self.num_features%2C%20self.num_features))%0A%20%20%20%20%20%20%20%20%20%20%20%20matrix_product%20%3D%20tf.matmul(matrix%2C%20matrix%2C%20transpose_b%3DTrue)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20tf.reduce_sum(self.l2reg%20*%20tf.square(matrix_product%20-%20self.eye))%0A%0A%20%20%20%20def%20tnet(inputs%2C%20num_features)%3A%0A%20%20%20%20%20%20%20%20bias%20%3D%20keras.initializers.Constant(np.eye(num_features).flatten())%0A%20%20%20%20%20%20%20%20regularizer%20%3D%20OrthogonalRegularizer(num_features)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(inputs%2C%2032)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(x%2C%2064)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(x%2C%20128)%0A%20%20%20%20%20%20%20%20x%20%3D%20keras.layers.GlobalMaxPooling1D()(x)%0A%20%20%20%20%20%20%20%20x%20%3D%20dense_bn(x%2C%2064)%0A%20%20%20%20%20%20%20%20x%20%3D%20dense_bn(x%2C%2032)%0A%20%20%20%20%20%20%20%20transform%20%3D%20keras.layers.Dense(num_features%20*%20num_features%2C%20kernel_initializer%3D%22zeros%22%2C%20bias_initializer%3Dbias%2C%20activity_regularizer%3Dregularizer)(x)%0A%20%20%20%20%20%20%20%20transform%20%3D%20keras.layers.Reshape((num_features%2C%20num_features))(transform)%0A%20%20%20%20%20%20%20%20return%20keras.layers.Dot(axes%3D(2%2C%201))(%5Binputs%2C%20transform%5D)%0A%0A%20%20%20%20return%20conv_bn%2C%20dense_bn%2C%20tnet%0A%0A%0A%40app.cell%0Adef%20_(class_names%2C%20conv_bn%2C%20dense_bn%2C%20device_name%2C%20tnet%2C%20train_points)%3A%0A%20%20%20%20with%20tf.device(device_name)%3A%0A%20%20%20%20%20%20%20%20inputs%20%3D%20keras.Input(shape%3D(train_points.shape%5B1%5D%2C%20train_points.shape%5B2%5D))%0A%20%20%20%20%20%20%20%20x%20%3D%20tnet(inputs%2C%203)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(x%2C%2032)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(x%2C%2032)%0A%20%20%20%20%20%20%20%20x%20%3D%20tnet(x%2C%2032)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(x%2C%2032)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(x%2C%2064)%0A%20%20%20%20%20%20%20%20x%20%3D%20conv_bn(x%2C%20128)%0A%20%20%20%20%20%20%20%20x%20%3D%20keras.layers.GlobalMaxPooling1D()(x)%0A%20%20%20%20%20%20%20%20x%20%3D%20dense_bn(x%2C%20128)%0A%20%20%20%20%20%20%20%20x%20%3D%20keras.layers.Dropout(0.3)(x)%0A%20%20%20%20%20%20%20%20x%20%3D%20dense_bn(x%2C%2064)%0A%20%20%20%20%20%20%20%20outputs%20%3D%20keras.layers.Dense(len(class_names)%2C%20activation%3D%22softmax%22)(x)%0A%20%20%20%20%20%20%20%20model%20%3D%20keras.Model(inputs%3Dinputs%2C%20outputs%3Doutputs%2C%20name%3D%22synthetic_pointnet%22)%0A%20%20%20%20return%20(model%2C)%0A%0A%0A%40app.cell%0Adef%20_(model%2C%20test_dataset%2C%20train_dataset)%3A%0A%20%20%20%20model.compile(loss%3D%22sparse_categorical_crossentropy%22%2C%20optimizer%3Dkeras.optimizers.Adam(learning_rate%3D1e-3)%2C%20metrics%3D%5B%22sparse_categorical_accuracy%22%5D)%0A%20%20%20%20history%20%3D%20model.fit(train_dataset%2C%20epochs%3D12%2C%20validation_data%3Dtest_dataset%2C%20verbose%3D0%2C%20callbacks%3D%5Bkeras.callbacks.EarlyStopping(patience%3D3%2C%20restore_best_weights%3DTrue)%5D)%0A%20%20%20%20history_frame%20%3D%20pd.DataFrame(history.history)%0A%20%20%20%20test_metrics%20%3D%20model.evaluate(test_dataset%2C%20verbose%3D0%2C%20return_dict%3DTrue)%0A%20%20%20%20return%20history_frame%2C%20test_metrics%0A%0A%0A%40app.cell%0Adef%20_(history_frame)%3A%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3D(10%2C%204))%0A%20%20%20%20_axes%5B0%5D.plot(history_frame%5B%22loss%22%5D%2C%20label%3D%22train%22)%0A%20%20%20%20_axes%5B0%5D.plot(history_frame%5B%22val_loss%22%5D%2C%20label%3D%22validation%22)%0A%20%20%20%20_axes%5B0%5D.legend()%0A%20%20%20%20_axes%5B0%5D.set_title(%22Loss%22)%0A%20%20%20%20_axes%5B1%5D.plot(history_frame%5B%22sparse_categorical_accuracy%22%5D%2C%20label%3D%22train%22)%0A%20%20%20%20_axes%5B1%5D.plot(history_frame%5B%22val_sparse_categorical_accuracy%22%5D%2C%20label%3D%22validation%22)%0A%20%20%20%20_axes%5B1%5D.legend()%0A%20%20%20%20_axes%5B1%5D.set_title(%22Accuracy%22)%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(test_metrics)%3A%0A%20%20%20%20pd.DataFrame(%5Btest_metrics%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(model%2C%20test_labels%2C%20test_points)%3A%0A%20%20%20%20from%20sklearn.metrics%20import%20confusion_matrix%0A%0A%20%20%20%20probs%20%3D%20model.predict(test_points%2C%20verbose%3D0)%0A%20%20%20%20predictions%20%3D%20np.argmax(probs%2C%20axis%3D1)%0A%20%20%20%20confusion%20%3D%20confusion_matrix(test_labels%2C%20predictions)%0A%20%20%20%20return%20confusion%2C%20predictions%0A%0A%0A%40app.cell%0Adef%20_(class_names%2C%20confusion)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(5%2C%204))%0A%20%20%20%20_image%20%3D%20_ax.imshow(confusion%2C%20cmap%3D%22Purples%22)%0A%20%20%20%20_ax.set_xticks(range(len(class_names))%2C%20class_names%2C%20rotation%3D30)%0A%20%20%20%20_ax.set_yticks(range(len(class_names))%2C%20class_names)%0A%20%20%20%20for%20row%20in%20range(confusion.shape%5B0%5D)%3A%0A%20%20%20%20%20%20%20%20for%20col%20in%20range(confusion.shape%5B1%5D)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax.text(col%2C%20row%2C%20confusion%5Brow%2C%20col%5D%2C%20ha%3D%22center%22%2C%20va%3D%22center%22%2C%20fontsize%3D8)%0A%20%20%20%20_ax.set_title(%22Confusion%20matrix%22)%0A%20%20%20%20_fig.colorbar(_image%2C%20ax%3D_ax)%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(class_names%2C%20predictions%2C%20test_labels%2C%20test_points)%3A%0A%20%20%20%20_fig%20%3D%20plt.figure(figsize%3D(10%2C%208))%0A%20%20%20%20for%20axis_index%2C%20sample_index%20in%20enumerate(%5B0%2C%2020%2C%2040%2C%2060%5D%2C%20start%3D1)%3A%0A%20%20%20%20%20%20%20%20_axis%20%3D%20_fig.add_subplot(2%2C%202%2C%20axis_index%2C%20projection%3D%223d%22)%0A%20%20%20%20%20%20%20%20_points%20%3D%20test_points%5Bsample_index%5D%0A%20%20%20%20%20%20%20%20_axis.scatter(_points%5B%3A%2C%200%5D%2C%20_points%5B%3A%2C%201%5D%2C%20_points%5B%3A%2C%202%5D%2C%20s%3D4)%0A%20%20%20%20%20%20%20%20_axis.set_title(f%22pred%3D%7Bclass_names%5Bpredictions%5Bsample_index%5D%5D%7D%2C%20true%3D%7Bclass_names%5Btest_labels%5Bsample_index%5D%5D%7D%22)%0A%20%20%20%20%20%20%20%20_axis.set_axis_off()%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%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
7b1ce611b554bda94a48798eabbb16a9