반응형

keras 손실함수 중에 아래 두 개가 비슷하지만 사용할 때는 완전히 다르다.

주의가 필요하다.


+ categorical_crossentropy ; 다중 분류 손실함수. one-hot encoding 클래스

출력값이 one-hot encoding 된 결과로 나오고 실측 결과와의 비교시에도 실측 결과는 one-hot encoding 형태로 구성된다.

예를 들면 출력 실측값이 아래와 같은 형태(one-hot encoding)로 만들어 줘야 하는 과정을 거쳐야 한다.

[[0 0 1]

[0 1 0]

[1 0 0]]  (배치 사이즈 3개인 경우)

네트웍 레이어 구성시 마지막에 Dense(3, activation='softmax') 로 3개의 클래스 각각 별로 positive 확률값이 나오게 된다.

[0.2, 0.3, 0.5]

위 네트웍 출력값과 실측값의 오차값을 계산한다.

model.compile(optimizer=.., loss='categorical_entropy')


+ sparse_categorical_crossentropy ; 다중 분류 손실함수. 위와 동일하지만 , integer type 클래스라는 것이 다르다.

예를 들면 출력 실측값이 아래와 같은 형태로 one-hot encoding 과정을 하지 않아도 된다. 

[0, 1, 2]  (배치 사이즈 3개로 했을 때)


네트웍 구성은 동일하게 Dense(3, activation='softmax')로 하고 출력값도 3개가 나오게 된다.

단 실측 출력값을 입력하는 부분에서 별도로 one-hot encoding을 할 필요가 없이 정수값 그대로 주고, 손실함수를  sparse_categorical_crossentropy 로 바꿔주기만 하면 된다.

model.compile(optimizer=.., loss='sparse_categorical_entropy')





반응형

벡터 구조체 필드 기준으로 최대값 최소값 찾기


#include <algorithm>

#include <vector>


typedef struct _A {

double x ;

double y ;

} A ;


bool compareA(const A& a1, const A&a2) {

// 앞에 있는 노드의 x값이 더 작게 소팅한다.

return a1.x < a2.x ;

}



std::vector<A> alist ;

A tmp ;

tmp.x = 10 ;

tmp.y = 70 ;

alist.push_back(tmp) ;

tmp.x = 5 ;

tmp.y = 60 ;

alist.push_back(tmp) ;

tmp.x = 3 ;

tmp.y = 50 ;

alist.push_back(tmp) ;

tmp.x = 8 ;

tmp.y = 80 ;

alist.push_back(tmp) ;


A mina = *std::min_element(alist.begin(), alist.end(), compareA) ;

A maxa = *std::max_element(alist.begin(), alist.end(), compareA) ;

// 이터레이터를 리턴하므로 *를 붙여 객체값을 얻어온다. 


printf("mina %lf %lf \n", mina.x, mina.y) ;

printf("maxa %lf %lf \n", maxa.x, maxa.y) ;


mina 3.000000 50.000000 
maxa 10.000000 70.000000 




반응형

[UI] Qt5

파이썬으로 간단한 UI 프로그램 개발

QWidget , inputBox, MessageBox, 버튼 처리. 텍스트 출력. 도형 그리기.

슬라이드바 사용.



옛날에는 윈도우에서 VS로 MFC나 C# windows form 등을 만들었었는데, 좀 더 쉽게 간단하게 만들 방법이 없을까 하다가. 리눅스에서 Python으로 PyQt5를 한 번 써보게 됐다.

먼저 PyQt5를 설치해 준다.  Qt는 어느 플랫폼에서도 돌아가니까 좋은 것 같다.

만들 프로그램은 조건에 따른 통계 수치를 기록하는 간단한 구조이다.

먼저 분석할 데이터를 DB에서 가져와  numpy save file로 만들어 두었다. 

아래 프로그램에서는 save data를 로딩해서 분석만 하면 된다.

조건에 따른 분기를 순서도 처럼 그린다.


도형 그림을 그려야 되기 때문에 도형 클래스를 간단하게 만든다.

도형은 네모, 다이아(조건) 두 개로 하고, 선분 클래스도 추가한다.

네모 타입은 내부에 텍스트를 출력한다.

다이아 타입도 내부에 텍스트 출력 기능이 있고, 왼쪽, 오른쪽에 각각 텍스트 출력도 한다.

필요한 라이브로리 로딩.

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *


SHAPE_RECT = 0
SHAPE_DIA = 1

