From aaae2e60f196cbe0ee84f5d9076c4449a4ba0c28 Mon Sep 17 00:00:00 2001 From: Private Island Networks Inc Date: Mon, 24 Aug 2026 20:05:22 -0400 Subject: initial commit to match up with https://privateisland.tech/dev/pi-w-inference-server --- .gitignore | 5 +++ infer/__init__.py | 0 infer/http_infer_mlp.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ mlp/.gitignore | 4 ++ mlp/__init__.py | 0 mlp/mlp_1.py | 94 +++++++++++++++++++++++++++++++++++++++++++++++ mlp/mlp_2.py | 79 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 279 insertions(+) create mode 100644 .gitignore create mode 100644 infer/__init__.py create mode 100644 infer/http_infer_mlp.py create mode 100644 mlp/.gitignore create mode 100644 mlp/__init__.py create mode 100644 mlp/mlp_1.py create mode 100644 mlp/mlp_2.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..404ad9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.project +.pydevproject +*.bin +*.xml + diff --git a/infer/__init__.py b/infer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infer/http_infer_mlp.py b/infer/http_infer_mlp.py new file mode 100644 index 0000000..f7fa227 --- /dev/null +++ b/infer/http_infer_mlp.py @@ -0,0 +1,97 @@ +# +# http_infer_mlp +# +import sys +import numpy as np +import datetime +import argparse +import tritonclient.http as httpclient +from sklearn.datasets import make_moons +from sklearn.preprocessing import StandardScaler +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Sends requests via KServe REST API using images in numpy format. ' + 'It displays performance statistics and optionally the model accuracy') + parser.add_argument('--http_address', required=False, default='localhost', help='Specify url to http service. default:localhost') + parser.add_argument('--http_port', required=False, default=8000, help='Specify port to http service. default: 8000') + parser.add_argument('--input_name', required=False, default='input', help='Specify input tensor name. default: input') + parser.add_argument('--output_name', required=False, default='resnet_v1_50/predictions/Reshape_1', + help='Specify output name. default: resnet_v1_50/predictions/Reshape_1') + parser.add_argument('--iterations', default=1000, + help='Number of requests iterations', + dest='iterations', type=int) + parser.add_argument('--model_name', default='resnet', help='Define model name, must be same as is in service. default: resnet', + dest='model_name') + parser.add_argument('--pipeline_name', default='', help='Define pipeline name, must be same as is in service', + dest='pipeline_name') + parser.add_argument('--binary_data', default=False, action='store_true', help='Send input data in binary format', dest='binary_data') + parser.add_argument('--tls', default=False, action='store_true', help='use TLS communication with gRPC endpoint') + parser.add_argument('--server_cert', required=False, help='Path to server certificate', default=None) + parser.add_argument('--client_cert', required=False, help='Path to client certificate', default=None) + parser.add_argument('--client_key', required=False, help='Path to client key', default=None) + + args = vars(parser.parse_args()) + iterations = args.get('iterations') + + # Create the data + X, y = make_moons(n_samples=iterations, noise=0.2, random_state=42) + scaler = StandardScaler() + X = scaler.fit_transform(X) + + address = "{}:{}".format(args['http_address'], args['http_port']) + batch_size = 1 + + if args['tls']: + ssl_options = { + 'keyfile':args['client_key'], + 'cert_file':args['client_cert'], + 'ca_certs':args['server_cert'] + } + else: + ssl_options = None + + triton_client = httpclient.InferenceServerClient( + url=address, + ssl=args['tls'], + ssl_options=ssl_options, + verbose=False) + + processing_times = np.zeros((0), int) + + print('Start processing:') + print('\tModel name: {}'.format(args.get('pipeline_name') if bool(args.get('pipeline_name')) else args.get('model_name'))) + print('\tIterations: {}'.format(iterations)) + + iteration = 0 + is_pipeline_request = bool(args.get('pipeline_name')) + y_test = [] + num_correct = 0 + + while iteration < iterations: + inputs = [] + inputs.append(httpclient.InferInput(args['input_name'], [1,2], "FP32")) + point = np.array([X[iteration]],dtype=np.float32) + inputs[0].set_data_from_numpy(point) + start_time = datetime.datetime.now() + results = triton_client.infer( + model_name=args.get('pipeline_name') if is_pipeline_request else args.get('model_name'), + inputs=inputs) + end_time = datetime.datetime.now() + duration = (end_time - start_time).total_seconds() * 1000 + processing_times = np.append(processing_times, np.array([int(duration)])) + output = results.as_numpy(args['output_name']) + y_test.append(float(output[0][0])) + if y[iteration] == round(float(output[0][0])): + num_correct += 1 + + + # for object classification models show imagenet class + print('Iteration {}; Processing time: {:.2f} ms; speed {:.2f} fps'.format(iteration, round(np.average(duration), 2), + round(1000 * batch_size / np.average(duration), 2) + )) + iteration += 1 + + + + print('finished with {} out of {} correct'.format(num_correct, iterations)) + + diff --git a/mlp/.gitignore b/mlp/.gitignore new file mode 100644 index 0000000..b4ca3a3 --- /dev/null +++ b/mlp/.gitignore @@ -0,0 +1,4 @@ +*.bin +*.xml +.project +.pydevproject diff --git a/mlp/__init__.py b/mlp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mlp/mlp_1.py b/mlp/mlp_1.py new file mode 100644 index 0000000..d6d513d --- /dev/null +++ b/mlp/mlp_1.py @@ -0,0 +1,94 @@ +""" + "Building a Simple MLP from Scratch Using PyTorch" by Aymen Noor + https://medium.com/@mn05052002/building-a-simple-mlp-from-scratch-using-pytorch-7d50ca66512b +""" +import torch +import matplotlib.pyplot as plt +from sklearn.datasets import make_moons +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import StandardScaler + +class SimpleMLP(torch.nn.Module): + def __init__(self, input_size, hidden_size, output_size): + super(SimpleMLP, self).__init__() + self.W1 = torch.randn(input_size, hidden_size, requires_grad=True) + self.b1 = torch.randn(1, hidden_size, requires_grad=True) + self.W2 = torch.randn(hidden_size, output_size, requires_grad=True) + self.b2 = torch.randn(1, output_size, requires_grad=True) + + def forward(self, X): + self.z1 = torch.matmul(X, self.W1) + self.b1 + self.a1 = torch.sigmoid(self.z1) # Hidden layer activation + self.z2 = torch.matmul(self.a1, self.W2) + self.b2 + self.a2 = torch.sigmoid(self.z2) # Output layer activation + return self.a2 + + def backward(self,X,y,output,lr=0.01): + m=X.shape[0] + dz2=output-y + dW2=torch.matmul(self.a1.T,dz2) + db2=torch.sum(dz2,axis=0)/m + + da1=torch.matmul(dz2,self.W2.T) + dz1=da1*(self.a1*(1-self.a1)) + dw1=torch.matmul(X.T,dz1)/m + db1 = torch.sum(dz1, axis=0) / m + + with torch.no_grad(): + self.W1 -= lr * dw1 + self.b1 -= lr * db1 + self.W2 -= lr * dW2 + self.b2 -= lr * db2 + + def train(self, X, y, epochs=1000, lr=0.01): + losses = [] + for epoch in range(epochs): + output = self.forward(X) + #Compute loss using (Mean Squared Error) + loss = torch.mean((output - y) ** 2) + losses.append(loss.item()) + #update weights + self.backward(X, y, output, lr) + if (epoch + 1) % 100 == 0: + print(f"Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}") + return losses + + +if __name__ == '__main__': + + # Generate dataset + X, y = make_moons(n_samples=1000, noise=0.2, random_state=42) + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) + + # Standardize the data + scaler = StandardScaler() + X_train = scaler.fit_transform(X_train) + X_test = scaler.transform(X_test) + + # Convert to PyTorch tensors + X_train = torch.tensor(X_train, dtype=torch.float32) + y_train = torch.tensor(y_train, dtype=torch.float32).reshape(-1, 1) + X_test = torch.tensor(X_test, dtype=torch.float32) + y_test = torch.tensor(y_test, dtype=torch.float32).reshape(-1, 1) + + input_size = 2 + hidden_size = 4 + output_size = 1 + model = SimpleMLP(input_size, hidden_size, output_size) + + #Train model and store the losses + losses = model.train(X_train, y_train, epochs=1000, lr=0.1) + + plt.plot(losses) + plt.xlabel("Epoch") + plt.ylabel("Loss") + plt.title("Training Loss over Epochs") + plt.show() + + with torch.no_grad(): + test_output = model.forward(X_test) + test_output = (test_output > 0.5).float() + accuracy = torch.mean((test_output == y_test).float()) + print(f"Test Accuracy: {accuracy.item() * 100:.2f}%") + + print('finished') diff --git a/mlp/mlp_2.py b/mlp/mlp_2.py new file mode 100644 index 0000000..4616fb2 --- /dev/null +++ b/mlp/mlp_2.py @@ -0,0 +1,79 @@ +""" + Create and Train Simple MLP for scikit make_moons. + Convert and Save in OpenVino Intermediate Representation (IR) + +""" + +import openvino as ov +import torch +from torch import nn +import matplotlib.pyplot as plt +from sklearn.datasets import make_moons +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import StandardScaler + +class SimpleMLP(nn.Module): + def __init__(self): + super(SimpleMLP, self).__init__() + self.layer1 = nn.Linear(2, 4) # Hidden layer + self.layer2 = nn.Linear(4, 1) # Output layer + + def forward(self, x): + x = self.layer1(x) + x = torch.sigmoid(x) # Activation function + x = self.layer2(x) + return x + +if __name__ == '__main__': + # Generate dataset + X, y = make_moons(n_samples=1000, noise=0.2, random_state=42) + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) + + # Standardize the data + scaler = StandardScaler() + X_train = scaler.fit_transform(X_train) + X_test = scaler.transform(X_test) + + # Plot make_moons + fig,ax1 = plt.subplots(nrows=1,ncols=1,figsize=(8,4)) + ax1.scatter(X[:,0],X[:,1],c=y) + plt.show() + + # Convert to PyTorch tensors + X_train = torch.tensor(X_train, dtype=torch.float32) + y_train = torch.tensor(y_train, dtype=torch.float32).reshape(-1, 1) + X_test = torch.tensor(X_test, dtype=torch.float32) + y_test = torch.tensor(y_test, dtype=torch.float32).reshape(-1, 1) + + model = SimpleMLP() + criterion = nn.MSELoss() # Mean Squared Error for regression + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # Stochastic Gradient Descent + + losses = [] + for epoch in range(1000): # Number of epochs + optimizer.zero_grad() # Clear gradients + outputs = model(X_train) # Forward pass + loss = criterion(outputs, y_train) # Compute loss + loss.backward() # Backward pass + losses.append(loss.item()) + optimizer.step() # Update parameters + + plt.plot(losses) + plt.xlabel("Epoch") + plt.ylabel("Loss") + plt.title("Training Loss over Epochs") + plt.show() + + with torch.no_grad(): + raw_output = model.forward(X_test) + test_output = (raw_output > 0.5).float() + accuracy = torch.mean((test_output == y_test).float()) + print(f"Test Accuracy: {accuracy.item() * 100:.2f}%") + + # Convert and Save to OpenVino Intermediate Representation (IR) + ov_input=(ov.PartialShape([1, 2]), ov.Type.f32) + ov_model = ov.convert_model(model, input=ov_input) + compiled_model = ov.compile_model(ov_model, "AUTO") + ov.save_model(ov_model,'./mlp.xml') + + print("finished") -- cgit v1.2.3-8-gadcc