| import numpy as np
|
| import json
|
|
|
| class LayerConfig:
|
| def __init__(self, name, size, activation):
|
| self.name = name
|
| self.size = size
|
| self.activation = activation
|
|
|
| class SimpleMLModel:
|
| def __init__(self, layer_configs, learning_rate=0.01, loss='mse'):
|
| self.learning_rate = learning_rate
|
| self.loss = loss
|
| self.layer_configs = layer_configs
|
| self.model = self._init_model()
|
|
|
| def _init_model(self):
|
| model = {}
|
| sizes = [self.layer_configs[0].size]
|
|
|
| for config in self.layer_configs[1:]:
|
| sizes.append(config.size)
|
|
|
| for i in range(len(sizes) - 1):
|
| model[f'W{i}'] = np.random.randn(sizes[i], sizes[i+1]) * 0.01
|
| model[f'b{i}'] = np.zeros((1, sizes[i+1]))
|
|
|
| return model
|
|
|
| def forward(self, X):
|
| activations = [X]
|
| for i, config in enumerate(self.layer_configs[1:]):
|
| W = self.model[f'W{i}']
|
| b = self.model[f'b{i}']
|
| X = np.dot(X, W) + b
|
|
|
| if config.activation == 'relu':
|
| X = np.maximum(0, X)
|
| elif config.activation == 'sigmoid':
|
| X = 1 / (1 + np.exp(-X))
|
| elif config.activation == 'tanh':
|
| X = np.tanh(X)
|
|
|
| activations.append(X)
|
| return activations
|
|
|
| def backward(self, activations, y_true):
|
| grads = {}
|
| dA = activations[-1] - y_true
|
|
|
| for i in reversed(range(len(self.model) // 2)):
|
| dZ = dA * (activations[i+1] > 0)
|
| grads[f'dW{i}'] = np.dot(activations[i].T, dZ) / y_true.shape[0]
|
| grads[f'db{i}'] = np.sum(dZ, axis=0, keepdims=True) / y_true.shape[0]
|
| if i > 0:
|
| dA = np.dot(dZ, self.model[f'W{i}'].T)
|
|
|
| return grads
|
|
|
| def update_params(self, grads):
|
| for i in range(len(self.model) // 2):
|
| self.model[f'W{i}'] -= self.learning_rate * grads[f'dW{i}']
|
| self.model[f'b{i}'] -= self.learning_rate * grads[f'db{i}']
|
|
|
| def train(self, X, y, epochs=100):
|
| for epoch in range(epochs):
|
| activations = self.forward(X)
|
| grads = self.backward(activations, y)
|
| self.update_params(grads)
|
|
|
| def predict(self, X):
|
| activations = self.forward(X)
|
| return activations[-1]
|
|
|
| def save_model(self, filepath):
|
| np.savez(filepath, **self.model)
|
|
|
| def load_model(self, filepath):
|
| data = np.load(filepath)
|
| self.model = {k: data[k] for k in data}
|
|
|
| def save_config(self, filepath):
|
| config_list = []
|
| for config in self.layer_configs:
|
| config_list.append({
|
| "name": config.name,
|
| "size": config.size,
|
| "activation": config.activation
|
| })
|
|
|
| with open(filepath, 'w') as f:
|
| json.dump(config_list, f, indent=4)
|
|
|
| def load_config(self, filepath):
|
| with open(filepath, 'r') as f:
|
| config_list = json.load(f)
|
|
|
| self.layer_configs = []
|
| for config_data in config_list:
|
| self.layer_configs.append(LayerConfig(**config_data))
|
|
|
| self.model = self._init_model()
|
|
|
| input_size = 2
|
| output_size = 1
|
|
|
|
|
| X = np.array([
|
| [10, 10],
|
| [5, 5],
|
| [15, 15],
|
| ], dtype=np.float32)
|
|
|
| y = np.array([
|
| [20],
|
| [10],
|
| [30],
|
| ], dtype=np.float32)
|
|
|
|
|
| layer_configs = [
|
| LayerConfig("input", input_size, None),
|
| LayerConfig("hidden1", 16, "sigmoid"),
|
|
|
| LayerConfig("output", output_size, None)
|
| ]
|
|
|
|
|
| model = SimpleMLModel(layer_configs, learning_rate=0.01, loss='mse')
|
| model.train(X, y, epochs=1000)
|
|
|
|
|
| model.save_model("trained_model.npz")
|
|
|
|
|
| predictions = model.predict(X)
|
|
|
| print(predictions) |