|
|
|
@@ -6,18 +6,20 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"import os.path as osp\n", |
|
|
|
"\n", |
|
|
|
"import numpy as np\n", |
|
|
|
"import torch.nn as nn\n", |
|
|
|
"import torch\n", |
|
|
|
"import torch.nn as nn\n", |
|
|
|
"\n", |
|
|
|
"from abl.reasoning import ReasonerBase, prolog_KB\n", |
|
|
|
"from abl.learning import BasicNN, ABLModel\n", |
|
|
|
"from abl.evaluation import SymbolMetric, ABLMetric\n", |
|
|
|
"from abl.utils import ABLLogger, reform_list\n", |
|
|
|
"\n", |
|
|
|
"from abl.evaluation import SemanticsMetric, SymbolMetric\n", |
|
|
|
"from abl.learning import ABLModel, BasicNN\n", |
|
|
|
"from abl.reasoning import PrologKB, ReasonerBase\n", |
|
|
|
"from abl.utils import ABLLogger, print_log, reform_list\n", |
|
|
|
"from examples.hed.datasets.get_hed import get_hed, split_equation\n", |
|
|
|
"from examples.hed.hed_bridge import HEDBridge\n", |
|
|
|
"from models.nn import SymbolNet\n", |
|
|
|
"from datasets.get_hed import get_hed, split_equation" |
|
|
|
"from examples.models.nn import SymbolNet\n", |
|
|
|
"from zoopt import Dimension, Objective, Parameter, Opt" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
@@ -26,8 +28,12 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"# Initialize logger\n", |
|
|
|
"logger = ABLLogger.get_instance(\"abl\")" |
|
|
|
"# Build logger\n", |
|
|
|
"print_log(\"Abductive Learning on the HED example.\", logger=\"current\")\n", |
|
|
|
"\n", |
|
|
|
"# Retrieve the directory of the Log file and define the directory for saving the model weights.\n", |
|
|
|
"log_dir = ABLLogger.get_current_instance().log_dir\n", |
|
|
|
"weights_dir = osp.join(log_dir, \"weights\")" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
@@ -45,61 +51,52 @@ |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"# Initialize knowledge base and abducer\n", |
|
|
|
"class HED_prolog_KB(prolog_KB):\n", |
|
|
|
"class HedKB(PrologKB):\n", |
|
|
|
" def __init__(self, pseudo_label_list, pl_file):\n", |
|
|
|
" super().__init__(pseudo_label_list, pl_file)\n", |
|
|
|
" \n", |
|
|
|
"\n", |
|
|
|
" def consist_rule(self, exs, rules):\n", |
|
|
|
" rules = str(rules).replace(\"\\'\",\"\")\n", |
|
|
|
" rules = str(rules).replace(\"'\", \"\")\n", |
|
|
|
" return len(list(self.prolog.query(\"eval_inst_feature(%s, %s).\" % (exs, rules)))) != 0\n", |
|
|
|
"\n", |
|
|
|
" def abduce_rules(self, pred_res):\n", |
|
|
|
" prolog_result = list(self.prolog.query(\"consistent_inst_feature(%s, X).\" % pred_res))\n", |
|
|
|
" if len(prolog_result) == 0:\n", |
|
|
|
" return None\n", |
|
|
|
" prolog_rules = prolog_result[0]['X']\n", |
|
|
|
" prolog_rules = prolog_result[0][\"X\"]\n", |
|
|
|
" rules = [rule.value for rule in prolog_rules]\n", |
|
|
|
" return rules\n", |
|
|
|
" \n", |
|
|
|
"\n", |
|
|
|
"kb = HED_prolog_KB(pseudo_label_list=[1, 0, '+', '='], pl_file='./datasets/learn_add.pl')\n", |
|
|
|
"\n", |
|
|
|
"class HED_Abducer(ReasonerBase):\n", |
|
|
|
" def __init__(self, kb, dist_func='hamming'):\n", |
|
|
|
" super().__init__(kb, dist_func, zoopt=True)\n", |
|
|
|
" \n", |
|
|
|
" def _revise_by_idxs(self, pred_res, key, all_address_flag, idxs):\n", |
|
|
|
" pred = []\n", |
|
|
|
" k = []\n", |
|
|
|
" address_flag = []\n", |
|
|
|
" for idx in idxs:\n", |
|
|
|
" pred.append(pred_res[idx])\n", |
|
|
|
" k.append(key[idx])\n", |
|
|
|
" address_flag += list(all_address_flag[idx])\n", |
|
|
|
" address_idx = np.where(np.array(address_flag) != 0)[0] \n", |
|
|
|
" candidate = self.revise_by_idx(pred, k, address_idx)\n", |
|
|
|
"class HedReasoner(ReasonerBase):\n", |
|
|
|
" def revise_at_idx(self, data_sample):\n", |
|
|
|
" revision_idx = np.where(np.array(data_sample.flatten(\"revision_flag\")) != 0)[0]\n", |
|
|
|
" candidate = self.kb.revise_at_idx(\n", |
|
|
|
" data_sample.pred_pseudo_label, data_sample.Y, revision_idx\n", |
|
|
|
" )\n", |
|
|
|
" return candidate\n", |
|
|
|
" \n", |
|
|
|
" def zoopt_revision_score(self, pred_res, pseudo_label, pred_res_prob, key, sol): \n", |
|
|
|
" all_address_flag = reform_list(sol.get_x(), pseudo_label)\n", |
|
|
|
" lefted_idxs = [i for i in range(len(pred_res))]\n", |
|
|
|
" candidate_size = [] \n", |
|
|
|
"\n", |
|
|
|
" def zoopt_revision_score(self, symbol_num, data_sample, sol):\n", |
|
|
|
" revision_flag = reform_list(list(sol.get_x().astype(np.int32)), data_sample.pred_pseudo_label)\n", |
|
|
|
" data_sample.revision_flag = revision_flag\n", |
|
|
|
"\n", |
|
|
|
" lefted_idxs = [i for i in range(len(data_sample.pred_idx))]\n", |
|
|
|
" candidate_size = []\n", |
|
|
|
" while lefted_idxs:\n", |
|
|
|
" idxs = []\n", |
|
|
|
" idxs.append(lefted_idxs.pop(0))\n", |
|
|
|
" max_candidate_idxs = []\n", |
|
|
|
" found = False\n", |
|
|
|
" for idx in range(-1, len(pred_res)):\n", |
|
|
|
" for idx in range(-1, len(data_sample.pred_idx)):\n", |
|
|
|
" if (not idx in idxs) and (idx >= 0):\n", |
|
|
|
" idxs.append(idx)\n", |
|
|
|
" candidate = self._revise_by_idxs(pseudo_label, key, all_address_flag, idxs)\n", |
|
|
|
" candidate = self.revise_at_idx(data_sample[idxs])\n", |
|
|
|
" if len(candidate) == 0:\n", |
|
|
|
" if len(idxs) > 1:\n", |
|
|
|
" idxs.pop()\n", |
|
|
|
" else:\n", |
|
|
|
" if len(idxs) > len(max_candidate_idxs):\n", |
|
|
|
" found = True\n", |
|
|
|
" max_candidate_idxs = idxs.copy() \n", |
|
|
|
" max_candidate_idxs = idxs.copy()\n", |
|
|
|
" removed = [i for i in lefted_idxs if i in max_candidate_idxs]\n", |
|
|
|
" if found:\n", |
|
|
|
" candidate_size.append(len(removed) + 1)\n", |
|
|
|
@@ -107,32 +104,40 @@ |
|
|
|
" candidate_size.sort()\n", |
|
|
|
" score = 0\n", |
|
|
|
" import math\n", |
|
|
|
"\n", |
|
|
|
" for i in range(0, len(candidate_size)):\n", |
|
|
|
" score -= math.exp(-i) * candidate_size[i]\n", |
|
|
|
" return score\n", |
|
|
|
" \n", |
|
|
|
" def abduce(self, data, max_revision=-1, require_more_revision=0):\n", |
|
|
|
" batch_pred_label, batch_pred_prob, batch_pred_pseudo_label, batch_y = data\n", |
|
|
|
" def abduce(self, data_sample):\n", |
|
|
|
" symbol_num = data_sample.elements_num(\"pred_pseudo_label\")\n", |
|
|
|
" max_revision_num = self._get_max_revision_num(self.max_revision, symbol_num)\n", |
|
|
|
"\n", |
|
|
|
" solution = self.zoopt_get_solution(symbol_num, data_sample, max_revision_num)\n", |
|
|
|
"\n", |
|
|
|
" solution = self.zoopt_get_solution(\n", |
|
|
|
" batch_pred_label, batch_pred_pseudo_label, batch_pred_prob, batch_y, max_revision\n", |
|
|
|
" data_sample.revision_flag = reform_list(\n", |
|
|
|
" solution.astype(np.int32), data_sample.pred_pseudo_label\n", |
|
|
|
" )\n", |
|
|
|
" batch_revision_idx = reform_list(solution.astype(np.int32), batch_pred_label)\n", |
|
|
|
" \n", |
|
|
|
" batch_abduced_pseudo_label = []\n", |
|
|
|
" for pred_pseudo_label, pred_prob, revision_idx in zip(batch_pred_pseudo_label, batch_pred_prob, batch_revision_idx):\n", |
|
|
|
" candidates = self.revise_by_idx([pred_pseudo_label], None, list(np.nonzero(np.array(revision_idx))[0]))\n", |
|
|
|
"\n", |
|
|
|
" abduced_pseudo_label = []\n", |
|
|
|
"\n", |
|
|
|
" for single_instance in data_sample:\n", |
|
|
|
" single_instance.pred_pseudo_label = [single_instance.pred_pseudo_label]\n", |
|
|
|
" candidates = self.revise_at_idx(single_instance)\n", |
|
|
|
" if len(candidates) == 0:\n", |
|
|
|
" batch_abduced_pseudo_label.append([])\n", |
|
|
|
" abduced_pseudo_label.append([])\n", |
|
|
|
" else:\n", |
|
|
|
" batch_abduced_pseudo_label.append(candidates[0][0])\n", |
|
|
|
" # batch_abduced_pseudo_label.append(self._get_one_candidate(pred_pseudo_label, pred_prob, candidates)[0])\n", |
|
|
|
" return batch_abduced_pseudo_label\n", |
|
|
|
" abduced_pseudo_label.append(candidates[0][0])\n", |
|
|
|
" data_sample.abduced_pseudo_label = abduced_pseudo_label\n", |
|
|
|
" return abduced_pseudo_label\n", |
|
|
|
"\n", |
|
|
|
" def abduce_rules(self, pred_res):\n", |
|
|
|
" return self.kb.abduce_rules(pred_res)\n", |
|
|
|
" \n", |
|
|
|
"abducer = HED_Abducer(kb)" |
|
|
|
"\n", |
|
|
|
"kb = HedKB(\n", |
|
|
|
" pseudo_label_list=[1, 0, \"+\", \"=\"], pl_file=\"./datasets/learn_add.pl\"\n", |
|
|
|
")\n", |
|
|
|
"reasoner = HedReasoner(kb, dist_func=\"hamming\", use_zoopt=True, max_revision=20)" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
@@ -149,14 +154,12 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"# Initialize necessary component for machine learning part\n", |
|
|
|
"cls = SymbolNet(\n", |
|
|
|
" num_classes=len(kb.pseudo_label_list),\n", |
|
|
|
" image_size=(28, 28, 1),\n", |
|
|
|
")\n", |
|
|
|
"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n", |
|
|
|
"# Build necessary components for BasicNN\n", |
|
|
|
"cls = SymbolNet(num_classes=4)\n", |
|
|
|
"criterion = nn.CrossEntropyLoss()\n", |
|
|
|
"optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6)" |
|
|
|
"optimizer = torch.optim.RMSprop(cls.parameters(), lr=0.001, weight_decay=1e-6)\n", |
|
|
|
"# optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99))\n", |
|
|
|
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
@@ -165,17 +168,17 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"# Initialize BasicNN\n", |
|
|
|
"# Build BasicNN\n", |
|
|
|
"# The function of BasicNN is to wrap NN models into the form of an sklearn estimator\n", |
|
|
|
"base_model = BasicNN(\n", |
|
|
|
" cls,\n", |
|
|
|
" criterion,\n", |
|
|
|
" optimizer,\n", |
|
|
|
" device,\n", |
|
|
|
" save_interval=1,\n", |
|
|
|
" save_dir=logger.save_dir,\n", |
|
|
|
" batch_size=32,\n", |
|
|
|
" num_epochs=1,\n", |
|
|
|
" save_interval=1,\n", |
|
|
|
" save_dir=weights_dir,\n", |
|
|
|
")" |
|
|
|
] |
|
|
|
}, |
|
|
|
@@ -185,8 +188,8 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"# Initialize ABL model\n", |
|
|
|
"# The main function of the ABL model is to serialize data and \n", |
|
|
|
"# Build ABLModel\n", |
|
|
|
"# The main function of the ABL model is to serialize data and\n", |
|
|
|
"# provide a unified interface for different machine learning models\n", |
|
|
|
"model = ABLModel(base_model)" |
|
|
|
] |
|
|
|
@@ -205,8 +208,8 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"# Add metric\n", |
|
|
|
"metric = [SymbolMetric(prefix=\"hed\"), ABLMetric(prefix=\"hed\")]" |
|
|
|
"# Set up metrics\n", |
|
|
|
"metric_list = [SymbolMetric(prefix=\"hed\"), SemanticsMetric(prefix=\"hed\")]" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
@@ -223,7 +226,7 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"bridge = HEDBridge(model, abducer, metric)" |
|
|
|
"bridge = HEDBridge(model, reasoner, metric_list)" |
|
|
|
] |
|
|
|
}, |
|
|
|
{ |
|
|
|
@@ -259,7 +262,7 @@ |
|
|
|
"metadata": {}, |
|
|
|
"outputs": [], |
|
|
|
"source": [ |
|
|
|
"bridge.pretrain(\"./weights/\")\n", |
|
|
|
"bridge.pretrain(\"./weights\")\n", |
|
|
|
"bridge.train(train_data, val_data)" |
|
|
|
] |
|
|
|
} |
|
|
|
|