class ShapeObject():
def __init__(self, x,y,w,h, shape, name):
self.rect = QRectF(x,y,w,h) # x,y w,h
self.x = x
self.y = y
self.w = w
self.h = h
self.shape = shape
self.name = name
self.text = name
self.text_l = ''
self.text_r = ''
self.value=0.0
self.button=None

def set_name(self, n):
self.name = n
self.text = self.name+'\n'+str(self.value)

def set_text(self, t, addName=False):
if addName:
self.text = self.name+'\n'+t
else:
self.text = t
def set_value(self, v):
self.value = v
self.text = self.name+'\n'+str(v)
def set_textl(self, l):
self.text_l = l
def set_textr(self, r):
self.text_r = r
def set_button(self, btn):
self.button = btn

def draw(self, painter):
if self.shape == SHAPE_RECT:
painter.drawRect(self.rect) # x,y, w,h
painter.drawText(self.rect, Qt.AlignCenter, self.text)
elif self.shape == SHAPE_DIA:
points = [QPoint(self.rect.center().x(), self.rect.top()),
QPoint(self.rect.right(), self.rect.center().y()),
QPoint(self.rect.center().x(), self.rect.bottom()),
QPoint(self.rect.left(), self.rect.center().y())]
painter.drawPolygon(QPolygon(points))
painter.drawText(self.rect, Qt.AlignCenter, self.text)
if len(self.text_l)>0:
rect = QRectF( self.x-50, self.y+10, 50, 50 )
painter.drawText(rect, Qt.AlignCenter, self.text_l)
if len(self.text_r)>0:
rect = QRectF( self.x+self.w+10, self.y+10, 50, 50 )
painter.drawText(rect, Qt.AlignCenter, self.text_r)



도형들을 이어주는 선분의 위치 정보 얻는 함수

align은 C면 첫번째 도형의 가운데, L=left, R=right에서 선이 출발하도록 한다.



def get_connect_line(o1, o2, align='C'):
points=[0,0,0,0, 0]
if align=='C':
points[0]=int(o1.x+o1.w/2)
points[1]=int(o1.y+o1.h)
elif align=='L':
points[0]=int(o1.x)
points[1]=int(o1.y+o1.h/2)
points[4]=0x0000FF
elif align=='R':
points[0]=int(o1.x+o1.w)
points[1]=int(o1.y+o1.h/2)
points[4]=0xFF0000

points[2]=int(o2.x+o2.w/2)
points[3]=int(o2.y)

return points

앱의 메인이다. 좌표들은 그림을 먼저 그림판에다 대충 그리고, 좌표를 대략적으로 뽑아서 출력해 본다.


class MyApp(QWidget):
def __init__(self):
super().__init__()
self.shapes = []
self.lines = []
self.selected = 0
self.slideValue = 0.0
self.statmsg = ''
self.statmsg1 = ''
self.statmsg2 = ''

self.initUI()


def initUI(self):
self.setWindowTitle('Decision Graph')
self.setWindowIcon(QIcon('icon1.png'))

# 메인 화면 크기 위치 지정.
self.move(300,300)
self.resize(650,800)
            
        ############## 버튼. 클릭 이벤트 콜백 설정. 종료연결.
btnQuit = QPushButton('Quit', self)
btnQuit.setToolTip('exit <b>decision graph</b> program')
btnQuit.move(10, 10)
btnQuit.resize( btnQuit.sizeHint())
btnQuit.clicked.connect(QCoreApplication.instance().quit)


offx=20

## 네모 도형 객체를 만든다.
self.shape1 = ShapeObject(offx+200, 50, 200, 50, SHAPE_RECT, 'CompareSet')
self.shapes.append(self.shape1)

## 아래쪽에 다이아 객체를 만든다.
self.shape2 = ShapeObject(offx+200, 150, 200, 50, SHAPE_DIA, 'v2.0')
self.shape2.set_text('0.9', True)
self.shape2.set_value(0.9)
self.shape2.set_textl('869')
self.shape2.set_textr('3584')
self.shapes.append(self.shape2)


## 선분 객체를 만든다. 네모와 다이아를 연결한다.
self.lines.append( get_connect_line(self.shape1, self.shape2, 'C'))

## 왼쪽 아래에 다이아 객체 추가.
self.shape3 = ShapeObject(offx+100, 240, 200, 50, SHAPE_DIA, 'P0')
self.shape3.set_text('0.7', True)
self.shape3.set_value(0.7)
self.shape3.set_textl('744')
self.shape3.set_textr('125')
self.shapes.append(self.shape3)
self.lines.append( get_connect_line(self.shape2, self.shape3, 'L'))

