안녕하세요. 강의에서 나오는 BitsAndBytesConfig 를 통한 양자화 예시에서 CUDA 가 필수로 요구되어 macbook에서 진행할 수 있는 방안을 찾다가 mlx_lm 을 통해서 MPS(mac의 gpu)를 활용하여 양자화가 가능하단 사실을 알게되어 공유드리고자 합니다. 아마 맥북 사용자도 꽤 많을 것으로 예상됩니다. langchain에서 MLXPipeline 을 제공하지만 이를 사용했을 때 현재 invoke시 호출되는 _call 메서드 내부에서 generate_step 이 mlx_lm에서 제공은 하지만 MLXPipeline 에서 제대로 불러올 수 없어 RunnableLambda 를 통해서 에러를 우회해봤습니다.(Q? 강사님은 혹시 해결 방법을 알고 계실까요? 공홈 코드가 다 안 되네요 ㅜㅜ 오류 코드는 맨 아래 첨부하겠습니다. ) 먼저 양자화 진행하는 방식입니다. cli를 통한 command 또는 python-api 를 활용하는 방법 두 가지가 있습니다. 자세한건 링크 첨부하겠습니다. 양자화 개념에 대해서 자세히 나오니 참고하면 좋으실 듯 합니다. 링크: [quantization with xlm_lm]( https://developer.apple.com/kr/videos/play/wwdc2025/298/?time=187 ) mlx_lm을 통한 양자화 먼저 양자화한 model을 local path에 저장합니다. 그 전에 apple의 gpu를 확인할 수 있는 코드 부분은 처음 부분에서 확인하실 수 있습니다. 사실 python코드를 싸는 것보다 command로 양자화 진행하는게 편한 것 같습니다. 전 projection layer와 embedding layer는 다른 layer보다 높은 bit로 해주는게 좋다고 하여 python으로 진행했습니다. dequantize on-the-fly(게산 추론) 시 더 좋다고 합니다. # mac에서 mps를 사용한 예제 import torch from mlx_lm.convert import convert print("MPS available on this device =>", torch.backends.mps.is_available()) # projection layer & embedding layer는 6bit, 양자화 가능한 layer는 4bit, 양자화 불가능은 False return def mixed_quantization(layer_path, layer): if "lm_head" in layer_path or 'embed_tokens' in layer_path: return {"bits": 6, "group_size": 64} elif hasattr(layer, "to_quantized"): return {"bits": 4, "group_size": 64} else: return False # quantization 진행 convert( hf_path="microsoft/Phi-3-mini-4k-instruct", mlx_path="./models/microsoft-Phi-3-mini-4k-instruct-mixed-4-6-bit", dtype="float16", quantize=True, q_bits=4, q_group_size=64, quant_predicate=mixed_quantization ) $) mlx_lm.convert --hf-path "mistralai/Mistral-7B-Instruct-v0.3" \ --mlx-path "./mistral-7b-v0.3-4bit" \ --dtype float16 \ --quantize --q-bits 4 --q-group-size 64 --upload-repo "my-name/mistral-7b-v0.3-4bit" Langchain과 연계하기 from functools import wraps from langchain_core.runnables import RunnableLambda from langchain_core.output_parsers import StrOutputParser from mlx_lm import generate, load quantized_model_path = "./models/microsoft-Phi-3-mini-4k-instruct-mixed-4-6-bit" model, tokenizer = load(quantized_model_path) def runnable_wrapper(func): """RunnableLambda wrapper function""" @wraps(func) def wrapper(*args, **kwargs): return RunnableLambda(func) return wrapper @runnable_wrapper def create_chat_prompt(question): messages = [ { "role": "system", "content": """ You are an expert in information retrieval and summarization. Your job is to read the provided text and produce a precise, faithful, and concise summary. Prioritize the author’s main claim, key evidence, and conclusions. Use plain English and avoid filler. Do not invent facts that aren’t present in the input. """ }, { "role": "user", "content": f""" Question: {question} """ } ] prompt_without_tokenized = tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False) prompt_with_tokenized = tokenizer.apply_chat_template(messages, add_generation_prompt=True) print("생성된 prompt👇\n", prompt_without_tokenized) return prompt_with_tokenized @runnable_wrapper def run_llm_with_mlx(prompt): return generate(model=model, tokenizer=tokenizer, prompt=prompt) @runnable_wrapper def output_parser(answer): return answer.replace("<|end|>", "") chain = create_chat_prompt() | run_llm_with_mlx() | output_parser() 오류 코드 llm.invoke 에서 에러가 발생하며 TypeError: generate_step() got an unexpected keyword argument 'formatter' 라는 에러가 발생합니다. from langchain_community.llms.mlx_pipeline import MLXPipeline from mlx_lm import load model_path = "./models/microsoft-Phi-3-mini-4k-instruct-mixed-4-6-bit" model, tokenizer = load(model_path) llm = MLXPipeline( model=model, tokenizer=tokenizer ) llm.invoke("what's my name?")
[VOD] 6주 완성! 개발 실무를 위한 고농축 바이브코딩 (Cursor AI, Figma)
안녕하세요~ 백앤드 소스 코드 요청 드립니다. [ 부트캠프에서 만든 고농축 백엔드 코스] 메일로도 요청드리고, 코드캠프 백앤드 게시판에도 요청드렸는데, 답변이 안달려서 여기 한번더 남깁니다. 부분적으로 필요한 부분만 수강하고 싶은데, 앞부분을 수강하지 않으면 수강하기 곤란한 부분이 있어서 소스코드좀 보내주시면 감사하겠습니다~ sunshinew@naver.com
21:09 지금 까지 이해한 포인터의 방법은 주소 사용할때는 & 또는 생략, 값을 사용할때는 *로 이해하고 있습니다. 해당 printf("%s\n", arr[0][0]); 라는 구문에 질문이 있습니다. 포인터 변수로 해당 문자열의 주소를 각 맵핑하였고 배열에 맞게 출력하는걸로 해석이 되는데 이때 왜 값을 안 가져오고 주소를 가져오는지 궁금합니다. 또한 %s로 출력하고 해서 주소대신에 값으로 가져오는지 궁금합니다.
유형 9번에서 처음에 Child obj = new Child(); 의 뜻이 Child 타입의 새로운 생성자를 생성하는 것이고, 이 생성자의 자식 class로 갔는데, 생성자가 없고, 부모에도 생성자가 없어서 출력되는 값은 없는 것이고, 그 뒤의 obj.display()코드를 실행해 display의 메서드에서 부모로부터 상속받아 Parent display, Child display가 답이 되는것이 맞을까요?
[Live 챌린지] 6주 완성! 개발 실무를 위한 고농축 바이브코딩 (Cursor AI, Figma)
공통 컴포넌트 부분의 프롬프트를 실행하던 중에 궁금한 점이 있어요. 아래와 같이 실행을 했는데, 1) input 버튼을 만들기 위해 파일 실행 - commons/components/input/prompts/prompt.101.ui.txt 2) 아래와 같은 답변이 나옴 (Claude-4.5-sonnet thinking model 사용): 🤔 룰 간 충돌 분석 prompt.101.ui.txt: variant 시스템 구현 요구 03-ui.mdc: 피그마 디자인 그대로만 구현하라고 요구 피그마 실제: 단일 Input만 존재 그리고 저 또한, AI가 돌린 코드를 분석하고 룰 재검토 및 실행을 몇 번 반복하는 과정에서 실질적으로 문제가 있을 수 있다고 보였어요. 1) Case 1 처음에 Button 컴포넌트를 위해서 프롬프트를 실행했을 때는 prompt.101.ui.txt 의 " 다음 조건을 모두 만족하는 완전한 variant 시스템을 구현할 것 ." 이 조건을 만족하기 위해서 노드ID 제공했는데도 불구하고, 계속해서 피그마의 모든 button을 다 찾아서 사이즈를 가져오는 것을 볼 수 있었습니다. 2) Case 2 그 다음에 Input 컴포넌트를 위해서 프롬프트를 실행했을 때는 03-ui.mdc 의 " 피그마 링크가 제공되면, 모든 사이즈는 제공된 피그마와 동일하게 처리할 것 " 이라는 룰을 검토하는 과정에서 문제가 있었습니다. 이 조건 때문에 반응형 웹은 고려하지 못하고 width를 진짜 있는 그대로 갖고 와서 상수로 넣어버리고, 유연성이 전혀 없게 만들었습니다. 몇 번 룰을 재검토하라고 시키고 원하는 코드와 비슷하게 만들긴 했지만, 혹시 이런 경우에 대한 해결 방법이 있을까요?