테스트한 PC의 SPEC입니다.
Text2Image 모델로 생성 시간을 측정 해보았습니다.
애니메이션 스타일 이미지 생성모델인 NetaYume Lumina 를 이용하였습니다. 아래 화면에서 제일 우측 하단 입니다.
테스트한 PC의 SPEC입니다.
Text2Image 모델로 생성 시간을 측정 해보았습니다.
애니메이션 스타일 이미지 생성모델인 NetaYume Lumina 를 이용하였습니다. 아래 화면에서 제일 우측 하단 입니다.
윈도우의 탐색기와 비슷합니다. 좌측 하단에 파인더앱을 선택해서 실행을 합니다.
윈도우의 바탕 화면과 비슷한 개념으로 데스크탑 폴더에 들어 있는 항목은 로그인 시 홈화면 바탕화면에 나타납니다.
아래 그림에서는 desktopfolder 라는 폴더를 만들어서 넣어두었는데 우측에 나타나고 있습니다.
최상위 드라이브를 말합니다. 기본적으로 보이지 않으나 Finder의 설정의 하드 디스크 옵션으로 테스크탑에 보이게 할 수 있습니다. 개인적으로 보이게 하는것을 추천합니다.
해당 옵션을 선택하면 2번 화면 우측에 Machintosh HD 가 나타나며 더블 클릭하면 Finder의 경로가 최상단 경로가 나타나는 화면이 나타납니다."데스트탑" 및 "문서" 폴더가 동기화 되고 계정 홈 폴더 아래에 있던 "데스트탑" 및 "문서" 폴더가 사라지고 iColud Drive 위치에서만 접근이 됩니다.
cmd line 명령으로 확인해보면 폴더가 사라진것은 아니고 보이지 않는 상태 됩니다.
중요한 문서의 경우 문서 폴더에 만들어서 iCloud Drive에 백업하도록 만들고, 임시로 작업하거나 설치하는 어플의 iCloud Drive에 백업할 필요가 없는것들은 임의의 폴더에 저장 하도록 합니다. 임의의 폴더를 만들고 나서 꼭 즐겨 찾기에 등록(끌어다 놓기)하도록 합니다. 즐겨 찾기에 등록하지 않으면 그곳에 저장할때 루트부터 접근 할 수 있는 방법을 제공하지 않습니다.
여기에서는 work 폴더를 계정 아래에 만들고 즐겨찾기에 추가하였고 색상도 변경하였습니다. (해당 폴더는 iCloud Drive 백업이 되지 않습니다.)
/Applications : 사용하는 앱들이 저장된 공간입니다.
/Library : os 또는 시스템, 어플리케이션 프로그램들이 사용하는 각종 파일들이 여기에 있습니다.
/System : os의 시스템 폴더입니다.
/Users : 유저별 디렉토리입니다. /Users/(사용자계정이름)/ 위치가 사용자의 홈이 되고 여기 위치에 데스크탑이나 문서, 그림, 다운로드, 동영상, 음악 같은 폴더가 존재합니다. (4번에 의해 데스크탑이나 문서 폴더는 안보일 수 있습니다.)
파일명이 DMG(Disk Image) 파일은 macOS에서 주로 사용하는 가상 디스크 이미지 파일 형식으로, 파일을 더블 클릭하여 마운트한 후(마운트를 하게 되면 파인더의 외장 디스크 설정에 따라 우측에 마운트 포인트가 보이게 됨) 앱을 응용 프로그램 폴더로 드래그하여 설치합니다. 설치 후 삭제해도 무방합니다
바탕화면 우측에 나타나는 마운트 포인트들은 파일 > 추출로 마운트를 해제 할 수도 있습니다.
Mac 을 처음 사용하다보니 윈도우와 다르게 뭔가 적응이 안되서 정리해 놓습니다.
ComfyUI 는 많은 모델과 체크포인트 데이터를 추가로 다운로드 하게 됩니다. 그런데 대부분의 Mac 사용자는 iCloud sync를 사용하고 있습니다.
그리고 ComfyUI 가 기본으로 문서(Documents)폴더 아래에 설치하고 있습니다. 그렇게 되면 클라우드 용량이 꽉차는 현상이 벌어집니다. 따라서 사용자 아래 iCloud와 sync 하지 않는 폴더를 만들고 해당 폴더 아래에 설치하기 바랍니다.
참고 work 폴더를 만들고 설치하는 과정
잘못 설치하였다면 삭제해야하는데
다음과 같은 과정으로 삭제를 하면 됩니다.
응용 프로그램(Applications) 폴더에서 ComfyUI (또는 ComfyUI 앱)를 찾아 휴지통으로 이동합니다.Shift + Command + G를 누르고 아래 경로들을 찾아 삭제합니다:~/Library/Application Support/ComfyUI/~/Library/Preferences/com.comfyui.plist (존재하는 경우)~/Library/Caches/com.comfyui/ (존재하는 경우)Documents/ComfyUI) 자체를 삭제합니다.{"input":"오늘 날씨가 정말 좋다. 하늘이 맑아서 기분이 상쾌하다. 오랜만에 산책을 나갔다."}
{"input":"비가 하루 종일 내렸다. 우산을 챙기지 않아서 옷이 다 젖었다. 날씨가 우울하다."}
{"input":"기온이 갑자기 떨어졌다. 바람도 많이 불어서 체감 온도가 낮다."}
{"input":"점심으로 김치찌개를 먹었다. 국물이 진하고 고기가 부드러웠다. 다음에는 또 오고 싶다."}
{"input":"저녁에 친구들과 치킨을 시켜 먹었다. 양이 많고 바삭해서 만족스러웠다."}
{"input":"이탈리안 레스토랑에 갔다. 파스타와 피자가 정말 맛있었다. 분위기도 좋았다."}
{"input":"파이썬으로 머신러닝을 공부하고 있다. 데이터 전처리가 가장 어렵다. 그래도 재미있다."}
{"input":"딥러닝 모델의 성능을 개선했다. 하이퍼파라미터 튜닝이 효과적이었다."}
{"input":"자연어 처리를 위해 Sentence-BERT를 사용하고 있다. 임베딩 성능이 매우 좋다."}
{"input":"주식 시장이 크게 하락했다. 투자 심리가 위축되고 있다. 당분간 변동성이 클 것 같다."}
{"input":"비트코인 가격이 다시 상승했다. 가상자산 시장에 관심이 몰리고 있다."}
{"input":"환율 변동이 심해지고 있다. 수입 기업들의 부담이 커지고 있다."}
{"input":"The weather is really nice today. The sky is clear and blue. I decided to take a walk."}
{"input":"It rained all day. I forgot my umbrella and got completely soaked."}
{"input":"The temperature dropped suddenly. It feels much colder than yesterday."}
{"input":"I had pasta for lunch. The sauce was rich and delicious. I would love to visit again."}
{"input":"We ordered fried chicken for dinner. It was crispy and well seasoned."}
{"input":"The restaurant had a great atmosphere. The food was amazing and fresh."}
{"input":"I am studying machine learning with Python. Data preprocessing is harder than expected."}
{"input":"The deep learning model achieved better accuracy. Hyperparameter tuning really helped."}
{"input":"Sentence embeddings are useful for text clustering. SBERT works very well."}
{"input":"The stock market dropped significantly today. Investors are getting nervous."}
{"input":"Bitcoin prices are rising again. The crypto market is becoming volatile."}
{"input":"Exchange rates are fluctuating rapidly. Global markets are reacting."}
{"input":"오늘은 회의가 많았다. 프로젝트 일정에 대해 논의했다. 생각보다 시간이 오래 걸렸다."}
{"input":"팀원들과 협업이 잘 되고 있다. 커뮤니케이션이 프로젝트 성공의 핵심이다."}
{"input":"I had a meeting all morning. We discussed the project timeline in detail."}
{"input":"Team collaboration is going well. Clear communication makes everything easier."}
{"input":"파이썬으로 데이터 분석을 진행했다. 판다스와 넘파이를 활용했다. 결과가 만족스럽다."}
{"input":"I analyzed the dataset using pandas and numpy. The results were quite interesting."}
# python -m pip install kss spacy langdetect sentence-transformers umap-learn hdbscan
# python -m spacy download en_core_web_sm
import json
import numpy as np
from langdetect import detect, DetectorFactory
from kss import split_sentences as split_ko
import spacy
from sentence_transformers import SentenceTransformer
import umap
import hdbscan
# 2 자잘한 클러스터 폭증
# 5 적당 (추천 시작점)
# 10 큰 주제만 남음
min_cluster_size = 5
min_samples = min_cluster_size // 2
# -----------------------------------
# 0. 초기 설정
# -----------------------------------
DetectorFactory.seed = 42 # langdetect 재현성
nlp_en = spacy.load("en_core_web_sm")
model = SentenceTransformer(
"paraphrase-multilingual-mpnet-base-v2"
)
# -----------------------------------
# 1. 언어별 문장 분리 함수
# -----------------------------------
def split_english(text: str):
doc = nlp_en(text)
return [sent.text.strip() for sent in doc.sents if sent.text.strip()]
def split_korean(text: str):
try:
# mecab이 있으면 사용
return split_ko(text, backend="mecab", strip=True)
except ImportError:
# 없으면 기본 backend로 fallback
return split_ko(text, strip=True)
def split_sentences_auto(text: str):
"""
언어 감지 후 자동 분기
"""
try:
lang = detect(text)
except Exception:
return [text]
if lang == "ko":
sents = split_korean(text)
elif lang == "en":
sents = split_english(text)
else:
# 기타 언어 or 짧은 텍스트
sents = [text]
return sents if sents else [text]
# -----------------------------------
# 2. JSONL 로드 + 문장 분리
# -----------------------------------
documents = [] # 문장 리스트
raw_texts = [] # 원문
with open("input.jsonl", "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
# ✅ 빈 줄 무시
if not line:
continue
obj = json.loads(line)
text = obj["input"].strip()
raw_texts.append(text)
sentences = split_sentences_auto(text)
documents.append(sentences)
# -----------------------------------
# 3. Sentence-BERT 문장 임베딩
# -----------------------------------
doc_embeddings = []
for sentences in documents:
sent_embeddings = model.encode(
sentences,
convert_to_numpy=True,
normalize_embeddings=True
)
# ✅ 문단 임베딩 = 문장 평균
doc_embedding = sent_embeddings.mean(axis=0)
doc_embeddings.append(doc_embedding)
doc_embeddings = np.vstack(doc_embeddings)
# -----------------------------------
# 4. UMAP 차원 축소
# -----------------------------------
umap_embeddings = umap.UMAP(
n_neighbors=15,
n_components=5,
metric="cosine",
random_state=42
).fit_transform(doc_embeddings)
# -----------------------------------
# 5. HDBSCAN 클러스터링
# -----------------------------------
clusterer = hdbscan.HDBSCAN(
min_cluster_size=min_cluster_size,
min_samples=min_samples,
metric="euclidean"
)
labels = clusterer.fit_predict(umap_embeddings)
# -----------------------------------
# 6. 결과 출력
# -----------------------------------
for i, label in enumerate(labels):
print(f"[클러스터 {label}] {raw_texts[i]}")
from collections import defaultdict
# 클러스터별로 묶기
clustered = defaultdict(list)
for text, label in zip(raw_texts, labels):
clustered[label].append(text)
# 결과 출력
for label in sorted(clustered.keys()):
if label == -1:
print("\n[Noise / Outlier]")
else:
print(f"\n[클러스터 {label}] ({len(clustered[label])}개)")
for t in clustered[label]:
print(f"- {t}")
# -----------------------------------
# 7. 결과 JSONL 저장
# -----------------------------------
with open("result.jsonl", "w", encoding="utf-8") as f:
for i, label in enumerate(labels):
out = {
"input": raw_texts[i],
"cluster_id": int(label)
}
f.write(json.dumps(out, ensure_ascii=False) + "\n")
[클러스터 0] 오늘 날씨가 정말 좋다. 하늘이 맑아서 기분이 상쾌하다. 오랜만에 산책을 나갔다.
[클러스터 1] 비가 하루 종일 내렸다. 우산을 챙기지 않아서 옷이 다 젖었다. 날씨가 우울하다.
[클러스터 1] 기온이 갑자기 떨어졌다. 바람도 많이 불어서 체감 온도가 낮다.
[클러스터 0] 점심으로 김치찌개를 먹었다. 국물이 진하고 고기가 부드러웠다. 다음에는 또 오고 싶다.
[클러스터 0] 저녁에 친구들과 치킨을 시켜 먹었다. 양이 많고 바삭해서 만족스러웠다.
[클러스터 0] 이탈리안 레스토랑에 갔다. 파스타와 피자가 정말 맛있었다. 분위기도 좋았다.
[클러스터 1] 파이썬으로 머신러닝을 공부하고 있다. 데이터 전처리가 가장 어렵다. 그래도 재미있다.
[클러스터 1] 딥러닝 모델의 성능을 개선했다. 하이퍼파라미터 튜닝이 효과적이었다.
[클러스터 1] 자연어 처리를 위해 Sentence-BERT를 사용하고 있다. 임베딩 성능이 매우 좋다.
[클러스터 1] 주식 시장이 크게 하락했다. 투자 심리가 위축되고 있다. 당분간 변동성이 클 것 같다.
[클러스터 1] 비트코인 가격이 다시 상승했다. 가상자산 시장에 관심이 몰리고 있다.
[클러스터 1] 환율 변동이 심해지고 있다. 수입 기업들의 부담이 커지고 있다.
[클러스터 0] The weather is really nice today. The sky is clear and blue. I decided to take a walk.
[클러스터 1] It rained all day. I forgot my umbrella and got completely soaked.
[클러스터 1] The temperature dropped suddenly. It feels much colder than yesterday.
[클러스터 0] I had pasta for lunch. The sauce was rich and delicious. I would love to visit again.
[클러스터 0] We ordered fried chicken for dinner. It was crispy and well seasoned.
[클러스터 0] The restaurant had a great atmosphere. The food was amazing and fresh.
[클러스터 1] I am studying machine learning with Python. Data preprocessing is harder than expected.
[클러스터 1] The deep learning model achieved better accuracy. Hyperparameter tuning really helped.
[클러스터 1] Sentence embeddings are useful for text clustering. SBERT works very well.
[클러스터 1] The stock market dropped significantly today. Investors are getting nervous.
[클러스터 1] Bitcoin prices are rising again. The crypto market is becoming volatile.
[클러스터 1] Exchange rates are fluctuating rapidly. Global markets are reacting.
[클러스터 1] 오늘은 회의가 많았다. 프로젝트 일정에 대해 논의했다. 생각보다 시간이 오래 걸렸다.
[클러스터 1] 팀원들과 협업이 잘 되고 있다. 커뮤니케이션이 프로젝트 성공의 핵심이다.
[클러스터 -1] I had a meeting all morning. We discussed the project timeline in detail.
[클러스터 1] Team collaboration is going well. Clear communication makes everything easier.
[클러스터 1] 파이썬으로 데이터 분석을 진행했다. 판다스와 넘파이를 활용했다. 결과가 만족스럽다.
[클러스터 1] I analyzed the dataset using pandas and numpy. The results were quite interesting.
[Noise / Outlier]
- I had a meeting all morning. We discussed the project timeline in detail.
[클러스터 0] (8개)
- 오늘 날씨가 정말 좋다. 하늘이 맑아서 기분이 상쾌하다. 오랜만에 산책을 나갔다.
- 점심으로 김치찌개를 먹었다. 국물이 진하고 고기가 부드러웠다. 다음에는 또 오고 싶다.
- 저녁에 친구들과 치킨을 시켜 먹었다. 양이 많고 바삭해서 만족스러웠다.
- 이탈리안 레스토랑에 갔다. 파스타와 피자가 정말 맛있었다. 분위기도 좋았다.
- The weather is really nice today. The sky is clear and blue. I decided to take a walk.
- I had pasta for lunch. The sauce was rich and delicious. I would love to visit again.
- We ordered fried chicken for dinner. It was crispy and well seasoned.
- The restaurant had a great atmosphere. The food was amazing and fresh.
[클러스터 1] (21개)
- 비가 하루 종일 내렸다. 우산을 챙기지 않아서 옷이 다 젖었다. 날씨가 우울하다.
- 기온이 갑자기 떨어졌다. 바람도 많이 불어서 체감 온도가 낮다.
- 파이썬으로 머신러닝을 공부하고 있다. 데이터 전처리가 가장 어렵다. 그래도 재미있다.
- 딥러닝 모델의 성능을 개선했다. 하이퍼파라미터 튜닝이 효과적이었다.
- 자연어 처리를 위해 Sentence-BERT를 사용하고 있다. 임베딩 성능이 매우 좋다.
- 주식 시장이 크게 하락했다. 투자 심리가 위축되고 있다. 당분간 변동성이 클 것 같다.
- 비트코인 가격이 다시 상승했다. 가상자산 시장에 관심이 몰리고 있다.
- 환율 변동이 심해지고 있다. 수입 기업들의 부담이 커지고 있다.
- It rained all day. I forgot my umbrella and got completely soaked.
- The temperature dropped suddenly. It feels much colder than yesterday.
- I am studying machine learning with Python. Data preprocessing is harder than expected.
- The deep learning model achieved better accuracy. Hyperparameter tuning really helped.
- Sentence embeddings are useful for text clustering. SBERT works very well.
- The stock market dropped significantly today. Investors are getting nervous.
- Bitcoin prices are rising again. The crypto market is becoming volatile.
- Exchange rates are fluctuating rapidly. Global markets are reacting.
- 오늘은 회의가 많았다. 프로젝트 일정에 대해 논의했다. 생각보다 시간이 오래 걸렸다.
- 팀원들과 협업이 잘 되고 있다. 커뮤니케이션이 프로젝트 성공의 핵심이다.
- Team collaboration is going well. Clear communication makes everything easier.
- 파이썬으로 데이터 분석을 진행했다. 판다스와 넘파이를 활용했다. 결과가 만족스럽다.
- I analyzed the dataset using pandas and numpy. The results were quite interesting.
Android Storage Access Framework(SAF)
안드로이드 앱을 만들다 보면 “사용자가 파일을 직접 선택해서 열거나 저장하게 하고 싶다” 는 순간이 꼭 찾아옵니다. 예전에는 단순히 파일 경로를 받아 File API로 접근하면 됐지만, 보안이나 호환성 문제 때문에 이제는 그렇게 단순하지 않습니다. 실제 해보면 권한 없다고 오류가 발생합니다.
막상 문서 찾고 하다보면 생각보다 잘안됩니다.
이때 등장하는 게 Storage Access Framework(SAF) 입니다.
SAF는 Android 4.4 (KitKat)부터 도입된 파일 접근 방식으로,
앱이 사용자가 직접 선택한 파일이나 폴더에만 접근할 수 있도록 도와주는 프레임워크입니다.
즉, 개발자가 마음대로 기기 저장소를 뒤지지 못하고, 사용자가 시스템이 제공하는 파일 선택 화면에서 골라준 파일에만 접근할 수 있습니다.
Unity에서 SAF를 사용하면 안드로이드 파일 선택창이 뜨게 됩니다. 여기에서 사용자가 골라주는 파일에 대해서 Read/Write가 가능해집니다.
현재 Android 전체적으로 설명할것이 아니기 때문에 Unity에서 사용하는 방법만 설명을 드리겠습니다.
일단 GPT를 이용해서 SAF로 만들어 달라면 잘 만들어 줍니다. 그런데 코틀린 소스 파일도 만들어야 하고 폴더 구정에 넣어서 그래들 빌드까지 해야하는데 실제 빈 프로젝트에서는 잘 동작될지 몰라도 기존에 이미 Plugins에 Android를 사용중인 경우 뭔가 잘 되지 않습니다.
Asset Store 에서 유용한 Free Asset 을 찾았습니다.
https://assetstore.unity.com/packages/tools/integration/native-file-picker-for-android-ios-173238
예제는 github 보시면 이해가 될것 입니다.
https://github.com/yasirkula/UnityNativeFilePicker#example-code
github 소스를 보면 이미 빌드가된 aar 형태로 들어있습니다. 따로 안드로이드 빌드는 안해도 되는데 NativeFilePicker.aar의 소스는 공개가 안되어 있습니다.
구조는 간단한데 예제가 거의 없어서 사용하는데 시간이 좀 걸렸습니다.
제가 사용한 예제 코드를 공유합니다. 예제에서는 샘플이므로 동작하지는 않습니다.
아래 코드는 SaveDataStruct 데이터를 JSON으로 직렬화한 뒤, 임시 저장소(temporaryCachePath)에 기록하고, 이후 SAF 기반으로 사용자가 선택한 경로로 내보냅니다.
// 저장 코드
public void SaveGameData(SaveDataSturct data, string fileName)
{
// JSON 직렬화
string json = JsonConvert.SerializeObject(data, Formatting.Indented);
string combinedData = $"{json}";
try
{
#if UNITY_ANDROID && !UNITY_EDITOR
// 임시 저장 경로
string downloadPath = Application.temporaryCachePath;
string fullPath = Path.Combine(downloadPath, fileName);
// 파일 저장
File.WriteAllText(fullPath, combinedData);
Debug.Log($"Data saved to: {fullPath}");
// SAF Export
bool permission = NativeFilePicker.CheckPermission();
if (permission == true) {
NativeFilePicker.ExportFile(fullPath, OnFileExported);
}
else {
NativeFilePicker.RequestPermissionAsync((result) =>
{
if (result == NativeFilePicker.Permission.Granted) {
NativeFilePicker.ExportFile(fullPath, OnFileExported);
} else {
Debug.LogError("사용자가 권한을 거부했습니다.");
}
});
}
#endif
}
catch (Exception ex)
{
Debug.LogError($"Failed to save data: {ex.Message}");
}
}
// ExportFile 콜백
private void OnFileExported(bool success)
{
if (success)
{
Debug.Log("File exported successfully!");
}
else
{
Debug.Log("File export failed or cancelled.");
}
}
아래 코드는 SAF 파일 선택기를 호출해 사용자가 직접 파일을 선택하고, 선택한 파일을 불러옵니다.
// 파일 로드
public void LocalLoad()
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (NativeFilePicker.IsFilePickerBusy())
return;
bool permission = NativeFilePicker.CheckPermission();
if (permission == true) {
OpenFilePicker();
}
else {
NativeFilePicker.RequestPermissionAsync((result) =>
{
if (result == NativeFilePicker.Permission.Granted) {
OpenFilePicker();
} else {
Debug.LogError("사용자가 권한을 거부했습니다.");
}
});
}
#endif
}
private void OpenFilePicker()
{
NativeFilePicker.PickFile((path) =>
{
if (path == null)
{
Debug.Log("Operation cancelled");
}
else {
Debug.Log("Picked file: " + path);
LocalLoadReal(path);
}
}, new string[] { "text/plain" }); // 허용할 파일 MIME 타입 지정
}
private void LocalLoadReal(string fullPath)
{
if (!File.Exists(fullPath))
{
Debug.LogWarning("Save file not found!");
return;
}
try
{
// 파일 읽기 샘플
string[] lines = File.ReadAllLines(fullPath);
Debug.Log($"Data loaded from: {fullPath}");
// TODO: lines를 역직렬화해서 SaveDataStruct로 변환
}
catch (Exception ex)
{
Debug.LogError($"Failed to load data: {ex.Message}");
return;
}
}
얘네(구글)들은 뭔가 변경 사항을 미리미리 예측못하는가? 갑자기 저런 공지를 날려서 3개월만에 해결하라고 ...
앱단이 아니라 OS 단에서 패딩을 넣어주면 되는것 아닌가 싶기도 한데... 출시한지 오래된 앱의 경우, 갑작스런 대응이 쉽지는 않습니다.
아래 이상의 버전을 사용해서 빌드만 하면 되는데 문제는 버전업하면 어떤 일이 일어 날지 모르니... API가 조금 바뀌는 경우도 있고.... 적절한 버전을 업데이트 해서 해결하면됩니다.
저의 경우 2022.3.10f1 사용중이라서 에디터 버전 2022.3.62f1 으로 업데이트 하였습니다.
다행이 오류는 없었고, target API Level을 최신으로 올려서 빌드하였습니다.
target API level은 Player setting Other 쪽에 있습니다.
2개의 앱을 작업했는데 하나의 앱에서 여전히 에러가 사라지지 않는 경우가 있어서 추가로 확인을 하였습니다.
아래 라이브러리들이 여전히 안되는 경우가 있음
Play Console 에 번들 패키지를 올리면 지원 유무를 알 수 있습니다.
찾아보니 해당 라이브러리는 "Unity Adaptive Performance" 사용함으로서 발생하는 포함되는 lib 인데
https://developer.android.com/games/engines/unity/unity-adpf?hl=ko
Unity Adaptive Performance는 제공자가 기기에서 필요한 모든 정보를 가져와야 합니다. Android 제공업체는 Adaptive Performance 5.0 이상에서 지원되며 Unity 2021.3 이상을 지원합니다. Unity 2021 및 2022 버전 패키지 관리자는 Adaptive Performance 4.0을 다운로드하므로 버전 5.0으로 수동 업데이트해야 합니다.
5.0으로 업데이트 하라는 문구는 보이는데 해결 될지 몰라서 성능 관련 내용이라 삭제하기로 마음 먹고 삭제 했습니다.
requests 사용시 아무 생각 없이 사용하곤 했었습니다. 그런데 어느 순간 thread가 강제 종료 되는 현상이 발생하였습니다. 구체적인 사유는 없는데 큰파일 다운로드시 발생하는 증상이 었습니다. 제가 사용할때는 ubuntu에서 3G 크기의 파일이었습니다.
메모리 부족 같아서 검색해보니 stream을 사용해야 한다고 합니다.
GPT를 이용해서 가이드를 받아서 코드를 수정했지만 사유없이 종료되는 경우 메모리 부족을 의심하시기 바랍니다.
import requests
url = 'https://example.com/largefile.zip' # 다운로드할 파일의 URL
file_name = 'largefile.zip' # 저장할 파일 이름
# 청크 단위로 다운로드
with requests.get(url, stream=True) as response:
response.raise_for_status() # 요청이 성공했는지 확인
with open(file_name, 'wb') as file:
for chunk in response.iter_content(chunk_size=8192): # 8KB 단위로 읽기
file.write(chunk)
print(f"{file_name} 다운로드 완료.")
RX 7700 XT GPU를 가지고 windows에서 stable diffusion을 동작시키기 위한 시행 착오에 대해서 정리해보았습니다.
누군가는 동일한 시행 착오를 격지 않길 바라는 마음에 정리를 해보았습니다.
따라하지 마시고 끝까지 다읽어 보시는걸 추천 드립니다.
NVIDIA의 막강한 무기가 CUDA인걸 모르는지 시간이 많이 지났음에도 AMD의 개발 환경은 여전히 쉽지 않았습니다.
요즘 딥러닝하면 pytorch를 많이 사용합니다. 그래서 pytorch site에서 설치하는 방법을 살펴 보았습니다.
여기에서부터 고행은 시작되었습니다.
Linux 에서는 설치가 가능했기 때문에 WSL을 이용해서 설치를 시도하였습니다.
**WSL(Windows Subsystem for Linux)**은 Windows에서 직접 Linux 환경을 실행할 수 있도록 하는 기능입니다.
즉, 가상 머신(VM) 없이 Windows에서 Linux 명령어, 도구, 애플리케이션을 사용할 수 있도록 지원하는 Microsoft의 서브시스템입니다.
아래를 참고해서 6.1.3 버전을 설치하였습니다.
https://www.reddit.com/r/ROCm/comments/1ep4cru/rocm_613_complete_install_instructions_from_wsl/
문제는 여전히 CUDA를 인식하지 못하는 이슈가 있었습니다.
다시 아래 AMD의 WSL 가이드를 이용하여 ROCm 6.2.3 버전 설치를 시도 하였습니다.
https://rocm.docs.amd.com/projects/radeon/en/latest/docs/install/wsl/install-radeon.html
여전히 unsupported GPU라고 뜹니다.
여기저기 찾아보니 내장 그래픽 카드를 off 하라고 해서 BIOS에서 Off 설정을 해보았지만 여전히 동일하였습니다.
여기에서 자세한 설명은 안하였지만 wsl 내에서 docker 이미지를 이용해서도 설치해보았습니다. 여전히 인식하지 못하였습니다.
중요한 문서가 있는데... 지원되는 그래픽 카드가 정해져 있다는 것입니다.
https://rocm.docs.amd.com/projects/radeon/en/latest/docs/compatibility/wsl/wsl_compatibility.html
이쯤와서는 거의 다 포기하였습니다.
stable diffusion 은 directml(윈도우의 DirectX12 API) 이란것을 이용해서 동작시키는 방법이 있었습니다. 또 다른 방법은 ZLUDA를 이용하는 방법인데 AMD GPU를 이용해서 CUDA 흉내를 내는 방식입니다.
그래서 아래 코드를 참고해서 git 을 받고
https://github.com/lshqqytiger/stable-diffusion-webui-amdgpu
아래와 같이 실행하였습니다. 물론 그전에 python 3.10.6 버전을 꼭 설치해야합니다.
webui-user.bat --use-zluda
Most of AMDGPUs are compatible.
Start WebUI with --use-zluda.
정리해 보면 아래와 같습니다.
git clone https://github.com/lshqqytiger/stable-diffusion-webui-amdgpu.git.webui-user.bat from Windows Explorer as normal, non-administrator, user.4번 실행시 webui-user.bat --use-zluda 라고 실행 시키면 됩니다.
동작하다가 numpy 관련 오류가 발생하는데 아래 가이드 보고 pip install numpy==1.23.5 로 새로 설치하였습니다.
https://myview7144.tistory.com/96
최초 동작시 NVIDIA 사용할때보다 굉장히 느립니다.
동작은 되는데 이미지 크기를 키우면 굉장히 느려집니다.
Unity6가 되면서 기본적으로 new input system을 기본으로 포함해서 따로 추가 설치가 필요 없게 되었습니다.
android로 개발하다 보니 pinch zoom이 필요하게 되어서 여기저기 검색도 해봤는데 멀티 터치가 생각보다 디버깅이 힘들었습니다.
제가 작업한 코드를 공개합니다. 디버깅 코드를 풀어서 디버깅 해가면서 적절하게 값을 조절 해서 사용해야 합니다.
카메라의 아래값을 변경하는 코드인데 이 환경은 프로젝트 마다 다를 수 있으므로 해당 부분을 참고하는것보다 저기에 넘기는 값을 보시기 바랍니다.
아래는 전체 코드입니다. 다음 feature 부분을 참고 하세요. USE_NEW_INPUT