## 버튼을 추가. user-defined callback으로 설정. 클릭 이벤트 처리.
self.btnShape3 = QPushButton('M', self)
self.btnShape3.move(self.shape3.x, self.shape3.y)
self.btnShape3.resize(self.btnShape3.sizeHint())
self.btnShape3.clicked.connect(self.btnShape3Click)

## 이런식으로 순서도 도형들을 그리고, 텍스트 정보 등을 추가한다.
self.shape4 = ShapeObject(offx+420, 240, 50, 50, SHAPE_RECT, 'F')
self.shapes.append(self.shape4)
self.lines.append( get_connect_line(self.shape2, self.shape4, 'R'))

self.shape5 = ShapeObject(offx+20, 340, 200, 50, SHAPE_DIA, 'P8')
self.shape5.set_text('0.8', True)
self.shape5.set_value(0.8)
self.shape5.set_textl('608')
self.shape5.set_textr('136')
self.shapes.append(self.shape5)
self.lines.append( get_connect_line(self.shape3, self.shape5, 'L'))
self.btnShape5 = QPushButton('A', self)
self.btnShape5.move(self.shape5.x, self.shape5.y)
self.btnShape5.resize(self.btnShape5.sizeHint())
self.btnShape5.clicked.connect(self.btnShape5Click)

self.shape6 = ShapeObject(offx+350, 340, 200, 50, SHAPE_DIA, 'P7')
self.shape6.set_text('0.6', True)
self.shape6.set_value(0.6)
self.shape6.set_textl('80')
self.shape6.set_textr('45')
self.shapes.append(self.shape6)
self.lines.append( get_connect_line(self.shape3, self.shape6, 'R'))
self.btnShape6 = QPushButton('B', self)
self.btnShape6.move(self.shape6.x, self.shape6.y)
self.btnShape6.resize(self.btnShape6.sizeHint())
self.btnShape6.clicked.connect(self.btnShape6Click)

self.shape7 = ShapeObject(offx+10, 470, 50, 50, SHAPE_RECT, 'T')
self.shapes.append(self.shape7)
self.lines.append( get_connect_line(self.shape5, self.shape7, 'L'))

self.shape8 = ShapeObject(offx+200, 470, 50, 50, SHAPE_RECT, 'F')
self.shapes.append(self.shape8)
self.lines.append( get_connect_line(self.shape5, self.shape8, 'R'))

self.shape9 = ShapeObject(offx+300, 470, 50, 50, SHAPE_RECT, 'T')
self.shapes.append(self.shape9)
self.lines.append( get_connect_line(self.shape6, self.shape9, 'L'))

self.shape10 = ShapeObject(offx+530, 470, 50, 50, SHAPE_RECT, 'F')
self.shapes.append(self.shape10)
self.lines.append( get_connect_line(self.shape6, self.shape10, 'R'))

# 슬라이드바 추가. 값을 조절하는 기능.
self.slider = QSlider(Qt.Horizontal, self)
self.slider.move(200, 550)
self.slider.resize(200, 20)

# 0~100 까지 값을 갖게 되고, 움직임은 1씩 변경되게 한다. 최초에 0값으로 설정함.
self.slider.setRange(0, 100)
self.slider.setSingleStep(1)
self.slider.setValue(0)

# 슬라이드를 움직여 값이 변경되면 감지되는 콜백 연결.
self.slider.valueChanged.connect(self.sliderChange)

# 하나의 버튼이 눌리면 다른 버튼들은 gray로 하고, 눌려진 버튼이 불 들어오게 한다.
btnUpdate = QPushButton('Update', self)
btnUpdate.setToolTip('test')
btnUpdate.move(250, 580)
btnUpdate.resize( btnUpdate.sizeHint())
btnUpdate.clicked.connect(self.btnUpdateClick)

self.btnShape3.setStyleSheet("background-color:gray")
self.btnShape5.setStyleSheet("background-color:gray")
self.btnShape6.setStyleSheet("background-color:gray")

btnChange = QPushButton('Change', self)
btnChange.setToolTip('change factor')
btnChange.move(10, 600)
btnChange.resize (btnChange.sizeHint())
btnChange.clicked.connect(self.btnChangeClick)

btnInput = QPushButton('Input', self)
btnInput.setToolTip('input threshold')
btnInput.move(410, 550)
btnInput.resize(50, 20)
btnInput.clicked.connect(self.btnInputClick)

self.show()

