안녕하세요, Unity UI Button onClick 이벤트 설정 위치에 대한 고민이 있어서 질문 글을 남깁니다. Button의 onClick 이벤트에 호출할 함수를 등록하는 방법에는 아래와 같이 두 가지 방법이 있다고 알고 있습니다. 1. 인스펙터 창에서 Button 게임오브젝트의 onClick 이벤트에 호출할 함수를 등록 코드 상에서 등록 Button sampleBtn; void Start() { sampleBtn.onClick.AddListener( () => { Debug.Log("Hello World"); }); } 첫 번째 방법으로 구현을 하면 프로젝트를 처음 열어본 사람의 입장에서 보았을 때 특정 버튼을 누른 경우 어떤 동작이 이어질지 전체적인 흐름을 파악하기 쉽다는 장점이 있습니다. 그리고 연결된 함수를 타고 가서 관련 스크립트를 열어볼 수도 있고요. 하지만 매번 인스펙터 창에서 하나씩 넣어주어야 해서 귀찮(?)을 수 있다는 단점이 있습니다. 두 번째 방법으로 구현을 하면 게임오브젝트를 하나 하나 눌러가면서 인스펙터 창에서 onClick 이벤트에 등록된 함수를 확인할 필요 없이, 코드만 보면 되기 때문에 편할 수도 있다는 장점이 있습니다. 하지만 처음 프로젝트를 열어본 사람은 어디에 뭐가 있는지 어떻게 연결되어있는지 초반에 조금 헤멜 수 있다는 단점이 있습니다. (뭔가 컨벤션이 정해져 있지 않고 아무런 정보 없이 프로젝트를 처음 열어본 사람) 둘 중 어느 방법을 추천하시는지 궁금해서 질문 남깁니다!!!
안녕하세요. x:Name 을 통해 코드 상에서 콘트롤(이 맞나요?)에 접근하는 원리에 대해서는 이해했습니다. 프로퍼티를 하나씩 살펴보는 중인데, x:Uid 의 쓰임에 대해 궁금합니다. 프로퍼티의 이름만 봤을 땐 고유 식별자로서 역할을 할 것 같은데요... 혹시 코드 상에서도 Uid 를 통해 콘트롤에 접근할 수 있을까요? '지역화'에 사용한다는 설명은 확인했는데, 지역화가 무엇인지, 실제로 어떻게 사용하는지에 대한 예제를 알고 싶습니다. WPF 관련 한국어 강의가 부족했는데, 강의를 만들어주셔서 감사합니다. :)
[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)
수업시간에 구글 프로토콜 버퍼를 이용하여 프로토콜 패킷을 생성하는데, 클라이언트와 서버단에서 PacketHandler에는 함수를 직접 정의해서 생성해야합니다. 이 과정이 꽤 번거롭고 이름도 정확하게 맞춰야합니다. 그래서 자동 툴을 이용하여 작성해야 할 코드를 자동으로 정확하게 생성해주는 툴을 제작하여 배포합니다. 이 기능의 배포는 여기에서만 합니다. 이 기능은 UnityEditor Tools를 구현하여 이용하는 방식입니다. [여기를 클릭하여 다운로드] 스크립트를 다운로드합니다. (또는 아래 스크립트를 복사하여 작성) 유니티 에디터 Assets 폴더 안에 넣습니다. 위치는 상관 없습니다. 유니티 에디터 상단 바에서 Tools/Bonnate/Socket/Generate Protocol Code From Enum을 선택합니다. 프로토콜 버퍼 에디터에서 MsgId에 프로토콜 이름을 복사합니다. 주석을 지원합니다. /* 주석은 구분 없이 모든곳에 동일하게 생성됩니다. // 주석은 프로토콜의 주석으로 생성됩니다. 본 글에서는 아래 이미지와 같이 복사하였습니다. 복사한 값 Enum 스니펫을 Tools 윈도우 창에 붙여넣기합니다. 우측의 변환 버튼을 클릭합니다. 생성된 값을 각 스크립트에 붙여넣기합니다. 변환된 프로토콜 코드는 프로토콜버퍼 에디터 구현부에 붙여넣으세요. 서버가 보내는 프로토콜은 클라이언트단(유니티)에서 사용합니다. 클라이언트에서 보내는 프로토콜은 서버단에서 사용합니다. 전체 코드입니다. 위에서 다운로드 받은 파일과 동일합니다. /* * GenerateProtocolCodeFromEnum - Enum을 이용한 프로토콜 코드 생성을 위한 유니티 에디터 창 * 작성자: [Bonnate] https://bonnate.tistory.com/ * 라이선스: 없음 (명시적인 라이선스 없이 제공됨) * * 설명: * 이 스크립트는 Enum 스니펫에서 프로토콜 코드, 클라이언트 핸들러 코드, 서버 핸들러 코드를 생성하기 위한 유니티 에디터 창을 정의합니다. * 입력한 Enum 스니펫을 자동으로 프로토콜 코드로 변환하고, 해당하는 클라이언트와 서버 핸들러 함수를 생성합니다. * 생성된 코드는 클립보드에 복사하여 추가적인 사용이 가능합니다. * * 주의 사항: * 이 스크립트는 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] https://www.inflearn.com/roadmaps/355 * 의 기능을 이용하기 위해 작성된 스크립트입니다. * * 사용 방법: * 1. 이 스크립트를 유니티 프로젝트의 Editor 폴더에 첨부합니다. * 2. GenerateProtocolCodeFromEnum 창을 열기 위해 Tools -> Bonnate -> Socket -> Generate Protocol Code From Enum을 선택합니다. * 3. 입력 텍스트 영역에 Enum 코드 스니펫을 입력합니다. * 4. "변환" 버튼을 클릭하여 프로토콜 코드, 클라이언트 핸들러 코드, 서버 핸들러 코드를 생성합니다. * 5. 생성된 코드는 각각의 텍스트 영역에 표시됩니다. * 6. 해당 영역의 텍스트를 클립보드에 복사하려면 옆에 있는 버튼을 클릭합니다. * 7. 생성된 코드를 복사하여 각 코드에 붙여넣기하여 편리하게 프로토콜을 디자인합니다. * * 참고: 이 스크립트는 현재 상태로 제공되며 일부 제한 사항과 문제가 있을 수 있습니다. * 개인적으로 업데이트 되나, 온라인(깃허브 리포지트리 등)에 배포하지는 않을 예정입니다. */ #if UNITY_EDITOR using UnityEngine; using UnityEditor; using System.Text; using System.Text.RegularExpressions; public class GenerateProtocolCodeFromEnum : EditorWindow { private string mInputText = ""; private string mProtocolText = ""; private string mClientHandlerText = ""; private string mServerHandlerText = ""; private Vector2 mScrollPosition; [MenuItem("Tools/Bonnate/Socket/Generate Protocol Code From Enum")] public static void ShowWindow() { GetWindow<GenerateProtocolCodeFromEnum>("Generate Protocol Code From Enum"); } private void OnGUI() { mScrollPosition = EditorGUILayout.BeginScrollView(mScrollPosition, GUILayout.ExpandHeight(true)); // 입력 텍스트 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("Enum 코드 스니펫 입력"); // 변환 버튼 if (GUILayout.Button("변환", GUILayout.Width(80))) { mInputText = RemoveCommonIndentation(mInputText); GenerateProtocol(); EditorGUIUtility.systemCopyBuffer = mProtocolText; // 변환된 텍스트를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mInputText = EditorGUILayout.TextArea(mInputText, GUILayout.ExpandHeight(true)); GUILayout.Space(30); // 프로토콜 코드 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("변환된 프로토콜 코드"); // 복사 버튼 if (GUILayout.Button("복사", GUILayout.Width(80))) { EditorGUIUtility.systemCopyBuffer = mProtocolText; // 프로토콜 코드를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mProtocolText = EditorGUILayout.TextArea(mProtocolText, GUILayout.ExpandHeight(true)); GUILayout.Space(10); // 서버 핸들러 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("서버가 보내는 프로토콜 (클라이언트단에서 구현)"); // 버튼 if (GUILayout.Button("복사", GUILayout.Width(80))) { EditorGUIUtility.systemCopyBuffer = mServerHandlerText; // 서버 핸들러 코드를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mServerHandlerText = EditorGUILayout.TextArea(mServerHandlerText, GUILayout.ExpandHeight(true)); GUILayout.Space(10); // 클라이언트 핸들러 영역 EditorGUILayout.BeginHorizontal(); GUILayout.Label("클라이언트가 보내는 프로토콜 (서버단에서 구현)"); // 버튼 if (GUILayout.Button("복사", GUILayout.Width(80))) { EditorGUIUtility.systemCopyBuffer = mClientHandlerText; // 클라이언트 핸들러 코드를 클립보드에 복사 } EditorGUILayout.EndHorizontal(); mClientHandlerText = EditorGUILayout.TextArea(mClientHandlerText, GUILayout.ExpandHeight(true)); EditorGUILayout.EndScrollView(); GUILayout.Space(20); GUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Powered by: Bonnate"); if (GUILayout.Button("Github", GetHyperlinkLabelStyle())) { OpenURL("https://github.com/bonnate"); } if (GUILayout.Button("Blog", GetHyperlinkLabelStyle())) { OpenURL("https://bonnate.tistory.com/"); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); EditorGUILayout.LabelField("이 기능은 인프런 강의의 기능을 편리하게 사용하기 위해 구현되었습니다."); if (GUILayout.Button("[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈]", GetHyperlinkLabelStyle())) { OpenURL("https://www.inflearn.com/roadmaps/355"); } GUILayout.EndHorizontal(); } private GUIStyle GetHyperlinkLabelStyle() { GUIStyle style = new GUIStyle(GUI.skin.label); style.normal.textColor = new Color(0f, 0.5f, 1f); style.stretchWidth = false; style.wordWrap = false; return style; } private void OpenURL(string url) { EditorUtility.OpenWithDefaultApp(url); } private string RemoveCommonIndentation(string input) { string[] lines = input.Split('\n'); // 찾아낼 공백 패턴 Regex indentRegex = new Regex(@"^\s+"); // 최소 공통 공백 찾기 int maxIndentLength = 0; foreach (string line in lines) { if (!string.IsNullOrWhiteSpace(line)) { Match match = indentRegex.Match(line); if (match.Success) { int indentLength = match.Length; if (indentLength > maxIndentLength) maxIndentLength = indentLength; } } } // 최소 공통 공백 제거 string output = ""; foreach (string line in lines) { if (line.Trim() == "") continue; if (!string.IsNullOrWhiteSpace(line)) { string trimmedLine = line.Substring(maxIndentLength); output += trimmedLine + "\n"; } } return output; } private void GenerateProtocol() { // 입력 텍스트를 줄 단위로 분할 string[] lines = mInputText.Split('\n'); // 생성된 코드 문자열 초기화 string generatedProtocolCode = ""; string generatedClientHandlerCode = ""; string generatedServerHandlerCode = ""; bool isMultiLineComment = false; bool isClientHandlerComment = false; bool isServerHandlerComment = false; for (int i = 0; i < lines.Length; ++i) { string line = lines[i]; // 다중 줄 주석 처리 if (line.Trim().StartsWith("/*")) { isMultiLineComment = true; } if (isMultiLineComment) { generatedProtocolCode += line + "\n"; generatedClientHandlerCode += line + "\n"; generatedServerHandlerCode += line + "\n"; // 다중 줄 주석 종료 if (line.Trim().EndsWith("*/")) { isMultiLineComment = false; } continue; } if (line == "\n") { generatedProtocolCode += "\n"; generatedClientHandlerCode += "\n"; generatedServerHandlerCode += "\n"; continue; } // 주석인 경우 처리하여 유지 if (line.Trim().StartsWith("//")) { StringBuilder funcComment = new StringBuilder(); for (; i < lines.Length; ++i) { line = lines[i]; if (!line.Trim().StartsWith("//")) { funcComment.Remove(funcComment.Length - 2, 2); --i; break; } funcComment.Append($"{line}\n"); } // 클라이언트 핸들러 주석 확인 if (i + 1 < lines.Length && lines[i + 1].Trim().StartsWith("C_")) { isClientHandlerComment = true; isServerHandlerComment = false; } // 서버 핸들러 주석 확인 else if (i + 1 < lines.Length && lines[i + 1].Trim().StartsWith("S_")) { isClientHandlerComment = false; isServerHandlerComment = true; } if (isClientHandlerComment) { generatedClientHandlerCode += funcComment + "\n"; } if (isServerHandlerComment) { generatedServerHandlerCode += funcComment + "\n"; } generatedProtocolCode += funcComment + "\n"; continue; } // 빈 줄이거나 등호 (=)가 없는 줄은 건너뜀 if (string.IsNullOrEmpty(line) || !line.Contains("=")) continue; // 줄에서 변수 이름과 값 추출 string[] parts = line.Split('='); string variableName = parts[0].Trim(); string variableValue = parts[1].Trim(); // 접두사 추출 및 나머지 이름을 카멜 표기법으로 변환 string[] nameParts = variableName.Split('_'); string prefix = nameParts[0]; string camelCaseName = ""; for (int j = 1; j < nameParts.Length; ++j) { camelCaseName += char.ToUpper(nameParts[j][0]) + nameParts[j].Substring(1).ToLower(); } // 새 프로토콜 메시지 생성 string protocolMessage = $"message {prefix}_{camelCaseName} {{\n}}"; // 생성된 프로토콜 메시지를 코드에 추가 generatedProtocolCode += protocolMessage + "\n"; // 클라이언트 핸들러 코드 생성 if (prefix.StartsWith('C')) { string clientHandlerCode = $"public static void {prefix}_{camelCaseName}Handler(PacketSession session, IMessage packet)\n{{\n {prefix}_{camelCaseName} {prefix.ToLower()}_{camelCaseName.ToLower()} = packet as {prefix}_{camelCaseName};\n // TODO\n}}\n"; generatedClientHandlerCode += clientHandlerCode + "\n"; } // 서버 핸들러 코드 생성 if (prefix.StartsWith('S')) { string serverHandlerCode = $"public static void {prefix}_{camelCaseName}Handler(PacketSession session, IMessage packet)\n{{\n {prefix}_{camelCaseName} {prefix.ToLower()}_{camelCaseName.ToLower()} = packet as {prefix}_{camelCaseName};\n // TODO\n}}\n"; generatedServerHandlerCode += serverHandlerCode + "\n"; } } // 생성된 코드를 입력 필드에 할당 mProtocolText = generatedProtocolCode; mClientHandlerText = generatedClientHandlerCode; mServerHandlerText = generatedServerHandlerCode; } } #endif
QueryDSL 내부 메소드 중 fetchResult() 나 fetchCount()는 만료된 메소드에 대해서는 QueryDSL에서 Blaze-persistence Integration 라이브러리 사용을 권장 하는데요, Blaze-persistence도 QueryDSL 처럼 쿼리 빌더 API 로서 개발자에게 유지보수하기 좋은 객체를 제공해주고 있습니다. 게다가 최신 업데이트 날짜가 글 작성일 기준(2023.06.21) 일주일 이전이라 여전히 유지보수되고 있어서 최신 스프링버전과 호환성도 어느정도 보장되었다고 볼 수 있습니다. 개인적으로 SpringBoot 3.1.0 기준으로 다음과 같이 세팅하니 정상적으로 동작하는 걸 확인했는데요, 혹시 저처럼 deprecated 메소드를 쓰는 것이 신경쓰이시는 분들을 위해 공유드립니다. build.gradle dependencies { //Blaze-Persistence implementation 'com.blazebit:blaze-persistence-integration-querydsl-expressions-jakarta:1.6.9' implementation 'com.blazebit:blaze-persistence-integration-hibernate-6.2:1.6.9' implementation 'com.blazebit:blaze-persistence-core-impl-jakarta:1.6.9' } BlazePersistenceConfiguration.java @Configuration public class BlazePersistenceConfiguration { @PersistenceUnit private EntityManagerFactory entityManagerFactory; @Bean @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) @Lazy(false) public CriteriaBuilderFactory createCriteriaBuilderFactory() { CriteriaBuilderConfiguration config = Criteria.getDefault(); // do some configuration return config.createCriteriaBuilderFactory(entityManagerFactory); } } QuerydslBasicTest.java ..... JPAQueryFactory queryFactory; @Autowired CriteriaBuilderFactory cbf; BlazeJPAQueryFactory blazeQueryFactory; @BeforeEach public void testEntity(){ queryFactory = new JPAQueryFactory(em); // 이건 동시성 문제를 고민하지 않아도 됨, 해결됨 blazeQueryFactory = new BlazeJPAQueryFactory(em, cbf); ..... 적용 결과 기존 QueryDSL 세팅한 것에 추가로 세팅하시면, 만료된 메소드에 대해 Blaze-persistence 객체로 대체되는데요, 기존 querydsl 클래스를 상속 받는 형태여서 QueryDSL이 제공하는 메소드를 그대로 쓸 수도 있습니다. fetchResults는 fetchPage로 바꿔서 사용할 것을 권장하고 있다는 점 참고하시면 될 것 같습니다. 추가로 내부로직이라든지 설명이 더 필요하시다면 Blaze-persistence 릴리즈 노트 와 Blaze Persistence Document 를 참고하시면 좋을 것 같습니다. 이 글에 대해 지적 및 피드백 해주시면 정말 감사하겠습니다. 감사합니다. 여담 및 고민 : 개인적으로 이 라이브러리의 내부로직을 뜯어보면서 분석하고 검증할 수 있는 역량은 부족한지라 분석 및 검증하는 방법에 대해서 팁이라든지, 아니면 blaze-persistence 사용할 시 주의해야할 점이라든지 조언해주실 수 있으시면 정말 감사드립니다. 강의를 듣던 중에 서브쿼리가 발생하는 부분에서는 정상동작하지 않는 것을 발견했습니다. @Test public void findUserDto(){ QMember memberSub = new QMember("memberSub"); List<UserDto> memberDtoList = queryFactory //이건 blazeQueryFactory가 정상 동작하지 않음 .select(Projections.fields(UserDto.class, //생성자 필드 순서에 맞게 변수를 만들어야 한다. member.username.as("name"), // member.age 대신 서브쿼리로 다 최대 나이로 찍고 싶어 ExpressionUtils.as( JPAExpressions .select(memberSub.age.max()) .from(memberSub), "age") )) .from(member) .fetch(); for (UserDto userDto : memberDtoList) { System.out.println("userDto = " + userDto); } } QueryDSL 쿼리 /* select member1.username as name, (select max(memberSub.age) from Member memberSub) as age from Member member1 */ select m1_0.username, (select max(m2_0.age) from member m2_0) from member m1_0 blaze-persistence 쿼리 /* SELECT member1.username AS name, member1.age AS generatedSubquery_1 FROM Member member1 */ select m1_0.username, m1_0.age from member m1_0 blaze-persistence generatedSubquery라 하여, 서브쿼리를 하나의 alias로 처리를 해버렸는데, 후행으로 이 generatedSubquery 에 대한 정의가 따라오질 않습니다... 왜 이런 차이가 나오는지는 모르겠지만 blaze-persistence 활용할 때는 유의해야할 것 같습니다.
[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part1: C# 기초 프로그래밍 입문
안녕하세요! 항상 좋은 강의 감사합니다. 게임 개발 중에서도 클라이언트 개발자가 되고 싶어서 관련된 질문을 드립니다! 클라이언트 개발자 관련해서 구글링을 해보니깐 제가 현재 공부하고 있는 것 외에도 컴퓨터 구조, 수학, 컴퓨터 그래픽스 등도 함께 공부해야 된다고 해서 어떤 걸 공부해야 하고 어떤 순서로 공부를 해야 되는지 방향성을 잡기 힘들어서 질문 드립니다! 현재는 c# 문법과 유니티 에디터 사용법을 공부하면서 간단한 퍼즐 게임과 같은 작은 규모의 게임을 기획하고 만들고 있습니다. c# 문법과 유니티 에디터 사용법 숙지가 어느정도 끝났다면 이어서 무엇을 공부하는 것이 좋을까요? 그리고 공부를 한다면 어떤 책과 강의를 통해서 공부하는 것이 좋을까요? 물론! 저는 루키스님 강의로 공부하고 싶습니다! ㅎㅎ 그리고 개인적으로 만들고 싶은 장르의 게임이 있어서 개인 프로젝트로 조금씩이라도 만들면서 학습을 병행해도 괜찮을까요? 공부 방향을 제대로 잡지 못한거 같아서 너무 혼란스럽네요 루키스님이 도와주셨으면 좋겠습니다! 항상 좋은 강의 감사합니다.
클리커 게임 강의의 코드를 보다가 프레임 워크 부분 코드가 기억이 안나고 이해가 힘들어 다시 강의를 보고 있습니다. 서버 같은 경우는 한강한강 이해 자체가 힘들어서 정리를 하면서 봤는데 완강까지 시간이 오래 걸렸어요. 유니티 강의 같은 경우는 볼 때는 나름 이해가 되어서 정리를 안하고 빨리 보는 것에 집중을 했는데 그래도 강의의 내용을 노트나 블로그에 정리를 하는게 나을까요? 아니면 생각 안나면 그냥 강의를 여러번 보는게 나을까요?
강의 파트를 1부터 7까지의 순서중 어떤 순서대로 수강을 하는게 수월한가요? 1-2-3-4의 순서로 강의를 들어보려했더니 1은 이해가 잘되었으나 2부터 갑자기 난이도가 엄청나게 올라가고 3은 다시 좀 쉬워졌다가 4는 아직 보지는 못했는데 난이도가 또 올라가더군요 5나 6은 좀 더 수월한 강의인것같구요. 뱀서강의를 보다가 좀 이해가 안되서 다시 이쪽 강의로 내려와서 3번부터 보고있습니다. 파트 1부터 7까지 차례로 공부하는것이 나을까요? 개발 흐름에 따라서라면 1부터 7이 근본인것같은데... 난이도로 따지면 파트순서가 아니니..고민입니다. 추천하는 순서가있으신가요?
강의를 정독해서 보고있는데 복붙부분이 많아서 이 부분을 직접 타이핑 해야하는지 아니면 복붙부분은 그냥 눈으로 읽고 이해하고 강의가 끝난후에 수강자료를 다운로드 받아서 복붙을 한다음에 분석을 하는 방식인지 어느쪽이 좋은지 모르겠습니다. 두가지 방식을 다 하다가 마지막에 강의 코드를 복붙하려고 했는데 어드레스블 강의코드부분만 복붙하려했는데 그 안에 오브젝트 풀링과 기타 배우지않은 부분까지 섞여서 이거 정리하는게 더 시간이 걸립니다. 어떻게 강의를 봐야 할까요? 해당강의에 해당 코드만 있으면 좋겠는데 멘토링을 참가하지 않은 저 같은 사람들은 따라가기가 좀 어려운것 같습니다.
함수에 대해 정의내릴 때 예를 들어 코랩 에서는 scaler = minmax_scale() 이렇게 정의를 내리고 scaler(data) 하는데 #코랩은 정의내릴 때 괄호를 빼면 동작안함 구름에서 테스트해보니까 scaler = minmax_scale()하고 scaler(data)하면 에러가 발생하고 괄호없이 scaler = minmax_scale 만해야 에러가 발생하지 않더라구요. 이게 구름 환경만의 특성이라서 그렇다고 보면 될까요?
안녕하세요 선생님. 우선 좋은 강의를 해주셔서 감사드립니다. 다름이 아니라 현재 섹션1,2 를 수강한 상태입니다. 섹션 1, 2를 수강하는데 수식이 굉장히 많이 등장하더라구요. 제가 수포자였어서 현재로썬 이해하는데 있어서 어려움이 많은 상태입니다.(지금은 열심히 공부하고 있습니다! 아무래도 딥러닝을 공부하는데 수학이 필수인거같아서) 그래서 작동 원리만 이해하고 우선은 넘어가는 방식으로 공부하려고 하는데 이렇게 해도 괜찮을까요?? 예를들면 경사하강법은 손실함수의 기울기가 적어지는 방향으로 학습하는 것이구나, 오차역전파는 미분을 거꾸로 하면서 가중치를 업데이트하는 것이구나, 손실함수는 이런게 있구나, 옵티마이저는 이런게 있구나 이렇게 작동하는구나 이런식으로요. 물론 언젠가는 반드시 다 이해해야겠지만 딥러닝입문자로써는 이렇게 이해만 하고 넘어가도 될까요??
[리뉴얼] 처음하는 파이썬 머신러닝 부트캠프 (쉽게! 실제 캐글 문제 풀며 정리하기) [데이터분석/과학 Part2]
train.corr().iplot(kind='heatmap', colorscale='Blues') 현재 위의 코드 수행시 에러가 발생하는데요. ValueError: could not convert string to float: 'Braund, Mr. Owen Harris' train 데이터프레임에서 문자열 데이터가 포함되어 있기 때문에 해당 에러가 발생할 수 있습니다. 이 경우, 상관 관계 행렬을 계산하기 전에 문자열 열을 제거해야합니다. 저의 경우 다음처럼 새로운 객체를 만들어 진행하였습니다. object_cols = train.select_dtypes(include=['object']).columns #열의 데이터 타입이 문자인녀석 추출 new_train = train.drop(columns=object_cols) # 열의 데이터가 문자열인 것들 제거 후 새로운 객체에 생성 new_train.corr().iplot(kind='heatmap', colorscale='Blues') 이러면 잘 나옵니다.
[리뉴얼] 처음하는 파이썬 머신러닝 부트캠프 (쉽게! 실제 캐글 문제 풀며 정리하기) [데이터분석/과학 Part2]
import plotly.io as pio pio.renderers.default='iframe' 다음 코드를 추가해주시면, iframe 을 통해 렌더링 됩니다. 저의 경우 다음 에러로 렌더링이 안됐습니다. ( F12 / Option+Command + i -> console 에서 확인 가능 .)
<강의 코드> transforms_for_train = transforms.Compose( [ transforms.Resize(feature_extractor.size), transforms.RandomHorizontalFlip(), transforms.ToTensor(), normalize, ] ) 강의 코드를 변경하지 않고 그대로 실행하면 아래와 같은 오류가 발생합니다 <오류 메시지> TypeError: Size should be int or sequence. Got <해결 방법> feature_extractor.size를 tuple(feature_extractor.size.values()) 로 변경한 뒤 실행합니다. transforms.Resize 내의 인자 뿐만 아니라 Crop 안의 인자도 함께 변경해주어야 합니다 transforms_for_train, transforms_for_val 모두 동일하게 변경한 뒤 실행하면 에러 없이 실행되는 것을 보실 수 있습니다.