목표: 독거노인 1인 가구의 사회복지사 방문 외 시간 때 응급상황을 알릴 수 있도록 위급 행동 구별
팀: 4명
개요
2021년 고독사 사망자 수는 총 3,378명으로 최근 5년간 증가 추세
고령 사회의 빠른 도래와 독거노인 가구의 급증으로 인해 고령자의 삶의 질 저하와 고령자 지원을 위한 사회 공공지출의 급격한 증가가 예상되고 있다. 이러한 사회 문제에 대한 해결책의 하나로 로봇이 고령자와 함께 생활하면서 고령자를 이해하고 정서적으로 교류하면서 상황에 맞는 건강, 생활, 인지, 정서 서비스를 제공하기 위해 필요한 로봇 지능기술의 개발이 요구되고 있다.
로봇이 휴먼에게 적절한 휴먼케어 서비스를 제공하기 위해서는 시시각각 변하는 휴먼에 대한 정보를 높은 신뢰도로 인식할 수 있는 능력이 기본적으로 필요하다. 휴먼 정보 인식 기술 중에서 휴먼이 행하고 있는 동작이 어떤 행동인지를 파악하는 행동 인식 기술은 고령자가 일생 생활에서 행하는 행위의 의도를 이해하고 고령자의 생활 패턴을 파악하기 위한 필수 기술이다.
고독사, 가족, 친척 등 주변사람들과 단절된 채 홀로 사는 사람
자살·병사 등으로 혼자 임종을 맞음
시신이 일정한 시간이 흐른 뒤에 발견되는 죽음
매년 남성 고독사가 여성 고독사에 비해 4배 이상 많으며,
가장 많은 비중을 차지하는 연령은 50∼60대 (매년 50% 이상)로 확인
※ 최근 5년 연평균 증가율 : 남성 고독사 10.0%, 여성 고독사 5.6%
데이터셋
[ETRI 나눔] 로봇환경에서 고령자의 일상행동 인식을 위한 3D 영상 데이터셋 - Skeleton, BodyIndex
70세 이상의 고령자 53명의 자택을 방문하여 기상부터 취침까지의 하루 행동을 직접 관찰하고 기록하였더니 총 245개의 일상 활동 유형으로 압축되었다. 이들 행동 중에 빈번하게 나타나는 행동으로 TV 시청, 식사관련 활동, 화장실 사용, 식사 준비, 전화 통화, 약 복용, 요리, 청소 등이 있었으며 이러한 다빈도 활동들을 기준으로 55종의 행동을 인식 대상으로 선정하였다.
#!/usr/bin/env python
import sys
import time
from random import choice
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Producer
if __name__ == '__main__':
# Record the start time
start_time = time.time()
# Parse the command line.
parser = ArgumentParser()
parser.add_argument('config_file', type=FileType('r'))
args = parser.parse_args()
# Parse the configuration.
# See https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md
config_parser = ConfigParser()
config_parser.read_file(args.config_file)
config = dict(config_parser['default'])
# Create Producer instance
producer = Producer(config)
# Optional per-message delivery callback (triggered by poll() or flush())
# when a message has been successfully delivered or permanently
# failed delivery (after retries).
def delivery_callback(err, msg):
if err:
print('ERROR: Message failed delivery: {}'.format(err))
else:
print("Produced event to topic {topic}: key = {key:12} value = {value:12}".format(
topic=msg.topic(), key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))
# Produce data by selecting random values from these lists.
topic = "purchases"
user_ids = ['eabara', 'jsmith', 'sgarcia', 'jbernard', 'htanaka', 'awalther']
products = ['book', 'alarm clock', 't-shirts', 'gift card', 'batteries']
count = 0
for _ in range(100): # Change the range to 100 for 100 messages
user_id = choice(user_ids)
product = choice(products)
producer.produce(topic, product, user_id, callback=delivery_callback)
# Introduce a delay of 0.1 seconds
time.sleep(0.1)
count += 1
# Block until the messages are sent.
producer.flush()
# Record the end time
end_time = time.time()
# Calculate and print the total execution time
total_time = end_time - start_time
print(f'Total execution time: {total_time:.2f} seconds')
하나의 프로듀서가 0.1 초가 걸리는 데이터 전송을 100개 전송했을 때 10.95 seconds 소요됨.
#!/usr/bin/env python
import sys
import time
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Consumer, OFFSET_BEGINNING
if __name__ == '__main__':
# Record the start time
start_time = time.time()
start_receive_time = time.time()
# Parse the command line.
parser = ArgumentParser()
parser.add_argument('config_file', type=FileType('r'))
parser.add_argument('--reset', action='store_true')
args = parser.parse_args()
# Parse the configuration.
# See https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md
config_parser = ConfigParser()
config_parser.read_file(args.config_file)
config = dict(config_parser['default'])
config.update(config_parser['consumer'])
# Create Consumer instance
consumer = Consumer(config)
# Set up a callback to handle the '--reset' flag.
def reset_offset(consumer, partitions):
if args.reset:
for p in partitions:
p.offset = OFFSET_BEGINNING
consumer.assign(partitions)
# Subscribe to topic
topic = "purchases"
consumer.subscribe([topic], on_assign=reset_offset)
wait = False
# Poll for new messages from Kafka and print them.
try:
while True:
msg = consumer.poll(1.0)
if msg is None:
# Initial message consumption may take up to
# `session.timeout.ms` for the consumer group to
# rebalance and start consuming
print("Waiting...")
if not wait:
# Calculate and print the waiting time
end_receive_time = time.time()
transfer_duration = end_receive_time - start_receive_time
print(f'Receive duration: {transfer_duration-1:.2f} seconds')
wait = True
elif msg.error():
print("ERROR: {}".format(msg.error()))
else:
# Extract the (optional) key and value, and print.
start_waiting_time = time.time() # Record the start time of waiting
print("Consumed event from topic {topic}: key = {key:12} value = {value:12}".format(
topic=msg.topic(), key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))
time.sleep(0.1)
wait = False
except KeyboardInterrupt:
pass
finally:
# Leave group and commit final offsets
consumer.close()
# Record the end time
end_time = time.time()
# Calculate and print the total execution time
total_time = end_time - start_time
print(f'Total execution time: {total_time:.2f} seconds')
하나의 컨슈머가 0.1 초가 걸리는 데이터 전송을 100개 수신했을 때 11.65 seconds 소요됨.
병렬 시스템
1번. 하나의 파티션을 두개의 consumer에서 소비하는 병렬방식
consumer_1.py
(config 파일인 "getting_started.ini" 안에는 group.id = group_1 가 지정되어 있음)
#!/usr/bin/env python
import sys
import time
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Consumer, KafkaError
if __name__ == '__main__':
# Record the start time
start_time = time.time()
start_receive_time = time.time()
# Parse the command line.
parser = ArgumentParser()
parser.add_argument('config_file', type=FileType('r'))
args = parser.parse_args()
# Parse the configuration.
config_parser = ConfigParser()
config_parser.read_file(args.config_file)
config = dict(config_parser['default'])
config.update(config_parser['consumer'])
# Set unique group.id for each consumer group
config['group.id'] = f"{config['group.id']}_{time.time()}"
# Create Consumer instance
consumer = Consumer(config)
# Subscribe to the topic
topic = "purchases"
consumer.subscribe([topic])
wait = False
# Poll for new messages from Kafka and print them.
try:
while True:
msg = consumer.poll(1.0)
if msg is None:
# No new messages within the timeout
print("Waiting...")
if not wait:
# Calculate and print the waiting time
end_receive_time = time.time()
transfer_duration = end_receive_time - start_receive_time
print(f'Receive duration: {transfer_duration - 1:.2f} seconds')
wait = True
elif msg.error():
if msg.error().code() == KafkaError._PARTITION_EOF:
# End of partition event (not an error)
continue
else:
print("ERROR: {}".format(msg.error()))
else:
# Extract the (optional) key and value, and print.
print("[Consumer 1] Consumed event from topic {topic}, partition {partition}, offset {offset}: key = {key:12} value = {value:12}".format(
topic=msg.topic(), partition=msg.partition(), offset=msg.offset(),
key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))
time.sleep(0.1)
if wait:
wait = False
start_receive_time = time.time()
except KeyboardInterrupt:
pass
finally:
# Leave group and commit final offsets
consumer.close()
# Record the end time
end_time = time.time()
# Calculate and print the total execution time
total_time = end_time - start_time
print(f'Total execution time: {total_time:.2f} seconds')
consumer_2.py
(config 파일인 "getting_started.ini" 안에는 group.id =group_2 가 지정되어 있음)
#!/usr/bin/env python
import sys
import time
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Consumer, KafkaError
if __name__ == '__main__':
# Record the start time
start_time = time.time()
start_receive_time = time.time()
# Parse the command line.
parser = ArgumentParser()
parser.add_argument('config_file', type=FileType('r'))
args = parser.parse_args()
# Parse the configuration.
config_parser = ConfigParser()
config_parser.read_file(args.config_file)
config = dict(config_parser['default'])
config.update(config_parser['consumer'])
# Set unique group.id for each consumer group
config['group.id'] = f"{config['group.id']}_{time.time()}"
# Create Consumer instance
consumer = Consumer(config)
# Subscribe to the topic
topic = "purchases"
consumer.subscribe([topic])
wait = False
# Poll for new messages from Kafka and print them.
try:
while True:
msg = consumer.poll(1.0)
if msg is None:
# No new messages within the timeout
print("Waiting...")
if not wait:
# Calculate and print the waiting time
end_receive_time = time.time()
transfer_duration = end_receive_time - start_receive_time
print(f'Receive duration: {transfer_duration - 1:.2f} seconds')
wait = True
elif msg.error():
if msg.error().code() == KafkaError._PARTITION_EOF:
# End of partition event (not an error)
continue
else:
print("ERROR: {}".format(msg.error()))
else:
# Extract the (optional) key and value, and print.
print("[Consumer 2] Consumed event from topic {topic}, partition {partition}, offset {offset}: key = {key:12} value = {value:12}".format(
topic=msg.topic(), partition=msg.partition(), offset=msg.offset(),
key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))
time.sleep(0.1)
if wait:
wait = False
start_receive_time = time.time()
except KeyboardInterrupt:
pass
finally:
# Leave group and commit final offsets
consumer.close()
# Record the end time
end_time = time.time()
# Calculate and print the total execution time
total_time = end_time - start_time
print(f'Total execution time: {total_time:.2f} seconds')
[ 컨슈머에서의 병렬처리 ]
2개의 컨슈머가 0.1 초가 걸리는 데이터 전송을 100개 수신했을 때각각 10.73 seconds소요됨.
2번. 여러 프로듀서가 동시에 메시지 생성 및 여러 파티션에 저장 / 여러 컨슈머가 병렬로 메시지 소비
#!/usr/bin/env python
import sys
import time
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Consumer, KafkaError, TopicPartition
if __name__ == '__main__':
# Record the start time
start_time = time.time()
start_receive_time = time.time()
# Parse the command line.
parser = ArgumentParser()
parser.add_argument('config_file', type=FileType('r'))
args = parser.parse_args()
# Parse the configuration.
config_parser = ConfigParser()
config_parser.read_file(args.config_file)
config = dict(config_parser['default'])
config.update(config_parser['consumer'])
# Set unique group.id for each consumer group
config['group.id'] = f"{config['group.id']}_{time.time()}"
# Create Consumer instance
consumer = Consumer(config)
# Specify the topic and partition to consume from
topic = "purchases_partition"
partition = 0 # Replace with the desired partition
# Assign the consumer to the specified topic and partition
consumer.assign([TopicPartition(topic, partition)])
wait = False
# Poll for new messages from Kafka and print them.
try:
while True:
msg = consumer.poll(1.0)
if msg is None:
# No new messages within the timeout
print("Waiting...")
if not wait:
# Calculate and print the waiting time
end_receive_time = time.time()
transfer_duration = end_receive_time - start_receive_time
print(f'Receive duration: {transfer_duration - 1:.2f} seconds')
wait = True
elif msg.error():
if msg.error().code() == KafkaError._PARTITION_EOF:
# End of partition event (not an error)
continue
else:
print("ERROR: {}".format(msg.error()))
else:
# Extract the (optional) key and value, and print.
print("[Consumer 1] Consumed event from topic {topic}, partition {partition}, offset {offset}: key = {key:12} value = {value:12}".format(
topic=msg.topic(), partition=msg.partition(), offset=msg.offset(),
key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))
time.sleep(0.1)
if wait:
wait = False
start_receive_time = time.time()
except KeyboardInterrupt:
pass
finally:
# Leave group and commit final offsets
consumer.close()
# Record the end time
end_time = time.time()
# Calculate and print the total execution time
total_time = end_time - start_time
print(f'Total execution time: {total_time:.2f} seconds')
#!/usr/bin/env python
import sys
import time
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Consumer, KafkaError, TopicPartition
if __name__ == '__main__':
# Record the start time
start_time = time.time()
start_receive_time = time.time()
# Parse the command line.
parser = ArgumentParser()
parser.add_argument('config_file', type=FileType('r'))
args = parser.parse_args()
# Parse the configuration.
config_parser = ConfigParser()
config_parser.read_file(args.config_file)
config = dict(config_parser['default'])
config.update(config_parser['consumer'])
# Set unique group.id for each consumer group
config['group.id'] = f"{config['group.id']}_{time.time()}"
# Create Consumer instance
consumer = Consumer(config)
# Specify the topic and partition to consume from
topic = "purchases_partition"
partition = 1 # Replace with the desired partition
# Assign the consumer to the specified topic and partition
consumer.assign([TopicPartition(topic, partition)])
wait = False
# Poll for new messages from Kafka and print them.
try:
while True:
msg = consumer.poll(1.0)
if msg is None:
# No new messages within the timeout
print("Waiting...")
if not wait:
# Calculate and print the waiting time
end_receive_time = time.time()
transfer_duration = end_receive_time - start_receive_time
print(f'Receive duration: {transfer_duration - 1:.2f} seconds')
wait = True
elif msg.error():
if msg.error().code() == KafkaError._PARTITION_EOF:
# End of partition event (not an error)
continue
else:
print("ERROR: {}".format(msg.error()))
else:
# Extract the (optional) key and value, and print.
print("[Consumer 2] Consumed event from topic {topic}, partition {partition}, offset {offset}: key = {key:12} value = {value:12}".format(
topic=msg.topic(), partition=msg.partition(), offset=msg.offset(),
key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))
time.sleep(0.1)
if wait:
wait = False
start_receive_time = time.time()
except KeyboardInterrupt:
pass
finally:
# Leave group and commit final offsets
consumer.close()
# Record the end time
end_time = time.time()
# Calculate and print the total execution time
total_time = end_time - start_time
print(f'Total execution time: {total_time:.2f} seconds')
프로듀서1, 프로듀서2 데이터를 각각 컨슈머1, 컨슈머2에게 전달하고자 할 때, 파티션을 나눈다.
그리고 이를 병렬처리하여 전달하면 throughput을 향상시킬 수 있다.
2개의 프로듀서가 0.1 초가 걸리는 데이터 전송을 파티션2개에 각각 50개씩 저장했을 때5.48seconds소요됨.
2개의 컨슈머가 0.1초 걸리는 데이터 수신을 파티션 2개에 각각 50개씩 가져왔을 때 5.33seconds소요됨.