# 버튼이 눌린쪽의 도형의 값을 슬라이드 값으로 변경한다.
def sliderChange(self, v):
# print( self.selected, v) # v 0~100
if self.selected>0:
shape = self.shapes[self.selected-1]
shape.set_value(v/self.slider.maximum())
self.slideValue = v/self.slider.maximum()
updatestat(self) ## live check... slow...
self.update()

def nextCaptureName(self, head):
for i in range(1000):
filename = head+"{:03d}".format(i)+".png"
if not os.path.exists(filename):
break
return filename

# 현재 윈도우 화면을 캡쳐해 봤다. 0으로 하면 전체 화면이 캡쳐된다. 맥에서 해보니 항상 전체화면이 캡쳐되었다. 버전이 다르긴 함.
def take_screenshot(self):
# full screen capture
# self.preview_screen = QApplication.primaryScreen().grabWindow(0)
self.preview_screen = QApplication.primaryScreen().grabWindow(self.winId())
filename = self.nextCaptureName("signanalyze_graph_")
print('filename=', filename)
self.preview_screen.save(filename)

def btnUpdateClick(self):
updatestat(self)
self.update()
self.take_screenshot()


# 슬라이드 말고 직접 값을 입력할 때, 입력 받도록 하였다.
def btnInputClick(self):
if self.selected>0:
text, okpressed = QInputDialog.getText(self, "Input", "Input Value(0.0~1.0):", QLineEdit.Normal, "" )
if okpressed and text!='':
try:
v = float(text)
self.slider.setValue(v*100)
except:
QMessageBox.about(self, "Input", "Invalid value!")

def btnChangeClick(self):
if self.selected>0:
text, okpressed = QInputDialog.getText(self, "Input", "Input Facotr(P0~P8):", QLineEdit.Normal, "" )
text = text.upper()
if okpressed and text in ['P0', 'P1', 'P2', 'P3', 'P4', 'P5', 'P6', 'P7', 'P8']:
shape = self.shapes[self.selected-1]
shape.set_name(text)
updatestat(self)
self.update()
elif text=="" :
pass
else:
QMessageBox.about(self, "Input", "Invalid P factor name!")

# 눌려진 버튼의 색을 변경한다. 다른 버튼들은 리셋함.
def btnShape3Click(self):
self.selected = 3
self.slideValue = self.shape3.value
self.slider.setValue(self.shape3.value * self.slider.maximum())
self.btnShape3.setStyleSheet("background-color:blue")
self.btnShape5.setStyleSheet("background-color:gray")
self.btnShape6.setStyleSheet("background-color:gray")
self.update()
def btnShape5Click(self):
self.selected = 5
self.slideValue = self.shape5.value
self.slider.setValue(self.shape5.value * self.slider.maximum())
self.btnShape3.setStyleSheet("background-color:gray")
self.btnShape5.setStyleSheet("background-color:blue")
self.btnShape6.setStyleSheet("background-color:gray")
self.update()
def btnShape6Click(self):
self.selected = 6
self.slideValue = self.shape6.value
self.slider.setValue(self.shape6.value * self.slider.maximum())
self.btnShape3.setStyleSheet("background-color:gray")
self.btnShape5.setStyleSheet("background-color:gray")
self.btnShape6.setStyleSheet("background-color:blue")
self.update()

# 그림을 그린다.
def paintEvent(self, QPaintEvent):
painter = QPainter(self)
painter.setPen(QPen(Qt.black, 1))
for s in self.shapes:
s.draw(painter)

for l in self.lines:
if l[4]==0:
painter.setPen(QPen(Qt.black, 1))
else:
painter.setPen(QPen(QColor(l[4]), 1))
painter.drawLine(l[0], l[1], l[2], l[3])

painter.setPen(QPen(Qt.black, 1))
rect = QRectF(10, 530, 200, 50)
if self.selected>0:
painter.drawText(rect, Qt.AlignCenter, 'Selected : ' + self.shapes[self.selected-1].name )
else:
painter.drawText(rect, Qt.AlignCenter, 'Selected : None' )
rect = QRectF(400, 530, 200, 50)
painter.drawText(rect, Qt.AlignCenter, str(self.slideValue))

        # 텍스트 출력.. align 설정.
rect = QRectF(200, 610, 500, 50)
painter.drawText(rect, Qt.AlignLeft, str(self.statmsg))
rect = QRectF(450, 50, 500, 50)
painter.drawText(rect, Qt.AlignLeft, str(self.statmsg1))
rect = QRectF(450, 150, 500, 50)
painter.drawText(rect, Qt.AlignLeft, str(self.statmsg2))

프로그램 구동

app = QApplication([])

ex = MyApp()

sys.exit(app.exec_())




+ Recent posts