{"id":34082329,"url":"https://github.com/cosmoquester/quickspacer","last_synced_at":"2026-03-08T23:34:42.673Z","repository":{"id":55613395,"uuid":"312965954","full_name":"cosmoquester/quickspacer","owner":"cosmoquester","description":"빠른 속도와 준수한 정확도를 목표로하는 한국어 띄어쓰기 교정 모델입니다. (It is a Korean spacing correction model that aims for fast speed and moderate accuracy.)","archived":false,"fork":false,"pushed_at":"2022-11-25T05:24:22.000Z","size":74129,"stargazers_count":36,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-12T14:57:28.601Z","etag":null,"topics":["fast","korean","spacer","tensorflow-js","tensorflow2"],"latest_commit_sha":null,"homepage":"https://cosmoquester.github.io/quickspacer/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cosmoquester.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-11-15T05:38:59.000Z","updated_at":"2025-11-04T17:19:59.000Z","dependencies_parsed_at":"2023-01-22T17:15:16.523Z","dependency_job_id":null,"html_url":"https://github.com/cosmoquester/quickspacer","commit_stats":null,"previous_names":["psj8252/quickspacer"],"tags_count":4,"template":false,"template_full_name":"cosmoquester/python3-template","purl":"pkg:github/cosmoquester/quickspacer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmoquester%2Fquickspacer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmoquester%2Fquickspacer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmoquester%2Fquickspacer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmoquester%2Fquickspacer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cosmoquester","download_url":"https://codeload.github.com/cosmoquester/quickspacer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cosmoquester%2Fquickspacer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30277036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T20:45:49.896Z","status":"ssl_error","status_checked_at":"2026-03-08T20:45:49.525Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fast","korean","spacer","tensorflow-js","tensorflow2"],"created_at":"2025-12-14T12:12:36.878Z","updated_at":"2026-03-08T23:34:42.665Z","avatar_url":"https://github.com/cosmoquester.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# QuickSpacer\n\n[![codecov](https://codecov.io/gh/cosmoquester/quickspacer/branch/master/graph/badge.svg)](https://codecov.io/gh/cosmoquester/quickspacer)\n\n\n- 빠른 속도와 준수한 정확도를 목표로하는 한국어 띄어쓰기 교정 모델입니다.\n- 이 레포지토리에 있는 모델들은 [모두의 말뭉치](https://corpus.korean.go.kr) `국립국어원 문어 말뭉치(버전 1.0)` 데이터를 이용하여 학습한 모델입니다.\n\n# Demo\n\n데모는 Tensorflow JS로 만들어져 있으며 https://cosmoquester.github.io/quickspacer/ 에서 사용해보실 수 있습니다.\n\n# Install \u0026 Usage\n\n```bash\npip install quickspacer\n```\n위 명령어로 설치하실 수 있습니다.\n\n```python\nfrom quickspacer import Spacer\n\nspacer = Spacer()\nspacer.space([\"띄어쓰기를안한나쁜말\", \"또는 띄어쓰기가 잘 되어있는 좋은 말\"])\nspacer.space([\"띄어쓰기를안한나쁜말\", \"또는 띄어쓰기가 잘 되어있는 좋은 말\", ...], batch_size=48)\n```\n이런식으로 사용하실 수 있습니다. spacer.space() 함수는 띄어쓰기가 된 리스트를 반환합니다.\n\nbatch_size옵션을 사용하면 batch단위로 묶여 연산합니다.\nbatch내에 있는 문장들은 가장 긴 문장길이를 기준으로 나머지 문장은 padding하여 연산을 진행하므로 batch_size가 너무 크고 길이가 엄청 긴 문장이 들어있다면 전체 추론 속도가 느려질 수 있습니다.\nbatch_size를 따로 넘기지 않으면 입력 데이터 전체를 한 번에 계산합니다.\n\n```python\nfrom quickspacer import Spacer\n\nspacer = Spacer(\"somewhere/my_custom_savedmodel_dir\")\nspacer = Spacer(saved_model_dir=\"somewhere/my_custom_savedmodel_dir\")\n```\n만약 모델을 따로 학습시키셨다면, 위와 같이 saved_model 경로를 인자로 넘겨 직접학습한 모델을 사용할 수 있습니다.\n\n물론 savedmodel이 레포지토리의 scripts.convert_to_savedmodel 스크립트를 통해 변환된 경우만 가능합니다.\n\n```python\nfrom quickspacer import Spacer\n\n# Level 1 Default, Same as Spacer()\nspacer1 = Spacer(level=1)\n# Level 2\nspacer2 = Spacer(level=2)\n# Level 3\nspacer1 = Spacer(level=3)\n```\nSpacer의 인스턴스를 만들 때 위와 같이 level 인자를 넘겨줄 수 있습니다. (기본: 1) 레벨은 높을수록 일반적인 띄어쓰기 성능이 향상되며 대신 속도가 더 오래걸립니다.\n\n# Train\n\n## Make Vocab\n\n```bash\npython -m scripts.make_vocab \\\n    --input-dir [corpus_directory_path] \\\n    --vocab-path [vocab_file_path]\n```\n기본 vocab은 quickspacer/resources/vocab.txt에 존재하지만 따로 문자열이 필요하거나 다른 언어의 띄어쓰기 모델을 만들 예정이라면 위 명령어를 통해 새로 vocab 파일을 만들 수 있습니다.\n\n## Model Train\n\n```bash\npython -m scripts.train_quickspacer \\\n    --model-name [model_name] \\\n    --dataset-file-path [dataset_paths] \\\n    --output-path [output_dir_path]\n```\n모델은 위 명령어로 학습할 수 있습니다.\n- 현재 레포지토리에 존재하는 모델은 [ConvSpacer1, ConvSpacer2, ConvSpacer3] 세 종류입니다. model-name에는 이 세 가지 중 하나를 입력합니다.\n- 각 모델마다 사용하는 파라미터가 있는데 configs 디렉토리에 기본 설정파일들이 있으며 이를 수정해서 사용하면 됩니다.\n- dataset은 UTF-8로 인코딩 된 텍스트파일 형태입니다. 띄어쓰기가 올바르게 되어있는 문장이라고 가정하고 학습합니다. 여러 파일을 입력할 수 있습니다. ex) \"corpus_*.txt\"\n\n```bash\npython -m scripts.train_quickspacer --help\n```\n를 보면 여러 학습 parameter을 입력할 수 있습니다.\n\n# Deploy\n\n배포는 SavedModel을 이용한 배포와 Tensorflowjs를 이용한 배포가 가능합니다.\n\n## Deploy using SavedModel\n\n### Make SavedModel\n\n```bash\npython -m scripts.convert_to_savedmodel \\\n    --model-weight-path [model_weight_path] \\\n    --output-path [saved_model_path]\n```\n위 명령어를 통해 모델을 TF SavedModel 형식으로 변환할 수 있습니다.\n- model-weight-path는 train을 통해서 models에 저장된 경로를 입력하면 되는데 \"spacer-XXepoch-xxx.index\" 이런 식으로 파일이 존재하는데 \"spacer-XXepoch-xxx\" 까지만 입력합니다.\n- SavedModel은 그대로 Tensorflow로 Load해서 그대로 사용해도 되고, Tensorflow serving 등을 통해 API 서버로 Deploy할 수 있습니다.\n\n### SavedModel Additional Description\n\nconvert_to_savedmodel로 변환한 모델은 두 개의 signature function을 가지고 있습니다. 아래 명령들은 SavedModel을 만드는 것과는 무관하며 추가적인 설명을 위한 것입니다.\n```bash\n$ saved_model_cli show --dir saved_spacer_model/1 \\\n    --tag_set serve \\\n    --signature_def serving_default\n2020-11-15 17:02:30.861944: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1\nThe given SavedModel SignatureDef contains the following input(s):\n  inputs['texts'] tensor_info:\n      dtype: DT_STRING\n      shape: (-1)\n      name: serving_default_texts:0\nThe given SavedModel SignatureDef contains the following output(s):\n  outputs['spaced_sentences'] tensor_info:\n      dtype: DT_STRING\n      shape: unknown_rank\n      name: StatefulPartitionedCall_1:0\nMethod name is: tensorflow/serving/predict\n```\n- default는 text를 입력받고 띄어쓰기가 완료된 문장을 반환하도록 되어있습니다. 위의 saved_model_cli를 통해 살펴보면 DT_STRING이 입출력인 것을 알 수 있습니다.\n\n```bash\n$ saved_model_cli run --dir saved_spacer_model/1 \\\n    --tag_set serve \\\n    --signature_def serving_default \\\n    --input_exprs 'texts=[\"근데이것좀띄워주시겠어요?\", \"싫은데영ㅎㅎ\"]'\n2020-11-15 17:06:27.735637: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1\n2020-11-15 17:06:28.659347: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcuda.so.1\n[각종 TF log들 ...]\nResult for output key spaced_sentences:\n[b'\\xea\\xb7\\xbc\\xeb\\x8d\\xb0 \\xec\\x9d\\xb4\\xea\\xb2\\x83 \\xec\\xa2\\x80 \\xeb\\x9d\\x84\\xec\\x9b\\x8c \\xec\\xa3\\xbc\\xec\\x8b\\x9c\\xea\\xb2\\xa0\\xec\\x96\\xb4\\xec\\x9a\\x94?'\n b'\\xec\\x8b\\xab\\xec\\x9d\\x80\\xeb\\x8d\\xb0 \\xec\\x98\\x81\\xe3\\x85\\x8e\\xe3\\x85\\x8e']\n```\n- 이런 식으로 saved_model이 잘 저장되었고 제대로 동작하는지 확인할 수 있습니다.\n- Unicode 바이너리로 나와서 조금 불편한데 한글로 바꿔보면 [\"근데 이것 좀 띄워 주시겠어요?\",\"싫은데 영ㅎㅎ\"] 으로 띄어쓰기를 해주었습니다.\n\n```bash\n$ saved_model_cli show --dir saved_spacer_model/1 \\\n    --tag_set serve \\\n    --signature_def model_inference\n2020-11-15 17:03:19.988061: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1\nThe given SavedModel SignatureDef contains the following input(s):\n  inputs['tokens'] tensor_info:\n      dtype: DT_INT32\n      shape: (-1, -1)\n      name: model_inference_tokens:0\nThe given SavedModel SignatureDef contains the following output(s):\n  outputs['output_0'] tensor_info:\n      dtype: DT_FLOAT\n      shape: (-1, -1)\n      name: StatefulPartitionedCall:0\nMethod name is: tensorflow/serving/predict\n```\n- 또 하나의 Signature 함수는 문장을 글자를 다 잘라서 Vocab을 이용해 숫자로 변환된 입력을 받고, 각 자리를 띄워야할 확률을 알려줍니다.\n- 아까와 같은 문장을 숫자로 변환하여 테스트해보겠습니다.\n\n```bash\n$ saved_model_cli run --dir saved_spacer_model/1 \\\n    --tag_set serve \\\n    --signature_def model_inference \\\n    --input_exprs 'tokens=[[88,26,4,100,112,1241,93,64,38,56, 6,19,15],[216,33,26,202,67,67,0,0,0,0,0,0,0]]'\n[각종 Tensorflow log...]\nResult for output key output_0:\n[[2.5608379e-03 9.8520654e-01 1.2721949e-03 9.7731644e-01 9.9997485e-01\n  1.6742251e-07 5.0763595e-01 2.1732522e-03 1.0649196e-03 2.6994228e-04\n  1.1066308e-04 1.4717710e-03 2.8897190e-01]\n [3.6909140e-04 1.2601367e-02 8.4685940e-01 7.0986725e-06 1.3404434e-05\n  5.6068022e-10 2.8169470e-12 1.1617506e-17 2.8605146e-17 2.8605146e-17\n  2.8605146e-17 5.3611558e-16 2.1768996e-07]]\n```\n- 두 문장의 길이가 다른 경우에는 위 예시처럼 0으로 패딩을 해줘야합니다.\n- 결과를 보면 각 위치마다 띄어야할 확률이 나왔습니다.\n\n### Deploy using Tensorflow/serving docker\n\n```bash\n$ docker run  --rm --name test -p 8500:8500 -p 8501:8501 \\\n    --mount type=bind,source=`pwd`/saved_spacer_model,target=/models/spacer \\\n    -e MODEL_NAME=spacer \\\n    -t tensorflow/serving:latest\n```\n간단히 docker로 tensorflow serving 서버를 여는 명령입니다. 현재 모델 파일은 실제로는 `pwd`/saved_1pacer_model/1 에 저장되어 있습니다.\n\n```bash\n$ curl -X POST localhost:8501/v1/models/spacer:predict \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\"instances\":[\"근데이것좀띄워주시겠어요!\", \"싫은데영ㅎㅎ\"]}'\n{\n    \"predictions\": [\"근데 이것 좀 띄워 주시겠어요!\", \"싫은데 영ㅎㅎ\"\n    ]\n}\n```\n이제 curl을 이용해 테스트해보면 정상적으로 띄어쓰기가 완료된 문장을 반환하는 것을 볼 수 있습니다. signature function을 지정하면 model_inference만 하는 것도 가능합니다.\n\n## Deploy using Tensorflowjs\n\n다음은 tensorflowjs를 이용해서 서버가 아닌 클라이언트의 브라우저에서 추론하도록할 수 있습니다. 데모페이지에 있는 것도 Tensorflow JS를 이용한 것입니다.\n\n### Make TFJS Graph Model\n\n```bash\npython -m scripts.convert_to_tfjsmodel \\\n    --saved-model-path [saved_model_path] \\\n    --output-path [output_dir_path]\n```\n이 명령어를 통해 Tensorflow JS 모델로 변환할 수 있습니다.\nTFJS에서도 문장을 넣고 문장이 나오도록 만들고 싶었지만 Vocab을 포함하고 있는 signature function은 TFJS로 변환하는데 에러가 발생하여 TFJS에선 모델 추론만 하도록 했습니다.\n위 파이썬 스크립트를 이용하지 않더라도 `tensorflowjs_wizard`나 `tensorflowjs_converter` 명령어를 바로 사용해도 됩니다.\n\n### Use Tensorflow JS Graph Model\n\n- https://js.tensorflow.org/api/latest/ 를 참고하면 js로 사용할 수 있는 API가 정리되어 있습니다.\n- tfjs를 사용하려면 https://www.tensorflow.org/js/tutorials/setup에 나와있는 것처럼 tensorflow js 파일을 넣어줘야합니다.\n\n우리가 위에서 만든 건 tf.GraphModel이므로 `tf.loadGraphModel` 함수로 불러와서 사용하면 됩니다.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcosmoquester%2Fquickspacer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcosmoquester%2Fquickspacer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcosmoquester%2Fquickspacer/lists"}