diff --git a/emblem5/.cursorignore b/emblem5/.cursorignore new file mode 100644 index 0000000..249cda9 --- /dev/null +++ b/emblem5/.cursorignore @@ -0,0 +1 @@ +/data \ No newline at end of file diff --git a/emblem5/.gitignore b/emblem5/.gitignore new file mode 100644 index 0000000..8050677 --- /dev/null +++ b/emblem5/.gitignore @@ -0,0 +1,7 @@ +/venv +/data +/models +/archive +/.ipynb_checkpoints +/reports +/dataset diff --git a/emblem5/.gitlab-ci.yml b/emblem5/.gitlab-ci.yml new file mode 100644 index 0000000..aed990f --- /dev/null +++ b/emblem5/.gitlab-ci.yml @@ -0,0 +1,48 @@ +stages: + - build + - prepare + - train + +baseimg: + stage: build + tags: + - emblem-dev2 + script: + - make -C baseimg + when: manual + +fetch_and_preprocess: + only: + - main + stage: prepare + tags: + - ailab + timeout: 5h + before_script: + - if ! test -d $HOME/venv; then python3 -m venv $HOME/venv; source $HOME/venv/bin/activate; pip install --upgrade pip; fi + - source $HOME/venv/bin/activate + - | + if ! cmp -s ./baseimg/requirements.txt $HOME/venv/requirements.txt; then + pip install -r ./baseimg/requirements.txt && cp ./baseimg/requirements.txt $HOME/venv/; + fi + - mkdir -p $HOME/emblem5-data + script: + - export DATA_DIR=$HOME/emblem5-data + - mkdir -p $DATA_DIR + - time make fetch + +train: &train_base + only: + - main + stage: train + tags: + - ailab + before_script: + - source $HOME/venv/bin/activate + - export DATA_DIR=$HOME/emblem5-data + script: + - echo "to be implemented" + artifacts: + paths: + - models/* + expire_in: 7 days \ No newline at end of file diff --git a/emblem5/Makefile b/emblem5/Makefile new file mode 100644 index 0000000..9346d1d --- /dev/null +++ b/emblem5/Makefile @@ -0,0 +1,73 @@ +.PHONY: FORCE + +DATA_DIR ?= ../data +MODEL ?= models/sbs2g-20250614_1551-pos97.22-neg94.72.pt +INF ?= 99999999 +METHOD ?= qrcmpnet +TRAIN_RATE ?= 0.8 +SCAN_IDS ?= 80653 +benchmark: + ./ai/benchmark.py -m $(MODEL) -d data/samples.json -s $(SCAN_IDS) + +upload: + ls -l $(MODEL) + ./ai/upload.py $(MODEL) + +upload-qrs: + ./scripts/upload-qrs.py --dir data/qrs/tree + +server_url=http://localhost:6500 +# server_url=https://themblem.com + +qr_verify: + echo 'pos' + for scan_id in 101378 124999; do \ + curl $(server_url)/api/v5/qr_verify \ + -F frame=@data/scans/$$scan_id/frame.jpg; \ + done + echo 'neg' + for scan_id in 102095 105387; do \ + curl $(server_url)/api/v5/qr_verify \ + -F frame=@data/scans/$$scan_id/frame.jpg; \ + done + +fullqr: + ./ai/fullqr.py + +fetch: + ./ai/fetch-scans.py --data-dir $(DATA_DIR) + ./ai/make-sbs.py --data-dir $(DATA_DIR) + +sbs: + ./ai/make-sbs.py --data-dir $(DATA_DIR) + +clarity: METHOD=clarity +clarity: train + + +VERIFY_RANGE ?= 160000-$(INF) +NCELLS ?= 1 +verify: + ./ai/verify.py -d $(DATA_DIR) -m $(MODEL) -r $(VERIFY_RANGE) --name $(notdir $(MODEL))-$(VERIFY_RANGE) --with-margins --ncells $(NCELLS) + +verify-ue: + ./ai/verify.py -d $(DATA_DIR) -m $(MODEL) -r 0-$(INF) --name $(notdir $(MODEL))-ue --labels ue + + +predict: + ./ai/predict.py -m $(MODEL) data/gridcrop2/117803/sbs.jpg + +aiweb: + cd ai/aiweb && npm run serve + +server: + ./ai/server.py --debug + +hypertrain: + ./ai/hypertrain.py --max-epochs 20 --min-epochs 10 --ntrials 20 + +train: + ./ai/train.py --sample-rate 1 --num-epochs 100 --data-dir $(DATA_DIR) --val-codes ai/validate-codes.txt + +quick: + ./ai/train.py --sample-rate 0.1 --num-epochs 1 --data-dir $(DATA_DIR) --val-codes ai/validate-codes.txt \ No newline at end of file diff --git a/emblem5/ai/Dockerfile b/emblem5/ai/Dockerfile new file mode 100644 index 0000000..3b3176f --- /dev/null +++ b/emblem5/ai/Dockerfile @@ -0,0 +1,8 @@ +FROM registry.cn-shenzhen.aliyuncs.com/emblem/baseimg:2025041707-4bc3e34 +RUN mkdir -p /emblem +# TODO: use new base image that has these +RUN apt-get update && apt-get install -y libglib2.0-0t64 libgl1 +RUN mkdir -p /emblem/ai +ADD . /emblem/ai/ +RUN bash -c 'source /venv/bin/activate && pip install -i https://mirrors.ustc.edu.cn/pypi/simple loguru tqdm' +CMD bash -c 'source /venv/bin/activate && cd /emblem/ai && python3 server.py' \ No newline at end of file diff --git a/emblem5/ai/Makefile b/emblem5/ai/Makefile new file mode 100644 index 0000000..6aebc8d --- /dev/null +++ b/emblem5/ai/Makefile @@ -0,0 +1,17 @@ +IMG_TAG := $(shell date +%Y%m%d-%H%M%S)-$(shell git rev-parse --short HEAD) +IMG_NAME := registry.cn-shenzhen.aliyuncs.com/emblem/infer:$(IMG_TAG) + +default: build push + +build: + docker build -t $(IMG_NAME) . + +push: + docker push $(IMG_NAME) + +deploy: build push + kubectl --kubeconfig=../deploy/kubeconfig.themblem -n emblem set image deployment/infer infer=$(IMG_NAME) + kubectl --kubeconfig=../deploy/kubeconfig.themblem -n emblem rollout status --timeout=300s deployment/infer + +train: + ./train.py diff --git a/emblem5/ai/browser.py b/emblem5/ai/browser.py new file mode 100644 index 0000000..ab82913 --- /dev/null +++ b/emblem5/ai/browser.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +import os +import streamlit as st +import random +import json +from PIL import Image + +def get_mispredicted_scans(): + with open('data/verify2.log', 'r') as f: + lines = f.readlines() + for line in lines: + fields = line.split() + if len(fields) != 6: + continue + if fields[1] != fields[2]: + yield fields[0] + +def main(): + st.title('Browser') + + # scan_ids = os.listdir('data/scans') + # to_show = sorted(scan_ids, key=lambda x: int(x), reverse=True)[:100] + to_show = list(get_mispredicted_scans()) + st.write(f'to show: {len(to_show)}') + for sid in to_show: + show_scan(sid) + +def show_scan(scan_id): + scan_dir = f'data/scans/{scan_id}' + mdfile = f'{scan_dir}/metadata.json' + md = json.load(open(mdfile)) + if not os.path.exists(mdfile): + return + sbs = Image.open(f'{scan_dir}/sbs.jpg') + st.write(f'{scan_id}: {md["labels"]}') + st.image(sbs.resize((512, 256))) + st.divider() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/emblem5/ai/common.py b/emblem5/ai/common.py new file mode 100644 index 0000000..53f5552 --- /dev/null +++ b/emblem5/ai/common.py @@ -0,0 +1,791 @@ +#!/usr/bin/env python3 +import sys +import torch +import torch.nn as nn +import torch.optim as optim +from torch.amp import autocast, GradScaler +from torch.utils.data import DataLoader, Dataset, ConcatDataset +import torchvision +from PIL import Image, ImageFilter +import os +from datetime import datetime +from collections import defaultdict +import argparse +from kornia.losses.focal import FocalLoss +from kornia.augmentation import ColorJiggle +import cv2 +import numpy as np +import random +import re +import shutil +import json +import tempfile +import time +import base64 +import subprocess +from loguru import logger +from collections import defaultdict +from multiprocessing import Pool, cpu_count, set_start_method +from tqdm import tqdm +import importlib + +concurrency = max(1, cpu_count() - 2) + +def info(msg): + logger.info(msg) + +def debug(msg): + logger.debug(msg) + +cuda_available = torch.cuda.is_available() +device = torch.device('cuda' if cuda_available else 'cpu') +default_model = 'best_model_ep82_pos98.94_neg96.13_20250720_222102.pt' +clarity_model = 'models/clarity-ep15-pos88.14-neg92.23-20250518_164155.pt' + +torch.set_float32_matmul_precision('high') + +def batch_generator(labels, batch_size): + for i in range(0, len(labels), batch_size): + yield labels[i:i+batch_size] + +def make_side_by_side_img(left, right): + min_width = min(left.width, right.width) + min_height = min(left.height, right.height) + left = left.resize((min_width, min_height)) + right = right.resize((min_width, min_height)) + ret = Image.new('RGB', (min_width * 2, min_height)) + ret.paste(left, (0, 0)) + ret.paste(right, (min_width, 0)) + return ret + +def warp_with_margin_ratio(orig, edge, corners, margin_ratio): + src_points = np.float32(corners) + dst_points = np.float32([ + [edge * margin_ratio, edge * margin_ratio], + [edge * (1 - margin_ratio), edge * margin_ratio], + [edge * (1 - margin_ratio), edge * (1 - margin_ratio)], + [edge * margin_ratio, edge * (1 - margin_ratio)], + ]) + M = cv2.getPerspectiveTransform(src_points, dst_points) + warped = cv2.warpPerspective(np.array(orig), M, (edge, edge)) + return Image.fromarray(warped) + +def find_min_margin_ratio(img, corners): + min_margin = None + for i in range(4): + point = corners[i] + x = point[0] + y = point[1] + this_min = min( + x / img.width, + (img.width - x) / img.width, + y / img.height, + (img.height - y) / img.height, + ) + if min_margin is None or this_min < min_margin: + min_margin = this_min + return min_margin + +def make_side_by_side_img_with_margins(frame_img, std_img): + std_qr, std_corners = find_qr(std_img) + frame_qr, frame_corners = find_qr(frame_img) + if std_corners is None or frame_corners is None: + return None + + edge_length = min(std_img.width, std_img.height) + margin_ratio = find_min_margin_ratio(std_img, std_corners) + std_warped = warp_with_margin_ratio(std_img, edge_length, std_corners, margin_ratio) + frame_warped = warp_with_margin_ratio(frame_img, edge_length, frame_corners, margin_ratio) + ret = Image.new('RGB', (edge_length, int(edge_length * margin_ratio))) + ret.paste(std_warped, (0, 0)) + ret.paste(frame_warped, (0, int(edge_length * margin_ratio))) + + return ret + +def get_top_margin(img, margin_ratio): + ret = Image.new('RGB', (img.width, int(img.height * margin_ratio))) + ret.paste(img, (0, 0)) + return ret + +def make_top_margin_stacked_img(frame_img, std_img): + std_qr, std_corners = find_qr(std_img) + frame_qr, frame_corners = find_qr(frame_img) + if std_corners is None or frame_corners is None: + return None + + edge_length = min(std_img.width, std_img.height) + margin_ratio = find_min_margin_ratio(std_img, std_corners) + std_warped = warp_with_margin_ratio(std_img, edge_length, std_corners, margin_ratio) + frame_warped = warp_with_margin_ratio(frame_img, edge_length, frame_corners, margin_ratio) + std_top_margin = get_top_margin(std_warped, margin_ratio) + frame_top_margin = get_top_margin(frame_warped, margin_ratio) + outheight = int(edge_length * margin_ratio * 2) + ret = Image.new('RGB', (edge_length, outheight)) + ret.paste(std_top_margin, (0, 0)) + ret.paste(frame_top_margin, (0, outheight // 2)) + + return ret + +def make_stripe_img(left, right, nstripes): + min_width = min(left.width, right.width) + min_height = min(left.height, right.height) + ret = Image.new('RGB', (min_width * 2, min_height)) + left_stripe_width = left.width // nstripes + right_stripe_width = right.width // nstripes + stripe_width = min_width // nstripes + for i in range(nstripes): + left_stripe = left.crop((i * left_stripe_width, 0, (i + 1) * left_stripe_width, left.height)) + left_stripe = left_stripe.resize((stripe_width, min_height)) + right_stripe = right.crop((i * right_stripe_width, 0, (i + 1) * right_stripe_width, right.height)) + right_stripe = right_stripe.resize((stripe_width, min_height)) + ret.paste(left_stripe, (i * stripe_width * 2, 0)) + ret.paste(right_stripe, (i * stripe_width * 2 + stripe_width, 0)) + return ret + +def predict_multi(model, transforms, images, ncells=1): + results_per_img = ncells * ncells * 2 + ret = [] + with torch.no_grad(): + tensors = [] + for image in images: + for xcoord in range(ncells): + for ycoord in range(ncells): + img = crop_side_by_side(image, ncells, xcoord, ycoord) + img_tensor = transforms(img).to(device) + tensors.append(img_tensor) + output = model(torch.stack(tensors, dim=0)) + sub_probs = torch.nn.functional.softmax(output, dim=1).cpu().numpy().tolist() + for i in range(len(images)): + probs = sub_probs[i * results_per_img:(i + 1) * results_per_img] + neg_sum = sum([x[0] for x in probs]) + pos_sum = sum([x[1] for x in probs]) + predicted_class = 1 if pos_sum > neg_sum else 0 + ret.append((predicted_class, probs)) + return ret + +def predict(model, transforms, image, ncells=1): + r = predict_multi(model, transforms, [image], ncells) + return r[0] + +qr_detector = cv2.wechat_qrcode_WeChatQRCode() + +def find_qr(img, scale=1.0): + # Convert PIL Image to OpenCV format + orig_size = img.size + if scale < 1.0: + img_w, img_h = img.size + new_w = int(img_w * scale) + new_h = int(img_h * scale) + new_size = (new_w, new_h) + resized_img = img.resize(new_size) + else: + new_size = orig_size + resized_img = img + img_cv = cv2.cvtColor(np.array(resized_img), cv2.COLOR_RGB2BGR) + qr, corners = qr_detector.detectAndDecode(img_cv) + if not qr: + if scale > 0.05: + return find_qr(img, scale * 2 / 3) + else: + return None, None + corners = np.array(corners[0], dtype=np.float32) + corners /= scale + return qr[0], corners + +def extract_qr(img): + qr, corners = find_qr(img) + if not qr: + raise Exception('No QR code found') + corners = np.array(corners, dtype=np.float32) + + img_cv = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) + # Define target rectangle corners (clockwise from top-left) + min_x = min(corners[:, 0]) + max_x = max(corners[:, 0]) + min_y = min(corners[:, 1]) + max_y = max(corners[:, 1]) + width = max_x - min_x + height = max_y - min_y + width = height = int(min(width, height)) + dst_corners = np.array([ + [0, 0], + [width, 0], + [width, height], + [0, height] + ], dtype=np.float32) + + matrix = cv2.getPerspectiveTransform(corners, dst_corners) + warped = cv2.warpPerspective(img_cv, matrix, (width, height)) + r = Image.fromarray(cv2.cvtColor(warped, cv2.COLOR_BGR2RGB)) + return qr, r + +def load_model(model_path): + checkpoint = torch.load(model_path, map_location=device, weights_only=False) + model = checkpoint['model'] # Load the complete model structure + model.load_state_dict(checkpoint['model_state_dict']) # Load the weights + model.eval() + model = model.to(device) + transforms = checkpoint['transforms'] + return model, transforms + +def save_model(model, transforms, save_path, metadata=None): + checkpoint = { + 'model': model, # Save the complete model structure + 'model_state_dict': model.state_dict(), + 'transforms': transforms + } + if metadata: + checkpoint['metadata'] = metadata + torch.save(checkpoint, save_path) + +def make_model(model_name): + model_makers = { + 'resnet': make_resnet, + 'resnet18': make_resnet18, + 'resnet101': make_resnet101, + 'regnet': make_regnet, + 'convnext': make_convnext, + 'efficientnet': make_efficientnet, + 'densenet': make_densenet, + 'mobilenet': make_mobilenet, + } + return model_makers[model_name]() + +def make_mobilenet(): + weights = torchvision.models.MobileNet_V3_Small_Weights.IMAGENET1K_V1 + model = torchvision.models.mobilenet_v3_small(weights=weights) + model.classifier = nn.Sequential( + nn.Dropout(p=0.3), + nn.Linear(576, 128), + nn.GELU(), + nn.Dropout(p=0.2), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_densenet(): + weights = models.DenseNet121_Weights.IMAGENET1K_V1 + model = models.densenet121(weights=weights) + model.classifier = nn.Sequential( + nn.Dropout(p=0.4), + nn.Linear(1024, 512), + nn.GELU(), + nn.Dropout(p=0.3), + nn.Linear(512, 128), + nn.GELU(), + nn.Dropout(p=0.2), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_efficientnet(): + weights = torchvision.models.EfficientNet_B3_Weights.IMAGENET1K_V1 + model = torchvision.models.efficientnet_b3(weights=weights) + model.classifier = nn.Sequential( + nn.Dropout(p=0.4), + nn.Linear(1536, 512), + nn.GELU(), + nn.Dropout(p=0.3), + nn.Linear(512, 128), + nn.GELU(), + nn.Dropout(p=0.2), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_convnext(): + weights = torchvision.models.ConvNeXt_Base_Weights.IMAGENET1K_V1 + model = torchvision.models.convnext_base(weights=weights) + model.classifier = nn.Sequential( + nn.Flatten(1), # 先 flatten (从 [B, 1024, 1, 1] 到 [B, 1024]) + nn.LayerNorm(1024, eps=1e-6), + nn.Dropout(p=0.4), + nn.Linear(1024, 512), + nn.GELU(), + nn.Dropout(p=0.3), + nn.Linear(512, 128), + nn.GELU(), + nn.Dropout(p=0.2), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_resnet101(): + weights = torchvision.models.ResNet101_Weights.IMAGENET1K_V1 + model = torchvision.models.resnet101(weights=weights) + model.fc = nn.Sequential( + nn.Dropout(p=0.4), + nn.Linear(2048, 512), + nn.GELU(), + nn.Dropout(p=0.3), + nn.Linear(512, 128), + nn.GELU(), + nn.Dropout(p=0.2), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_resnet18(): + weights = torchvision.models.ResNet18_Weights.IMAGENET1K_V1 + model = torchvision.models.resnet18(weights=weights) + model.fc = nn.Sequential( + nn.Dropout(p=0.4), + nn.Linear(512, 128), + nn.GELU(), + nn.Dropout(p=0.3), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_resnet(): + weights = torchvision.models.ResNet50_Weights.IMAGENET1K_V1 + model = torchvision.models.resnet50(weights=weights) + model.fc = nn.Sequential( + nn.Dropout(p=0.4), + nn.Linear(2048, 512), + nn.GELU(), + nn.Dropout(p=0.3), + nn.Linear(512, 128), + nn.GELU(), + nn.Dropout(p=0.2), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_regnet(): + weights = models.RegNet_Y_3_2GF_Weights.IMAGENET1K_V1 + model = models.regnet_y_3_2gf(weights=weights) + model.fc = nn.Sequential( + nn.Dropout(p=0.4), + nn.Linear(1512, 512), + nn.GELU(), + nn.Dropout(p=0.3), + nn.Linear(512, 128), + nn.GELU(), + nn.Dropout(p=0.1), + nn.Linear(128, 2) + ) + return model, make_generic_transforms() + +def make_generic_transforms(): + return torchvision.transforms.Compose([ + torchvision.transforms.Resize((128, 256)), + torchvision.transforms.ToTensor(), + torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + ]) + +class ScanDataset(Dataset): + def __init__(self, scans, transforms): + self.transforms = transforms + self.scans = scans + + def __len__(self): + return len(self.scans) + + def __getitem__(self, idx): + scan = self.scans[idx] + scan_id = scan['scan_id'] + gridcrop2_dir = os.path.join('data', 'gridcrop2', scan_id) + sbs_file = os.path.join(gridcrop2_dir, 'sbs.jpg') + sbs_img = Image.open(sbs_file).convert('RGB') + return self.transforms(sbs_img), 1 if 'pos' in scan['labels'] else 0 + + def stats(self): + return { + 'pos': sum(1 for scan in self.scans if 'pos' in scan['labels']), + 'neg': sum(1 for scan in self.scans if 'neg' in scan['labels']), + } + +def do_train(cfg): + train_dataset = cfg['train_dataset'] + val_dataset = cfg['val_dataset'] + + batch_size = cfg['batch_size'] + num_workers = cfg['num_workers'] + + prefetch_factor = 4 + train_loader = DataLoader( + train_dataset, + batch_size=batch_size, + shuffle=True, + num_workers=num_workers, + persistent_workers=True, + prefetch_factor=prefetch_factor, + pin_memory=True, + ) + val_loader = DataLoader( + val_dataset, + batch_size=batch_size*2, + shuffle=True, + num_workers=num_workers, + persistent_workers=True, + prefetch_factor=prefetch_factor, + pin_memory=True, + ) + + model = cfg['model'] + + # Set memory fraction for better GPU utilization + torch.cuda.set_per_process_memory_fraction(0.8) + + # Compile model with optimized settings + model = torch.compile(model).to(device) + + criterion = cfg['criterion'] + optimizer = cfg['optimizer'](model) + scheduler = cfg['scheduler'](optimizer) + max_epochs = cfg['max_epochs'] + + # Initialize variables for early stopping + best_epoch = None + + # Create GradScaler once at the start of training + scaler = torch.amp.GradScaler('cuda') + + for epoch in range(max_epochs): + info(f"Starting epoch {epoch+1}/{max_epochs}") + model.train() + running_loss = 0.0 + + for images, labels in tqdm(train_loader, desc=f"Train {epoch+1}/{max_epochs}", unit_scale=batch_size): + images, labels = images.to(device, non_blocking=True), labels.to(device, non_blocking=True) + optimizer.zero_grad() + with torch.amp.autocast(device_type='cuda', dtype=torch.float16): + outputs = model(images) + loss = criterion(outputs, labels).mean() + scaler.scale(loss).backward() + scaler.step(optimizer) + scaler.update() + running_loss += loss.detach().item() * len(images) + + running_loss = running_loss / len(train_loader) / cfg['learning_rate'] + info(f'Epoch [{epoch+1}/{max_epochs}], Loss: {running_loss:.5f}') + + # 验证阶段 + model.eval() + pos_correct = 0 + pos_total = 0 + neg_correct = 0 + neg_total = 0 + with torch.no_grad(): + for images, labels in tqdm(val_loader, desc=f"Validating {epoch+1}/{max_epochs}", unit_scale=batch_size): + images, labels = images.to(device), labels.to(device) + outputs = model(images) + _, predicted = torch.max(outputs.data, 1) + pos_correct += ((predicted == labels) & (labels == 1)).sum().item() + pos_total += (labels == 1).sum().item() + neg_correct += ((predicted == labels) & (labels == 0)).sum().item() + neg_total += (labels == 0).sum().item() + + pos_accu = pos_correct / pos_total if pos_total else 0 + neg_accu = neg_correct / neg_total if neg_total else 0 + total_accu = (pos_correct + neg_correct) / (pos_total + neg_total) + info(f'Pos Accu: {pos_accu:.2%} ({pos_correct}/{pos_total})') + info(f'Neg Accu: {neg_accu:.2%} ({neg_correct}/{neg_total})') + info(f'Total Accu: {total_accu:.2%} ({pos_correct + neg_correct}/{pos_total + neg_total})') + + if not best_epoch or total_accu > best_epoch['total_accu']: + best_epoch = { + 'epoch': epoch, + 'pos_accu': pos_accu, + 'neg_accu': neg_accu, + 'total_accu': total_accu, + 'model_state_dict': model.state_dict().copy(), + } + info(f'New best model found with total accuracy: {best_epoch["total_accu"]:.2%}') + + scheduler.step(total_accu) + + # Load the best model weights + if best_epoch is not None: + model.load_state_dict(best_epoch['model_state_dict']) + info(f'Loaded best model with total accuracy: {best_epoch["total_accu"]:.2%}') + + return model, best_epoch + +def verify_frame(model, transforms, frame_img, orig_img): + side_by_side_img = make_side_by_side_img_with_margins(frame_img, orig_img) + if side_by_side_img is None: + raise Exception("Failed to create side-by-side image with margins") + side_by_side_img = side_by_side_img.convert('RGB') + with tempfile.NamedTemporaryFile(suffix='.jpg') as f: + side_by_side_img.save(f.name) + return predict(model, transforms, Image.open(f.name).convert('RGB')) + +def parse_ranges(s): + ret = [] + for tr in s.split(','): + if '-' in tr: + begin, end = tr.split('-') + ret.append([int(begin), int(end)]) + else: + ret.append([int(tr), int(tr)]) + return ret + +def in_range(x, val_range): + if not val_range: + return False + start, end = val_range + return start <= int(x) <= end + +def train_model(model, train_dataset, val_dataset, max_epochs, pos_weight=0.99): + info(f"Train count: {len(train_dataset)}, val count: {len(val_dataset)}") + learning_rate = 0.001 + cfg = { + 'model': model, + 'train_dataset': train_dataset, + 'val_dataset': val_dataset, + 'criterion': FocalLoss(0.25, weight=torch.Tensor([1.0 - pos_weight, pos_weight]).to(device)), + 'learning_rate': learning_rate, + 'optimizer': lambda model: optim.AdamW( + model.parameters(), + lr=learning_rate, + weight_decay=0.001, + betas=(0.9, 0.999), + eps=1e-8 + ), + 'batch_size': 32, + 'max_epochs': max_epochs, + 'scheduler': lambda optimizer: torch.optim.lr_scheduler.ReduceLROnPlateau( + optimizer, + mode='max', + factor=0.1, + patience=3, + min_lr=1e-6 + ), + 'num_workers': concurrency, + } + + return do_train(cfg) + +def motion_blur_indicator(image): + def f(img): + equalized = cv2.equalizeHist(np.array(img)) + sobelx = cv2.Sobel(equalized, cv2.CV_64F, 1, 0, ksize=3) + sobely = cv2.Sobel(equalized, cv2.CV_64F, 0, 1, ksize=3) + + var_x = sobelx.var() + var_y = sobely.var() + + ratio = min(var_x, var_y) / max(var_x, var_y) + + return ratio + return f(image) * f(image.rotate(45)) + +def calc_clarity(img): + gray = img.convert('L') + blurred = gray.filter(ImageFilter.GaussianBlur(radius=1.5)) + equalized = cv2.equalizeHist(np.array(blurred)) + lap = cv2.Laplacian(equalized, cv2.CV_64F) + return lap.var() * motion_blur_indicator(gray) + +def load_codes(codes_file): + with open(codes_file, 'r') as f: + return [line.strip() for line in f.readlines() if line.strip()] + +def load_cell_labels(dataset_dir): + if not os.path.exists(dataset_dir): + raise Exception(f"Dataset directory {dataset_dir} does not exist") + neg_labels = [] + pos_labels = [] + all_files = [] + for label in ["pos", "neg"]: + for r, ds, fs in os.walk(os.path.join(dataset_dir, label)): + for f in fs: + if f.startswith('cell_') and f.endswith('.jpg'): + fp = os.path.join(r, f) + all_files.append((label, fp)) + random.shuffle(all_files) + for label, fp in all_files: + jpg_file = fp + json_file = os.path.join(os.path.dirname(fp), "metadata.json") + if not os.path.exists(json_file): + continue + with open(json_file, 'r') as f: + md = json.load(f) + if 'code' not in md: + continue + code = md['code'] + if label == "pos": + pos_labels.append((jpg_file, 1)) + else: + neg_labels.append((jpg_file, 0)) + total_pos = len(pos_labels) + total_neg = len(neg_labels) + info(f"Total positive: {total_pos}, total negative: {total_neg}") + if not total_pos: + raise Exception("No positive labels found") + if not total_neg: + raise Exception("No negative labels found") + return pos_labels, neg_labels + +def crop_side_by_side(img, cells, xcoord, ycoord, jitter=False): + width = img.width // (cells * 2) + height = img.height // cells + left = img.crop((xcoord * width, ycoord * height, (xcoord + 1) * width, (ycoord + 1) * height)) + right = img.crop(((xcoord + cells) * width, ycoord * height, (xcoord + cells + 1) * width, (ycoord + 1) * height)) + + if jitter: + movement = 0.02 + left = torchvision.transforms.RandomAffine(degrees=0, translate=(movement, movement))(left) + right = torchvision.transforms.RandomAffine(degrees=0, translate=(movement, movement))(right) + ret = Image.new('RGB', (width * 2, height)) + ret.paste(left, (0, 0)) + ret.paste(right, (width, 0)) + if jitter: + ret = torchvision.transforms.ColorJitter(brightness=0.2, saturation=0.2, hue=0.5)(ret) + return ret + +def average(values): + return sum(values) / len(values) + +def random_sample(values, count): + if len(values) <= count: + return values + return random.sample(values, count) + +class ClarityPredictor(object): + def __init__(self, model_path=clarity_model): + self.model_path = clarity_model + self.model = None + + def __call__(self, img): + if not self.model: + if not os.path.exists(self.model_path): + return None + self.model, self.transforms = load_model(self.model_path) + tensor = self.transforms(img).to(device).unsqueeze(0) + with torch.no_grad(): + output = self.model(tensor) + return output.argmax(dim=1).detach().cpu().item() == 1 + +clarity_predictor = ClarityPredictor() + +class BaseMethod(object): + def __init__(self, datadir): + self.datadir = datadir + + def preprocess(self, scans): + pass + + def load_scans(self, datadir, sample_rate=1.0): + self.datadir = datadir + pool = Pool(concurrency) + counts = defaultdict(int) + pos_scans = [] + neg_scans = [] + all_scan_ids = os.listdir(os.path.join(datadir, "scans")) + if sample_rate < 1.0: + all_scan_ids = random.sample(all_scan_ids, int(len(all_scan_ids) * sample_rate)) + for x in tqdm(pool.imap(self.load_one_scan, all_scan_ids), total=len(all_scan_ids), desc="Loading dataset"): + counts[(x.get('ok'), x.get('error'), x.get('lables'))] += 1 + if x.get('ok'): + labels = x['data'].get('labels', []) + if 'pos' in labels: + pos_scans.append(x['data']) + elif 'neg' in labels: + neg_scans.append(x['data']) + info(f"Counts: {counts}") + return sorted(pos_scans, key=lambda x: int(x['scan_id'])), sorted(neg_scans, key=lambda x: int(x['scan_id'])) + + def pre_load_one_scan(self, scan_id): + return True + + def load_one_scan(self, scan_id): + if not self.pre_load_one_scan(scan_id): + return { + "ok": False, + "error": f"pre_load_one_scan: skip", + } + scan_dir = os.path.join(self.datadir, 'scans', scan_id) + if not os.path.exists(scan_dir): + return { + "ok": False, + "error": f"Scan dir does not exist", + } + std_qr_file = os.path.join(scan_dir, "std-qr.jpg") + if not os.path.exists(std_qr_file): + return { + "ok": False, + "error": f"Std QR file does not exist", + } + mdfile = os.path.join(scan_dir, "metadata.json") + if not os.path.exists(mdfile): + return { + "ok": False, + "error": f"Metadata file does not exist", + } + with open(mdfile, 'r') as f: + try: + md = json.load(f) + except Exception as e: + return { + "ok": False, + "error": f"Error loading metadata file: {e}", + } + if not md.get('code'): + return { + "ok": False, + "error": f"Code not found in metadata file", + } + if not md.get('labels'): + return { + "ok": False, + "error": f"Labels not found in metadata file", + } + if not md.get('relative_clarity'): + std_qr_img = Image.open(std_qr_file) + std_qr_clarity = calc_clarity(std_qr_img) + if not std_qr_clarity: + return { + "ok": False, + "error": f"Std QR clarity invalid", + } + frame_qr_file = os.path.join(scan_dir, "frame-qr.jpg") + if not os.path.exists(frame_qr_file): + return { + "ok": False, + "error": f"Frame QR file does not exist", + } + frame_qr_img = Image.open(frame_qr_file) + frame_qr_clarity = calc_clarity(frame_qr_img) + relative_clarity = frame_qr_clarity / std_qr_clarity + md['relative_clarity'] = relative_clarity + with open(mdfile, 'w') as f: + json.dump(md, f, indent=2) + if md['relative_clarity'] < 0.5: + return { + "ok": False, + "error": f"Relative clarity too low", + } + self.post_load_one_scan(scan_id) + return { + "ok": True, + "data": { + "scan_id": scan_id, + "std_qr_file": std_qr_file, + "code": md['code'], + "labels": md['labels'], + }, + } + + def train(self, dataset, epochs): + raise Exception("Not implemented") + +def load_method(method_name, datadir): + mod = importlib.import_module('methods.' + method_name) + return mod.Method(datadir) + +def balance_pos_and_neg(scans): + pos_scans = [s for s in scans if 'pos' in s['labels']] + neg_scans = [s for s in scans if 'neg' in s['labels']] + random.shuffle(pos_scans) + random.shuffle(neg_scans) + min_count = min(len(pos_scans), len(neg_scans)) + pos = pos_scans[:min_count] + neg = neg_scans[:min_count] + info(f'balanced from pos: {len(pos_scans)} to {len(pos)}') + info(f'balanced from neg: {len(neg_scans)} to {len(neg)}') + ret = pos + neg + random.shuffle(ret) + return ret diff --git a/emblem5/ai/download.py b/emblem5/ai/download.py new file mode 100755 index 0000000..7ff9b6d --- /dev/null +++ b/emblem5/ai/download.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +import oss2 +import sys +import os + +oss_ak = 'LTAI5tC2qXGxwHZUZP7DoD1A' +oss_sk = 'qPo9O6ZvEfqo4t8oflGEm0DoxLHJhm' + +auth = oss2.Auth(oss_ak, oss_sk) +endpoint = 'https://oss-rg-china-mainland.aliyuncs.com' +bucket = oss2.Bucket(auth, endpoint, 'emblem-models') + +for x in sys.argv[1:]: + bucket.get_object_to_file(x, 'models/' + x) + diff --git a/emblem5/ai/fetch-scans.py b/emblem5/ai/fetch-scans.py new file mode 100755 index 0000000..a72f620 --- /dev/null +++ b/emblem5/ai/fetch-scans.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 + +import argparse +import os +import requests +import json +import multiprocessing as mp +from loguru import logger +import shutil +from PIL import Image +from ossclient import * +from common import * +import io +from tqdm import tqdm +import datetime + +data_dir = 'data' + +class ScanDataFetcher(object): + def __init__(self): + self.token = '3ebd8c33-f46e-4b06-bda8-4c0f5f5eb530' + + def make_headers(self): + return { + 'Authorization': f'Token {self.token}' + } + + def load_local_scan_data(self): + ret = {} + scans_dir = os.path.join(data_dir, 'scans') + os.makedirs(scans_dir, exist_ok=True) + for scan_id in os.listdir(scans_dir): + scan_dir = os.path.join(scans_dir, scan_id) + if not os.path.isdir(scan_dir): + continue + fetch_state_path = os.path.join(scan_dir, 'fetch-state.json') + if not os.path.exists(fetch_state_path): + continue + metadata_path = os.path.join(scan_dir, 'metadata.json') + if not os.path.exists(metadata_path): + continue + md = json.load(open(metadata_path)) + ret[md['id']] = md + return ret + + def fetch(self, sample_rate=None): + local_scan_data = self.load_local_scan_data() + logger.info(f'local_scan_data: {len(local_scan_data)}') + url = 'https://themblem.com/api/v1/scan-data-labels/' + r = requests.get(url, headers=self.make_headers()) + data = r.json() + fetch_backlog = [] + for item in data['items']: + if 'code' not in item or 'id' not in item or not item.get('labels') or 'image' not in item: + continue + if item['id'] in local_scan_data: + local_labels = local_scan_data[item['id']]['labels'] + if local_labels == item['labels']: + continue + fetch_backlog.append(item) + if sample_rate: + fetch_backlog = random.sample(fetch_backlog, int(len(fetch_backlog) * sample_rate)) + logger.info(f'fetch_backlog: {len(fetch_backlog)}') + pool = mp.Pool(mp.cpu_count() * 4) + counts = defaultdict(int) + for r in tqdm(pool.imap_unordered(self.fetch_one_scan, fetch_backlog), total=len(fetch_backlog)): + counts[r] += 1 + logger.info(f'counts: {counts}') + pool.close() + pool.join() + + def fetch_one_scan(self, scan): + try: + self.do_fetch_one_scan(scan) + return 'ok' + except Exception as e: + scan_dir = os.path.join(data_dir, 'scans', str(scan['id'])) + fetch_state_path = os.path.join(scan_dir, 'fetch-state.json') + with open(fetch_state_path, 'w') as f: + json.dump({ + 'status': 'error', + 'timestamp': datetime.datetime.now().isoformat(), + 'scan_id': scan['id'], + 'labels': scan.get('labels', ''), + 'error': str(e) + }, f, indent=2) + return 'error' + + def do_fetch_one_scan(self, scan): + scan_dir = os.path.join(data_dir, 'scans', str(scan['id'])) + os.makedirs(scan_dir, exist_ok=True) + + # Check if fetch-state.json exists, if so skip this scan + fetch_state_path = os.path.join(scan_dir, 'fetch-state.json') + if os.path.exists(fetch_state_path): + return + + metadata_path = os.path.join(scan_dir, 'metadata.json') + metadata_str = json.dumps(scan, indent=2) + frame_img_url = f'https://themblem.com/api/v1/oss-image/?token={self.token}&name={scan["image"]}' + frame_img_file = os.path.join(scan_dir, 'frame.jpg') + if not os.path.exists(frame_img_file): + frame_img_bytes = requests.get(frame_img_url).content + with open(frame_img_file, 'wb') as f: + f.write(frame_img_bytes) + std_img_file = os.path.join(scan_dir, 'std.jpg') + if not os.path.exists(std_img_file): + std_img = Image.open(io.BytesIO(get_qr_image_bytes(scan['code']))) + std_img.save(std_img_file) + with open(metadata_path, 'w') as f: + f.write(metadata_str) + frame_qr_img_file = os.path.join(scan_dir, 'frame-qr.jpg') + if not os.path.exists(frame_qr_img_file): + frame_img = Image.open(frame_img_file) + _, frame_qr = extract_qr(frame_img) + frame_qr.save(frame_qr_img_file) + std_qr_img_file = os.path.join(scan_dir, 'std-qr.jpg') + if not os.path.exists(std_qr_img_file): + std_img = Image.open(std_img_file) + _, std_qr = extract_qr(std_img) + std_qr.save(std_qr_img_file) + + # Create fetch-state.json to mark successful completion + fetch_state = { + 'status': 'completed', + 'timestamp': datetime.datetime.now().isoformat(), + 'scan_id': scan['id'], + 'labels': scan.get('labels', ''), + } + + with open(fetch_state_path, 'w') as f: + json.dump(fetch_state, f, indent=2) + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--data-dir', type=str, default='data') + parser.add_argument('--sample-rate', '-r', type=float) + return parser.parse_args() + +def main(): + args = parse_args() + global data_dir + data_dir = args.data_dir + fetcher = ScanDataFetcher() + logger.info('fetch') + fetcher.fetch(args.sample_rate) + +if __name__ == "__main__": + main() diff --git a/emblem5/ai/make-sbs.py b/emblem5/ai/make-sbs.py new file mode 100755 index 0000000..33ceb13 --- /dev/null +++ b/emblem5/ai/make-sbs.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +import os +import sys +import json +import random +import argparse +from common import * + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--data-dir', required=True) + return parser.parse_args() + +def process_scan(scan_dir): + if not os.path.isdir(scan_dir): + return "scan_dir not found" + frame_file = os.path.join(scan_dir, 'frame.jpg') + std_file = os.path.join(scan_dir, 'std.jpg') + if not os.path.exists(frame_file) or not os.path.exists(std_file): + return "frame.jpg or std.jpg not found" + sbs_file = os.path.join(scan_dir, 'sbs.jpg') + frame_qr_file = os.path.join(scan_dir, 'frame-qr.jpg') + std_qr_file = os.path.join(scan_dir, 'std-qr.jpg') + sbs_no_margin_file = os.path.join(scan_dir, 'sbs-nomargin.jpg') + try: + if not os.path.exists(sbs_file): + frame_img = Image.open(frame_file) + std_img = Image.open(std_file) + sbs_img = make_side_by_side_img_with_margins(frame_img, std_img) + if sbs_img: + sbs_img.save(sbs_file) + else: + return "make_side_by_side_img_with_margins failed" + if not os.path.exists(sbs_no_margin_file): + frame_img = Image.open(frame_file) + std_img = Image.open(std_file) + if not os.path.exists(frame_qr_file) or not os.path.exists(std_qr_file): + frame_qrcode, frame_qr_img = extract_qr(frame_img) + std_qrcode, std_qr_img = extract_qr(std_img) + frame_qr_img.save(frame_qr_file) + std_qr_img.save(std_qr_file) + else: + frame_qr_img = Image.open(frame_qr_file) + std_qr_img = Image.open(std_qr_file) + sbs_no_margin_img = make_side_by_side_img(frame_qr_img, std_qr_img) + sbs_no_margin_img.save(sbs_no_margin_file) + return "ok" + except Exception as e: + return f"error: {e}" + +def main(): + args = parse_args() + data_dir = args.data_dir + scans_dir = os.path.join(data_dir, 'scans') + pool = Pool(cpu_count()) + scan_ids = os.listdir(scans_dir) + counts = defaultdict(int) + for result in tqdm(pool.imap(process_scan, [os.path.join(scans_dir, scan_id) for scan_id in scan_ids]), total=len(scan_ids)): + counts[result] += 1 + for k, v in counts.items(): + print(f"{k}: {v}") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/emblem5/ai/ossclient.py b/emblem5/ai/ossclient.py new file mode 100644 index 0000000..763a864 --- /dev/null +++ b/emblem5/ai/ossclient.py @@ -0,0 +1,26 @@ +import oss2 +import re + +oss_ak = 'LTAI5tC2qXGxwHZUZP7DoD1A' +oss_sk = 'qPo9O6ZvEfqo4t8oflGEm0DoxLHJhm' + +def oss_get_object(endpoint, bucket_name, key): + auth = oss2.Auth(oss_ak, oss_sk) + bucket = oss2.Bucket(auth, endpoint, bucket_name) + return bucket.get_object(key) + +def oss_put_object(endpoint, bucket_name, key, data): + auth = oss2.Auth(oss_ak, oss_sk) + bucket = oss2.Bucket(auth, endpoint, bucket_name) + bucket.put_object(key, data) + +def get_qr_image_bytes(qr_code): + code_re = re.compile(r'[0-9]{6,}') + m = code_re.search(qr_code) + if not m: + return None + code = m.group(0) + prefix = code[:2] + key = f'v5/{prefix}/{code}.jpg' + obj = oss_get_object('https://oss-cn-guangzhou.aliyuncs.com', 'emblem-qrs', key) + return obj.read() \ No newline at end of file diff --git a/emblem5/ai/server.py b/emblem5/ai/server.py new file mode 100755 index 0000000..104c230 --- /dev/null +++ b/emblem5/ai/server.py @@ -0,0 +1,328 @@ +#! /usr/bin/env python3 +import flask +import oss2 +import os +from PIL import Image +import re +from common import * +import io +import time +from ossclient import * +import argparse +import hashlib + +''' +Emblem infer service. + +This provides a simple http api for torchvision model inference. + +The model is downloaded from a predefined aliyun oss bucket. + +''' + +app = flask.Flask(__name__) + +local_model_dir = 'models' +data_dir = 'data' +scans_dir = os.path.join(data_dir, 'scans') + +os.makedirs(local_model_dir, exist_ok=True) + +def get_file_md5(fname): + return hashlib.md5(open(fname, 'rb').read()).hexdigest() + +def download_model(model_name): + model_path = os.path.join(local_model_dir, model_name) + if not os.path.exists(model_path): + obj = oss_get_object('https://oss-rg-china-mainland.aliyuncs.com', 'emblem-models', model_name) + with open(model_path, 'wb') as f: + f.write(obj.read()) + return model_path, get_file_md5(model_path) + +report_dir = '/tmp/emblem-reports/' +@app.route('/api/v5/report', methods=['POST']) +def report(): + os.makedirs(report_dir, exist_ok=True) + for file in flask.request.files.values(): + with open(os.path.join(report_dir, file.filename), 'wb') as f: + f.write(file.read()) + return { + "ok": True, + } + +@app.route('/api/v5/report/', methods=['GET']) +def report_file(name): + return flask.send_file(os.path.join(report_dir, name)) + +@app.route('/api/v5/qr_verify', methods=['POST']) +def qr_verify(): + try: + return do_qr_verify() + except Exception as e: + return { + "ok": False, + "error": str(e), + } + +def find_best_frame(files): + best_frame = None + clarities = {} + best_clarity = 0 + for file in files.values(): + img = Image.open(file) + img_qrcode, img_qr = extract_qr(img) + if not img_qrcode: + continue + clarity = calc_clarity(img_qr) + clarities[file.filename] = clarity + if not best_frame or clarity > best_clarity: + best_frame = img + best_clarity = clarity + return best_frame, clarities + +def do_qr_verify(): + start_time = time.time() + fd = flask.request.form + model_path, model_md5 = download_model(fd.get('model', default_model)) + model, transforms = load_model(model_path) + + frame_image, clarities = find_best_frame(flask.request.files) + frame_qrcode, _ = extract_qr(frame_image) + std_image = Image.open(io.BytesIO(get_qr_image_bytes(frame_qrcode))) + if not std_image: + return { + "ok": False, + "error": f"No std image: {frame_qrcode}", + } + std_qrcode, _ = extract_qr(std_image) + if frame_qrcode != std_qrcode: + return { + "ok": False, + "error": "QR code mismatch", + } + + predicted_class, probabilities = verify_frame(model, transforms, frame_image, std_image) + return { + "ok": True, + "result": { + "process_time": time.time() - start_time, + "predicted_class": predicted_class, + "probabilities": ', '.join([f'{v:.2%}' for k, v in probabilities]), + "clarities": clarities, + "model_md5": model_md5, + } + } + +def make_qrsbs(frame_qrcode, frame_image): + qr_img = get_qr_image(frame_qrcode) + if not qr_img: + return None + ret = make_side_by_side_img(frame_image, qr_img) + with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as f: + ret.save(f.name) + with open(f.name, 'rb') as f: + return f.read() + +@app.route('/api/v5/qrsbs', methods=['POST']) +def qrsb(): + frame = flask.request.files['frame'] + if not frame: + return { + "ok": False, + "error": "frame is required", + } + frame_image = Image.open(frame) + frame_qrcode, _ = extract_qr(frame_image) + cache_key = f'qrsbs_v1/{frame_qrcode}.jpg' + try: + qrsbs = oss_get_object('https://oss-cn-guangzhou.aliyuncs.com', 'emblem-cache', cache_key) + except Exception as e: + print(f'cache miss: {cache_key}') + qrsbs = make_qrsbs(frame_qrcode, frame_image) + if not qrsbs: + return flask.abort(404, 'QR code not found') + oss_put_object('https://oss-cn-guangzhou.aliyuncs.com', 'emblem-cache', cache_key, qrsbs) + return flask.send_file(io.BytesIO(qrsbs), mimetype='image/jpeg') + +@app.route('/api/v5/infer/version', methods=['GET']) +def version(): + return {'version': '1.0.0'} + +@app.route('/api/v5/frame//', methods=['POST']) +def frame(session_id, frame_id): + data = flask.request.get_data() + auth = oss2.Auth(oss_ak, oss_sk) + endpoint = 'https://oss-cn-shenzhen.aliyuncs.com' + bucket = oss2.Bucket(auth, endpoint, 'emblem-frames-prod') + bucket.put_object(f'v5/{session_id}/{frame_id}', data) + return { + "ok": True, + } + +def make_data_url(fname): + bs = open(fname, 'rb').read() + encoded = base64.b64encode(bs).decode() + return f'data:image/jpeg;base64,{encoded}' + +def bottomcorner(img): + width = img.width + height = img.height + return img.crop((width - width // 4, height - height // 4, width, height)) + +def prepare_clarities(scan_dir): + frame_img = Image.open(os.path.join(scan_dir, 'frame-qr.jpg')) + std_img = Image.open(os.path.join(scan_dir, 'std-qr.jpg')) + frame_clarity = int(calc_clarity(bottomcorner(frame_img))) + std_clarity = int(calc_clarity(bottomcorner(std_img))) + return { + 'relative': int(frame_clarity / std_clarity * 100), + 'frame': frame_clarity, + 'std': std_clarity, + } + +def prepare_scan(scan, predicted_classes={}): + scan_dir = os.path.join(scans_dir, scan) + if not os.path.exists(scan_dir): + return None + files = os.listdir(scan_dir) + mdfile = os.path.join(scan_dir, 'metadata.json') + if os.path.exists(mdfile): + with open(mdfile, 'r') as f: + md = json.load(f) + else: + md = {} + frame_qr = Image.open(os.path.join(scan_dir, 'frame-qr.jpg')) + std_qr = Image.open(os.path.join(scan_dir, 'std-qr.jpg')) + return { + 'name': scan, + 'files': files, + 'labels': md.get('labels', '').split(','), + 'predicted_class': predicted_classes.get(scan), + 'clarities': prepare_clarities(scan_dir), + 'frame_qr_size': [frame_qr.width, frame_qr.height], + 'std_qr_size': [std_qr.width, std_qr.height], + } + +def match_one_term(md, term, predicted_class): + if term in ['mispredicted', 'incorrect']: + if predicted_class is None: + return False + pcname = 'pos' if predicted_class else 'neg' + labels = md.get('labels', '') + return labels and pcname not in labels + if term == 'correct': + if predicted_class is None: + return False + pcname = 'pos' if predicted_class else 'neg' + labels = md.get('labels', '') + return labels and pcname in labels + if term == 'pos': + return 'pos' in md.get('labels', '') + if term == 'neg': + return 'neg' in md.get('labels', '') + if term == 'succeeded': + return md.get('succeeded') == True + if term == 'failed': + return md.get('succeeded') == False + if re.match(r'^[0-9]+-[0-9]+$', term): + fs = term.split('-') + return int(fs[0]) <= int(md.get('id')) <= int(fs[1]) + +def match_query(md, q, predicted_class): + ret = True + for term in q.split() if q else []: + ret = ret and match_one_term(md, term, predicted_class) + return ret + +def search_scans(q, predicted_classes): + ret = [] + all_scans = os.listdir(scans_dir) + random.shuffle(all_scans) + for scan in all_scans: + scan_dir = os.path.join(scans_dir, scan) + state_file = os.path.join(scan_dir, 'fetch-state.json') + std_qr_file = os.path.join(scan_dir, 'std-qr.jpg') + if not os.path.exists(state_file) or not os.path.exists(std_qr_file): + continue + with open(os.path.join(scan_dir, 'metadata.json'), 'r') as f: + md = json.load(f) + if not match_query(md, q, predicted_classes.get(scan)): + continue + ret.append(scan) + return ret + +def highlight_nongray(image): + saturation_threshold = 30 + hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) + s_channel = hsv_image[:, :, 1] + return Image.fromarray(s_channel) + +@app.route('/api/sbs/.jpg', methods=['GET']) +def sbs(scan): + scan_dir = os.path.join(scans_dir, scan) + if not os.path.exists(scan_dir): + return { + "ok": False, + "error": f"Scan {scan} not found", + } + frame_img = Image.open(os.path.join(scan_dir, 'frame.jpg')) + std_img = Image.open(os.path.join(scan_dir, 'std.jpg')) + ret = make_side_by_side_img_with_margins(frame_img, std_img) + with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as f: + ret.save(f.name) + return flask.send_file(f.name, mimetype='image/jpeg') + +@app.route('/api/allinone/.jpg', methods=['GET']) +def allinone(scan): + scan_dir = os.path.join(scans_dir, scan) + if not os.path.exists(scan_dir): + return { + "ok": False, + "error": f"Scan {scan} not found", + } + frame_img = Image.open(os.path.join(scan_dir, 'frame.jpg')) + std_img = Image.open(os.path.join(scan_dir, 'std.jpg')) + sbs_img = make_side_by_side_img_with_margins(frame_img, std_img) + ret_width = sbs_img.width + ret_height = sbs_img.height + frame_img.height + ret = Image.new('RGB', (ret_width, ret_height)) + ret.paste(sbs_img, (0, 0)) + ret.paste(frame_img, (0, sbs_img.height)) + with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as f: + ret.save(f.name) + return flask.send_file(f.name, mimetype='image/jpeg') + +@app.route('/api/scans', methods=['GET']) +def scans(): + q = flask.request.args.get('filter', None) + verify_result = flask.request.args.get('verify_result', None) + if verify_result: + with open(f'data/{verify_result}', 'r') as f: + predicted_classes = json.load(f) + else: + predicted_classes = {} + scans = search_scans(q, predicted_classes) + scans = scans[:200] + return { + "scans": [prepare_scan(s, predicted_classes) for s in scans], + } + +@app.route('/api/verify_results', methods=['GET']) +def verify_results(): + return { + 'results': [x for x in os.listdir('data') if x.endswith('.json')], + } + +@app.route('/api/data/', methods=['GET']) +def data(path): + return flask.send_file(os.path.abspath(os.path.join(data_dir, path))) + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--port', type=int, default=6500) + parser.add_argument('--debug', action='store_true') + return parser.parse_args() + +if __name__ == '__main__': + args = parse_args() + app.run(host='0.0.0.0', port=args.port, debug=args.debug) \ No newline at end of file diff --git a/emblem5/ai/train2.py b/emblem5/ai/train2.py new file mode 100644 index 0000000..35a109a --- /dev/null +++ b/emblem5/ai/train2.py @@ -0,0 +1,545 @@ +#!/usr/bin/env python3 +''' +all children of data/scans are scan_ids +in each scan_id, there is a file called "metadata.json" +labels key has 'pos' or 'neg' +it also has 'code' key which is a string + +For the largest 20% scan_ids, we use as validation set +for all codes appearing in the validation set in all scans, we also use as validation set + +the rest are training set + +preprocess the sbs.jpg for both train and validation: + 1. split left and right half + 2. crop 3x3 of left + 3. crop 3x3 of right + 4. for each pair of crop, concat into grid-i-j.jpg, and apply some colorjitter + 5. all the grid-i-j.jpg are used with the label + +load a resnet18 model, and train it on the training set +train for 10 epochs, and print accuracy on validation set each epoch + +save the model in the end. +''' + +import os +import json +import random +import torch +import torch.nn as nn +import torch.optim as optim +import torchvision +import torchvision.transforms as transforms +from torch.utils.data import Dataset, DataLoader +from torch.optim.lr_scheduler import ReduceLROnPlateau +from PIL import Image +import numpy as np +from tqdm import tqdm +import argparse +from collections import defaultdict +import multiprocessing as mp +from functools import partial +from datetime import datetime +from common import * + +def process_scan_grid(scan_item, hue_jitter=0.1): + """Process a single scan to create grid files and metadata""" + scan_id, metadata = scan_item + sample_metadata = [] + + sbs_path = os.path.join('data/scans', scan_id, 'sbs.jpg') + if not os.path.exists(sbs_path): + return sample_metadata + + # Create grid directory if it doesn't exist + grid_dir = os.path.join('data/scans', scan_id, 'grids') + os.makedirs(grid_dir, exist_ok=True) + + # Check if all grid files already exist + all_grids_exist = True + for i in range(3): + for j in range(3): + grid_filename = f'grid-{i}-{j}.jpg' + grid_path = os.path.join(grid_dir, grid_filename) + if not os.path.exists(grid_path): + all_grids_exist = False + break + if not all_grids_exist: + break + + # If all grid files exist, just return metadata + if all_grids_exist: + for i in range(3): + for j in range(3): + grid_filename = f'grid-{i}-{j}.jpg' + grid_path = os.path.join(grid_dir, grid_filename) + label = 1 if 'pos' in metadata['labels'] else 0 + sample_metadata.append({ + 'scan_id': scan_id, + 'grid_path': grid_path, + 'grid_i': i, + 'grid_j': j, + 'label': label + }) + return sample_metadata + + # Load the side-by-side image + sbs_img = Image.open(sbs_path).convert('RGB') + width, height = sbs_img.size + + # Calculate crop dimensions + crop_width = width // 6 # width/2 / 3 + crop_height = height // 3 + + # Generate all 3x3 grid combinations + for i in range(3): + for j in range(3): + # Calculate crop positions directly from original image + left_x = i * crop_width + right_x = (i + 3) * crop_width # Skip middle section + y = j * crop_height + + # Crop directly from original image + left_crop = sbs_img.crop((left_x, y, left_x + crop_width, y + crop_height)) + right_crop = sbs_img.crop((right_x, y, right_x + crop_width, y + crop_height)) + + # Apply color jitter only to left crop + color_jitter = transforms.ColorJitter( + brightness=0.2, + contrast=0.2, + saturation=0.2, + hue=hue_jitter + ) + left_crop = color_jitter(left_crop) + + # Concatenate left and right crops horizontally + grid_img = Image.new('RGB', (crop_width * 2, crop_height)) + grid_img.paste(left_crop, (0, 0)) + grid_img.paste(right_crop, (crop_width, 0)) + + # Save grid image + grid_filename = f'grid-{i}-{j}.jpg' + grid_path = os.path.join(grid_dir, grid_filename) + grid_img.save(grid_path, 'JPEG', quality=95) + + # Store metadata + label = 1 if 'pos' in metadata['labels'] else 0 + sample_metadata.append({ + 'scan_id': scan_id, + 'grid_path': grid_path, + 'grid_i': i, + 'grid_j': j, + 'label': label + }) + + return sample_metadata + +class GridDataset(Dataset): + def __init__(self, scan_data, transform=None, num_workers=None, hue_jitter=0.1): + self.scan_data = scan_data + self.transform = transform + self.sample_metadata = [] + self.hue_jitter = hue_jitter + + if num_workers is None: + num_workers = min(mp.cpu_count(), 8) # Limit to 8 workers max + + print(f"Preprocessing {len(scan_data)} scans to create grid files using {num_workers} workers...") + + # Use multiprocessing to create grid files + with mp.Pool(processes=num_workers) as pool: + # Process all scans in parallel with hue_jitter parameter + process_func = partial(process_scan_grid, hue_jitter=self.hue_jitter) + results = list(tqdm( + pool.imap(process_func, scan_data.items()), + total=len(scan_data), + desc="Creating grid files" + )) + + # Collect all sample metadata + for result in results: + self.sample_metadata.extend(result) + + print(f"Created {len(self.sample_metadata)} grid files") + + def __len__(self): + return len(self.sample_metadata) + + def __getitem__(self, idx): + # Get sample metadata + metadata = self.sample_metadata[idx] + + # Load the pre-saved grid image directly + grid_img = Image.open(metadata['grid_path']).convert('RGB') + + # Apply transforms + if self.transform: + grid_img = self.transform(grid_img) + + return grid_img, torch.tensor(metadata['label'], dtype=torch.long) + +def load_scan_data(data_dir): + """Load all scan metadata and organize by scan_id""" + scan_data = {} + scans_dir = os.path.join(data_dir, 'scans') + + if not os.path.exists(scans_dir): + raise FileNotFoundError(f"Scans directory not found: {scans_dir}") + + scan_ids = [d for d in os.listdir(scans_dir) + if os.path.isdir(os.path.join(scans_dir, d))] + + print(f"Loading metadata for {len(scan_ids)} scans...") + for scan_id in tqdm(scan_ids, desc="Loading scan metadata"): + metadata_path = os.path.join(scans_dir, scan_id, 'metadata.json') + if os.path.exists(metadata_path): + try: + with open(metadata_path, 'r') as f: + metadata = json.load(f) + scan_data[scan_id] = metadata + except Exception as e: + print(f"Error loading metadata for {scan_id}: {e}") + + return scan_data + +def split_train_val(scan_data): + """Split data into train and validation sets""" + scan_ids = list(scan_data.keys()) + + print("Splitting data into train and validation sets...") + + # Select 10% random scan_ids for initial validation set + val_size = int(len(scan_ids) * 0.1) + initial_val_scan_ids = random.sample(scan_ids, val_size) + + print(f"Initial random split: {len(scan_ids) - val_size} train, {val_size} validation") + + # Get all (code, labels) combinations that appear in the initial validation set + val_code_labels = set() + for scan_id in tqdm(initial_val_scan_ids, desc="Collecting validation code-label combinations"): + if scan_id in scan_data: + code = scan_data[scan_id].get('code') + labels = tuple(sorted(scan_data[scan_id].get('labels', []))) + if code: + val_code_labels.add((code, labels)) + + print(f"Found {len(val_code_labels)} unique (code, labels) combinations in validation set") + + # Find all scans in train that have matching (code, labels) combinations and move them to validation + additional_val_scan_ids = set() + train_scan_ids = set(scan_ids) - set(initial_val_scan_ids) + + for scan_id in tqdm(train_scan_ids, desc="Finding scans with matching code-label combinations"): + if scan_id in scan_data: + code = scan_data[scan_id].get('code') + labels = tuple(sorted(scan_data[scan_id].get('labels', []))) + # If (code, labels) combination matches, move to validation + if code and (code, labels) in val_code_labels: + additional_val_scan_ids.add(scan_id) + + # Combine validation sets + all_val_scan_ids = set(initial_val_scan_ids) | additional_val_scan_ids + all_train_scan_ids = set(scan_data.keys()) - all_val_scan_ids + + # Create train and validation data dictionaries + train_data = {scan_id: scan_data[scan_id] for scan_id in all_train_scan_ids} + val_data = {scan_id: scan_data[scan_id] for scan_id in all_val_scan_ids} + + print(f"Final split:") + print(f" Total scans: {len(scan_data)}") + print(f" Training scans: {len(train_data)}") + print(f" Validation scans: {len(val_data)}") + + return train_data, val_data + +def train_model(model, train_loader, val_loader, criterion, optimizer, scheduler, device, transform, args, train_metadata=None, num_epochs=10): + """Train the model for specified number of epochs""" + best_val_acc = 0.0 + + # Enable mixed precision training + scaler = torch.amp.GradScaler('cuda') + + for epoch in range(num_epochs): + # Training phase + model.train() + train_loss = 0.0 + train_correct = 0 + train_total = 0 + train_pos_correct = 0 + train_pos_total = 0 + train_neg_correct = 0 + train_neg_total = 0 + + train_pbar = tqdm(train_loader, desc=f'Epoch {epoch+1}/{num_epochs} [Train]') + for batch_idx, (data, target) in enumerate(train_pbar): + data, target = data.to(device), target.to(device) + + optimizer.zero_grad() + + # Use mixed precision training + with torch.amp.autocast('cuda'): + output = model(data) + loss = criterion(output, target).mean() + + # Scale loss and backpropagate + scaler.scale(loss).backward() + scaler.step(optimizer) + scaler.update() + + train_loss += loss.detach().item() + pred = output.argmax(dim=1, keepdim=True) + train_correct += pred.eq(target.view_as(pred)).sum().item() + train_total += target.size(0) + + # Track per-class accuracy + for i in range(target.size(0)): + if target[i] == 1: # Positive class + train_pos_total += 1 + if pred[i] == target[i]: + train_pos_correct += 1 + else: # Negative class + train_neg_total += 1 + if pred[i] == target[i]: + train_neg_correct += 1 + + # Clear memory after each batch + del data, target, output, loss, pred + + # Calculate per-class accuracies + train_pos_acc = 100. * train_pos_correct / max(train_pos_total, 1) + train_neg_acc = 100. * train_neg_correct / max(train_neg_total, 1) + + train_pbar.set_postfix({ + 'Loss': f'{train_loss/(batch_idx+1):.4f}', + 'Acc': f'{100.*train_correct/train_total:.2f}%', + 'Pos': f'{train_pos_acc:.2f}%', + 'Neg': f'{train_neg_acc:.2f}%' + }) + + # Validation phase + model.eval() + val_loss = 0.0 + val_correct = 0 + val_total = 0 + val_pos_correct = 0 + val_pos_total = 0 + val_neg_correct = 0 + val_neg_total = 0 + + with torch.no_grad(): + val_pbar = tqdm(val_loader, desc=f'Epoch {epoch+1}/{num_epochs} [Val]') + for batch_idx, (data, target) in enumerate(val_pbar): + data, target = data.to(device), target.to(device) + + # Use mixed precision for validation too + with torch.amp.autocast('cuda'): + output = model(data) + loss = criterion(output, target).mean() + + val_loss += loss.item() + pred = output.argmax(dim=1, keepdim=True) + val_correct += pred.eq(target.view_as(pred)).sum().item() + val_total += target.size(0) + + # Track per-class accuracy + for i in range(target.size(0)): + if target[i] == 1: # Positive class + val_pos_total += 1 + if pred[i] == target[i]: + val_pos_correct += 1 + else: # Negative class + val_neg_total += 1 + if pred[i] == target[i]: + val_neg_correct += 1 + + # Clear memory after each batch + del data, target, output, loss, pred + + # Calculate per-class accuracies + val_pos_acc = 100. * val_pos_correct / max(val_pos_total, 1) + val_neg_acc = 100. * val_neg_correct / max(val_neg_total, 1) + + val_pbar.set_postfix({ + 'Loss': f'{val_loss/(batch_idx+1):.4f}', + 'Acc': f'{100.*val_correct/val_total:.2f}%', + 'Pos': f'{val_pos_acc:.2f}%', + 'Neg': f'{val_neg_acc:.2f}%' + }) + + # Calculate final accuracies + train_acc = 100. * train_correct / train_total + val_acc = 100. * val_correct / val_total + train_pos_acc = 100. * train_pos_correct / max(train_pos_total, 1) + train_neg_acc = 100. * train_neg_correct / max(train_neg_total, 1) + val_pos_acc = 100. * val_pos_correct / max(val_pos_total, 1) + val_neg_acc = 100. * val_neg_correct / max(val_neg_total, 1) + + print(f'Epoch {epoch+1}/{num_epochs}:') + print(f' Train Loss: {train_loss/len(train_loader):.4f}, Train Acc: {train_acc:.2f}% (Pos: {train_pos_acc:.2f}%, Neg: {train_neg_acc:.2f}%)') + print(f' Val Loss: {val_loss/len(val_loader):.4f}, Val Acc: {val_acc:.2f}% (Pos: {val_pos_acc:.2f}%, Neg: {val_neg_acc:.2f}%)') + print(f' Train samples - Pos: {train_pos_total}, Neg: {train_neg_total}') + print(f' Val samples - Pos: {val_pos_total}, Neg: {val_neg_total}') + + # Step the scheduler with validation accuracy + scheduler.step(val_acc) + current_lr = optimizer.param_groups[0]['lr'] + print(f' Current learning rate: {current_lr:.6f}') + + # Save best model + if val_acc > best_val_acc: + best_val_acc = val_acc + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + mode_suffix = "_quick" if args.quick else "" + best_model_path = f'models/best_model_ep{epoch+1}_pos{val_pos_acc:.2f}_neg{val_neg_acc:.2f}{mode_suffix}_{timestamp}.pt' + save_model(model, transform, best_model_path, train_metadata) + print(f' New best validation accuracy: {val_acc:.2f}%') + print(f' Best model saved: {best_model_path}') + + return model, val_acc, val_pos_acc, val_neg_acc + +def main(): + parser = argparse.ArgumentParser(description='Train ResNet18 model on grid data') + parser.add_argument('--data-dir', default='data', help='Data directory') + parser.add_argument('--batch-size', type=int, default=64, help='Batch size (increased for better GPU utilization)') + parser.add_argument('--lr', type=float, default=0.001, help='Learning rate') + parser.add_argument('--epochs', type=int, default=100, help='Number of epochs') + parser.add_argument('--num-workers', type=int, default=None, help='Number of workers for preprocessing (default: auto)') + parser.add_argument('--quick', action='store_true', help='Quick mode: use only 1%% of scans for faster testing') + parser.add_argument('--hue-jitter', type=float, default=0.1, help='Hue jitter parameter for ColorJitter (default: 0.1)') + parser.add_argument('--scheduler-patience', type=int, default=3, help='Patience for ReduceLROnPlateau scheduler (default: 3)') + parser.add_argument('--scheduler-factor', type=float, default=0.1, help='Factor for ReduceLROnPlateau scheduler (default: 0.1)') + parser.add_argument('--scheduler-min-lr', type=float, default=1e-6, help='Minimum learning rate for ReduceLROnPlateau scheduler (default: 1e-6)') + args = parser.parse_args() + + # Set device + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + print(f'Using device: {device}') + print(f'Using hue jitter: {args.hue_jitter}') + + # Create models directory if it doesn't exist + os.makedirs('models', exist_ok=True) + + # Load scan data + print("Loading scan data...") + scan_data = load_scan_data(args.data_dir) + + if not scan_data: + print("No scan data found!") + return + + # Quick mode: use only 1% of scans for faster testing + if args.quick: + original_count = len(scan_data) + scan_ids = list(scan_data.keys()) + # Take 1% of scans, but at least 10 scans for meaningful training + quick_count = max(10, int(len(scan_ids) * 0.005)) + selected_scan_ids = random.sample(scan_ids, quick_count) + scan_data = {scan_id: scan_data[scan_id] for scan_id in selected_scan_ids} + print(f"Quick mode enabled: Using {len(scan_data)} scans out of {original_count} (1%)") + + # Split into train and validation + print("Splitting data into train and validation...") + train_data, val_data = split_train_val(scan_data) + + # Define transforms + transform = transforms.Compose([ + transforms.Resize((224, 224)), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + ]) + + # Create datasets + print("Creating training dataset...") + train_dataset = GridDataset(train_data, transform=transform, num_workers=args.num_workers, hue_jitter=args.hue_jitter) + print(f"Training samples: {len(train_dataset)}") + + print("Creating validation dataset...") + val_dataset = GridDataset(val_data, transform=transform, num_workers=args.num_workers, hue_jitter=args.hue_jitter) + print(f"Validation samples: {len(val_dataset)}") + + # Create data loaders + print("Creating data loaders...") + train_loader = DataLoader( + train_dataset, + batch_size=args.batch_size, + shuffle=True, + num_workers=8, + pin_memory=False, + persistent_workers=True, + prefetch_factor=2 + ) + val_loader = DataLoader( + val_dataset, + batch_size=args.batch_size, + shuffle=False, + num_workers=8, + pin_memory=False, + persistent_workers=True, + prefetch_factor=2 + ) + print(f"Train batches: {len(train_loader)}, Val batches: {len(val_loader)}") + + # Create model + print("Creating ResNet18 model...") + # model = torchvision.models.resnet18(pretrained=True) + model, _ = load_model('models/gridcrop-resnet-ep24-pos97.29-neg75.10-20250509_051300.pt') + # Modify final layer for binary classification + # model.fc = nn.Linear(model.fc.in_features, 2) + model = model.to(device) + print(f"Model created and moved to {device}") + + # Define loss function and optimizer + print("Setting up loss function and optimizer...") + # Use FocalLoss with 0.99:0.01 weights for positive/negative classes + pos_weight = 0.99 + criterion = FocalLoss(0.25, weight=torch.Tensor([1.0 - pos_weight, pos_weight]).to(device)) + optimizer = optim.Adam(model.parameters(), lr=args.lr) + + # Create ReduceLROnPlateau scheduler + scheduler = ReduceLROnPlateau( + optimizer, + mode='max', + factor=args.scheduler_factor, + patience=args.scheduler_patience, + min_lr=args.scheduler_min_lr + ) + + print(f"Using Adam optimizer with lr={args.lr}") + print(f"Using FocalLoss with weights: Negative={1.0 - pos_weight:.2f}, Positive={pos_weight:.2f}") + print(f"Using ReduceLROnPlateau scheduler with factor={args.scheduler_factor}, patience={args.scheduler_patience}, min_lr={args.scheduler_min_lr}") + + # Collect training metadata + train_scan_ids = list(train_data.keys()) + train_codes = set() + for scan_id, metadata in train_data.items(): + code = metadata.get('code') + if code: + train_codes.add(code) + + train_metadata = { + 'train_scan_ids': train_scan_ids, + 'train_codes': list(train_codes), + 'hue_jitter': args.hue_jitter, + 'quick_mode': args.quick + } + + print(f"Training metadata:") + print(f" Train scan IDs: {len(train_scan_ids)}") + print(f" Train codes: {len(train_codes)}") + print(f" Hue jitter: {args.hue_jitter}") + print(f" Quick mode: {args.quick}") + + # Train the model + print("Starting training...") + model, final_val_acc, final_val_pos_acc, final_val_neg_acc = train_model(model, train_loader, val_loader, criterion, optimizer, scheduler, device, transform, args, train_metadata, args.epochs) + + # Save final model + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + mode_suffix = "_quick" if args.quick else "" + final_model_path = f'models/final_model_ep{args.epochs}_pos{final_val_pos_acc:.2f}_neg{final_val_neg_acc:.2f}{mode_suffix}_{timestamp}.pt' + save_model(model, transform, final_model_path, train_metadata) + print(f"Training completed! Final model saved: {final_model_path}") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/emblem5/ai/upload.py b/emblem5/ai/upload.py new file mode 100755 index 0000000..9f3f638 --- /dev/null +++ b/emblem5/ai/upload.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +import oss2 +import sys +import os + +oss_ak = 'LTAI5tC2qXGxwHZUZP7DoD1A' +oss_sk = 'qPo9O6ZvEfqo4t8oflGEm0DoxLHJhm' + +auth = oss2.Auth(oss_ak, oss_sk) +endpoint = 'https://oss-rg-china-mainland.aliyuncs.com' +bucket = oss2.Bucket(auth, endpoint, 'emblem-models') + +for x in sys.argv[1:]: + bucket.put_object_from_file(os.path.basename(x), x) + diff --git a/emblem5/ai/validate-codes.txt b/emblem5/ai/validate-codes.txt new file mode 100644 index 0000000..394d9c2 --- /dev/null +++ b/emblem5/ai/validate-codes.txt @@ -0,0 +1,167 @@ +9041518155696 +9043391705032 +9047560846288 +9047175442152 +9046645732164 +9048448971990 +9047231003796 +9046667514583 +9047217570340 +9043862855714 +9047719805291 +9046067235268 +9044607756016 +9049438906993 +9048110553084 +9044313130824 +9046610110726 +9048196228678 +9042527399330 +9041865329320 +9043038880530 +9043211403350 +9042124015937 +9048747140763 +9048907683811 +9044055383558 +9044961109172 +9046289086854 +9045378241113 +9049268170237 +9043251838574 +9043425154373 +9042596134496 +9047999799544 +9041017580514 +9048457850808 +9046098673325 +9044596429399 +9047671774248 +9048108092652 +9045835321309 +9044679005902 +9048208086422 +9049703639151 +9041824087492 +9048993912134 +9047797019579 +9042176791662 +9049916444625 +9046735238974 +9046044876640 +9042964782271 +9046081233017 +9047151569363 +9043467200041 +9042652128603 +9046393672383 +9044036329705 +9047824031869 +9044526583112 +9044604195977 +9043745698353 +9046855799440 +9041870423863 +9043385501906 +9047466185021 +9043986284948 +9049268008982 +9045179435607 +9043885459754 +9041362669101 +9048090113001 +9047484404980 +9049495526869 +9044101220760 +9044101220760 +9045453464619 +9046473812518 +9045683245091 +9045913691663 +9042549358206 +9044446342115 +9044357449196 +9046629219878 +9048128593651 +9049834888165 +9044664345848 +9049588698348 +9041635328789 +9047205431361 +9041704601110 +9045204595658 +9045789047781 +9047522816803 +9047843727318 +9049482594873 +9044866091316 +9047760719652 + +4292859353771 +4291283577956 +4292091386770 +4293067912516 +4292069800308 +4299999931135 +4292045885091 +4293959856775 +4295757450024 +4299348480765 +4299496909661 +4296911416779 +4295370931573 +4296920517990 +4296693440435 +4295217706242 +4299655305592 +4296536108258 +4298797246935 +4292384445350 +4299197224943 +4298223657987 +4293625631612 +4299656315895 +4299436471684 +4295932375321 + + +1162010093987 +1169941547790 +1167433463200 +1168073514307 +1161874738818 +1165899663363 +1163234869247 +1163522365275 +1166807824551 +1165813695823 +1168402949263 +1162255504991 +1166442217897 +1162733112181 +1167084078863 +1164804351567 +1169071099109 +1164135002853 +1165104857536 +1162802553605 +1162410467884 +1164659148887 +1162015664585 +1167309572217 +1168586487143 +1167825009551 +1168243803466 +1162683501280 +1164839838856 +1168003168625 +1166662251448 +1165064496397 +1169221746833 +1164728213265 +1166019005564 +1163925013376 +1167589827603 +1164868647043 +1163089588202 +1169765273422 \ No newline at end of file diff --git a/emblem5/ai/verify2.py b/emblem5/ai/verify2.py new file mode 100755 index 0000000..5df50f2 --- /dev/null +++ b/emblem5/ai/verify2.py @@ -0,0 +1,349 @@ +#!/usr/bin/env python3 +''' +Load the best model and run inference on all scan IDs. +For each scan, predict on all 3x3 grid images and use voting to determine the final scan label. +Calculate accuracy against the original scan labels. +''' + +import os +import json +import torch +import torch.nn as nn +import torchvision.transforms as transforms +from torch.utils.data import Dataset, DataLoader +from PIL import Image +import numpy as np +from tqdm import tqdm +import argparse +import random +from collections import defaultdict +from common import * + +class GridInferenceDataset(Dataset): + def __init__(self, scan_data, transform=None): + self.scan_data = scan_data + self.transform = transform + self.sample_metadata = [] + + print(f"Loading grid files for {len(scan_data)} scans...") + + # Collect all grid files for each scan + for scan_id, metadata in tqdm(scan_data.items(), desc="Loading grid metadata"): + grid_dir = os.path.join('data/scans', scan_id, 'grids') + if not os.path.exists(grid_dir): + continue + + # Check for all 9 grid files + grid_files = [] + for i in range(3): + for j in range(3): + grid_filename = f'grid-{i}-{j}.jpg' + grid_path = os.path.join(grid_dir, grid_filename) + if os.path.exists(grid_path): + grid_files.append({ + 'scan_id': scan_id, + 'grid_path': grid_path, + 'grid_i': i, + 'grid_j': j, + 'label': 1 if 'pos' in metadata['labels'] else 0 + }) + + # Only include scans that have all 9 grid files + if len(grid_files) == 9: + self.sample_metadata.extend(grid_files) + else: + print(f"Warning: Scan {scan_id} has {len(grid_files)}/9 grid files, skipping") + + print(f"Loaded {len(self.sample_metadata)} grid files from {len(self.sample_metadata)//9} complete scans") + + def __len__(self): + return len(self.sample_metadata) + + def __getitem__(self, idx): + # Get sample metadata + metadata = self.sample_metadata[idx] + + # Load the grid image + grid_img = Image.open(metadata['grid_path']).convert('RGB') + + # Apply transforms + if self.transform: + grid_img = self.transform(grid_img) + + return grid_img, torch.tensor(metadata['label'], dtype=torch.long), metadata['scan_id'] + +def load_scan_data(data_dir): + """Load all scan metadata and organize by scan_id""" + scan_data = {} + scans_dir = os.path.join(data_dir, 'scans') + + if not os.path.exists(scans_dir): + raise FileNotFoundError(f"Scans directory not found: {scans_dir}") + + scan_ids = [d for d in os.listdir(scans_dir) + if os.path.isdir(os.path.join(scans_dir, d))] + + print(f"Loading metadata for {len(scan_ids)} scans...") + for scan_id in tqdm(scan_ids, desc="Loading scan metadata"): + metadata_path = os.path.join(scans_dir, scan_id, 'metadata.json') + if os.path.exists(metadata_path): + try: + with open(metadata_path, 'r') as f: + metadata = json.load(f) + scan_data[scan_id] = metadata + except Exception as e: + print(f"Error loading metadata for {scan_id}: {e}") + + return scan_data + +def run_inference(model, data_loader, device): + """Run inference on all data and collect predictions by scan_id""" + model.eval() + + # Dictionary to store predictions for each scan + scan_predictions = defaultdict(list) + scan_labels = {} + + # Track running accuracy + total_predictions = 0 + correct_predictions = 0 + pos_correct = 0 + pos_total = 0 + neg_correct = 0 + neg_total = 0 + + print("Running inference...") + with torch.no_grad(): + pbar = tqdm(data_loader, desc="Inference") + for batch_idx, (data, target, scan_ids) in enumerate(pbar): + data = data.to(device) + + # Get predictions + output = model(data) + probabilities = torch.softmax(output, dim=1) + predictions = torch.argmax(output, dim=1) + + # Move target to same device as predictions for comparison + target_device = target.to(device) + + # Calculate batch accuracy + batch_correct = (predictions == target_device).sum().item() + correct_predictions += batch_correct + total_predictions += len(target) + + # Track per-class accuracy + for i in range(len(target)): + if target[i] == 1: # Positive class + pos_total += 1 + if predictions[i] == target_device[i]: + pos_correct += 1 + else: # Negative class + neg_total += 1 + if predictions[i] == target_device[i]: + neg_correct += 1 + + # Store predictions by scan_id + for i in range(len(scan_ids)): + scan_id = scan_ids[i] + pred = predictions[i].item() + prob = probabilities[i][1].item() # Probability of positive class + + scan_predictions[scan_id].append({ + 'prediction': pred, + 'probability': prob + }) + + # Store the true label (should be the same for all grids in a scan) + if scan_id not in scan_labels: + scan_labels[scan_id] = target[i].item() + + # Calculate running accuracies + overall_acc = 100. * correct_predictions / total_predictions if total_predictions > 0 else 0 + pos_acc = 100. * pos_correct / pos_total if pos_total > 0 else 0 + neg_acc = 100. * neg_correct / neg_total if neg_total > 0 else 0 + + # Update progress bar with accuracy info + pbar.set_postfix({ + 'Overall': f'{overall_acc:.2f}%', + 'Pos': f'{pos_acc:.2f}%', + 'Neg': f'{neg_acc:.2f}%', + 'Pos/Total': f'{pos_correct}/{pos_total}', + 'Neg/Total': f'{neg_correct}/{neg_total}' + }) + + # Clear memory + del data, output, probabilities, predictions + + return scan_predictions, scan_labels + +def calculate_voting_accuracy(scan_predictions, scan_labels): + """Calculate accuracy using voting mechanism""" + correct_predictions = 0 + total_scans = 0 + pos_correct = 0 + pos_total = 0 + neg_correct = 0 + neg_total = 0 + + # Create log file + log_file = 'data/verify2.log' + os.makedirs(os.path.dirname(log_file), exist_ok=True) + + with open(log_file, 'w') as f: + f.write("Voting Results:\n") + f.write("-" * 80 + "\n") + f.write(f"{'Scan ID':<15} {'True Label':<12} {'Vote Result':<12} {'Pos Votes':<10} {'Neg Votes':<10} {'Correct':<8}\n") + f.write("-" * 80 + "\n") + + print("\nVoting Results:") + print("-" * 80) + print(f"{'Scan ID':<15} {'True Label':<12} {'Vote Result':<12} {'Pos Votes':<10} {'Neg Votes':<10} {'Correct':<8}") + print("-" * 80) + + for scan_id, predictions in scan_predictions.items(): + if scan_id not in scan_labels: + continue + + true_label = scan_labels[scan_id] + total_scans += 1 + + # Count positive and negative votes + pos_votes = sum(1 for p in predictions if p['prediction'] == 1) + neg_votes = sum(1 for p in predictions if p['prediction'] == 0) + + # Determine final prediction by majority vote + final_prediction = 1 if pos_votes > neg_votes else 0 + + # Check if prediction is correct + is_correct = final_prediction == true_label + if is_correct: + correct_predictions += 1 + + # Track per-class accuracy + if true_label == 1: # Positive class + pos_total += 1 + if is_correct: + pos_correct += 1 + else: # Negative class + neg_total += 1 + if is_correct: + neg_correct += 1 + + # Print result + status = "✓" if is_correct else "✗" + result_line = f"{scan_id:<15} {true_label:<12} {final_prediction:<12} {pos_votes:<10} {neg_votes:<10} {status:<8}" + print(result_line) + + # Write to log file + with open(log_file, 'a') as f: + f.write(result_line + "\n") + + # Calculate accuracies + overall_accuracy = 100. * correct_predictions / total_scans if total_scans > 0 else 0 + pos_accuracy = 100. * pos_correct / pos_total if pos_total > 0 else 0 + neg_accuracy = 100. * neg_correct / neg_total if neg_total > 0 else 0 + + # Write summary to log file + with open(log_file, 'a') as f: + f.write("-" * 80 + "\n") + f.write(f"Overall Accuracy: {overall_accuracy:.2f}% ({correct_predictions}/{total_scans})\n") + f.write(f"Positive Accuracy: {pos_accuracy:.2f}% ({pos_correct}/{pos_total})\n") + f.write(f"Negative Accuracy: {neg_accuracy:.2f}% ({neg_correct}/{neg_total})\n") + + print("-" * 80) + print(f"Overall Accuracy: {overall_accuracy:.2f}% ({correct_predictions}/{total_scans})") + print(f"Positive Accuracy: {pos_accuracy:.2f}% ({pos_correct}/{pos_total})") + print(f"Negative Accuracy: {neg_accuracy:.2f}% ({neg_correct}/{neg_total})") + + return overall_accuracy, pos_accuracy, neg_accuracy + +def main(): + parser = argparse.ArgumentParser(description='Verify model accuracy using voting mechanism') + parser.add_argument('--data-dir', default='data', help='Data directory') + parser.add_argument('--model', default='models/final_model_ep10_pos98.54_neg78.52_20250706_143910.pt', help='Path to the model file') + parser.add_argument('--batch-size', type=int, default=128, help='Batch size for inference') + parser.add_argument('--sample', type=float, default=1.0, help='Fraction of scans to sample (0.0-1.0, default: 1.0 for all scans)') + args = parser.parse_args() + + # Set device + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + print(f'Using device: {device}') + + # Load scan data + print("Loading scan data...") + scan_data = load_scan_data(args.data_dir) + + if not scan_data: + print("No scan data found!") + return + + # Sample scans if requested + if args.sample < 1.0: + scan_ids = list(scan_data.keys()) + num_to_sample = max(1, int(len(scan_ids) * args.sample)) + sampled_scan_ids = random.sample(scan_ids, num_to_sample) + scan_data = {scan_id: scan_data[scan_id] for scan_id in sampled_scan_ids} + print(f"Sampled {len(sampled_scan_ids)} scans out of {len(scan_ids)} total scans ({args.sample*100:.1f}%)") + else: + print(f"Using all {len(scan_data)} scans") + + # Define transforms + transform = transforms.Compose([ + transforms.Resize((224, 224)), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + ]) + + # Create dataset + print("Creating inference dataset...") + dataset = GridInferenceDataset(scan_data, transform=transform) + + if len(dataset) == 0: + print("No valid grid files found!") + return + + # Create data loader + print("Creating data loader...") + data_loader = DataLoader( + dataset, + batch_size=args.batch_size, + shuffle=True, + num_workers=8, + pin_memory=False, + persistent_workers=True, + prefetch_factor=2 + ) + print(f"Total batches: {len(data_loader)}") + + # Load model + print(f"Loading model from {args.model}...") + try: + model, _ = load_model(args.model) + model = model.to(device) + print("Model loaded successfully") + except Exception as e: + print(f"Error loading model: {e}") + return + + # Run inference + scan_predictions, scan_labels = run_inference(model, data_loader, device) + + # Calculate voting accuracy + overall_acc, pos_acc, neg_acc = calculate_voting_accuracy(scan_predictions, scan_labels) + + print(f"\nFinal Results:") + print(f"Overall Accuracy: {overall_acc:.2f}%") + print(f"Positive Accuracy: {pos_acc:.2f}%") + print(f"Negative Accuracy: {neg_acc:.2f}%") + + # Write final results to log file + with open('data/verify2.log', 'a') as f: + f.write(f"\nFinal Results:\n") + f.write(f"Overall Accuracy: {overall_acc:.2f}%\n") + f.write(f"Positive Accuracy: {pos_acc:.2f}%\n") + f.write(f"Negative Accuracy: {neg_acc:.2f}%\n") + + print(f"\nResults have been written to data/verify2.log") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/emblem5/ai/wechat_qrcode/detect.caffemodel b/emblem5/ai/wechat_qrcode/detect.caffemodel new file mode 100644 index 0000000..453126c Binary files /dev/null and b/emblem5/ai/wechat_qrcode/detect.caffemodel differ diff --git a/emblem5/ai/wechat_qrcode/detect.prototxt b/emblem5/ai/wechat_qrcode/detect.prototxt new file mode 100644 index 0000000..bd2417c --- /dev/null +++ b/emblem5/ai/wechat_qrcode/detect.prototxt @@ -0,0 +1,2716 @@ +layer { + name: "data" + type: "Input" + top: "data" + input_param { + shape { + dim: 1 + dim: 1 + dim: 384 + dim: 384 + } + } +} +layer { + name: "data/bn" + type: "BatchNorm" + bottom: "data" + top: "data" + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } +} +layer { + name: "data/bn/scale" + type: "Scale" + bottom: "data" + top: "data" + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + scale_param { + filler { + type: "constant" + value: 1.0 + } + bias_term: true + bias_filler { + type: "constant" + value: 0.0 + } + } +} +layer { + name: "stage1" + type: "Convolution" + bottom: "data" + top: "stage1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 1 + kernel_size: 3 + group: 1 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage1/bn" + type: "BatchNorm" + bottom: "stage1" + top: "stage1" + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } +} +layer { + name: "stage1/bn/scale" + type: "Scale" + bottom: "stage1" + top: "stage1" + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + scale_param { + filler { + type: "constant" + value: 1.0 + } + bias_term: true + bias_filler { + type: "constant" + value: 0.0 + } + } +} +layer { + name: "stage1/relu" + type: "ReLU" + bottom: "stage1" + top: "stage1" +} +layer { + name: "stage2" + type: "Pooling" + bottom: "stage1" + top: "stage2" + pooling_param { + pool: MAX + kernel_size: 3 + stride: 2 + pad: 0 + } +} +layer { + name: "stage3_1/conv1" + type: "Convolution" + bottom: "stage2" + top: "stage3_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_1/conv1/relu" + type: "ReLU" + bottom: "stage3_1/conv1" + top: "stage3_1/conv1" +} +layer { + name: "stage3_1/conv2" + type: "Convolution" + bottom: "stage3_1/conv1" + top: "stage3_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_1/conv3" + type: "Convolution" + bottom: "stage3_1/conv2" + top: "stage3_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_1/relu" + type: "ReLU" + bottom: "stage3_1/conv3" + top: "stage3_1/conv3" +} +layer { + name: "stage3_2/conv1" + type: "Convolution" + bottom: "stage3_1/conv3" + top: "stage3_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_2/conv1/relu" + type: "ReLU" + bottom: "stage3_2/conv1" + top: "stage3_2/conv1" +} +layer { + name: "stage3_2/conv2" + type: "Convolution" + bottom: "stage3_2/conv1" + top: "stage3_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_2/conv3" + type: "Convolution" + bottom: "stage3_2/conv2" + top: "stage3_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_2/sum" + type: "Eltwise" + bottom: "stage3_1/conv3" + bottom: "stage3_2/conv3" + top: "stage3_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage3_2/relu" + type: "ReLU" + bottom: "stage3_2/sum" + top: "stage3_2/sum" +} +layer { + name: "stage3_3/conv1" + type: "Convolution" + bottom: "stage3_2/sum" + top: "stage3_3/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_3/conv1/relu" + type: "ReLU" + bottom: "stage3_3/conv1" + top: "stage3_3/conv1" +} +layer { + name: "stage3_3/conv2" + type: "Convolution" + bottom: "stage3_3/conv1" + top: "stage3_3/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_3/conv3" + type: "Convolution" + bottom: "stage3_3/conv2" + top: "stage3_3/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_3/sum" + type: "Eltwise" + bottom: "stage3_2/sum" + bottom: "stage3_3/conv3" + top: "stage3_3/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage3_3/relu" + type: "ReLU" + bottom: "stage3_3/sum" + top: "stage3_3/sum" +} +layer { + name: "stage3_4/conv1" + type: "Convolution" + bottom: "stage3_3/sum" + top: "stage3_4/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_4/conv1/relu" + type: "ReLU" + bottom: "stage3_4/conv1" + top: "stage3_4/conv1" +} +layer { + name: "stage3_4/conv2" + type: "Convolution" + bottom: "stage3_4/conv1" + top: "stage3_4/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_4/conv3" + type: "Convolution" + bottom: "stage3_4/conv2" + top: "stage3_4/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_4/sum" + type: "Eltwise" + bottom: "stage3_3/sum" + bottom: "stage3_4/conv3" + top: "stage3_4/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage3_4/relu" + type: "ReLU" + bottom: "stage3_4/sum" + top: "stage3_4/sum" +} +layer { + name: "stage4_1/conv1" + type: "Convolution" + bottom: "stage3_4/sum" + top: "stage4_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_1/conv1/relu" + type: "ReLU" + bottom: "stage4_1/conv1" + top: "stage4_1/conv1" +} +layer { + name: "stage4_1/conv2" + type: "Convolution" + bottom: "stage4_1/conv1" + top: "stage4_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_1/conv3" + type: "Convolution" + bottom: "stage4_1/conv2" + top: "stage4_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_1/relu" + type: "ReLU" + bottom: "stage4_1/conv3" + top: "stage4_1/conv3" +} +layer { + name: "stage4_2/conv1" + type: "Convolution" + bottom: "stage4_1/conv3" + top: "stage4_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_2/conv1/relu" + type: "ReLU" + bottom: "stage4_2/conv1" + top: "stage4_2/conv1" +} +layer { + name: "stage4_2/conv2" + type: "Convolution" + bottom: "stage4_2/conv1" + top: "stage4_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_2/conv3" + type: "Convolution" + bottom: "stage4_2/conv2" + top: "stage4_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_2/sum" + type: "Eltwise" + bottom: "stage4_1/conv3" + bottom: "stage4_2/conv3" + top: "stage4_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_2/relu" + type: "ReLU" + bottom: "stage4_2/sum" + top: "stage4_2/sum" +} +layer { + name: "stage4_3/conv1" + type: "Convolution" + bottom: "stage4_2/sum" + top: "stage4_3/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_3/conv1/relu" + type: "ReLU" + bottom: "stage4_3/conv1" + top: "stage4_3/conv1" +} +layer { + name: "stage4_3/conv2" + type: "Convolution" + bottom: "stage4_3/conv1" + top: "stage4_3/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_3/conv3" + type: "Convolution" + bottom: "stage4_3/conv2" + top: "stage4_3/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_3/sum" + type: "Eltwise" + bottom: "stage4_2/sum" + bottom: "stage4_3/conv3" + top: "stage4_3/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_3/relu" + type: "ReLU" + bottom: "stage4_3/sum" + top: "stage4_3/sum" +} +layer { + name: "stage4_4/conv1" + type: "Convolution" + bottom: "stage4_3/sum" + top: "stage4_4/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_4/conv1/relu" + type: "ReLU" + bottom: "stage4_4/conv1" + top: "stage4_4/conv1" +} +layer { + name: "stage4_4/conv2" + type: "Convolution" + bottom: "stage4_4/conv1" + top: "stage4_4/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_4/conv3" + type: "Convolution" + bottom: "stage4_4/conv2" + top: "stage4_4/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_4/sum" + type: "Eltwise" + bottom: "stage4_3/sum" + bottom: "stage4_4/conv3" + top: "stage4_4/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_4/relu" + type: "ReLU" + bottom: "stage4_4/sum" + top: "stage4_4/sum" +} +layer { + name: "stage4_5/conv1" + type: "Convolution" + bottom: "stage4_4/sum" + top: "stage4_5/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_5/conv1/relu" + type: "ReLU" + bottom: "stage4_5/conv1" + top: "stage4_5/conv1" +} +layer { + name: "stage4_5/conv2" + type: "Convolution" + bottom: "stage4_5/conv1" + top: "stage4_5/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_5/conv3" + type: "Convolution" + bottom: "stage4_5/conv2" + top: "stage4_5/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_5/sum" + type: "Eltwise" + bottom: "stage4_4/sum" + bottom: "stage4_5/conv3" + top: "stage4_5/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_5/relu" + type: "ReLU" + bottom: "stage4_5/sum" + top: "stage4_5/sum" +} +layer { + name: "stage4_6/conv1" + type: "Convolution" + bottom: "stage4_5/sum" + top: "stage4_6/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_6/conv1/relu" + type: "ReLU" + bottom: "stage4_6/conv1" + top: "stage4_6/conv1" +} +layer { + name: "stage4_6/conv2" + type: "Convolution" + bottom: "stage4_6/conv1" + top: "stage4_6/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_6/conv3" + type: "Convolution" + bottom: "stage4_6/conv2" + top: "stage4_6/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_6/sum" + type: "Eltwise" + bottom: "stage4_5/sum" + bottom: "stage4_6/conv3" + top: "stage4_6/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_6/relu" + type: "ReLU" + bottom: "stage4_6/sum" + top: "stage4_6/sum" +} +layer { + name: "stage4_7/conv1" + type: "Convolution" + bottom: "stage4_6/sum" + top: "stage4_7/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_7/conv1/relu" + type: "ReLU" + bottom: "stage4_7/conv1" + top: "stage4_7/conv1" +} +layer { + name: "stage4_7/conv2" + type: "Convolution" + bottom: "stage4_7/conv1" + top: "stage4_7/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_7/conv3" + type: "Convolution" + bottom: "stage4_7/conv2" + top: "stage4_7/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_7/sum" + type: "Eltwise" + bottom: "stage4_6/sum" + bottom: "stage4_7/conv3" + top: "stage4_7/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_7/relu" + type: "ReLU" + bottom: "stage4_7/sum" + top: "stage4_7/sum" +} +layer { + name: "stage4_8/conv1" + type: "Convolution" + bottom: "stage4_7/sum" + top: "stage4_8/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_8/conv1/relu" + type: "ReLU" + bottom: "stage4_8/conv1" + top: "stage4_8/conv1" +} +layer { + name: "stage4_8/conv2" + type: "Convolution" + bottom: "stage4_8/conv1" + top: "stage4_8/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_8/conv3" + type: "Convolution" + bottom: "stage4_8/conv2" + top: "stage4_8/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_8/sum" + type: "Eltwise" + bottom: "stage4_7/sum" + bottom: "stage4_8/conv3" + top: "stage4_8/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_8/relu" + type: "ReLU" + bottom: "stage4_8/sum" + top: "stage4_8/sum" +} +layer { + name: "stage5_1/conv1" + type: "Convolution" + bottom: "stage4_8/sum" + top: "stage5_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_1/conv1/relu" + type: "ReLU" + bottom: "stage5_1/conv1" + top: "stage5_1/conv1" +} +layer { + name: "stage5_1/conv2" + type: "Convolution" + bottom: "stage5_1/conv1" + top: "stage5_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_1/conv3" + type: "Convolution" + bottom: "stage5_1/conv2" + top: "stage5_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_1/relu" + type: "ReLU" + bottom: "stage5_1/conv3" + top: "stage5_1/conv3" +} +layer { + name: "stage5_2/conv1" + type: "Convolution" + bottom: "stage5_1/conv3" + top: "stage5_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_2/conv1/relu" + type: "ReLU" + bottom: "stage5_2/conv1" + top: "stage5_2/conv1" +} +layer { + name: "stage5_2/conv2" + type: "Convolution" + bottom: "stage5_2/conv1" + top: "stage5_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_2/conv3" + type: "Convolution" + bottom: "stage5_2/conv2" + top: "stage5_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_2/sum" + type: "Eltwise" + bottom: "stage5_1/conv3" + bottom: "stage5_2/conv3" + top: "stage5_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage5_2/relu" + type: "ReLU" + bottom: "stage5_2/sum" + top: "stage5_2/sum" +} +layer { + name: "stage5_3/conv1" + type: "Convolution" + bottom: "stage5_2/sum" + top: "stage5_3/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_3/conv1/relu" + type: "ReLU" + bottom: "stage5_3/conv1" + top: "stage5_3/conv1" +} +layer { + name: "stage5_3/conv2" + type: "Convolution" + bottom: "stage5_3/conv1" + top: "stage5_3/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_3/conv3" + type: "Convolution" + bottom: "stage5_3/conv2" + top: "stage5_3/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_3/sum" + type: "Eltwise" + bottom: "stage5_2/sum" + bottom: "stage5_3/conv3" + top: "stage5_3/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage5_3/relu" + type: "ReLU" + bottom: "stage5_3/sum" + top: "stage5_3/sum" +} +layer { + name: "stage5_4/conv1" + type: "Convolution" + bottom: "stage5_3/sum" + top: "stage5_4/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_4/conv1/relu" + type: "ReLU" + bottom: "stage5_4/conv1" + top: "stage5_4/conv1" +} +layer { + name: "stage5_4/conv2" + type: "Convolution" + bottom: "stage5_4/conv1" + top: "stage5_4/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_4/conv3" + type: "Convolution" + bottom: "stage5_4/conv2" + top: "stage5_4/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_4/sum" + type: "Eltwise" + bottom: "stage5_3/sum" + bottom: "stage5_4/conv3" + top: "stage5_4/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage5_4/relu" + type: "ReLU" + bottom: "stage5_4/sum" + top: "stage5_4/sum" +} +layer { + name: "stage6_1/conv4" + type: "Convolution" + bottom: "stage5_4/sum" + top: "stage6_1/conv4" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_1/conv1" + type: "Convolution" + bottom: "stage5_4/sum" + top: "stage6_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_1/conv1/relu" + type: "ReLU" + bottom: "stage6_1/conv1" + top: "stage6_1/conv1" +} +layer { + name: "stage6_1/conv2" + type: "Convolution" + bottom: "stage6_1/conv1" + top: "stage6_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage6_1/conv3" + type: "Convolution" + bottom: "stage6_1/conv2" + top: "stage6_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_1/sum" + type: "Eltwise" + bottom: "stage6_1/conv4" + bottom: "stage6_1/conv3" + top: "stage6_1/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage6_1/relu" + type: "ReLU" + bottom: "stage6_1/sum" + top: "stage6_1/sum" +} +layer { + name: "stage6_2/conv1" + type: "Convolution" + bottom: "stage6_1/sum" + top: "stage6_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_2/conv1/relu" + type: "ReLU" + bottom: "stage6_2/conv1" + top: "stage6_2/conv1" +} +layer { + name: "stage6_2/conv2" + type: "Convolution" + bottom: "stage6_2/conv1" + top: "stage6_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage6_2/conv3" + type: "Convolution" + bottom: "stage6_2/conv2" + top: "stage6_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_2/sum" + type: "Eltwise" + bottom: "stage6_1/sum" + bottom: "stage6_2/conv3" + top: "stage6_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage6_2/relu" + type: "ReLU" + bottom: "stage6_2/sum" + top: "stage6_2/sum" +} +layer { + name: "stage7_1/conv4" + type: "Convolution" + bottom: "stage6_2/sum" + top: "stage7_1/conv4" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_1/conv1" + type: "Convolution" + bottom: "stage6_2/sum" + top: "stage7_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_1/conv1/relu" + type: "ReLU" + bottom: "stage7_1/conv1" + top: "stage7_1/conv1" +} +layer { + name: "stage7_1/conv2" + type: "Convolution" + bottom: "stage7_1/conv1" + top: "stage7_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage7_1/conv3" + type: "Convolution" + bottom: "stage7_1/conv2" + top: "stage7_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_1/sum" + type: "Eltwise" + bottom: "stage7_1/conv4" + bottom: "stage7_1/conv3" + top: "stage7_1/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage7_1/relu" + type: "ReLU" + bottom: "stage7_1/sum" + top: "stage7_1/sum" +} +layer { + name: "stage7_2/conv1" + type: "Convolution" + bottom: "stage7_1/sum" + top: "stage7_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_2/conv1/relu" + type: "ReLU" + bottom: "stage7_2/conv1" + top: "stage7_2/conv1" +} +layer { + name: "stage7_2/conv2" + type: "Convolution" + bottom: "stage7_2/conv1" + top: "stage7_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage7_2/conv3" + type: "Convolution" + bottom: "stage7_2/conv2" + top: "stage7_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_2/sum" + type: "Eltwise" + bottom: "stage7_1/sum" + bottom: "stage7_2/conv3" + top: "stage7_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage7_2/relu" + type: "ReLU" + bottom: "stage7_2/sum" + top: "stage7_2/sum" +} +layer { + name: "stage8_1/conv4" + type: "Convolution" + bottom: "stage7_2/sum" + top: "stage8_1/conv4" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_1/conv1" + type: "Convolution" + bottom: "stage7_2/sum" + top: "stage8_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_1/conv1/relu" + type: "ReLU" + bottom: "stage8_1/conv1" + top: "stage8_1/conv1" +} +layer { + name: "stage8_1/conv2" + type: "Convolution" + bottom: "stage8_1/conv1" + top: "stage8_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage8_1/conv3" + type: "Convolution" + bottom: "stage8_1/conv2" + top: "stage8_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_1/sum" + type: "Eltwise" + bottom: "stage8_1/conv4" + bottom: "stage8_1/conv3" + top: "stage8_1/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage8_1/relu" + type: "ReLU" + bottom: "stage8_1/sum" + top: "stage8_1/sum" +} +layer { + name: "stage8_2/conv1" + type: "Convolution" + bottom: "stage8_1/sum" + top: "stage8_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_2/conv1/relu" + type: "ReLU" + bottom: "stage8_2/conv1" + top: "stage8_2/conv1" +} +layer { + name: "stage8_2/conv2" + type: "Convolution" + bottom: "stage8_2/conv1" + top: "stage8_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage8_2/conv3" + type: "Convolution" + bottom: "stage8_2/conv2" + top: "stage8_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_2/sum" + type: "Eltwise" + bottom: "stage8_1/sum" + bottom: "stage8_2/conv3" + top: "stage8_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage8_2/relu" + type: "ReLU" + bottom: "stage8_2/sum" + top: "stage8_2/sum" +} +layer { + name: "cls1/conv" + type: "Convolution" + bottom: "stage4_8/sum" + top: "cls1/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls1/permute" + type: "Permute" + bottom: "cls1/conv" + top: "cls1/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls1/flatten" + type: "Flatten" + bottom: "cls1/permute" + top: "cls1/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc1/conv" + type: "Convolution" + bottom: "stage4_8/sum" + top: "loc1/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc1/permute" + type: "Permute" + bottom: "loc1/conv" + top: "loc1/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc1/flatten" + type: "Flatten" + bottom: "loc1/permute" + top: "loc1/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage4_8/sum/prior_box" + type: "PriorBox" + bottom: "stage4_8/sum" + bottom: "data" + top: "stage4_8/sum/prior_box" + prior_box_param { + min_size: 50.0 + max_size: 100.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 16.0 + } +} +layer { + name: "cls2/conv" + type: "Convolution" + bottom: "stage5_4/sum" + top: "cls2/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls2/permute" + type: "Permute" + bottom: "cls2/conv" + top: "cls2/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls2/flatten" + type: "Flatten" + bottom: "cls2/permute" + top: "cls2/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc2/conv" + type: "Convolution" + bottom: "stage5_4/sum" + top: "loc2/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc2/permute" + type: "Permute" + bottom: "loc2/conv" + top: "loc2/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc2/flatten" + type: "Flatten" + bottom: "loc2/permute" + top: "loc2/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage5_4/sum/prior_box" + type: "PriorBox" + bottom: "stage5_4/sum" + bottom: "data" + top: "stage5_4/sum/prior_box" + prior_box_param { + min_size: 100.0 + max_size: 150.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "cls3/conv" + type: "Convolution" + bottom: "stage6_2/sum" + top: "cls3/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls3/permute" + type: "Permute" + bottom: "cls3/conv" + top: "cls3/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls3/flatten" + type: "Flatten" + bottom: "cls3/permute" + top: "cls3/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc3/conv" + type: "Convolution" + bottom: "stage6_2/sum" + top: "loc3/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc3/permute" + type: "Permute" + bottom: "loc3/conv" + top: "loc3/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc3/flatten" + type: "Flatten" + bottom: "loc3/permute" + top: "loc3/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage6_2/sum/prior_box" + type: "PriorBox" + bottom: "stage6_2/sum" + bottom: "data" + top: "stage6_2/sum/prior_box" + prior_box_param { + min_size: 150.0 + max_size: 200.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "cls4/conv" + type: "Convolution" + bottom: "stage7_2/sum" + top: "cls4/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls4/permute" + type: "Permute" + bottom: "cls4/conv" + top: "cls4/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls4/flatten" + type: "Flatten" + bottom: "cls4/permute" + top: "cls4/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc4/conv" + type: "Convolution" + bottom: "stage7_2/sum" + top: "loc4/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc4/permute" + type: "Permute" + bottom: "loc4/conv" + top: "loc4/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc4/flatten" + type: "Flatten" + bottom: "loc4/permute" + top: "loc4/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage7_2/sum/prior_box" + type: "PriorBox" + bottom: "stage7_2/sum" + bottom: "data" + top: "stage7_2/sum/prior_box" + prior_box_param { + min_size: 200.0 + max_size: 300.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "cls5/conv" + type: "Convolution" + bottom: "stage8_2/sum" + top: "cls5/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls5/permute" + type: "Permute" + bottom: "cls5/conv" + top: "cls5/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls5/flatten" + type: "Flatten" + bottom: "cls5/permute" + top: "cls5/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc5/conv" + type: "Convolution" + bottom: "stage8_2/sum" + top: "loc5/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc5/permute" + type: "Permute" + bottom: "loc5/conv" + top: "loc5/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc5/flatten" + type: "Flatten" + bottom: "loc5/permute" + top: "loc5/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage8_2/sum/prior_box" + type: "PriorBox" + bottom: "stage8_2/sum" + bottom: "data" + top: "stage8_2/sum/prior_box" + prior_box_param { + min_size: 300.0 + max_size: 400.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "mbox_conf" + type: "Concat" + bottom: "cls1/flatten" + bottom: "cls2/flatten" + bottom: "cls3/flatten" + bottom: "cls4/flatten" + bottom: "cls5/flatten" + top: "mbox_conf" + concat_param { + axis: 1 + } +} +layer { + name: "mbox_loc" + type: "Concat" + bottom: "loc1/flatten" + bottom: "loc2/flatten" + bottom: "loc3/flatten" + bottom: "loc4/flatten" + bottom: "loc5/flatten" + top: "mbox_loc" + concat_param { + axis: 1 + } +} +layer { + name: "mbox_priorbox" + type: "Concat" + bottom: "stage4_8/sum/prior_box" + bottom: "stage5_4/sum/prior_box" + bottom: "stage6_2/sum/prior_box" + bottom: "stage7_2/sum/prior_box" + bottom: "stage8_2/sum/prior_box" + top: "mbox_priorbox" + concat_param { + axis: 2 + } +} +layer { + name: "mbox_conf_reshape" + type: "Reshape" + bottom: "mbox_conf" + top: "mbox_conf_reshape" + reshape_param { + shape { + dim: 0 + dim: -1 + dim: 2 + } + } +} +layer { + name: "mbox_conf_softmax" + type: "Softmax" + bottom: "mbox_conf_reshape" + top: "mbox_conf_softmax" + softmax_param { + axis: 2 + } +} +layer { + name: "mbox_conf_flatten" + type: "Flatten" + bottom: "mbox_conf_softmax" + top: "mbox_conf_flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "detection_output" + type: "DetectionOutput" + bottom: "mbox_loc" + bottom: "mbox_conf_flatten" + bottom: "mbox_priorbox" + top: "detection_output" + detection_output_param { + num_classes: 2 + share_location: true + background_label_id: 0 + nms_param { + nms_threshold: 0.44999998807907104 + top_k: 100 + } + code_type: CENTER_SIZE + keep_top_k: 100 + confidence_threshold: 0.20000000298023224 + } +} diff --git a/emblem5/ai/wechat_qrcode/sr.caffemodel b/emblem5/ai/wechat_qrcode/sr.caffemodel new file mode 100644 index 0000000..168b54d Binary files /dev/null and b/emblem5/ai/wechat_qrcode/sr.caffemodel differ diff --git a/emblem5/ai/wechat_qrcode/sr.prototxt b/emblem5/ai/wechat_qrcode/sr.prototxt new file mode 100644 index 0000000..e85caa1 --- /dev/null +++ b/emblem5/ai/wechat_qrcode/sr.prototxt @@ -0,0 +1,403 @@ +layer { + name: "data" + type: "Input" + top: "data" + input_param { + shape { + dim: 1 + dim: 1 + dim: 224 + dim: 224 + } + } +} +layer { + name: "conv0" + type: "Convolution" + bottom: "data" + top: "conv0" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 1 + kernel_size: 3 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "conv0/lrelu" + type: "ReLU" + bottom: "conv0" + top: "conv0" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/reduce" + type: "Convolution" + bottom: "conv0" + top: "db1/reduce" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db1/reduce/lrelu" + type: "ReLU" + bottom: "db1/reduce" + top: "db1/reduce" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/3x3" + type: "Convolution" + bottom: "db1/reduce" + top: "db1/3x3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 1 + kernel_size: 3 + group: 8 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db1/3x3/lrelu" + type: "ReLU" + bottom: "db1/3x3" + top: "db1/3x3" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/1x1" + type: "Convolution" + bottom: "db1/3x3" + top: "db1/1x1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db1/1x1/lrelu" + type: "ReLU" + bottom: "db1/1x1" + top: "db1/1x1" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/concat" + type: "Concat" + bottom: "conv0" + bottom: "db1/1x1" + top: "db1/concat" + concat_param { + axis: 1 + } +} +layer { + name: "db2/reduce" + type: "Convolution" + bottom: "db1/concat" + top: "db2/reduce" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db2/reduce/lrelu" + type: "ReLU" + bottom: "db2/reduce" + top: "db2/reduce" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db2/3x3" + type: "Convolution" + bottom: "db2/reduce" + top: "db2/3x3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 1 + kernel_size: 3 + group: 8 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db2/3x3/lrelu" + type: "ReLU" + bottom: "db2/3x3" + top: "db2/3x3" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db2/1x1" + type: "Convolution" + bottom: "db2/3x3" + top: "db2/1x1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db2/1x1/lrelu" + type: "ReLU" + bottom: "db2/1x1" + top: "db2/1x1" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db2/concat" + type: "Concat" + bottom: "db1/concat" + bottom: "db2/1x1" + top: "db2/concat" + concat_param { + axis: 1 + } +} +layer { + name: "upsample/reduce" + type: "Convolution" + bottom: "db2/concat" + top: "upsample/reduce" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "upsample/reduce/lrelu" + type: "ReLU" + bottom: "upsample/reduce" + top: "upsample/reduce" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "upsample/deconv" + type: "Deconvolution" + bottom: "upsample/reduce" + top: "upsample/deconv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 1 + kernel_size: 3 + group: 32 + stride: 2 + weight_filler { + type: "msra" + } + } +} +layer { + name: "upsample/lrelu" + type: "ReLU" + bottom: "upsample/deconv" + top: "upsample/deconv" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "upsample/rec" + type: "Convolution" + bottom: "upsample/deconv" + top: "upsample/rec" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 1 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "nearest" + type: "Deconvolution" + bottom: "data" + top: "nearest" + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 1 + bias_term: false + pad: 0 + kernel_size: 2 + group: 1 + stride: 2 + weight_filler { + type: "constant" + value: 1.0 + } + } +} +layer { + name: "Crop1" + type: "Crop" + bottom: "nearest" + bottom: "upsample/rec" + top: "Crop1" +} +layer { + name: "fc" + type: "Eltwise" + bottom: "Crop1" + bottom: "upsample/rec" + top: "fc" + eltwise_param { + operation: SUM + } +} diff --git a/emblem5/baseimg/Dockerfile b/emblem5/baseimg/Dockerfile new file mode 100644 index 0000000..5754cb1 --- /dev/null +++ b/emblem5/baseimg/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:24.04 +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + git \ + python3-pip \ + python3-venv \ + libglib2.0-0 \ + libgl1 +RUN python3 -m venv /venv +RUN /venv/bin/pip install torch torchvision torchaudio -i https://download.pytorch.org/whl/cu121 +ADD requirements.txt /tmp/requirements.txt +RUN /venv/bin/pip install --upgrade pip +RUN /venv/bin/pip install -r /tmp/requirements.txt diff --git a/emblem5/baseimg/Makefile b/emblem5/baseimg/Makefile new file mode 100644 index 0000000..e03ee39 --- /dev/null +++ b/emblem5/baseimg/Makefile @@ -0,0 +1,10 @@ +IMG_TAG := $(shell date +%Y%m%d%H)-$(shell git rev-parse --short HEAD) +IMG_NAME := registry.cn-shenzhen.aliyuncs.com/emblem/baseimg:$(IMG_TAG) + +default: build push + +build: + docker build -t $(IMG_NAME) . + +push: + docker push $(IMG_NAME) \ No newline at end of file diff --git a/emblem5/baseimg/requirements.txt b/emblem5/baseimg/requirements.txt new file mode 100644 index 0000000..fb8748c --- /dev/null +++ b/emblem5/baseimg/requirements.txt @@ -0,0 +1,15 @@ +tqdm +loguru +pillow +numpy +pandas +matplotlib +scikit-learn +scipy +seaborn +flask +oss2 +requests +kornia +opencv-python +opencv-contrib-python \ No newline at end of file diff --git a/emblem5/baseimg/ubuntu.sources b/emblem5/baseimg/ubuntu.sources new file mode 100644 index 0000000..f6b118d --- /dev/null +++ b/emblem5/baseimg/ubuntu.sources @@ -0,0 +1,12 @@ +Types: deb +#URIs: http://archive.ubuntu.com/ubuntu/ +URIs: http://mirrors.aliyun.com/ubuntu/ +Suites: noble noble-updates noble-backports +Components: main restricted universe multiverse +Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg + +Types: deb +URIs: http://mirrors.aliyun.com/ubuntu/ +Suites: noble-security +Components: main restricted universe multiverse +Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg \ No newline at end of file diff --git a/emblem5/deploy/all.yaml.tmpl b/emblem5/deploy/all.yaml.tmpl new file mode 100644 index 0000000..fd79ee6 --- /dev/null +++ b/emblem5/deploy/all.yaml.tmpl @@ -0,0 +1,114 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: "emblem" + labels: + name: "emblem" +--- +apiVersion: v1 +kind: Secret +metadata: + name: regcred + namespace: emblem +data: + .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOiB7CgkJCSJhdXRoIjogIlptRnRlbWhsYm1jNmFuUmFOamMwWlhSMmNHNTVTMEk9IgoJCX0sCgkJInJlZ2lzdHJ5LmNuLWJlaWppbmcuYWxpeXVuY3MuY29tIjogewoJCQkiYXV0aCI6ICJaWFZ3YUc5dU9ucEZPRjVlWTJ0cWJtTktRa29xIgoJCX0sCgkJInJlZ2lzdHJ5LmNuLXNoZW56aGVuLmFsaXl1bmNzLmNvbSI6IHsKCQkJImF1dGgiOiAiWlhWd2FHOXVPbnBGT0Y1ZVkydHFibU5LUWtvcSIKCQl9LAoJCSJyZWdpc3RyeS5naXRsYWIuY29tIjogewoJCQkiYXV0aCI6ICJabUZ0ZW1obGJtYzZaMnh3WVhRdFIyWjZXbmxFUjNCMU9XZEtlVGRSTVZSUmVtWT0iCgkJfQoJfQp9Cg== +type: kubernetes.io/dockerconfigjson +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: server + deploy-timestamp: "${deploy_timestamp}" + name: server + namespace: emblem +spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app.kubernetes.io/name: server + template: + metadata: + labels: + app.kubernetes.io/name: server + deploy-timestamp: "${deploy_timestamp}" + spec: + imagePullSecrets: + - name: regcred + volumes: + - name: data + hostPath: + path: /data/emblem + type: Directory + containers: + - image: ${image} + imagePullPolicy: IfNotPresent + name: server + volumeMounts: + - mountPath: /emblem/data + name: data + env: + - name: EMBLEM_ENV + value: ${emblem_env} + - name: EMBLEM_DB_TYPE + value: postgres + - name: EMBLEM_DB_HOST + value: ${db_host} + resources: + requests: + memory: "2048Mi" + cpu: "1000m" + limits: + memory: "2048Mi" + cpu: "1000m" + ports: + - containerPort: 80 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: server + namespace: emblem +spec: + selector: + app.kubernetes.io/name: server + ports: + - protocol: TCP + port: 80 + targetPort: http +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: server + namespace: emblem + annotations: + traefik.ingress.kubernetes.io/router.tls.certresolver: le +spec: + tls: + - hosts: +% for host in hosts: + - ${host} +% endfor + rules: +% for host in hosts: + - host: ${host} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: server + port: + number: 80 +% endfor diff --git a/emblem5/deploy/elastic-agent.yml b/emblem5/deploy/elastic-agent.yml new file mode 100644 index 0000000..2bda929 --- /dev/null +++ b/emblem5/deploy/elastic-agent.yml @@ -0,0 +1,1135 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: agent-node-datastreams + namespace: kube-system + labels: + k8s-app: elastic-agent +data: + agent.yml: |- + id: 73a81330-1910-11ee-b20d-d98d3a64e60b + outputs: + default: + type: elasticsearch + hosts: + - 'https://es.euphon.uk:443' + username: 'elastic' + password: 'f37QjBRklMXU4hPn' + allow_older_versions: true + inputs: + - id: kubernetes/metrics-kubelet-9d099e73-6c3c-4b20-acab-5f460f2a9709 + revision: 1 + name: emblem + type: kubernetes/metrics + data_stream: + namespace: default + use_output: default + package_policy_id: 9d099e73-6c3c-4b20-acab-5f460f2a9709 + streams: + - id: >- + kubernetes/metrics-kubernetes.container-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.container + metricsets: + - container + add_metadata: true + hosts: + - 'https://${env.NODE_NAME}:10250' + period: 10s + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.verification_mode: none + - id: >- + kubernetes/metrics-kubernetes.node-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.node + metricsets: + - node + add_metadata: true + hosts: + - 'https://${env.NODE_NAME}:10250' + period: 10s + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.verification_mode: none + - id: >- + kubernetes/metrics-kubernetes.pod-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.pod + metricsets: + - pod + add_metadata: true + hosts: + - 'https://${env.NODE_NAME}:10250' + period: 10s + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.verification_mode: none + - id: >- + kubernetes/metrics-kubernetes.system-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.system + metricsets: + - system + add_metadata: true + hosts: + - 'https://${env.NODE_NAME}:10250' + period: 10s + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.verification_mode: none + - id: >- + kubernetes/metrics-kubernetes.volume-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.volume + metricsets: + - volume + add_metadata: true + hosts: + - 'https://${env.NODE_NAME}:10250' + period: 10s + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.verification_mode: none + meta: + package: + name: kubernetes + version: 1.29.2 + - id: >- + kubernetes/metrics-kube-state-metrics-9d099e73-6c3c-4b20-acab-5f460f2a9709 + revision: 1 + name: emblem + type: kubernetes/metrics + data_stream: + namespace: default + use_output: default + package_policy_id: 9d099e73-6c3c-4b20-acab-5f460f2a9709 + streams: + - id: >- + kubernetes/metrics-kubernetes.state_container-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_container + metricsets: + - state_container + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_cronjob-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_cronjob + metricsets: + - state_cronjob + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_daemonset-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_daemonset + metricsets: + - state_daemonset + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_deployment-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_deployment + metricsets: + - state_deployment + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_job-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_job + metricsets: + - state_job + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_node-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_node + metricsets: + - state_node + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_persistentvolume-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_persistentvolume + metricsets: + - state_persistentvolume + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_persistentvolumeclaim-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_persistentvolumeclaim + metricsets: + - state_persistentvolumeclaim + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_pod-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_pod + metricsets: + - state_pod + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_replicaset-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_replicaset + metricsets: + - state_replicaset + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_resourcequota-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_resourcequota + metricsets: + - state_resourcequota + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_service-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_service + metricsets: + - state_service + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_statefulset-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_statefulset + metricsets: + - state_statefulset + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + - id: >- + kubernetes/metrics-kubernetes.state_storageclass-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.state_storageclass + metricsets: + - state_storageclass + add_metadata: true + hosts: + - 'kube-state-metrics:8080' + period: 10s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + meta: + package: + name: kubernetes + version: 1.29.2 + - id: kubernetes/metrics-kube-apiserver-9d099e73-6c3c-4b20-acab-5f460f2a9709 + revision: 1 + name: emblem + type: kubernetes/metrics + data_stream: + namespace: default + use_output: default + package_policy_id: 9d099e73-6c3c-4b20-acab-5f460f2a9709 + streams: + - id: >- + kubernetes/metrics-kubernetes.apiserver-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.apiserver + metricsets: + - apiserver + hosts: + - >- + https://${env.KUBERNETES_SERVICE_HOST}:${env.KUBERNETES_SERVICE_PORT} + period: 30s + condition: '${kubernetes_leaderelection.leader} == true' + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + ssl.certificate_authorities: + - /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + meta: + package: + name: kubernetes + version: 1.29.2 + - id: kubernetes/metrics-kube-proxy-9d099e73-6c3c-4b20-acab-5f460f2a9709 + revision: 1 + name: emblem + type: kubernetes/metrics + data_stream: + namespace: default + use_output: default + package_policy_id: 9d099e73-6c3c-4b20-acab-5f460f2a9709 + streams: + - id: >- + kubernetes/metrics-kubernetes.proxy-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.proxy + metricsets: + - proxy + hosts: + - 'localhost:10249' + period: 10s + meta: + package: + name: kubernetes + version: 1.29.2 + - id: kubernetes/metrics-events-9d099e73-6c3c-4b20-acab-5f460f2a9709 + revision: 1 + name: emblem + type: kubernetes/metrics + data_stream: + namespace: default + use_output: default + package_policy_id: 9d099e73-6c3c-4b20-acab-5f460f2a9709 + streams: + - id: >- + kubernetes/metrics-kubernetes.event-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: metrics + dataset: kubernetes.event + metricsets: + - event + period: 10s + add_metadata: true + skip_older: true + condition: '${kubernetes_leaderelection.leader} == true' + meta: + package: + name: kubernetes + version: 1.29.2 + - id: filestream-container-logs-9d099e73-6c3c-4b20-acab-5f460f2a9709 + revision: 1 + name: emblem + type: filestream + data_stream: + namespace: default + use_output: default + package_policy_id: 9d099e73-6c3c-4b20-acab-5f460f2a9709 + streams: + - id: >- + kubernetes-container-logs-${kubernetes.pod.name}-${kubernetes.container.id} + data_stream: + type: logs + dataset: kubernetes.container_logs + paths: + - '/var/log/containers/*${kubernetes.container.id}.log' + prospector.scanner.symlinks: true + parsers: + - container: + stream: all + format: auto + meta: + package: + name: kubernetes + version: 1.29.2 + - id: filestream-audit-logs-9d099e73-6c3c-4b20-acab-5f460f2a9709 + revision: 1 + name: emblem + type: filestream + data_stream: + namespace: default + use_output: default + package_policy_id: 9d099e73-6c3c-4b20-acab-5f460f2a9709 + streams: + - id: >- + filestream-kubernetes.audit_logs-9d099e73-6c3c-4b20-acab-5f460f2a9709 + data_stream: + type: logs + dataset: kubernetes.audit_logs + paths: + - /var/log/kubernetes/kube-apiserver-audit.log + exclude_files: + - .gz$ + parsers: + - ndjson: + add_error_key: true + target: kubernetes_audit + processors: + - rename: + fields: + - from: kubernetes_audit + to: kubernetes.audit + - drop_fields: + when: + has_fields: kubernetes.audit.responseObject + fields: + - kubernetes.audit.responseObject.metadata + - drop_fields: + when: + has_fields: kubernetes.audit.requestObject + fields: + - kubernetes.audit.requestObject.metadata + - script: + lang: javascript + id: dedot_annotations + source: | + function process(event) { + var audit = event.Get("kubernetes.audit"); + for (var annotation in audit["annotations"]) { + var annotation_dedoted = annotation.replace(/\./g,'_') + event.Rename("kubernetes.audit.annotations."+annotation, "kubernetes.audit.annotations."+annotation_dedoted) + } + return event; + } function test() { + var event = process(new Event({ "kubernetes": { "audit": { "annotations": { "authorization.k8s.io/decision": "allow", "authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"system:kube-scheduler\" of ClusterRole \"system:kube-scheduler\" to User \"system:kube-scheduler\"" } } } })); + if (event.Get("kubernetes.audit.annotations.authorization_k8s_io/decision") !== "allow") { + throw "expected kubernetes.audit.annotations.authorization_k8s_io/decision === allow"; + } + } + meta: + package: + name: kubernetes + version: 1.29.2 + - id: logfile-system-51bc31a5-c238-4281-be45-87d5111fc100 + revision: 1 + name: system-1 + type: logfile + data_stream: + namespace: default + use_output: default + package_policy_id: 51bc31a5-c238-4281-be45-87d5111fc100 + streams: + - id: logfile-system.auth-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: logs + dataset: system.auth + ignore_older: 72h + paths: + - /var/log/auth.log* + - /var/log/secure* + exclude_files: + - .gz$ + multiline: + pattern: ^\s + match: after + tags: + - system-auth + processors: + - add_locale: null + - id: logfile-system.syslog-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: logs + dataset: system.syslog + paths: + - /var/log/messages* + - /var/log/syslog* + exclude_files: + - .gz$ + multiline: + pattern: ^\s + match: after + processors: + - add_locale: null + ignore_older: 72h + meta: + package: + name: system + version: 1.25.2 + - id: winlog-system-51bc31a5-c238-4281-be45-87d5111fc100 + revision: 1 + name: system-1 + type: winlog + data_stream: + namespace: default + use_output: default + package_policy_id: 51bc31a5-c238-4281-be45-87d5111fc100 + streams: + - id: winlog-system.application-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: logs + dataset: system.application + name: Application + condition: '${host.platform} == ''windows''' + ignore_older: 72h + - id: winlog-system.security-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: logs + dataset: system.security + name: Security + condition: '${host.platform} == ''windows''' + ignore_older: 72h + - id: winlog-system.system-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: logs + dataset: system.system + name: System + condition: '${host.platform} == ''windows''' + ignore_older: 72h + meta: + package: + name: system + version: 1.25.2 + - id: system/metrics-system-51bc31a5-c238-4281-be45-87d5111fc100 + revision: 1 + name: system-1 + type: system/metrics + data_stream: + namespace: default + use_output: default + package_policy_id: 51bc31a5-c238-4281-be45-87d5111fc100 + streams: + - id: system/metrics-system.cpu-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.cpu + metricsets: + - cpu + cpu.metrics: + - percentages + - normalized_percentages + period: 10s + - id: system/metrics-system.diskio-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.diskio + metricsets: + - diskio + diskio.include_devices: null + period: 10s + - id: >- + system/metrics-system.filesystem-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.filesystem + metricsets: + - filesystem + period: 1m + processors: + - drop_event.when.regexp: + system.filesystem.mount_point: ^/(sys|cgroup|proc|dev|etc|host|lib|snap)($|/) + - id: system/metrics-system.fsstat-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.fsstat + metricsets: + - fsstat + period: 1m + processors: + - drop_event.when.regexp: + system.fsstat.mount_point: ^/(sys|cgroup|proc|dev|etc|host|lib|snap)($|/) + - id: system/metrics-system.load-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.load + metricsets: + - load + condition: '${host.platform} != ''windows''' + period: 10s + - id: system/metrics-system.memory-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.memory + metricsets: + - memory + period: 10s + - id: system/metrics-system.network-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.network + metricsets: + - network + period: 10s + network.interfaces: null + - id: system/metrics-system.process-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.process + metricsets: + - process + period: 10s + process.include_top_n.by_cpu: 5 + process.include_top_n.by_memory: 5 + process.cmdline.cache.enabled: true + process.cgroups.enabled: false + process.include_cpu_ticks: false + processes: + - .* + - id: >- + system/metrics-system.process.summary-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.process.summary + metricsets: + - process_summary + period: 10s + - id: >- + system/metrics-system.socket_summary-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.socket_summary + metricsets: + - socket_summary + period: 10s + - id: system/metrics-system.uptime-51bc31a5-c238-4281-be45-87d5111fc100 + data_stream: + type: metrics + dataset: system.uptime + metricsets: + - uptime + period: 10s + meta: + package: + name: system + version: 1.25.2 + revision: 2 + agent: + download: + source_uri: 'https://artifacts.elastic.co/downloads/' + monitoring: + namespace: default + use_output: default + enabled: true + logs: true + metrics: true + output_permissions: + default: + _elastic_agent_monitoring: + indices: + - names: + - logs-elastic_agent.apm_server-default + privileges: &ref_0 + - auto_configure + - create_doc + - names: + - metrics-elastic_agent.apm_server-default + privileges: *ref_0 + - names: + - logs-elastic_agent.auditbeat-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.auditbeat-default + privileges: *ref_0 + - names: + - logs-elastic_agent.cloud_defend-default + privileges: *ref_0 + - names: + - logs-elastic_agent.cloudbeat-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.cloudbeat-default + privileges: *ref_0 + - names: + - logs-elastic_agent-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.elastic_agent-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.endpoint_security-default + privileges: *ref_0 + - names: + - logs-elastic_agent.endpoint_security-default + privileges: *ref_0 + - names: + - logs-elastic_agent.filebeat_input-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.filebeat_input-default + privileges: *ref_0 + - names: + - logs-elastic_agent.filebeat-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.filebeat-default + privileges: *ref_0 + - names: + - logs-elastic_agent.fleet_server-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.fleet_server-default + privileges: *ref_0 + - names: + - logs-elastic_agent.heartbeat-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.heartbeat-default + privileges: *ref_0 + - names: + - logs-elastic_agent.metricbeat-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.metricbeat-default + privileges: *ref_0 + - names: + - logs-elastic_agent.osquerybeat-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.osquerybeat-default + privileges: *ref_0 + - names: + - logs-elastic_agent.packetbeat-default + privileges: *ref_0 + - names: + - metrics-elastic_agent.packetbeat-default + privileges: *ref_0 + _elastic_agent_checks: + cluster: + - monitor + 9d099e73-6c3c-4b20-acab-5f460f2a9709: + indices: + - names: + - metrics-kubernetes.container-default + privileges: *ref_0 + - names: + - metrics-kubernetes.node-default + privileges: *ref_0 + - names: + - metrics-kubernetes.pod-default + privileges: *ref_0 + - names: + - metrics-kubernetes.system-default + privileges: *ref_0 + - names: + - metrics-kubernetes.volume-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_container-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_cronjob-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_daemonset-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_deployment-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_job-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_node-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_persistentvolume-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_persistentvolumeclaim-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_pod-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_replicaset-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_resourcequota-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_service-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_statefulset-default + privileges: *ref_0 + - names: + - metrics-kubernetes.state_storageclass-default + privileges: *ref_0 + - names: + - metrics-kubernetes.apiserver-default + privileges: *ref_0 + - names: + - metrics-kubernetes.proxy-default + privileges: *ref_0 + - names: + - metrics-kubernetes.event-default + privileges: *ref_0 + - names: + - logs-kubernetes.container_logs-default + privileges: *ref_0 + - names: + - logs-kubernetes.audit_logs-default + privileges: *ref_0 + 51bc31a5-c238-4281-be45-87d5111fc100: + indices: + - names: + - logs-system.auth-default + privileges: *ref_0 + - names: + - logs-system.syslog-default + privileges: *ref_0 + - names: + - logs-system.application-default + privileges: *ref_0 + - names: + - logs-system.security-default + privileges: *ref_0 + - names: + - logs-system.system-default + privileges: *ref_0 + - names: + - metrics-system.cpu-default + privileges: *ref_0 + - names: + - metrics-system.diskio-default + privileges: *ref_0 + - names: + - metrics-system.filesystem-default + privileges: *ref_0 + - names: + - metrics-system.fsstat-default + privileges: *ref_0 + - names: + - metrics-system.load-default + privileges: *ref_0 + - names: + - metrics-system.memory-default + privileges: *ref_0 + - names: + - metrics-system.network-default + privileges: *ref_0 + - names: + - metrics-system.process-default + privileges: *ref_0 + - names: + - metrics-system.process.summary-default + privileges: *ref_0 + - names: + - metrics-system.socket_summary-default + privileges: *ref_0 + - names: + - metrics-system.uptime-default + privileges: *ref_0 + +--- +# For more information refer https://www.elastic.co/guide/en/fleet/current/running-on-kubernetes-standalone.html +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: elastic-agent + namespace: kube-system + labels: + app: elastic-agent +spec: + selector: + matchLabels: + app: elastic-agent + template: + metadata: + labels: + app: elastic-agent + spec: + # Tolerations are needed to run Elastic Agent on Kubernetes control-plane nodes. + # Agents running on control-plane nodes collect metrics from the control plane components (scheduler, controller manager) of Kubernetes + tolerations: + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule + - key: node-role.kubernetes.io/master + effect: NoSchedule + serviceAccountName: elastic-agent + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + containers: + - name: elastic-agent + image: docker.elastic.co/beats/elastic-agent:8.5.1 + args: [ + "-c", "/etc/agent.yml", + "-e", + ] + env: + # The basic authentication username used to connect to Elasticsearch + # This user needs the privileges required to publish events to Elasticsearch. + - name: ES_USERNAME + value: "elastic" + # The basic authentication password used to connect to Elasticsearch + - name: ES_PASSWORD + value: "changeme" + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + securityContext: + runAsUser: 0 + resources: + limits: + memory: 700Mi + requests: + cpu: 100m + memory: 400Mi + volumeMounts: + - name: datastreams + mountPath: /etc/agent.yml + readOnly: true + subPath: agent.yml + - name: proc + mountPath: /hostfs/proc + readOnly: true + - name: cgroup + mountPath: /hostfs/sys/fs/cgroup + readOnly: true + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + - name: varlog + mountPath: /var/log + readOnly: true + - name: etc-kubernetes + mountPath: /hostfs/etc/kubernetes + readOnly: true + - name: var-lib + mountPath: /hostfs/var/lib + readOnly: true + - name: passwd + mountPath: /hostfs/etc/passwd + readOnly: true + - name: group + mountPath: /hostfs/etc/group + readOnly: true + - name: etcsysmd + mountPath: /hostfs/etc/systemd + readOnly: true + volumes: + - name: datastreams + configMap: + defaultMode: 0640 + name: agent-node-datastreams + - name: proc + hostPath: + path: /proc + - name: cgroup + hostPath: + path: /sys/fs/cgroup + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers + - name: varlog + hostPath: + path: /var/log + # Needed for cloudbeat + - name: etc-kubernetes + hostPath: + path: /etc/kubernetes + # Needed for cloudbeat + - name: var-lib + hostPath: + path: /var/lib + # Needed for cloudbeat + - name: passwd + hostPath: + path: /etc/passwd + # Needed for cloudbeat + - name: group + hostPath: + path: /etc/group + # Needed for cloudbeat + - name: etcsysmd + hostPath: + path: /etc/systemd +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: elastic-agent +subjects: + - kind: ServiceAccount + name: elastic-agent + namespace: kube-system +roleRef: + kind: ClusterRole + name: elastic-agent + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + namespace: kube-system + name: elastic-agent +subjects: + - kind: ServiceAccount + name: elastic-agent + namespace: kube-system +roleRef: + kind: Role + name: elastic-agent + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: elastic-agent-kubeadm-config + namespace: kube-system +subjects: + - kind: ServiceAccount + name: elastic-agent + namespace: kube-system +roleRef: + kind: Role + name: elastic-agent-kubeadm-config + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: elastic-agent + labels: + k8s-app: elastic-agent +rules: + - apiGroups: [""] + resources: + - nodes + - namespaces + - events + - pods + - services + - configmaps + # Needed for cloudbeat + - serviceaccounts + - persistentvolumes + - persistentvolumeclaims + verbs: ["get", "list", "watch"] + # Enable this rule only if planing to use kubernetes_secrets provider + #- apiGroups: [""] + # resources: + # - secrets + # verbs: ["get"] + - apiGroups: ["extensions"] + resources: + - replicasets + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: + - statefulsets + - deployments + - replicasets + - daemonsets + verbs: ["get", "list", "watch"] + - apiGroups: ["batch"] + resources: + - jobs + - cronjobs + verbs: ["get", "list", "watch"] + - apiGroups: + - "" + resources: + - nodes/stats + verbs: + - get + # Needed for apiserver + - nonResourceURLs: + - "/metrics" + verbs: + - get + # Needed for cloudbeat + - apiGroups: ["rbac.authorization.k8s.io"] + resources: + - clusterrolebindings + - clusterroles + - rolebindings + - roles + verbs: ["get", "list", "watch"] + # Needed for cloudbeat + - apiGroups: ["policy"] + resources: + - podsecuritypolicies + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: elastic-agent + # Should be the namespace where elastic-agent is running + namespace: kube-system + labels: + k8s-app: elastic-agent +rules: + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: ["get", "create", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: elastic-agent-kubeadm-config + namespace: kube-system + labels: + k8s-app: elastic-agent +rules: + - apiGroups: [""] + resources: + - configmaps + resourceNames: + - kubeadm-config + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: elastic-agent + namespace: kube-system + labels: + k8s-app: elastic-agent +--- diff --git a/emblem5/deploy/kubeconfig.dev b/emblem5/deploy/kubeconfig.dev new file mode 100644 index 0000000..093d2db --- /dev/null +++ b/emblem5/deploy/kubeconfig.dev @@ -0,0 +1,20 @@ +apiVersion: v1 +clusters: +- cluster: + insecure-skip-tls-verify: true + server: https://derby.euphon.net:6443 + name: default +contexts: +- context: + cluster: default + namespace: emblem + user: default + name: default +current-context: default +kind: Config +preferences: {} +users: +- name: default + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrRENDQVRlZ0F3SUJBZ0lJYlV6UGpWalNzYll3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOekl6TURVNU9UQTNNQjRYRFRJME1EZ3dOekU1TkRVd04xb1hEVEkxTURndwpOekU1TkRVd04xb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJHZjgvYlFKaU1rQUdIdUMKdG9qK0crVmsrbGgvalBvTUs1V29Zbi9xaGZBL0NrT05QMlIvTy9yci9uK2xZUERIZkMvaXVIcmx5ZUtkL1ZwTAozeVR4SVc2alNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCUXdtL2pDTWozOXhEbG1aU05HNmdCTGJvL2ZPREFLQmdncWhrak9QUVFEQWdOSEFEQkUKQWlBOVREdHBIK0RaQ3g3Q2NWVXZYQVpLMFg2UUpxUldESWMrdkxIMEdRc3p0d0lnRkZObTk1R015ZXdIN3hqYQppVnhHREVjT281OG9sNDF3SUU2WFpRa2pNdEU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTWpNd05UazVNRGN3SGhjTk1qUXdPREEzTVRrME5UQTNXaGNOTXpRd09EQTFNVGswTlRBMwpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTWpNd05UazVNRGN3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSdEtyd3hYRTB2L0FCV3FYS1dheGtGQlU0VmZuZmxGOFUwcjViUmt5cFQKRjRhVzV3N21ONkhOK01TdGo4T3BlVHBKSzJtM0VNbkE5SnFrS0ZhM3N0S0lvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVU1KdjR3akk5L2NRNVptVWpSdW9BClMyNlAzemd3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnUW9XYlhZT3Brb1owL1hIeGRNTXEydWJYWUNrSmo3c2IKMnJqT3UxRlhmUEVDSVFEMEpId0NsZDdrME9FK2ZVK1ZYWDVSRWdWMFFmK2gxU3RNUS9KdFBjMXVkdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU04Q0dzMGRZNGN0MWJZaUJScGVvK1dLTmhBbzl0b1d2NHpCcmR4S3U0RWVvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWi96OXRBbUl5UUFZZTRLMmlQNGI1V1Q2V0grTStnd3JsYWhpZitxRjhEOEtRNDAvWkg4NwordXYrZjZWZzhNZDhMK0s0ZXVYSjRwMzlXa3ZmSlBFaGJnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= diff --git a/emblem5/deploy/kubeconfig.emblem-s1 b/emblem5/deploy/kubeconfig.emblem-s1 new file mode 100644 index 0000000..cc3e587 --- /dev/null +++ b/emblem5/deploy/kubeconfig.emblem-s1 @@ -0,0 +1,20 @@ +apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTURneE1EazROekF3SGhjTk1qUXdNakUyTVRnMU56VXdXaGNOTXpRd01qRXpNVGcxTnpVdwpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTURneE1EazROekF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFUd1FEUnZaRDV0OFJTcnBDU0pSOG5wdVg1NS8wdkJDTTJrUnBKdlFyanUKcTY3MnJCeUhyM3RQSmRWdmRnSHpYZnM4VzhpVTdiS2RvUlk4UWNuU2xKWjNvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVStYZjFsbjBjVll5Q3QrYTFFUEdnClkzdGVNTFF3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUlxWDJsczNlSkNoRnF1Vis1bklGY0R5N3RlUnhZdTMKMWJYNU1aYTkvRU9xQWlBN0M2MXZGV1B3Mk55WW83NG1pSUE2bldEMUxwVi9GOXBjVE9BaW5wdzR5Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + server: https://127.0.0.1:6443 + name: default +contexts: +- context: + cluster: default + user: default + namespace: emblem + name: default +current-context: default +kind: Config +preferences: {} +users: +- name: default + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJWGNzc0Y1QnpJeE13Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOekE0TVRBNU9EY3dNQjRYRFRJME1ESXhOakU0TlRjMU1Gb1hEVEkxTURJeApOVEU0TlRjMU1Gb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJHbWlZUUdxK3E4Y3JEQkQKemwraS9kb3BaNHphQWk1cXdFQkR4ZE1Bc1dabTdUOGNXT3BoejdtMTdaV3JZcm1rOTdFWXVmci8xcm1iREdPaAprOGhsUUdXalNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCUUhBNkdNMEdVSjBVN2NxeUVXS0VXNzdlVGlYakFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlCSi9XOXNFaU1JTUV5dGk3N1lDM2hud0c1eXNyeHAvWVgySFVKQUpFQlBVQUloQU4xM2M1anU5azd4a3ZlWgpVYmk1MmZNQzBIZUxUUUdNNitSblZ4VkVJKzZkCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTURneE1EazROekF3SGhjTk1qUXdNakUyTVRnMU56VXdXaGNOTXpRd01qRXpNVGcxTnpVdwpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTURneE1EazROekF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFUR3VZcmN6eVRsc09sUkRNMm5JRmFXUDVyeHdRRHp2amk5dkhDQ2grNnYKb1V0V3NsRWF3YnNqQjByVkZPdzYvQzZoZEgxQWNwVVE4TmM4K3RQQ2FJdFdvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVUJ3T2hqTkJsQ2RGTzNLc2hGaWhGCnUrM2s0bDR3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQU1xaTc5OHhoK3lwN3NrU3RtYmVuNFVuOGQ5bDU3SXAKck9NLzRaUU9CUnBNQWlFQXB2RUQxV3poVEVaZmt2a1hheTZrZlYvM2pLYXZEcnkrcG1LZVA0LzNpU2M9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUNjenNWazJ0ZCtzL1hVTGhNZ1BUbDVCVnpFYThPZ0hxWWViQTZRcXlOVTNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFYWFKaEFhcjZyeHlzTUVQT1g2TDkyaWxuak5vQ0xtckFRRVBGMHdDeFptYnRQeHhZNm1IUAp1Ylh0bGF0aXVhVDNzUmk1K3YvV3Vac01ZNkdUeUdWQVpRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= diff --git a/emblem5/deploy/kubeconfig.themblem b/emblem5/deploy/kubeconfig.themblem new file mode 100644 index 0000000..cbf61ac --- /dev/null +++ b/emblem5/deploy/kubeconfig.themblem @@ -0,0 +1,20 @@ +apiVersion: v1 +clusters: +- cluster: + insecure-skip-tls-verify: true + server: https://g.themblem.com:6443 + name: default +contexts: +- context: + cluster: default + namespace: emblem + user: default + name: default +current-context: default +kind: Config +preferences: {} +users: +- name: default + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrRENDQVRlZ0F3SUJBZ0lJRnlqb0ZiODFyTDR3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOekEwTkRRMU16QTBNQjRYRFRJME1ERXdOVEE1TURFME5Gb1hEVEkyTURJeApOREl5TXpBMU1Gb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJFRDREb0VCK042ZjN3cHIKWUpsZmpKN2puTnQxZmIvUi9laHpVSXNqNE41Smo3UVU2Z0MrQnUyUnUwRnczL2k1ZTdrODZqUU9LVjhicDBsVAptWHRHL25TalNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCVFNBRUk1dml6N1RQUlBmYUZpcm1jY0RQREVZVEFLQmdncWhrak9QUVFEQWdOSEFEQkUKQWlCeGo5NUNGSitDZzRiL1h0VEdiZlcyOWpUYUNlNDVSNHo3cndEQ3Yvd0Vud0lnUk9ZMHBFdjFMdnNZdEpnOQphZ2dEMkhTVDRMUnBlZTQrNlZhUTRkT3k0RVU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTURRME5EVXpNRFF3SGhjTk1qUXdNVEExTURrd01UUTBXaGNOTXpRd01UQXlNRGt3TVRRMApXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTURRME5EVXpNRFF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFRMituSHNmRzl2ZDcwc0RGUVh2aHFJTUZCbDlIMEh3TTFuNm8xZytEcFcKeWRwVisvSnEvSk9IZXNPT3VJWm5Pdi85bTZWemlmZE1QOTdXL1hBTWNWV0NvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBnQkNPYjRzKzB6MFQzMmhZcTVuCkhBend4R0V3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnQTdVMlVPOGdCVVNnMENEUnIzZlYwSEhDQTVxclIydzgKMkxVTnRtR0JSaXdDSVFEcVJZRXpxRHVTTXVSanlwU2JWcHYzbGNiSTIxOGhjUXV6eW1BcSs1czJQQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSURpam90Y2J6c3c0cE1rQlljZGFEQUlwVGJIRDNFY1F0L1pjbitDenpOMHdvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUVBnT2dRSDQzcC9mQ210Z21WK01udU9jMjNWOXY5SDk2SE5RaXlQZzNrbVB0QlRxQUw0Rwo3Wkc3UVhEZitMbDd1VHpxTkE0cFh4dW5TVk9aZTBiK2RBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= diff --git a/emblem5/pyrightconfig.json b/emblem5/pyrightconfig.json new file mode 100644 index 0000000..76eec29 --- /dev/null +++ b/emblem5/pyrightconfig.json @@ -0,0 +1,6 @@ +{ + "exclude": [ + "data", + "models" + ] +} \ No newline at end of file diff --git a/emblem5/scripts/copy-pos.py b/emblem5/scripts/copy-pos.py new file mode 100755 index 0000000..4237aa9 --- /dev/null +++ b/emblem5/scripts/copy-pos.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import os +import shutil +import json +import argparse + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--num-samples', '-n', type=int, default=100) + return parser.parse_args() + +def main(): + args = parse_args() + scan_samples = [x for x in os.listdir('data/samples') if 'scan-' in x] + scan_samples = sorted(scan_samples, reverse=True) + todo = args.num_samples + for scan in scan_samples: + if todo <= 0: + break + scan_dir = f'data/samples/{scan}' + md_file = f'data/samples/{scan}/metadata.json' + md = json.load(open(md_file)) + scan_id = scan.split('-')[-1] + targetd = f'/data/emblem/dataset/pos/scans/{scan_id}' + if os.path.exists(targetd): + continue + if 'pos' in md['labels']: + full_sbs_jpg = f'{scan_dir}/full-sbs.jpg' + if os.path.exists(full_sbs_jpg): + os.makedirs(targetd, exist_ok=True) + print(f'Copying {full_sbs_jpg} => {targetd}/fullqrsbs.jpg') + shutil.copy(full_sbs_jpg, f'{targetd}/fullqrsbs.jpg') + print(f'Copying {md_file} => {targetd}/metadata.json') + shutil.copy(md_file, f'{targetd}/metadata.json') + todo -= 1 + +if __name__ == '__main__': + main() diff --git a/emblem5/scripts/emcli b/emblem5/scripts/emcli new file mode 100755 index 0000000..0837237 --- /dev/null +++ b/emblem5/scripts/emcli @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 + +import os +import sys +import json +import requests +import argparse + +class SubCommand(object): + """ Base class of subcommand""" + help = "" + aliases = [] + want_argv = False # Whether the command accepts extra arguments + + envs = { + 'prod': { + 'server': 'https://themblem.com', + 'token': '3ebd8c33-f46e-4b06-bda8-4c0f5f5eb530', + }, + 'dev': { + 'server': 'https://dev.themblem.com', + 'token': 'D91AB64B-C5CA-4B78-AC76-01722B8C8A5C', + }, + } + + def setup_args(self, parser): + pass + + def do(self, args, argv): + """Do command""" + print("Not implemented") + + def get_env(self): + return self.envs[self.args.env] + + def get_server(self): + return self.get_env()['server'] + + def make_headers(self): + return { + 'Authorization': 'token ' + self.get_env()['token'], + } + +class ActivateCommand(SubCommand): + name = "activate" + want_argv = True + help = "Activate code" + + def setup_args(self, parser): + pass + + def do(self, args, argv): + for i in argv: + print(i) + self.activate(i) + + def activate(self, code): + server = self.get_server() + pk = self.get_pk(code) + url = f'{server}/api/v1/code/{pk}/' + r = requests.patch(url, headers=self.make_headers(), json={ + 'is_active': True, + }) + print(r.text) + + def get_pk(self, code): + server = self.get_server() + url = f'{server}/api/v1/code/?code=' + code + r = requests.get(url, headers=self.make_headers()) + r = r.json() + return r['objects'][0]['id'] + +class GetScanDataCommand(SubCommand): + name = "get-scan-data" + want_argv = True + help = "Get scan data from api" + + def setup_args(self, parser): + parser.add_argument("--output", "-o", required=True) + + def do(self, args, argv): + os.makedirs(args.output, exist_ok=True) + for i in argv: + sd = self.get_scan_data(i) + with open(f"{args.output}/metadata.json", "w") as f: + f.write(json.dumps(sd, indent=2) + "\n") + with open(f"{args.output}/frame.jpg", "wb") as f: + f.write(self.get_image(sd['image'])) + + def get_scan_data(self, i): + server = self.get_server() + url = f'{server}/api/v1/scan-data/{i}/' + print(url) + r = requests.get(url, headers=self.make_headers()) + return r.json() + + def get_image(self, name): + server = self.get_server() + token = self.get_env()['token'] + url = f'{server}/api/v1/oss-image/?token={token}&name={name}' + r = requests.get(url) + r.raise_for_status() + return r.content + + def get_roi(self, code): + server = self.get_server() + token = self.get_env()['token'] + url = f'{server}/api/v1/code-feature-roi/?token={token}&code={code}' + r = requests.get(url) + if r.status_code == 404: + return None + return r.content + +class UploadRoiCommand(SubCommand): + name = "upload-roi" + want_argv = True + help = "Upload roi, filename should be {code}.jpg" + + def setup_args(self, parser): + parser.add_argument("file", action="append") + + def do(self, args, argv): + for f in args.file: + print(f) + url = self.get_server() + "/api/v1/code-feature-roi/" + print(url) + r = requests.post(url, headers=self.make_headers(), files={ + f: open(f, 'rb'), + }) + print(r.text) + +class UserInfoCommand(SubCommand): + name = "userinfo" + want_argv = True + help = "Call the userinfo API" + + def setup_args(self, parser): + pass + + def do(self, args, argv): + server = self.get_server() + url = f'{server}/api/v1/userinfo/' + r = requests.get(url, headers=self.make_headers()) + r.raise_for_status() + print(r.json()) + +def global_args(parser): + parser.add_argument("--env", "-E", help="Env", default="prod") + parser.add_argument("-D", "--debug", action="store_true", + help="Enable debug output") + +def main(): + parser = argparse.ArgumentParser() + global_args(parser) + subparsers = parser.add_subparsers(title="subcommands") + for c in SubCommand.__subclasses__(): + cmd = c() + p = subparsers.add_parser(cmd.name, aliases=cmd.aliases, + help=cmd.help) + cmd.setup_args(p) + p.set_defaults(func=cmd.do, cmdobj=cmd, all=False) + args, argv = parser.parse_known_args() + if not hasattr(args, "cmdobj"): + parser.print_usage() + return 1 + if args.debug: + logging.basicConfig(level=logging.DEBUG) + if argv and not args.cmdobj.want_argv: + raise Exception("Unrecognized arguments:\n" + argv[0]) + args.cmdobj.args = args + r = args.func(args, argv) + return r + +if __name__ == '__main__': + sys.exit(main()) diff --git a/emblem5/scripts/qrs.py b/emblem5/scripts/qrs.py new file mode 100755 index 0000000..6ebc4f9 --- /dev/null +++ b/emblem5/scripts/qrs.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +import os + +def mv_qr(src, dst): + basename = os.path.basename(src) + if len(basename) < 2: + raise Exception('invalid basename: %s' % basename) + prefix = basename[:2] + dd = os.path.join(dst, prefix) + os.makedirs(dd, exist_ok=True) + print("%s => %s" % (src, os.path.join(dd, basename))) + os.rename(src, os.path.join(dd, basename)) + +def main(): + src = '/data/qrs/GYCY-241216-119-02' + dst = '/data/qrs/tree' + for r, ds, fs in os.walk(src): + for f in fs: + if f.endswith('.jpg'): + mv_qr(os.path.join(r, f), dst) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/emblem5/scripts/refresh-dataset.py b/emblem5/scripts/refresh-dataset.py new file mode 100755 index 0000000..a87efb5 --- /dev/null +++ b/emblem5/scripts/refresh-dataset.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import os +import sys +import shutil +import json +import random + +def main(): + dataset_base = '/data/dataset' + shutil.rmtree(dataset_base + '/pos') + shutil.rmtree(dataset_base + '/neg') + os.makedirs(dataset_base + '/pos', exist_ok=True) + os.makedirs(dataset_base + '/neg', exist_ok=True) + all_samples = os.listdir('data/samples') + random.shuffle(all_samples) + for sample in all_samples[:1000]: + newname = f'{sample}.jpg' + md_name = f'data/samples/{sample}/metadata.json' + pos_or_neg = None + if 'pos' in sample: + pos_or_neg = 'pos' + elif 'neg' in sample: + pos_or_neg = 'neg' + elif os.path.exists(md_name): + with open(md_name, 'r') as f: + md = json.load(f) + if 'pos' in md['labels']: + pos_or_neg = 'pos' + elif 'neg' in md['labels']: + pos_or_neg = 'neg' + if not pos_or_neg: + continue + src = f'data/samples/{sample}/full-sbs.jpg' + if not os.path.exists(src): + continue + print(src) + shutil.copy(src, os.path.join(dataset_base, pos_or_neg, newname)) + +if __name__ == '__main__': + main() diff --git a/emblem5/scripts/reorg-frames.py b/emblem5/scripts/reorg-frames.py new file mode 100644 index 0000000..9b34164 --- /dev/null +++ b/emblem5/scripts/reorg-frames.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +import os +import sys +import json +import shutil + +for root, dirs, files in os.walk('data/frames/v5'): + for f in files: + if not f.endswith('-side-by-side.jpg'): + continue + frame_idx = f.split('-')[0] + parent_dir = os.path.basename(root) + outd = f'/data/samples/frame-{parent_dir}-{frame_idx}' + os.makedirs(outd, exist_ok=True) + frame_file = os.path.join(root, f) + if os.path.exists(frame_file): + shutil.copy(frame_file, os.path.join(outd, 'frame.jpg')) + qr_file = os.path.join(root, f'{frame_idx}-qr.jpg') + if os.path.exists(qr_file): + shutil.copy(qr_file, os.path.join(outd, 'frame-qr.jpg')) + orig_file = os.path.join(root, f'{frame_idx}-orig.jpg') + if os.path.exists(orig_file): + shutil.copy(orig_file, os.path.join(outd, 'std.jpg')) + side_by_side_file = os.path.join(root, f'{frame_idx}-side-by-side.jpg') + if os.path.exists(side_by_side_file): + shutil.copy(side_by_side_file, os.path.join(outd, 'side-by-side.jpg')) + metadata_file = os.path.join(root, f'{frame_idx}') + shutil.copy(metadata_file, os.path.join(outd, 'metadata.json')) \ No newline at end of file diff --git a/emblem5/scripts/reorganize.sh b/emblem5/scripts/reorganize.sh new file mode 100644 index 0000000..592a0ed --- /dev/null +++ b/emblem5/scripts/reorganize.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +for scan_id in $(ls data/scans); do + echo $scan_id + outd=data/samples/scan-${scan_id} + mkdir -p data/samples/scan-${scan_id} +# data/scans/80423/80423.txt +# data/scans/80423/80423-std.jpg +# data/scans/80423/80423-qr-side-by-side.jpg +# data/scans/80423/80423-frame.jpg +# data/scans/80423/80423.json +# data/scans/80423/80423-roi.jpg +# data/scans/80423/80423-std-qr.jpg +# data/scans/80423/80423-qr.jpg + mv data/scans/${scan_id}/${scan_id}.json $outd/metadata.json + mv data/scans/${scan_id}/${scan_id}-frame.jpg $outd/frame.jpg + mv data/scans/${scan_id}/${scan_id}-qr.jpg $outd/frame-qr.jpg + mv data/scans/${scan_id}/${scan_id}-std.jpg $outd/std.jpg + mv data/scans/${scan_id}/${scan_id}-std-qr.jpg $outd/std-qr.jpg + mv data/scans/${scan_id}/${scan_id}-qr-side-by-side.jpg $outd/side-by-side.jpg +done + diff --git a/emblem5/scripts/upload-qrs.py b/emblem5/scripts/upload-qrs.py new file mode 100755 index 0000000..1e4f134 --- /dev/null +++ b/emblem5/scripts/upload-qrs.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +import oss2 +import sys +import os +import time +import argparse + +oss_ak = 'LTAI5tC2qXGxwHZUZP7DoD1A' +oss_sk = 'qPo9O6ZvEfqo4t8oflGEm0DoxLHJhm' + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--dir', '-d', type=str, default='/data/qrs/tree', help='directory of qrs') + return parser.parse_args() + +def all_qrs(dir): + for r, ds, fs in os.walk(dir): + for f in fs: + if f.endswith('.jpg'): + yield os.path.join(r, f) + +def main(): + args = parse_args() + auth = oss2.Auth(oss_ak, oss_sk) + endpoint = 'https://oss-cn-guangzhou.aliyuncs.com' + bucket = oss2.Bucket(auth, endpoint, 'emblem-qrs') + + rootdir = args.dir + + aqrs = list(all_qrs(rootdir)) + total = len(aqrs) + done = 0 + print(f'total: {total}') + for qr in aqrs: + qrcode = os.path.basename(qr).split('.')[0] + prefix = qrcode[:2] + key = f'v5/{prefix}/{qrcode}.jpg' + for i in range(3): + try: + print(f'{done}/{total} {qr} -> {key}') + bucket.put_object_from_file(key, qr) + done += 1 + break + except Exception as e: + print(f'{e}') + time.sleep(1) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/emblem5/scripts/vis.py b/emblem5/scripts/vis.py new file mode 100755 index 0000000..46c0796 --- /dev/null +++ b/emblem5/scripts/vis.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import flask +import subprocess + +app = flask.Flask(__name__) + +def show_frames(): + cmd = '''find data/frames/v5/*neg -name '*-qr.jpg' | sort -R | head -n 100''' + lines = subprocess.check_output(cmd, shell=True).decode().splitlines() + ret = '
' + for line in lines: + ret += f'' + ret += '
' + return ret + +@app.route('/') +def index(): + ret = ''' + + + + + + ''' + ret += show_frames() + + ret += ''' + + + ''' + return ret + +@app.route('/data/') +def data(path): + return flask.send_file('../data/' + path) + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=8080, debug=True) \ No newline at end of file diff --git a/emblem5/wechat_qrcode/detect.caffemodel b/emblem5/wechat_qrcode/detect.caffemodel new file mode 100644 index 0000000..453126c Binary files /dev/null and b/emblem5/wechat_qrcode/detect.caffemodel differ diff --git a/emblem5/wechat_qrcode/detect.prototxt b/emblem5/wechat_qrcode/detect.prototxt new file mode 100644 index 0000000..bd2417c --- /dev/null +++ b/emblem5/wechat_qrcode/detect.prototxt @@ -0,0 +1,2716 @@ +layer { + name: "data" + type: "Input" + top: "data" + input_param { + shape { + dim: 1 + dim: 1 + dim: 384 + dim: 384 + } + } +} +layer { + name: "data/bn" + type: "BatchNorm" + bottom: "data" + top: "data" + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } +} +layer { + name: "data/bn/scale" + type: "Scale" + bottom: "data" + top: "data" + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + scale_param { + filler { + type: "constant" + value: 1.0 + } + bias_term: true + bias_filler { + type: "constant" + value: 0.0 + } + } +} +layer { + name: "stage1" + type: "Convolution" + bottom: "data" + top: "stage1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 1 + kernel_size: 3 + group: 1 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage1/bn" + type: "BatchNorm" + bottom: "stage1" + top: "stage1" + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + param { + lr_mult: 0.0 + decay_mult: 0.0 + } +} +layer { + name: "stage1/bn/scale" + type: "Scale" + bottom: "stage1" + top: "stage1" + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + scale_param { + filler { + type: "constant" + value: 1.0 + } + bias_term: true + bias_filler { + type: "constant" + value: 0.0 + } + } +} +layer { + name: "stage1/relu" + type: "ReLU" + bottom: "stage1" + top: "stage1" +} +layer { + name: "stage2" + type: "Pooling" + bottom: "stage1" + top: "stage2" + pooling_param { + pool: MAX + kernel_size: 3 + stride: 2 + pad: 0 + } +} +layer { + name: "stage3_1/conv1" + type: "Convolution" + bottom: "stage2" + top: "stage3_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_1/conv1/relu" + type: "ReLU" + bottom: "stage3_1/conv1" + top: "stage3_1/conv1" +} +layer { + name: "stage3_1/conv2" + type: "Convolution" + bottom: "stage3_1/conv1" + top: "stage3_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_1/conv3" + type: "Convolution" + bottom: "stage3_1/conv2" + top: "stage3_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_1/relu" + type: "ReLU" + bottom: "stage3_1/conv3" + top: "stage3_1/conv3" +} +layer { + name: "stage3_2/conv1" + type: "Convolution" + bottom: "stage3_1/conv3" + top: "stage3_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_2/conv1/relu" + type: "ReLU" + bottom: "stage3_2/conv1" + top: "stage3_2/conv1" +} +layer { + name: "stage3_2/conv2" + type: "Convolution" + bottom: "stage3_2/conv1" + top: "stage3_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_2/conv3" + type: "Convolution" + bottom: "stage3_2/conv2" + top: "stage3_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_2/sum" + type: "Eltwise" + bottom: "stage3_1/conv3" + bottom: "stage3_2/conv3" + top: "stage3_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage3_2/relu" + type: "ReLU" + bottom: "stage3_2/sum" + top: "stage3_2/sum" +} +layer { + name: "stage3_3/conv1" + type: "Convolution" + bottom: "stage3_2/sum" + top: "stage3_3/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_3/conv1/relu" + type: "ReLU" + bottom: "stage3_3/conv1" + top: "stage3_3/conv1" +} +layer { + name: "stage3_3/conv2" + type: "Convolution" + bottom: "stage3_3/conv1" + top: "stage3_3/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_3/conv3" + type: "Convolution" + bottom: "stage3_3/conv2" + top: "stage3_3/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_3/sum" + type: "Eltwise" + bottom: "stage3_2/sum" + bottom: "stage3_3/conv3" + top: "stage3_3/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage3_3/relu" + type: "ReLU" + bottom: "stage3_3/sum" + top: "stage3_3/sum" +} +layer { + name: "stage3_4/conv1" + type: "Convolution" + bottom: "stage3_3/sum" + top: "stage3_4/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_4/conv1/relu" + type: "ReLU" + bottom: "stage3_4/conv1" + top: "stage3_4/conv1" +} +layer { + name: "stage3_4/conv2" + type: "Convolution" + bottom: "stage3_4/conv1" + top: "stage3_4/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 16 + pad: 1 + kernel_size: 3 + group: 16 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_4/conv3" + type: "Convolution" + bottom: "stage3_4/conv2" + top: "stage3_4/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 64 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage3_4/sum" + type: "Eltwise" + bottom: "stage3_3/sum" + bottom: "stage3_4/conv3" + top: "stage3_4/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage3_4/relu" + type: "ReLU" + bottom: "stage3_4/sum" + top: "stage3_4/sum" +} +layer { + name: "stage4_1/conv1" + type: "Convolution" + bottom: "stage3_4/sum" + top: "stage4_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_1/conv1/relu" + type: "ReLU" + bottom: "stage4_1/conv1" + top: "stage4_1/conv1" +} +layer { + name: "stage4_1/conv2" + type: "Convolution" + bottom: "stage4_1/conv1" + top: "stage4_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_1/conv3" + type: "Convolution" + bottom: "stage4_1/conv2" + top: "stage4_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_1/relu" + type: "ReLU" + bottom: "stage4_1/conv3" + top: "stage4_1/conv3" +} +layer { + name: "stage4_2/conv1" + type: "Convolution" + bottom: "stage4_1/conv3" + top: "stage4_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_2/conv1/relu" + type: "ReLU" + bottom: "stage4_2/conv1" + top: "stage4_2/conv1" +} +layer { + name: "stage4_2/conv2" + type: "Convolution" + bottom: "stage4_2/conv1" + top: "stage4_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_2/conv3" + type: "Convolution" + bottom: "stage4_2/conv2" + top: "stage4_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_2/sum" + type: "Eltwise" + bottom: "stage4_1/conv3" + bottom: "stage4_2/conv3" + top: "stage4_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_2/relu" + type: "ReLU" + bottom: "stage4_2/sum" + top: "stage4_2/sum" +} +layer { + name: "stage4_3/conv1" + type: "Convolution" + bottom: "stage4_2/sum" + top: "stage4_3/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_3/conv1/relu" + type: "ReLU" + bottom: "stage4_3/conv1" + top: "stage4_3/conv1" +} +layer { + name: "stage4_3/conv2" + type: "Convolution" + bottom: "stage4_3/conv1" + top: "stage4_3/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_3/conv3" + type: "Convolution" + bottom: "stage4_3/conv2" + top: "stage4_3/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_3/sum" + type: "Eltwise" + bottom: "stage4_2/sum" + bottom: "stage4_3/conv3" + top: "stage4_3/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_3/relu" + type: "ReLU" + bottom: "stage4_3/sum" + top: "stage4_3/sum" +} +layer { + name: "stage4_4/conv1" + type: "Convolution" + bottom: "stage4_3/sum" + top: "stage4_4/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_4/conv1/relu" + type: "ReLU" + bottom: "stage4_4/conv1" + top: "stage4_4/conv1" +} +layer { + name: "stage4_4/conv2" + type: "Convolution" + bottom: "stage4_4/conv1" + top: "stage4_4/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_4/conv3" + type: "Convolution" + bottom: "stage4_4/conv2" + top: "stage4_4/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_4/sum" + type: "Eltwise" + bottom: "stage4_3/sum" + bottom: "stage4_4/conv3" + top: "stage4_4/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_4/relu" + type: "ReLU" + bottom: "stage4_4/sum" + top: "stage4_4/sum" +} +layer { + name: "stage4_5/conv1" + type: "Convolution" + bottom: "stage4_4/sum" + top: "stage4_5/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_5/conv1/relu" + type: "ReLU" + bottom: "stage4_5/conv1" + top: "stage4_5/conv1" +} +layer { + name: "stage4_5/conv2" + type: "Convolution" + bottom: "stage4_5/conv1" + top: "stage4_5/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_5/conv3" + type: "Convolution" + bottom: "stage4_5/conv2" + top: "stage4_5/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_5/sum" + type: "Eltwise" + bottom: "stage4_4/sum" + bottom: "stage4_5/conv3" + top: "stage4_5/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_5/relu" + type: "ReLU" + bottom: "stage4_5/sum" + top: "stage4_5/sum" +} +layer { + name: "stage4_6/conv1" + type: "Convolution" + bottom: "stage4_5/sum" + top: "stage4_6/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_6/conv1/relu" + type: "ReLU" + bottom: "stage4_6/conv1" + top: "stage4_6/conv1" +} +layer { + name: "stage4_6/conv2" + type: "Convolution" + bottom: "stage4_6/conv1" + top: "stage4_6/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_6/conv3" + type: "Convolution" + bottom: "stage4_6/conv2" + top: "stage4_6/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_6/sum" + type: "Eltwise" + bottom: "stage4_5/sum" + bottom: "stage4_6/conv3" + top: "stage4_6/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_6/relu" + type: "ReLU" + bottom: "stage4_6/sum" + top: "stage4_6/sum" +} +layer { + name: "stage4_7/conv1" + type: "Convolution" + bottom: "stage4_6/sum" + top: "stage4_7/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_7/conv1/relu" + type: "ReLU" + bottom: "stage4_7/conv1" + top: "stage4_7/conv1" +} +layer { + name: "stage4_7/conv2" + type: "Convolution" + bottom: "stage4_7/conv1" + top: "stage4_7/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_7/conv3" + type: "Convolution" + bottom: "stage4_7/conv2" + top: "stage4_7/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_7/sum" + type: "Eltwise" + bottom: "stage4_6/sum" + bottom: "stage4_7/conv3" + top: "stage4_7/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_7/relu" + type: "ReLU" + bottom: "stage4_7/sum" + top: "stage4_7/sum" +} +layer { + name: "stage4_8/conv1" + type: "Convolution" + bottom: "stage4_7/sum" + top: "stage4_8/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_8/conv1/relu" + type: "ReLU" + bottom: "stage4_8/conv1" + top: "stage4_8/conv1" +} +layer { + name: "stage4_8/conv2" + type: "Convolution" + bottom: "stage4_8/conv1" + top: "stage4_8/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 1 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_8/conv3" + type: "Convolution" + bottom: "stage4_8/conv2" + top: "stage4_8/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage4_8/sum" + type: "Eltwise" + bottom: "stage4_7/sum" + bottom: "stage4_8/conv3" + top: "stage4_8/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage4_8/relu" + type: "ReLU" + bottom: "stage4_8/sum" + top: "stage4_8/sum" +} +layer { + name: "stage5_1/conv1" + type: "Convolution" + bottom: "stage4_8/sum" + top: "stage5_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_1/conv1/relu" + type: "ReLU" + bottom: "stage5_1/conv1" + top: "stage5_1/conv1" +} +layer { + name: "stage5_1/conv2" + type: "Convolution" + bottom: "stage5_1/conv1" + top: "stage5_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 2 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_1/conv3" + type: "Convolution" + bottom: "stage5_1/conv2" + top: "stage5_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_1/relu" + type: "ReLU" + bottom: "stage5_1/conv3" + top: "stage5_1/conv3" +} +layer { + name: "stage5_2/conv1" + type: "Convolution" + bottom: "stage5_1/conv3" + top: "stage5_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_2/conv1/relu" + type: "ReLU" + bottom: "stage5_2/conv1" + top: "stage5_2/conv1" +} +layer { + name: "stage5_2/conv2" + type: "Convolution" + bottom: "stage5_2/conv1" + top: "stage5_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_2/conv3" + type: "Convolution" + bottom: "stage5_2/conv2" + top: "stage5_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_2/sum" + type: "Eltwise" + bottom: "stage5_1/conv3" + bottom: "stage5_2/conv3" + top: "stage5_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage5_2/relu" + type: "ReLU" + bottom: "stage5_2/sum" + top: "stage5_2/sum" +} +layer { + name: "stage5_3/conv1" + type: "Convolution" + bottom: "stage5_2/sum" + top: "stage5_3/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_3/conv1/relu" + type: "ReLU" + bottom: "stage5_3/conv1" + top: "stage5_3/conv1" +} +layer { + name: "stage5_3/conv2" + type: "Convolution" + bottom: "stage5_3/conv1" + top: "stage5_3/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_3/conv3" + type: "Convolution" + bottom: "stage5_3/conv2" + top: "stage5_3/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_3/sum" + type: "Eltwise" + bottom: "stage5_2/sum" + bottom: "stage5_3/conv3" + top: "stage5_3/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage5_3/relu" + type: "ReLU" + bottom: "stage5_3/sum" + top: "stage5_3/sum" +} +layer { + name: "stage5_4/conv1" + type: "Convolution" + bottom: "stage5_3/sum" + top: "stage5_4/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_4/conv1/relu" + type: "ReLU" + bottom: "stage5_4/conv1" + top: "stage5_4/conv1" +} +layer { + name: "stage5_4/conv2" + type: "Convolution" + bottom: "stage5_4/conv1" + top: "stage5_4/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage5_4/conv3" + type: "Convolution" + bottom: "stage5_4/conv2" + top: "stage5_4/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage5_4/sum" + type: "Eltwise" + bottom: "stage5_3/sum" + bottom: "stage5_4/conv3" + top: "stage5_4/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage5_4/relu" + type: "ReLU" + bottom: "stage5_4/sum" + top: "stage5_4/sum" +} +layer { + name: "stage6_1/conv4" + type: "Convolution" + bottom: "stage5_4/sum" + top: "stage6_1/conv4" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_1/conv1" + type: "Convolution" + bottom: "stage5_4/sum" + top: "stage6_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_1/conv1/relu" + type: "ReLU" + bottom: "stage6_1/conv1" + top: "stage6_1/conv1" +} +layer { + name: "stage6_1/conv2" + type: "Convolution" + bottom: "stage6_1/conv1" + top: "stage6_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage6_1/conv3" + type: "Convolution" + bottom: "stage6_1/conv2" + top: "stage6_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_1/sum" + type: "Eltwise" + bottom: "stage6_1/conv4" + bottom: "stage6_1/conv3" + top: "stage6_1/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage6_1/relu" + type: "ReLU" + bottom: "stage6_1/sum" + top: "stage6_1/sum" +} +layer { + name: "stage6_2/conv1" + type: "Convolution" + bottom: "stage6_1/sum" + top: "stage6_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_2/conv1/relu" + type: "ReLU" + bottom: "stage6_2/conv1" + top: "stage6_2/conv1" +} +layer { + name: "stage6_2/conv2" + type: "Convolution" + bottom: "stage6_2/conv1" + top: "stage6_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage6_2/conv3" + type: "Convolution" + bottom: "stage6_2/conv2" + top: "stage6_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage6_2/sum" + type: "Eltwise" + bottom: "stage6_1/sum" + bottom: "stage6_2/conv3" + top: "stage6_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage6_2/relu" + type: "ReLU" + bottom: "stage6_2/sum" + top: "stage6_2/sum" +} +layer { + name: "stage7_1/conv4" + type: "Convolution" + bottom: "stage6_2/sum" + top: "stage7_1/conv4" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_1/conv1" + type: "Convolution" + bottom: "stage6_2/sum" + top: "stage7_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_1/conv1/relu" + type: "ReLU" + bottom: "stage7_1/conv1" + top: "stage7_1/conv1" +} +layer { + name: "stage7_1/conv2" + type: "Convolution" + bottom: "stage7_1/conv1" + top: "stage7_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage7_1/conv3" + type: "Convolution" + bottom: "stage7_1/conv2" + top: "stage7_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_1/sum" + type: "Eltwise" + bottom: "stage7_1/conv4" + bottom: "stage7_1/conv3" + top: "stage7_1/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage7_1/relu" + type: "ReLU" + bottom: "stage7_1/sum" + top: "stage7_1/sum" +} +layer { + name: "stage7_2/conv1" + type: "Convolution" + bottom: "stage7_1/sum" + top: "stage7_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_2/conv1/relu" + type: "ReLU" + bottom: "stage7_2/conv1" + top: "stage7_2/conv1" +} +layer { + name: "stage7_2/conv2" + type: "Convolution" + bottom: "stage7_2/conv1" + top: "stage7_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage7_2/conv3" + type: "Convolution" + bottom: "stage7_2/conv2" + top: "stage7_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage7_2/sum" + type: "Eltwise" + bottom: "stage7_1/sum" + bottom: "stage7_2/conv3" + top: "stage7_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage7_2/relu" + type: "ReLU" + bottom: "stage7_2/sum" + top: "stage7_2/sum" +} +layer { + name: "stage8_1/conv4" + type: "Convolution" + bottom: "stage7_2/sum" + top: "stage8_1/conv4" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_1/conv1" + type: "Convolution" + bottom: "stage7_2/sum" + top: "stage8_1/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_1/conv1/relu" + type: "ReLU" + bottom: "stage8_1/conv1" + top: "stage8_1/conv1" +} +layer { + name: "stage8_1/conv2" + type: "Convolution" + bottom: "stage8_1/conv1" + top: "stage8_1/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage8_1/conv3" + type: "Convolution" + bottom: "stage8_1/conv2" + top: "stage8_1/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_1/sum" + type: "Eltwise" + bottom: "stage8_1/conv4" + bottom: "stage8_1/conv3" + top: "stage8_1/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage8_1/relu" + type: "ReLU" + bottom: "stage8_1/sum" + top: "stage8_1/sum" +} +layer { + name: "stage8_2/conv1" + type: "Convolution" + bottom: "stage8_1/sum" + top: "stage8_2/conv1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_2/conv1/relu" + type: "ReLU" + bottom: "stage8_2/conv1" + top: "stage8_2/conv1" +} +layer { + name: "stage8_2/conv2" + type: "Convolution" + bottom: "stage8_2/conv1" + top: "stage8_2/conv2" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 32 + pad: 2 + kernel_size: 3 + group: 32 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 2 + } +} +layer { + name: "stage8_2/conv3" + type: "Convolution" + bottom: "stage8_2/conv2" + top: "stage8_2/conv3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + convolution_param { + num_output: 128 + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "stage8_2/sum" + type: "Eltwise" + bottom: "stage8_1/sum" + bottom: "stage8_2/conv3" + top: "stage8_2/sum" + eltwise_param { + operation: SUM + } +} +layer { + name: "stage8_2/relu" + type: "ReLU" + bottom: "stage8_2/sum" + top: "stage8_2/sum" +} +layer { + name: "cls1/conv" + type: "Convolution" + bottom: "stage4_8/sum" + top: "cls1/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls1/permute" + type: "Permute" + bottom: "cls1/conv" + top: "cls1/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls1/flatten" + type: "Flatten" + bottom: "cls1/permute" + top: "cls1/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc1/conv" + type: "Convolution" + bottom: "stage4_8/sum" + top: "loc1/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc1/permute" + type: "Permute" + bottom: "loc1/conv" + top: "loc1/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc1/flatten" + type: "Flatten" + bottom: "loc1/permute" + top: "loc1/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage4_8/sum/prior_box" + type: "PriorBox" + bottom: "stage4_8/sum" + bottom: "data" + top: "stage4_8/sum/prior_box" + prior_box_param { + min_size: 50.0 + max_size: 100.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 16.0 + } +} +layer { + name: "cls2/conv" + type: "Convolution" + bottom: "stage5_4/sum" + top: "cls2/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls2/permute" + type: "Permute" + bottom: "cls2/conv" + top: "cls2/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls2/flatten" + type: "Flatten" + bottom: "cls2/permute" + top: "cls2/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc2/conv" + type: "Convolution" + bottom: "stage5_4/sum" + top: "loc2/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc2/permute" + type: "Permute" + bottom: "loc2/conv" + top: "loc2/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc2/flatten" + type: "Flatten" + bottom: "loc2/permute" + top: "loc2/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage5_4/sum/prior_box" + type: "PriorBox" + bottom: "stage5_4/sum" + bottom: "data" + top: "stage5_4/sum/prior_box" + prior_box_param { + min_size: 100.0 + max_size: 150.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "cls3/conv" + type: "Convolution" + bottom: "stage6_2/sum" + top: "cls3/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls3/permute" + type: "Permute" + bottom: "cls3/conv" + top: "cls3/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls3/flatten" + type: "Flatten" + bottom: "cls3/permute" + top: "cls3/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc3/conv" + type: "Convolution" + bottom: "stage6_2/sum" + top: "loc3/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc3/permute" + type: "Permute" + bottom: "loc3/conv" + top: "loc3/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc3/flatten" + type: "Flatten" + bottom: "loc3/permute" + top: "loc3/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage6_2/sum/prior_box" + type: "PriorBox" + bottom: "stage6_2/sum" + bottom: "data" + top: "stage6_2/sum/prior_box" + prior_box_param { + min_size: 150.0 + max_size: 200.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "cls4/conv" + type: "Convolution" + bottom: "stage7_2/sum" + top: "cls4/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls4/permute" + type: "Permute" + bottom: "cls4/conv" + top: "cls4/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls4/flatten" + type: "Flatten" + bottom: "cls4/permute" + top: "cls4/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc4/conv" + type: "Convolution" + bottom: "stage7_2/sum" + top: "loc4/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc4/permute" + type: "Permute" + bottom: "loc4/conv" + top: "loc4/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc4/flatten" + type: "Flatten" + bottom: "loc4/permute" + top: "loc4/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage7_2/sum/prior_box" + type: "PriorBox" + bottom: "stage7_2/sum" + bottom: "data" + top: "stage7_2/sum/prior_box" + prior_box_param { + min_size: 200.0 + max_size: 300.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "cls5/conv" + type: "Convolution" + bottom: "stage8_2/sum" + top: "cls5/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 12 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "cls5/permute" + type: "Permute" + bottom: "cls5/conv" + top: "cls5/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "cls5/flatten" + type: "Flatten" + bottom: "cls5/permute" + top: "cls5/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "loc5/conv" + type: "Convolution" + bottom: "stage8_2/sum" + top: "loc5/conv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 24 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + dilation: 1 + } +} +layer { + name: "loc5/permute" + type: "Permute" + bottom: "loc5/conv" + top: "loc5/permute" + permute_param { + order: 0 + order: 2 + order: 3 + order: 1 + } +} +layer { + name: "loc5/flatten" + type: "Flatten" + bottom: "loc5/permute" + top: "loc5/flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "stage8_2/sum/prior_box" + type: "PriorBox" + bottom: "stage8_2/sum" + bottom: "data" + top: "stage8_2/sum/prior_box" + prior_box_param { + min_size: 300.0 + max_size: 400.0 + aspect_ratio: 2.0 + aspect_ratio: 0.5 + aspect_ratio: 3.0 + aspect_ratio: 0.3333333432674408 + flip: false + clip: false + variance: 0.10000000149011612 + variance: 0.10000000149011612 + variance: 0.20000000298023224 + variance: 0.20000000298023224 + step: 32.0 + } +} +layer { + name: "mbox_conf" + type: "Concat" + bottom: "cls1/flatten" + bottom: "cls2/flatten" + bottom: "cls3/flatten" + bottom: "cls4/flatten" + bottom: "cls5/flatten" + top: "mbox_conf" + concat_param { + axis: 1 + } +} +layer { + name: "mbox_loc" + type: "Concat" + bottom: "loc1/flatten" + bottom: "loc2/flatten" + bottom: "loc3/flatten" + bottom: "loc4/flatten" + bottom: "loc5/flatten" + top: "mbox_loc" + concat_param { + axis: 1 + } +} +layer { + name: "mbox_priorbox" + type: "Concat" + bottom: "stage4_8/sum/prior_box" + bottom: "stage5_4/sum/prior_box" + bottom: "stage6_2/sum/prior_box" + bottom: "stage7_2/sum/prior_box" + bottom: "stage8_2/sum/prior_box" + top: "mbox_priorbox" + concat_param { + axis: 2 + } +} +layer { + name: "mbox_conf_reshape" + type: "Reshape" + bottom: "mbox_conf" + top: "mbox_conf_reshape" + reshape_param { + shape { + dim: 0 + dim: -1 + dim: 2 + } + } +} +layer { + name: "mbox_conf_softmax" + type: "Softmax" + bottom: "mbox_conf_reshape" + top: "mbox_conf_softmax" + softmax_param { + axis: 2 + } +} +layer { + name: "mbox_conf_flatten" + type: "Flatten" + bottom: "mbox_conf_softmax" + top: "mbox_conf_flatten" + flatten_param { + axis: 1 + } +} +layer { + name: "detection_output" + type: "DetectionOutput" + bottom: "mbox_loc" + bottom: "mbox_conf_flatten" + bottom: "mbox_priorbox" + top: "detection_output" + detection_output_param { + num_classes: 2 + share_location: true + background_label_id: 0 + nms_param { + nms_threshold: 0.44999998807907104 + top_k: 100 + } + code_type: CENTER_SIZE + keep_top_k: 100 + confidence_threshold: 0.20000000298023224 + } +} diff --git a/emblem5/wechat_qrcode/sr.caffemodel b/emblem5/wechat_qrcode/sr.caffemodel new file mode 100644 index 0000000..168b54d Binary files /dev/null and b/emblem5/wechat_qrcode/sr.caffemodel differ diff --git a/emblem5/wechat_qrcode/sr.prototxt b/emblem5/wechat_qrcode/sr.prototxt new file mode 100644 index 0000000..e85caa1 --- /dev/null +++ b/emblem5/wechat_qrcode/sr.prototxt @@ -0,0 +1,403 @@ +layer { + name: "data" + type: "Input" + top: "data" + input_param { + shape { + dim: 1 + dim: 1 + dim: 224 + dim: 224 + } + } +} +layer { + name: "conv0" + type: "Convolution" + bottom: "data" + top: "conv0" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 1 + kernel_size: 3 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "conv0/lrelu" + type: "ReLU" + bottom: "conv0" + top: "conv0" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/reduce" + type: "Convolution" + bottom: "conv0" + top: "db1/reduce" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db1/reduce/lrelu" + type: "ReLU" + bottom: "db1/reduce" + top: "db1/reduce" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/3x3" + type: "Convolution" + bottom: "db1/reduce" + top: "db1/3x3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 1 + kernel_size: 3 + group: 8 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db1/3x3/lrelu" + type: "ReLU" + bottom: "db1/3x3" + top: "db1/3x3" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/1x1" + type: "Convolution" + bottom: "db1/3x3" + top: "db1/1x1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db1/1x1/lrelu" + type: "ReLU" + bottom: "db1/1x1" + top: "db1/1x1" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db1/concat" + type: "Concat" + bottom: "conv0" + bottom: "db1/1x1" + top: "db1/concat" + concat_param { + axis: 1 + } +} +layer { + name: "db2/reduce" + type: "Convolution" + bottom: "db1/concat" + top: "db2/reduce" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db2/reduce/lrelu" + type: "ReLU" + bottom: "db2/reduce" + top: "db2/reduce" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db2/3x3" + type: "Convolution" + bottom: "db2/reduce" + top: "db2/3x3" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 8 + bias_term: true + pad: 1 + kernel_size: 3 + group: 8 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db2/3x3/lrelu" + type: "ReLU" + bottom: "db2/3x3" + top: "db2/3x3" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db2/1x1" + type: "Convolution" + bottom: "db2/3x3" + top: "db2/1x1" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "db2/1x1/lrelu" + type: "ReLU" + bottom: "db2/1x1" + top: "db2/1x1" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "db2/concat" + type: "Concat" + bottom: "db1/concat" + bottom: "db2/1x1" + top: "db2/concat" + concat_param { + axis: 1 + } +} +layer { + name: "upsample/reduce" + type: "Convolution" + bottom: "db2/concat" + top: "upsample/reduce" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "upsample/reduce/lrelu" + type: "ReLU" + bottom: "upsample/reduce" + top: "upsample/reduce" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "upsample/deconv" + type: "Deconvolution" + bottom: "upsample/reduce" + top: "upsample/deconv" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 32 + bias_term: true + pad: 1 + kernel_size: 3 + group: 32 + stride: 2 + weight_filler { + type: "msra" + } + } +} +layer { + name: "upsample/lrelu" + type: "ReLU" + bottom: "upsample/deconv" + top: "upsample/deconv" + relu_param { + negative_slope: 0.05000000074505806 + } +} +layer { + name: "upsample/rec" + type: "Convolution" + bottom: "upsample/deconv" + top: "upsample/rec" + param { + lr_mult: 1.0 + decay_mult: 1.0 + } + param { + lr_mult: 1.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 1 + bias_term: true + pad: 0 + kernel_size: 1 + group: 1 + stride: 1 + weight_filler { + type: "msra" + } + } +} +layer { + name: "nearest" + type: "Deconvolution" + bottom: "data" + top: "nearest" + param { + lr_mult: 0.0 + decay_mult: 0.0 + } + convolution_param { + num_output: 1 + bias_term: false + pad: 0 + kernel_size: 2 + group: 1 + stride: 2 + weight_filler { + type: "constant" + value: 1.0 + } + } +} +layer { + name: "Crop1" + type: "Crop" + bottom: "nearest" + bottom: "upsample/rec" + top: "Crop1" +} +layer { + name: "fc" + type: "Eltwise" + bottom: "Crop1" + bottom: "upsample/rec" + top: "fc" + eltwise_param { + operation: SUM + } +}