1. Development Environment Setup
Using Docker to set web development environment
1-1) Dockerfile
FROM python:3.7.8 # Base Image LABEL maintainer "WLU" # Maincontainer RUN pip install --upgrade pip # Upgrade pip COPY . /path WORKDIR /path # applied to RUN, CMD RUN pip install --no-cache-dir -r requirements.txt # install Python modules # copied files required for the app to run
COPY app.py /path/ COPY templates/ /path/templates/ COPY static/ /path/static/ EXPOSE 80 #Port number the container should expose CMD ["python", "./app.py"] # Run the application |
Docker+flask
1-2) docker-compose.yml
version: '3.3' #version services: welungu: #service name build: . #current path ports: #open port - "80:80" |
Specify the version at the beginning of the docker-compose.yml. Define a service named 'welungu' and it starts the container after building an image of the configuration defined in Dockerfile(build:) and exposing port 80 to the outside(port:).
1-3) requirements.txt
Flask==1.1.2 werkzeug torchvision torch |
Put python modules needed by the app in requirements.txt.
reference: 완벽한 IT 인프라 구축을 위한 Docker 2판(Asa Shiho 지음, 이영란 옮김)
2. Web Development
2-1) File upload & Model load
def get_instance_segmentation_model(num_classes): # Load a model pre-trained pre-trained on COCO model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
# Replace the classifier with a new one, that has # num_classes which is user-defined # Get number of input features for the classifier in_features = model.roi_heads.box_predictor.cls_score.in_features # Replace the pre-trained head with a new one model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes) return model
def drawPrediction(img, prediction): #image = Image.fromarray(img.mul(255).permute(1, 2, 0).byte().numpy()) draw = ImageDraw.Draw(img) results = [0.0, 0.0, 0.0]
for element in range(len(prediction[0]["boxes"])): boxes = prediction[0]["boxes"][element].detach().numpy() score = np.round(prediction[0]["scores"][element].detach().numpy() , decimals=4) temp = []
label = int(prediction[0]["labels"][element].detach().numpy())
if label == 1 : temp.extend(["covid-19", "red"]) elif label == 2 : temp.extend(["nodule", "blue"]) elif label == 3 : temp.extend(["cancer", "green"]) if results[label-1] < round(score*100, 2) : results[label-1] = round(score*100, 2)
if score > 0.5 : draw.text((boxes[0], boxes[1]-20), text=temp[0]) draw.rectangle([(boxes[0], boxes[1]), (boxes[2], boxes[3])], outline=temp[1], width=3) draw.text((boxes[0], boxes[1]-10), text=str(round(score*100, 2))+" %")
img.save("./static/img/predict.png") return results @app.route('/check', methods=['GET', 'POST'])
def check(): if request.method == 'POST': # 파일이 없을 때 if request.files['file'] is None: return render_template('check.html', title='Check', check_message_test='empty') else: file = request.files['file'] file.save(secure_filename(file.filename))
model = get_instance_segmentation_model(4) model.load_state_dict(torch.load("model_epoch100.pth", map_location=torch.device('cpu')))
img = Image.open(file.filename).convert('RGB') copy = torchvision.transforms.ToTensor()(img).unsqueeze(0)
model.eval() prediction = model(copy) results = drawPrediction(img, prediction) disease = 'You are healty!'
if sum(results) == 0 : pass elif results.index(max(results)) == 0 : disease = 'covid-19' elif results.index(max(results)) == 1 : disease = 'nodule' elif results.index(max(results)) == 2 : disease = 'cancer'
os.remove("./"+file.filename)
return render_template('check.html', title='Check', filepath="predict.png", result=disease, c=results[0], n=results[1], LC=results[2]) else: return render_template('check.html', title='Check', check_message_test='empty') |
3. File Structure
we_Lung_u_flask |-- static |-- css |-- fonts |-- img |-- js |-- templates |-- check.html |-- contact.html |-- index.html |-- layout.html |-- team.html |-- Dockerfile |-- app.py |-- docker-compose.yml |-- requirements.txt |