전체 코드
더보기
# 필요한 라이브러리 불러오기
import tensorflow as tf
import numpy as np
import openai
import time
import google.generativeai as genai
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import random
# ✅ 1️⃣ Google AI API 설정 (API Key 필요)
genai.configure(api_key="API_KEY") # 발급받은 API 키 입력
def summarize_news(text):
"""Google Gemini AI를 사용하여 뉴스 내용을 요약하는 함수"""
model = genai.GenerativeModel("gemini-pro") # Gemini 모델 선택
response = model.generate_content(f"다음 뉴스를 요약해줘:\n\n{text}")
return response.text # 요약된 뉴스 반환
# ✅ 2️⃣ 학습된 모델 불러오기 (.h5 파일)
model_path = "C:/FakeNewsProject/FakeNews_py/ModelFolder/datatext_binary_model.h5" # 모델 파일 경로
model = tf.keras.models.load_model(model_path)
# ✅ 3️⃣ 예측할 뉴스 텍스트 입력
news_texts = [
"""
뉴진스 멤버들의 부모들은 12일 "하니는 적법한 절차를 통해 11일 새로운 비자를 발급받았다"고 밝혔다.
호주 베트남 이중국적자인 하니는 예술흥행(E-6) 비자로 활동해왔다. 그러나 이달 초 비자가 만료됨에 따라 체류 자격을 두고 여러가지 설이 제기됐다.
그러던 중 어도어가 하니에게 비자 연장 서류를 준비해줬으나 하니가 사인을 거절했다는 보도가 나왔다. 이에 멤버들의 부모들이 직접 입장을 밝힌 것.
부모들은 "어도어는 어도어를 소속사로 기재한 연장 동의서에 서명을 요구하며 동의하지 않으면 불법 체류가 될 수 있다는 메일을 보내는 등 국내 거주 외국인으로는 민감할 수 밖에 없는 '비자'문제를 빌미로 부모와 당사자에게 압박을 가했다.
심지어, 동의 없이 개인정보와 본인서명이 필요한 서류를 관련 기관에 멋대로 제출하고 추후 통보하는 등 상식적으로 이해되지 않은 행동을 보였다. '당사자'가 아니면 현재 멤버들의 개인정보를 알고 있는 '어도어'만이 줄 수 있는 정보가 언론을 통해 무분별하게 확산되었다는 점에 심각한 유감을 표한다"고 주장했다.
이어 "이전에도 멤버 개개인의 개인정보를 사용하여 출입국 내용을 알아내는 등 상황이 점점 더 심각해지고 있어, 멤버들을 보호하기 위해 관련 법적 대응을 고려하고 있다"고 덧붙였다.
""",
"""
강원도 속초경찰서는 3월 31일 오전 6시 30분경에 경기도 부천에 거주하는 설악산 관광 가이드 김 모(45) 씨의 설명을 듣다가 중요지방문화재 37호 '흔들바위' 를 밀어 떨어뜨린 미국인 관광객 제럴드(42) 등 일행 11명에 대해 문화재 훼손 혐의와 문화재보호법 위반 혐의로 입건했다.
이들 일행은 이날 새벽 5시 일출 관광을 마친 뒤 흔들바위 관광을 하면서 "이 바위는 아무리 흔들어도 흔들리기만 할 뿐 떨어지지는 않는다"는 가이드 김 씨의 말에 따라 평균 체중 89Kg의 거구인 11명이 힘껏 밀어낸 끝에 바위를 추락시켰다.
그러나 이들 일행은 경찰에서 "가이드의 말이 말도 안 되는 소리라 생각해 밀어본 것일 뿐 다른 의도는 없었다"며 범행의 고의성을 완강히 부인했다.
주한 미군 근무 경험이 있는 미국 애리조나주 출신의 도널드 씨는 역도 코치 등을 하는 애리조나 주립체육연맹 회원 10명과 함께 지난 주 일주일 관광 예정으로 입국한 것으로 알려졌다.
이에 따라 소식을 접한 문화관광부와 강원도청은 대책 마련에 부심하고 있다. 근처에서 관광 중이던 일부 목격자들의 증언에 따르면 '흔들바위'는 추락시 "뻥!!!" 하는 엄청난 굉음을 냈던 것으로 알려졌다.
""",
"""
잠실·삼성·대치·청담동(잠삼대청) 아파트 상당수에 '갭투자(전세 끼고 매매)'가 가능해진 만큼 부동산 시장 침체 상황에서도 이곳엔 수요가 몰릴 가능성이 제기된다. 다만 토지거래허가구역(토허제) 해제로 인해 기대감이 한풀 꺾여 큰 가격 상승은 없을 것이란 반론도 있다.
12일 서울시는 제2차 도시계획위원회를 열고 토허제 지정을 해제하는 토허제 조정(안)을 승인했다.
구체적으로 국제교류복합지구 인근 잠삼대청 4개 동 내 305개 아파트 중 291개가 해제됐다. 안전진단을 통과한 재건축 아파트 14곳만 투기 과열 가능성이 있다는 이유로 토허제 지정이 유지됐다.
토허제 해제가 불러오는 가장 큰 변화는 해당 지역에서 갭투자가 가능해진다는 점이다. 토허제는 일정 규모 이상 주택·상가·토지 등을 거래할 때 관할 구청장으로터 사전허가를 받게 하는 제도다. 주택은 2년간 실거주 목적 매매만 허용해 갭투자가 불가능했다.
전문가들은 특히 잠실의 '엘리트(엘스·리센츠·트리지움)' 등 아직 재건축과 무관한 아파트들에 투자 수요가 늘어날 수 있다고 분석했다. 이곳의 경우 오세훈 서울시장이 지난달 14일 열린 시민 대토론회에서 "특단의 조치로 행해졌던 토지거래허가구역을 해제하는 방안을 상당히 적극적으로 검토하고 있고 조만간 발표하겠다"고 밝힌 후 매수 문의가 확 늘어났다.
한국부동산원이 발표한 주간 아파트 가격 동향에 따르면 2월 첫째 주 기준 서울 집값은 6주 만에 보합에서 0.02% 상승 전환했는데 이 중에서도 송파(0.13%)의 상승폭이 두드러졌다. 실제로 서울 부동산 시장이 조용한 상황에서도 '트리지움' 전용 59㎡(16층)는 지난달 15일에 22억5500만원에 거래되며 신고가를 경신하기도 했다.
함영진 우리은행 부동산리서치랩장은 "토허제가 풀린 지역의 아파트는 지금보다 호가가 더 뛰고 매도자가 우위에 서게 될 것"이라며 "주춤했던 거래량도 살아날 가능성이 있다"고 설명했다.
토허제 해제 지역의 신축아파트를 중심으로 가격과 거래량 모두 늘어날 수 있다는 분석도 있다. 똘똘한 한 채와 상대적으로 신축이라는 투자 선호 조건을 동시에 만족시키는 곳들이기 때문이다. 구체적으로 강남구 대치동의 '래미안대치팰리스'와 청담동의 '청담자이' 등이 꼽힌다.
반면 토허제 해제가 이뤄지면 기존에 쌓였던 기대감이 해소돼 추가적인 아파트 가격 상승은 없을 것이란 목소리도 있다. 김인만 김인만부동산경제연구소장은 "오 시장의 토허제 해제 발언 이후 잠실 아파트 호가가 30억원까지 오르기도 했다"면서 "그 가격이면 서초구 등 다른 지역 투자도 가능해 높아진 호가만큼 실거래가 이뤄지지는 않을 수 있다"고 내다봤다.
그러면서 그는 "GTX(수도권 광역급행철도) 호재 지역 아파트도 개통 이전에 가격이 오르고 수요가 몰렸다가 실제 개통 이후에는 집값 상승이 두드러지지 않았다"고 부연했다.
토허제 해제가 되지 않은 지역도 당장 눈에 띄는 변화는 없겠지만 향후 해제 기대감에 꾸준히 수요가 유입될 것이란 분석도 있다. 한 부동산업계 관계자는 "토허제가 유지된 지역 아파트는 당장 갭투자가 가능하지 않으니 이전과 크게 달라지는 점은 없을 것"이라면서도 "이미 인기가 있는 동네인 만큼 꾸준한 수요는 있을 것"이라고 말했다.
""",
"""
지난 12일 제주 해상에서 발생한 어선 전복사고로 5명이 실종된 가운데 해경이 실종자를 찾기 위한 수색 작업에 집중하고 있다.
13일 서귀포해양경찰서에 따르면 전날 오후 7시56분께 서귀포시 표선면 남서쪽 12km 해상에서 서귀포 선적 근해연승 어선 2066재성호(32t, 승선원 10명)가 전복되는 사고가 났다.
사고 현장에 출동한 해경에 의해 한국인 선장 등 5명이 구조됐으나 나머지 5명은 실종된 상태다. 이에 해경은 실종자를 찾기 위한 주·야간 수색에 총력을 다하고 있다.
다만 전날부터 이날 오전 9시까지 진행된 수색에서는 특이점이 발견되지 않았다. 이날 오전 10시부터는 사고 현장에서 해수면 위로 보이는 선체 위에서 리프트백을 설치하는 작업이 이뤄지고 있다.
특히 해경은 동원 가능한 잠수 인력을 전원 투입해 전복된 선체 내부에 대한 집중 수색도 벌이고 있다.
하지만 사고 해역 인근은 풍랑주의보가 내려진 상황으로, 순간풍속 초속 16~18m의 태풍급 강풍과 3.5m에 달하는 파도가 일고 있어 수색이 쉽지 않은 상황으로 전해졌다.
무엇보다 악기상 속 수색에 나선 해경 구조대원 2명이 다쳐 치료를 받고 있는 것으로 알려졌다.
""",
"""
미국 항공우주국(NASA)은 최근 달 뒷면에서 외계 생명체의 흔적을 발견했다고 공식 발표했다. NASA의 루나 익스플로러 탐사선은 지난 1월 말, 달 뒷면을 탐사하던 중 기이한 구조물과 생체 흔적을 감지했다고 보고했다.
NASA 연구원 제임스 핸더슨 박사는 기자회견에서 "이 구조물은 자연적으로 형성될 가능성이 낮다. 현재로서는 고등 지적 생명체가 만든 것일 수도 있다는 가능성을 배제할 수 없다"고 밝혔다.
이에 따라 미국 정부는 긴급 국가안보회의를 개최했으며, 향후 몇 주 내에 전 세계 과학자들과 협력해 추가 탐사를 진행할 예정이라고 밝혔다.
한편, 전 세계 네티즌들은 이번 발표를 두고 "외계 생명체의 존재가 드디어 밝혀지는 순간이다"라며 뜨거운 반응을 보이고 있다.
""",
"""
연초 식품업체들의 가격 인상이 이어지면서 가공식품 물가가 1년 만에 가장 큰 폭으로 오른 것으로 나타났다. 원재료 가격이 오르는 데다 고환율 상황까지 겹치면서 물가 상승 압력은 더 커지고 있다.
13일 통계청 국가통계포털(KOSIS)와 소비자물가동향에 따르면 지난 1월 가공식품 물가지수는 122.03으로 전년동기대비 2.7% 올랐다. 이는 지난해 1월(3.2%) 이후 가장 높은 상승률로, 전체 소비자물가상승률(2.2%)를 웃돌았다. 가공식품 물가상승률은 지난해 하반기까지는 2.0% 이하로 비교적 안정세였으나 최근 크게 올랐다.
지난달 가공식품 중 가장 크게 오른 품목은 오징어채(22.9%)였다. 이어 맛김(22.1%), 김치(17.5%) 시리얼(14.7%), 유산균(13.0%), 초콜릿(11.2%) 순이었다.
조미료류도 크게 올랐다. 참기름(8.9%), 간장(8.8%), 식용유(7.8%) 등이 7~8%대 상승률을 보였다. 밀가루를 원료로하는 가공식품 가격도 올랐다. 비스킷(7.0%) 케이크(3.3%), 빵(3.2%)가 대표적이다.
식품업체들은 올해들어 제품 가격을 대대적으로 올리고 있다. 동아오츠카는 지난달 1일 포카리스웨트 등 주요제품 가격을 100원 올렸다. 대상도 지난달 16일부터 마요네즈 후추 등 소스류 가격을 평균 19.1% 올렸다. SPC 파리바게뜨는 지난 10일부터 빵 96종과 케이크 25종 가격을 평균 5.9% 인상한다고 밝혔다. 롯데 웰푸드도 오는 17일 부터 초코 빼빼로 등 26종 가격을 평균 9.5% 인상한다.
식품업계는 원재료값과 부대비용이 올라 가격 인상이 불가피하다는 입장이다. 맛김의 원재료인 김 원초 가격이 높은 수준이고, 김치에 쓰이는 배추도 작황 부진으로 가격이 치솟았다. 기후변화로 코코아, 커피 원두 가격도 크게 올랐다. 1400원을 웃도는 원/달러 환율도 물가상승 요인이다. 식재료를 대부분 수입에 의존하는 식품업체로서는 원가 압박이 커지는 셈이다.
통계청 관계자는 “원/달러 환율 상승이 1월 가공식품 물가에도 일부 영향을 미쳤으나 앞으로 시차를 두고 더 반영될 것”이라고 했다.
"""
]
random.shuffle(news_texts)
# ✅ 4️⃣ 뉴스 요약 수행 (Google AI 사용)
summarized_news_texts = [summarize_news(text) for text in news_texts]
# ✅ 5️⃣ Tokenizer를 사용하여 텍스트를 숫자로 변환
tokenizer = Tokenizer(num_words=5000) # 최대 단어 개수 설정
tokenizer.fit_on_texts(summarized_news_texts) # 요약된 텍스트 학습
# 텍스트를 숫자로 변환
sequences = tokenizer.texts_to_sequences(summarized_news_texts)
# ✅ 6️⃣ 입력 크기에 맞게 패딩 추가 (최대 길이 조정)
max_length = 10000 # ⚠ 모델에 맞게 조정하세요.
processed_input = pad_sequences(sequences, maxlen=max_length, padding="post")
# ✅ 7️⃣ 모델로 예측 수행
prediction = model.predict(processed_input)
is_fake = (prediction > 0.5).astype(int).flatten() # 0.5 기준으로 판별 모델이 자동으로 모든 뉴스 예측 → 0.6로 올림
# ✅ 8️⃣ 성능 평가 (정확도를 실제 모델 예측값을 기반으로 계산)
true_labels = np.array([0, 1, 0, 0, 1, 0]) # 실제 정답 (0: 진짜 뉴스, 1: 가짜 뉴스)
# 성능 평가 지표 계산
accuracy = accuracy_score(true_labels, is_fake)
precision = precision_score(true_labels, is_fake)
recall = recall_score(true_labels, is_fake)
f1 = f1_score(true_labels, is_fake)
# --------------------------------------------------------------------
# 확률 보정 함수(너무 작은 값은 올리고, 너무 큰 값은 낮춤)
def adjust_probabilities(pred, alpha = 0.2):
return (1 - alpha) * pred + alpha * 0.5
# 모델의 원본 예측값
raw_predictions = np.array([0.33028343, 0., 0., 0., 0., 1.])
# 조정된 확률값 적용
adjusted_predictions = adjust_probabilities(raw_predictions)
print("조정된 확률값: ", adjusted_predictions)
# --------------------------------------------------------------------
# ✅ 성능 분석 결과 출력 (저장 X)
print(f"🎯 모델 성능 평가 (값 저장 없이 출력만)")
print(f"✅ 정확도 (Accuracy): {accuracy:.2f}")
print(f"✅ 정밀도 (Precision): {precision:.2f}")
print(f"✅ 재현율 (Recall): {recall:.2f}")
print(f"✅ F1-score: {f1:.2f}")
print("🔍 모델 원본 예측값 확인:")
print(prediction.flatten())
print(prediction)
print("-" * 50)
# ✅ 개별 예측 결과 출력 (값 저장 없이 출력만)
for i, (original_text, summary) in enumerate(zip(news_texts, summarized_news_texts)):
print(f"🔹 원본 뉴스 {i+1}: {original_text[:100]}...\n") # 너무 길면 앞부분만 출력
print(f"🔸 요약된 뉴스: {summary[:100]}...\n")
# 예측 확률값을 함께 출력
for i, prob in enumerate(prediction.flatten()):
print(f"⚖ 판별 결과: {'⚠ 가짜 뉴스' if is_fake[i] else '✔ 진짜 뉴스'} (확률: {prob:.2%})")
print("-" * 50)
# ✅ 9️⃣ 결과 출력
for i, (original_text, summary) in enumerate(zip(news_texts, summarized_news_texts)):
print(f"🔹 원본 뉴스: {original_text}\n")
print(f"🔸 요약된 뉴스: {summary}\n")
print(f"⚖ 판별 결과: {'⚠ 가짜 뉴스' if is_fake[i] else '✔ 진짜 뉴스'}")
print("-" * 50)
# 성능 지표 시각화
labels = ["Accuracy", "Precision", "Recall", "F1-score"]
scores = [accuracy, precision, recall, f1]
plt.bar(labels, scores)
plt.ylim(0, 1)
plt.title("Fake News Detection Model Performance")
plt.ylabel("Score")
plt.show()
흐름
1. Google AI API 및 모델 불러오기
- `google.generativeai` 설정 → `genai.configure(api_key=...)`
- 사전 학습된 모델 불러오기 → `tf.keras.models.load_model(model_path)`
2. 뉴스 요약 기능
- Google Gemini AI를 활용해 뉴스 요약 수행(`summarize_news()` 함수)
3. 뉴스 데이터 준비 및 랜덤 섞기
- 여러 개의 뉴스 기사 리스트(`news_texts`) 준비
- `random.suffle(news_texts)`로 랜덤하게 섞음
4. 뉴스 요약 및 전처리
- `summarize_news()`를 사용해 각 뉴스 기사를 요약
- `Tokenizer`를 이용해 단어 인덱싱
- 요약된 뉴스 텍스트를 토큰 시퀀스로 변환
- 모델 입력 크기에 맞춰 패딩(`pad_sequences`) 적용
5. 모델 예측 수행
- `model.predict()`를 사용하여 예측값 도출
- 예측값이 0(진짜 뉴스)인지 1(가짜 뉴스)인지 확인
6. 예측값 보정(확률 조정)
- 너무 극단적인 확률을 방지하기 위해 조정 함수(`adjust_probabilities`) 적용
7. 가짜 뉴스 판별 및 설명(LIME 사용)
- 요약된 뉴스와 원본 뉴스를 함께 출력
- 예측된 확률값(`prob`)을 확인하고 0.5 초과 시 "가짜 뉴스" 판정
- `LimeTextExplainer`를 사용하여 가짜 뉴스 근거 키워드 제공(예외 처리 포함)
8. 성능 평가
- 실제 정답(`true_labels`)과 모델 예측값 비교
- 정확도(Accuracy), 정밀도(Precision), 재현율(Recall), F1-score 측정
- `accuracy_score`, `precision_score`, `recall_score`, `f1_score`를 사용해 평가
9. 성능 지표 시각화
- 성능 지표를 바(bar) 그래프로 출력
- `matplotlib.pyplot`을 활용해 시각화
개선점
1. 예외 처리 강화
- `genai.GenerativeModel("gemini-pro")`를 사용할 때, API 응답 실패나 지연이 발생할 경우를 대비한 예외 처리가 필요합니다.
- 모델 로드 및 예측 단계에서도 예외 처리를 추가하면 코드 안정성이 높아집니다.
# ✅ 뉴스 요약 수행
def summarize_news(text):
"""Google Gemini AI를 사용하여 뉴스 내용을 요약하는 함수"""
try:
model = genai.GenerativeModel("gemini-pro")
response = model.generate_content(f"다음 뉴스를 요약해줘:\n\n{text}")
return response.text if response else "요약 실패"
except Exception as e:
print(f"⚠ 뉴스 요약 중 오류 발생: {e}")
return "요약 실패"
2. 뉴스 데이터에서 중복 제거
- `random.shuffle(news_texts)`를 사용하지만, 동일한 뉴스가 여러 번 등장할 가능성이 있어 중복 제거하는 코드 추가
news_texts = list(set(news_texts)) # 중복 제거
random.shuffle(news_texts)
3. 모델 입력 크기 자동 조정
- 현재 `max_length = 10000`으로 고정되어 있는데, 뉴스 요약 길이에 맞춰 최대 길이를 동적으로 설정하면 더 유연하게 동작할 수 있습니다.
# ⚠ 모델 입력 크기에 맞게 수정
max_length = max(len(seq) for seq in tokenizer.texts_to_sequences(summarized_news_texts)) # 최대 길이 자동 계산
processed_input = pad_sequences(sequences, maxlen=max_length, padding="post")
4. LIME 분석에서 긴 뉴스일 경우 요약 활용
- 현재 LIME 분석이 원본 뉴스(`original_text`)를 기반으로 진행되는데, 뉴스 길이가 길 경우 요약된 뉴스(`summary`)를 사용하는 것이 더 적절할 수 있습니다.
# ✅ 결과 출력
for i, (original_text, summary, prob) in enumerate(zip(news_texts, summarized_news_texts, adjusted_predictions)):
print(f"🔹 원본 뉴스 {i+1}: {original_text[:100]}...\n") # 앞부분만 출력
print(f"🔸 요약된 뉴스: {summary[:100]}...\n")
print(f"⚖ 판별 결과: {'⚠ 가짜 뉴스' if prob > 0.5 else '✔ 진짜 뉴스'} (확률: {prob:.2%})")
# LIME 분석 시 요약된 뉴스 사용(긴 뉴스 처리) # 추가된 코드
lime_text = summary if len(summary) < 300 else original_text[:300]
# ✅ LIME 예외 처리 (모델이 1을 예측한 경우에만 실행)
if prob > 0.5:
try:
exp = explainer.explain_instance(original_text, predict_proba, num_features=6)
important_features = exp.as_list()
print("🔍 근거 키워드: " + ", ".join(['"{}"'.format(word) for word, weight in important_features]))
except IndexError:
print("⚠ LIME 오류 발생: 모델이 1(가짜 뉴스) 클래스를 예측하지 않음.")
else:
print("✔ 진짜 뉴스로 판별됨. LIME 분석 생략.")
print("=" * 50)
5. 데이터 불균형 해결(Threshold 조정) (보류)
- 현재는 `prob > 0.5`를 기준으로 가짜 뉴스를 판별하는데, 데이터 불균형이 있다면 `threshold` 값을 조정하여 성능을 개선할 수 있습니다.
threshold = 0.6 # 가짜 뉴스 판별 기준 상향 조정 (기본값 0.5에서 조정 가능)
is_fake = (adjusted_predictions > threshold).astype(int)
'Project > 가짜 뉴스 판별 AI' 카테고리의 다른 글
| 가짜 뉴스 판별 AI 개선하려다가 실패 (0) | 2025.02.17 |
|---|---|
| 가짜 뉴스 판별 AI 만들기 - 전략 변경 추가(실패 및 수정) (0) | 2025.02.14 |
| 가짜 뉴스 판별 AI 만들기 - 전략 변경(실패) (0) | 2025.02.13 |
| KoELECTRA 모델 이용하여 가짜 뉴스 탐지 AI 만들기 - 실패 (1) | 2025.02.12 |
| 네이버 뉴스 크롤링 및 가짜 뉴스 판별 (0) | 2025.02.10 |