class TestSVM(unittest.TestCase): def setUp(self) -> None: physical_devices = tf.config.list_physical_devices('GPU') if physical_devices is not None and len(physical_devices) > 0: tf.config.experimental.set_memory_growth(physical_devices[0], True) self.data_loader = DataLoader() def gen_dataset(self, x, y, batch_size): x, y = tf.cast(x, dtype=tf.float32), tf.reshape(tf.cast(y, dtype=tf.float32), shape=(-1, 1)) return tf.data.Dataset.from_tensor_slices( (x, y)).batch(batch_size, drop_remainder=True) def test_linear(self): (x_train, y_train), (x_test, y_test) = self.data_loader.loadIris1(0.8) svm = LinearSVM(num_feature=2) svm.compile(optimizer=tf.optimizers.SGD(0.01), loss=svm.loss, metrics=[svm.accu]) svm.fit(x_train, y_train, batch_size=64, epochs=400, verbose=0) results = svm.evaluate(x_test, y_test) print("test result: ", results, svm.params()) self.assertGreater(results[1], 0.9) a = float(-svm.W[0] / svm.W[1]) xx = np.linspace(-2.5, 2.5) yy = a * xx - float(svm.b / svm.W[1]) self.data_loader.plot1( (0.0, 10.0), (float(-svm.b.numpy() / svm.W.numpy()[1]), float( (-svm.b.numpy() - 10 * svm.W.numpy()[0]) / svm.W.numpy()[1])), color='black').show() def test_gaussian(self): def draw(x_vals, y_vals, show=True): class1_x = [x[0] for i, x in enumerate(x_vals) if y_vals[i] == 1] class1_y = [x[1] for i, x in enumerate(x_vals) if y_vals[i] == 1] class2_x = [x[0] for i, x in enumerate(x_vals) if y_vals[i] == -1] class2_y = [x[1] for i, x in enumerate(x_vals) if y_vals[i] == -1] if show: plt.plot(class1_x, class1_y, 'ro', label='I. setosa') plt.plot(class2_x, class2_y, 'kx', label='I. versicolor') # plt.plot(class3_x, class3_y, 'gv', label='I. virginica') plt.title('Gaussian SVM Results on Iris Data') plt.xlabel('Pedal Length') plt.ylabel('Sepal Width') plt.legend(loc='lower right') plt.show() return class1_x, class1_y, class2_x, class2_y (x_vals, y_vals) = sklearn.datasets.make_circles(n_samples=3000, factor=.5, noise=.1) y_vals = np.array([1.0 if y == 1.0 else -1.0 for y in y_vals], dtype=np.float) split_ratio = 0.9 x_train, y_train = x_vals[0:int(len(x_vals) * split_ratio)], y_vals[ 0:int(len(y_vals) * split_ratio)] x_test, y_test = x_vals[int(len(x_vals) * split_ratio ):], y_vals[int(len(y_vals) * split_ratio):] draw(x_train, y_train) draw(x_test, y_test) batch_size = 256 epochs = 300 svm = GaussianKernelSVM(batch_size=batch_size) optimizer = tf.keras.optimizers.SGD(0.001) train_dataset = self.gen_dataset(x_train, y_train, batch_size) test_dataset = self.gen_dataset(x_test, y_test, 5) # train def train_step(x_sample, y_sample): with tf.GradientTape() as tape: pred_kernel = svm(x_sample, x_sample) loss = svm.loss(y_sample, pred_kernel) accu, _ = svm.accu(y_sample, y_sample, pred_kernel) gradients = tape.gradient( loss, svm.trainable_variables) # had to indent this! optimizer.apply_gradients(zip(gradients, svm.trainable_variables)) return loss, accu for epoch in range(epochs): accus, losses = [], [] for (batch, (x, y)) in enumerate(train_dataset): loss, accu = train_step(x_sample=x, y_sample=y) accus.append(accu.numpy()) losses.append(loss.numpy()) print("Epoch: {}, accu: {}, loss: {}".format( epoch, np.mean(accus), np.mean(losses))) # test rand_index = np.random.choice(len(x_vals), size=batch_size) rand_x = x_vals[rand_index] rand_y = tf.convert_to_tensor(np.transpose([y_vals[rand_index]]), dtype=tf.float32) accus = [] for (batch, (x, y)) in enumerate(test_dataset): pred_kernel = svm(x, rand_x) accu, _ = svm.accu(y, rand_y, pred_kernel) accus.append(accu) print("test accuracy: {}".format(np.mean(accus))) self.assertGreater(np.mean(accus), 0.8) # plot results x_min, x_max = x_vals[:, 0].min() - 1, x_vals[:, 0].max() + 1 y_min, y_max = x_vals[:, 1].min() - 1, x_vals[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02)) grid_points = np.c_[xx.ravel(), yy.ravel()] output_kernel = svm(grid_points, rand_x) _, predictions = svm.accu(None, rand_y, output_kernel) grid_predictions = tf.reshape(predictions, xx.shape) # Plot points and grid class1_x, class1_y, class2_x, class2_y = draw(x_vals, y_vals, False) plt.contourf(xx, yy, grid_predictions, cmap=plt.cm.Paired, alpha=0.8) plt.plot(class1_x, class1_y, 'ro', label='Class 1') plt.plot(class2_x, class2_y, 'kx', label='Class -1') plt.title('Gaussian SVM Results') plt.xlabel('x') plt.ylabel('y') plt.legend(loc='lower right') plt.ylim([-1.5, 1.5]) plt.xlim([-1.5, 1.5]) plt.show() def test_amsvm(self): (x_train, y_train) = self.data_loader.loadIris2(0.8) svm = AMSVM(num_classes=3, num_feature=2, c=0.001) # optimizer = tf.keras.optimizers.Adam(0.1) # train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(50, drop_remainder=True).shuffle( # 50) # train # def train_step(x_sample, y_sample): # with tf.GradientTape() as tape: # output = svm(x_sample) # loss = svm.loss(y_sample, output) # accu = svm.accu(y_sample, output) # gradients = tape.gradient(loss, svm.trainable_variables) # had to indent this! # optimizer.apply_gradients(zip(gradients, svm.trainable_variables)) # return loss, accu # # for epoch in range(400): # accus, losses = [], [] # for (batch, (x, y)) in enumerate(train_dataset): # loss, accu = train_step(x_sample=x, y_sample=y) # accus.append(accu.numpy()) # losses.append(loss.numpy()) # print("Epoch: {}, accu: {}, loss: {}".format(epoch, np.mean(accus), np.mean(losses))) svm.compile(optimizer=tf.optimizers.Adam(0.1), loss=svm.loss, metrics=[svm.accu]) svm.fit(x_train, y_train, batch_size=50, epochs=100)
# -*- coding: utf-8 -*- """ @Ref: https://www.cvxpy.org/examples/machine_learning/svm.html @Author: xiezizhe @Date: 17/2/2020 下午2:45 """ import cvxpy as cp from utils.DataLoader import DataLoader import numpy as np if __name__ == "__main__": data_loader = DataLoader() (x_train, y_train), (x_test, y_test) = data_loader.loadIris1(0.8) n = 2 m = len(x_train) W = cp.Variable((n, 1)) b = cp.Variable() loss = cp.sum( cp.pos(1 - cp.multiply(np.reshape(y_train.numpy(), (m, 1)), x_train.numpy() @ W + b))) reg = cp.norm(W, 1) lambd = cp.Parameter(nonneg=True) prob = cp.Problem(cp.Minimize(loss / m + lambd * reg)) lambd.value = 0.1 prob.solve() print("{} * w + {}".format(W.value, b.value)) data_loader.plot1((0.0, 10.0), (float( -b.value / W.value[1]), float(